sui_crypto/
secp256r1.rs

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