sui_crypto/
secp256k1.rs

1use crate::SignatureError;
2use k256::ecdsa::SigningKey;
3use k256::ecdsa::VerifyingKey;
4use k256::elliptic_curve::group::GroupEncoding;
5use signature::Signer;
6use signature::Verifier;
7use sui_sdk_types::Secp256k1PublicKey;
8use sui_sdk_types::Secp256k1Signature;
9use sui_sdk_types::SignatureScheme;
10use sui_sdk_types::SimpleSignature;
11use sui_sdk_types::UserSignature;
12
13#[derive(Clone)]
14pub struct Secp256k1PrivateKey(SigningKey);
15
16impl std::fmt::Debug for Secp256k1PrivateKey {
17    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
18        f.debug_tuple("Secp256k1PrivateKey")
19            .field(&"__elided__")
20            .finish()
21    }
22}
23
24#[cfg(test)]
25impl proptest::arbitrary::Arbitrary for Secp256k1PrivateKey {
26    type Parameters = ();
27    type Strategy = proptest::strategy::BoxedStrategy<Self>;
28    fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
29        use proptest::strategy::Strategy;
30
31        proptest::arbitrary::any::<[u8; Self::LENGTH]>()
32            .prop_filter_map("invalid secp256k1 private key", |bytes| {
33                Self::new(bytes).ok()
34            })
35            .boxed()
36    }
37}
38
39impl Secp256k1PrivateKey {
40    /// The length of an secp256k1 private key in bytes.
41    pub const LENGTH: usize = 32;
42
43    pub fn new(bytes: [u8; Self::LENGTH]) -> Result<Self, SignatureError> {
44        SigningKey::from_bytes(&bytes.into()).map(Self)
45    }
46
47    pub fn scheme(&self) -> SignatureScheme {
48        SignatureScheme::Secp256k1
49    }
50
51    pub fn verifying_key(&self) -> Secp256k1VerifyingKey {
52        let verifying_key = self.0.verifying_key();
53        Secp256k1VerifyingKey(*verifying_key)
54    }
55
56    pub fn public_key(&self) -> Secp256k1PublicKey {
57        Secp256k1PublicKey::new(self.0.verifying_key().as_ref().to_bytes().into())
58    }
59
60    pub fn generate<R>(mut rng: R) -> Self
61    where
62        R: rand_core::RngCore + rand_core::CryptoRng,
63    {
64        Self(SigningKey::random(&mut rng))
65    }
66
67    #[cfg(feature = "pem")]
68    #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
69    /// Deserialize PKCS#8 private key from ASN.1 DER-encoded data (binary format).
70    pub fn from_der(bytes: &[u8]) -> Result<Self, SignatureError> {
71        k256::pkcs8::DecodePrivateKey::from_pkcs8_der(bytes)
72            .map(Self)
73            .map_err(SignatureError::from_source)
74    }
75
76    #[cfg(feature = "pem")]
77    #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
78    /// Serialize this private key as DER-encoded PKCS#8
79    pub fn to_der(&self) -> Result<Vec<u8>, SignatureError> {
80        use k256::pkcs8::EncodePrivateKey;
81
82        self.0
83            .to_pkcs8_der()
84            .map_err(SignatureError::from_source)
85            .map(|der| der.as_bytes().to_owned())
86    }
87
88    #[cfg(feature = "pem")]
89    #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
90    /// Deserialize PKCS#8-encoded private key from PEM.
91    pub fn from_pem(s: &str) -> Result<Self, SignatureError> {
92        k256::pkcs8::DecodePrivateKey::from_pkcs8_pem(s)
93            .map(Self)
94            .map_err(SignatureError::from_source)
95    }
96
97    #[cfg(feature = "pem")]
98    #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
99    /// Serialize this private key as PEM-encoded PKCS#8
100    pub fn to_pem(&self) -> Result<String, SignatureError> {
101        use pkcs8::EncodePrivateKey;
102
103        self.0
104            .to_pkcs8_pem(pkcs8::LineEnding::default())
105            .map_err(SignatureError::from_source)
106            .map(|pem| (*pem).to_owned())
107    }
108
109    #[cfg(feature = "pem")]
110    pub(crate) fn from_k256(private_key: SigningKey) -> Self {
111        Self(private_key)
112    }
113}
114
115impl Signer<Secp256k1Signature> for Secp256k1PrivateKey {
116    fn try_sign(&self, message: &[u8]) -> Result<Secp256k1Signature, SignatureError> {
117        let signature: k256::ecdsa::Signature = self.0.try_sign(message)?;
118        Ok(Secp256k1Signature::new(signature.to_bytes().into()))
119    }
120}
121
122impl Signer<SimpleSignature> for Secp256k1PrivateKey {
123    fn try_sign(&self, msg: &[u8]) -> Result<SimpleSignature, SignatureError> {
124        <Self as Signer<Secp256k1Signature>>::try_sign(self, msg).map(|signature| {
125            SimpleSignature::Secp256k1 {
126                signature,
127                public_key: self.public_key(),
128            }
129        })
130    }
131}
132
133impl Signer<UserSignature> for Secp256k1PrivateKey {
134    fn try_sign(&self, msg: &[u8]) -> Result<UserSignature, SignatureError> {
135        <Self as Signer<SimpleSignature>>::try_sign(self, msg).map(UserSignature::Simple)
136    }
137}
138
139#[derive(Debug, Clone, Eq, PartialEq)]
140pub struct Secp256k1VerifyingKey(VerifyingKey);
141
142impl Secp256k1VerifyingKey {
143    pub fn new(public_key: &Secp256k1PublicKey) -> Result<Self, SignatureError> {
144        VerifyingKey::try_from(public_key.inner().as_ref()).map(Self)
145    }
146
147    pub fn public_key(&self) -> Secp256k1PublicKey {
148        Secp256k1PublicKey::new(self.0.as_ref().to_bytes().into())
149    }
150
151    #[cfg(feature = "pem")]
152    #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
153    /// Deserialize public key from ASN.1 DER-encoded data (binary format).
154    pub fn from_der(bytes: &[u8]) -> Result<Self, SignatureError> {
155        k256::pkcs8::DecodePublicKey::from_public_key_der(bytes)
156            .map(Self)
157            .map_err(SignatureError::from_source)
158    }
159
160    #[cfg(feature = "pem")]
161    #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
162    /// Serialize this public key as DER-encoded data
163    pub fn to_der(&self) -> Result<Vec<u8>, SignatureError> {
164        use pkcs8::EncodePublicKey;
165
166        self.0
167            .to_public_key_der()
168            .map_err(SignatureError::from_source)
169            .map(|der| der.into_vec())
170    }
171
172    #[cfg(feature = "pem")]
173    #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
174    /// Deserialize public key from PEM.
175    pub fn from_pem(s: &str) -> Result<Self, SignatureError> {
176        k256::pkcs8::DecodePublicKey::from_public_key_pem(s)
177            .map(Self)
178            .map_err(SignatureError::from_source)
179    }
180
181    #[cfg(feature = "pem")]
182    #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
183    /// Serialize this public key into PEM
184    pub fn to_pem(&self) -> Result<String, SignatureError> {
185        use pkcs8::EncodePublicKey;
186
187        self.0
188            .to_public_key_pem(pkcs8::LineEnding::default())
189            .map_err(SignatureError::from_source)
190    }
191
192    #[cfg(feature = "pem")]
193    pub(crate) fn from_k256(verifying_key: VerifyingKey) -> Self {
194        Self(verifying_key)
195    }
196}
197
198impl Verifier<Secp256k1Signature> for Secp256k1VerifyingKey {
199    fn verify(&self, message: &[u8], signature: &Secp256k1Signature) -> Result<(), SignatureError> {
200        let signature = k256::ecdsa::Signature::from_bytes(signature.inner().into())?;
201        self.0.verify(message, &signature)
202    }
203}
204
205impl Verifier<SimpleSignature> for Secp256k1VerifyingKey {
206    fn verify(&self, message: &[u8], signature: &SimpleSignature) -> Result<(), SignatureError> {
207        let SimpleSignature::Secp256k1 {
208            signature,
209            public_key,
210        } = signature
211        else {
212            return Err(SignatureError::from_source("not a secp256k1 signature"));
213        };
214
215        if public_key.inner() != self.public_key().inner() {
216            return Err(SignatureError::from_source(
217                "public_key in signature does not match",
218            ));
219        }
220
221        <Self as Verifier<Secp256k1Signature>>::verify(self, message, signature)
222    }
223}
224
225impl Verifier<UserSignature> for Secp256k1VerifyingKey {
226    fn verify(&self, message: &[u8], signature: &UserSignature) -> Result<(), SignatureError> {
227        let UserSignature::Simple(signature) = signature else {
228            return Err(SignatureError::from_source("not a secp256k1 signature"));
229        };
230
231        <Self as Verifier<SimpleSignature>>::verify(self, message, signature)
232    }
233}
234
235#[derive(Default, Clone, Debug)]
236pub struct Secp256k1Verifier {}
237
238impl Secp256k1Verifier {
239    pub fn new() -> Self {
240        Self {}
241    }
242}
243
244impl Verifier<SimpleSignature> for Secp256k1Verifier {
245    fn verify(&self, message: &[u8], signature: &SimpleSignature) -> Result<(), SignatureError> {
246        let SimpleSignature::Secp256k1 {
247            signature,
248            public_key,
249        } = signature
250        else {
251            return Err(SignatureError::from_source("not a secp256k1 signature"));
252        };
253
254        let verifying_key = Secp256k1VerifyingKey::new(public_key)?;
255
256        verifying_key.verify(message, signature)
257    }
258}
259
260impl Verifier<UserSignature> for Secp256k1Verifier {
261    fn verify(&self, message: &[u8], signature: &UserSignature) -> Result<(), SignatureError> {
262        let UserSignature::Simple(signature) = signature else {
263            return Err(SignatureError::from_source("not a secp256k1 signature"));
264        };
265
266        <Self as Verifier<SimpleSignature>>::verify(self, message, signature)
267    }
268}
269
270#[cfg(test)]
271mod test {
272    use super::*;
273    use crate::SuiSigner;
274    use crate::SuiVerifier;
275    use sui_sdk_types::PersonalMessage;
276    use test_strategy::proptest;
277
278    #[cfg(target_arch = "wasm32")]
279    use wasm_bindgen_test::wasm_bindgen_test as test;
280
281    // TODO need to export proptest impl from core crate
282    // #[proptest]
283    // fn transaction_signing(signer: Secp256k1PrivateKey, transaction: Transaction) {
284    //     let signature = signer.sign_transaction(&transaction).unwrap();
285    //     let verifier = signer.public_key();
286    //     verifier
287    //         .verify_transaction(&transaction, &signature)
288    //         .unwrap();
289    // }
290
291    #[proptest]
292    fn personal_message_signing(signer: Secp256k1PrivateKey, message: Vec<u8>) {
293        let message = PersonalMessage(message.into());
294        let signature = signer.sign_personal_message(&message).unwrap();
295        let verifying_key = signer.verifying_key();
296        verifying_key
297            .verify_personal_message(&message, &signature)
298            .unwrap();
299
300        let verifier = Secp256k1Verifier::default();
301        verifier
302            .verify_personal_message(&message, &signature)
303            .unwrap();
304    }
305
306    #[test]
307    fn personal_message_signing_fixture() {
308        let key = [
309            172, 12, 96, 180, 207, 143, 111, 151, 81, 57, 242, 89, 74, 5, 150, 51, 56, 111, 245,
310            150, 182, 30, 149, 178, 29, 255, 188, 27, 48, 241, 151, 193,
311        ];
312
313        let signer = Secp256k1PrivateKey::new(key).unwrap();
314
315        let message = PersonalMessage(b"hello".into());
316        let sig = signer.sign_personal_message(&message).unwrap();
317        let external_sig = "AVFAWGjuD8+xUoc6jMC0lKqMtT+4ukln7vz+8Nuv+EbYKl47jwzOWn39maDsqu81kezLPgLzz6o/AfSE0M9+jVwClcrtiuyUggEt/6CEZi8+JQ+NS9TmOhPBZV2X1KjhGCw=";
318        let b64 = sig.to_base64();
319        assert_eq!(external_sig, b64);
320    }
321}