Skip to main content

sui_crypto/
simple.rs

1use crate::SignatureError;
2use signature::Verifier;
3use sui_sdk_types::SimpleSignature;
4use sui_sdk_types::UserSignature;
5
6pub struct SimpleVerifier;
7
8impl Verifier<SimpleSignature> for SimpleVerifier {
9    #[allow(unused_variables)]
10    fn verify(&self, message: &[u8], signature: &SimpleSignature) -> Result<(), SignatureError> {
11        match signature {
12            #[cfg(feature = "ed25519")]
13            SimpleSignature::Ed25519 {
14                signature,
15                public_key,
16            } => {
17                let verifying_key = crate::ed25519::Ed25519VerifyingKey::new(public_key)?;
18                verifying_key.verify(message, signature)
19            }
20            #[cfg(not(feature = "ed25519"))]
21            SimpleSignature::Ed25519 { .. } => Err(SignatureError::from_source(
22                "support for ed25519 is not enabled",
23            )),
24            #[cfg(feature = "secp256k1")]
25            SimpleSignature::Secp256k1 {
26                signature,
27                public_key,
28            } => {
29                let verifying_key = crate::secp256k1::Secp256k1VerifyingKey::new(public_key)?;
30                verifying_key.verify(message, signature)
31            }
32            #[cfg(not(feature = "secp256k1"))]
33            SimpleSignature::Secp256k1 { .. } => Err(SignatureError::from_source(
34                "support for secp256k1 is not enabled",
35            )),
36            #[cfg(feature = "secp256r1")]
37            SimpleSignature::Secp256r1 {
38                signature,
39                public_key,
40            } => {
41                let verifying_key = crate::secp256r1::Secp256r1VerifyingKey::new(public_key)?;
42                verifying_key.verify(message, signature)
43            }
44            #[cfg(not(feature = "secp256r1"))]
45            SimpleSignature::Secp256r1 { .. } => Err(SignatureError::from_source(
46                "support for secp256r1 is not enabled",
47            )),
48            _ => Err(SignatureError::from_source("unknown signature scheme")),
49        }
50    }
51}
52
53impl Verifier<UserSignature> for SimpleVerifier {
54    fn verify(&self, message: &[u8], signature: &UserSignature) -> Result<(), SignatureError> {
55        let UserSignature::Simple(signature) = signature else {
56            return Err(SignatureError::from_source("not a simple signature"));
57        };
58
59        <Self as Verifier<SimpleSignature>>::verify(self, message, signature)
60    }
61}
62
63#[cfg(any(feature = "ed25519", feature = "secp256r1", feature = "secp256k1",))]
64#[cfg_attr(
65    doc_cfg,
66    doc(cfg(any(feature = "ed25519", feature = "secp256r1", feature = "secp256k1",)))
67)]
68#[rustfmt::skip]
69pub use keypair::{SimpleKeypair, SimpleVerifiyingKey};
70
71#[cfg(any(feature = "ed25519", feature = "secp256r1", feature = "secp256k1",))]
72#[cfg_attr(
73    doc_cfg,
74    doc(cfg(any(feature = "ed25519", feature = "secp256r1", feature = "secp256k1",)))
75)]
76mod keypair {
77    use crate::SignatureError;
78    use signature::Signer;
79    use signature::Verifier;
80    use sui_sdk_types::MultisigMemberPublicKey;
81    use sui_sdk_types::SignatureScheme;
82    use sui_sdk_types::SimpleSignature;
83    use sui_sdk_types::UserSignature;
84
85    #[derive(Debug, Clone)]
86    pub struct SimpleKeypair {
87        inner: InnerKeypair,
88    }
89
90    #[derive(Debug, Clone)]
91    enum InnerKeypair {
92        #[cfg(feature = "ed25519")]
93        Ed25519(crate::ed25519::Ed25519PrivateKey),
94        #[cfg(feature = "secp256k1")]
95        Secp256k1(crate::secp256k1::Secp256k1PrivateKey),
96        #[cfg(feature = "secp256r1")]
97        Secp256r1(crate::secp256r1::Secp256r1PrivateKey),
98    }
99
100    impl SimpleKeypair {
101        pub fn scheme(&self) -> SignatureScheme {
102            match &self.inner {
103                #[cfg(feature = "ed25519")]
104                InnerKeypair::Ed25519(private_key) => private_key.scheme(),
105                #[cfg(feature = "secp256k1")]
106                InnerKeypair::Secp256k1(private_key) => private_key.scheme(),
107                #[cfg(feature = "secp256r1")]
108                InnerKeypair::Secp256r1(private_key) => private_key.scheme(),
109            }
110        }
111
112        pub fn verifying_key(&self) -> SimpleVerifiyingKey {
113            let verifying_key = match &self.inner {
114                #[cfg(feature = "ed25519")]
115                InnerKeypair::Ed25519(private_key) => {
116                    InnerVerifyingKey::Ed25519(private_key.verifying_key())
117                }
118                #[cfg(feature = "secp256k1")]
119                InnerKeypair::Secp256k1(private_key) => {
120                    InnerVerifyingKey::Secp256k1(private_key.verifying_key())
121                }
122                #[cfg(feature = "secp256r1")]
123                InnerKeypair::Secp256r1(private_key) => {
124                    InnerVerifyingKey::Secp256r1(private_key.verifying_key())
125                }
126            };
127
128            SimpleVerifiyingKey {
129                inner: verifying_key,
130            }
131        }
132
133        pub fn public_key(&self) -> MultisigMemberPublicKey {
134            self.verifying_key().public_key()
135        }
136
137        #[cfg(feature = "pem")]
138        #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
139        /// Deserialize PKCS#8 private key from ASN.1 DER-encoded data (binary format).
140        pub fn from_der(bytes: &[u8]) -> Result<Self, SignatureError> {
141            let private_key =
142                pkcs8::PrivateKeyInfo::try_from(bytes).map_err(SignatureError::from_source)?;
143
144            match private_key
145                .algorithm
146                .oids()
147                .map_err(SignatureError::from_source)?
148            {
149                #[cfg(feature = "ed25519")]
150                (ed25519_dalek::pkcs8::ALGORITHM_OID, None) => private_key
151                    .try_into()
152                    .map(crate::ed25519::Ed25519PrivateKey::from_dalek)
153                    .map(InnerKeypair::Ed25519)
154                    .map_err(SignatureError::from_source),
155
156                #[cfg(feature = "secp256r1")]
157                (
158                    p256::elliptic_curve::ALGORITHM_OID,
159                    Some(<p256::NistP256 as pkcs8::AssociatedOid>::OID),
160                ) => private_key
161                    .try_into()
162                    .map(crate::secp256r1::Secp256r1PrivateKey::from_p256)
163                    .map(InnerKeypair::Secp256r1)
164                    .map_err(SignatureError::from_source),
165
166                #[cfg(feature = "secp256k1")]
167                (
168                    k256::elliptic_curve::ALGORITHM_OID,
169                    Some(<k256::Secp256k1 as pkcs8::AssociatedOid>::OID),
170                ) => private_key
171                    .try_into()
172                    .map(crate::secp256k1::Secp256k1PrivateKey::from_k256)
173                    .map(InnerKeypair::Secp256k1)
174                    .map_err(SignatureError::from_source),
175
176                _ => Err(SignatureError::from_source(
177                    "unsupported or invalid private key type",
178                )),
179            }
180            .map(|inner| Self { inner })
181        }
182
183        #[cfg(feature = "pem")]
184        #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
185        /// Serialize this private key as DER-encoded PKCS#8
186        pub fn to_der(&self) -> Result<Vec<u8>, SignatureError> {
187            match &self.inner {
188                #[cfg(feature = "ed25519")]
189                InnerKeypair::Ed25519(private_key) => private_key.to_der(),
190                #[cfg(feature = "secp256k1")]
191                InnerKeypair::Secp256k1(private_key) => private_key.to_der(),
192                #[cfg(feature = "secp256r1")]
193                InnerKeypair::Secp256r1(private_key) => private_key.to_der(),
194            }
195        }
196
197        #[cfg(feature = "pem")]
198        #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
199        /// Deserialize PKCS#8-encoded private key from PEM.
200        pub fn from_pem(s: &str) -> Result<Self, SignatureError> {
201            use pkcs8::der::pem::PemLabel;
202
203            let (label, doc) =
204                pkcs8::SecretDocument::from_pem(s).map_err(SignatureError::from_source)?;
205            pkcs8::PrivateKeyInfo::validate_pem_label(label)
206                .map_err(SignatureError::from_source)?;
207            Self::from_der(doc.as_bytes())
208        }
209
210        #[cfg(feature = "pem")]
211        #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
212        /// Serialize this private key as DER-encoded PKCS#8
213        pub fn to_pem(&self) -> Result<String, SignatureError> {
214            match &self.inner {
215                #[cfg(feature = "ed25519")]
216                InnerKeypair::Ed25519(private_key) => private_key.to_pem(),
217                #[cfg(feature = "secp256k1")]
218                InnerKeypair::Secp256k1(private_key) => private_key.to_pem(),
219                #[cfg(feature = "secp256r1")]
220                InnerKeypair::Secp256r1(private_key) => private_key.to_pem(),
221            }
222        }
223
224        #[cfg(feature = "bech32")]
225        #[cfg_attr(doc_cfg, doc(cfg(feature = "bech32")))]
226        /// Decode a Bech32 `suiprivkey` string produced by the Sui CLI.
227        ///
228        /// The leading flag byte selects the scheme. Only the simple schemes
229        /// (Ed25519, Secp256k1, Secp256r1) are accepted, matching the
230        /// upstream `sui-types` parser.
231        pub fn from_suiprivkey(s: &str) -> Result<Self, SignatureError> {
232            let (scheme, key) = crate::suipriv::decode(s)?;
233            let inner = match scheme {
234                #[cfg(feature = "ed25519")]
235                SignatureScheme::Ed25519 => {
236                    let bytes: [u8; crate::ed25519::Ed25519PrivateKey::LENGTH] =
237                        key.try_into().map_err(|_: Vec<u8>| {
238                            SignatureError::from_source(
239                                "suipriv key has invalid length for ed25519",
240                            )
241                        })?;
242                    InnerKeypair::Ed25519(crate::ed25519::Ed25519PrivateKey::new(bytes))
243                }
244                #[cfg(feature = "secp256k1")]
245                SignatureScheme::Secp256k1 => {
246                    let bytes: [u8; crate::secp256k1::Secp256k1PrivateKey::LENGTH] =
247                        key.try_into().map_err(|_: Vec<u8>| {
248                            SignatureError::from_source(
249                                "suipriv key has invalid length for secp256k1",
250                            )
251                        })?;
252                    InnerKeypair::Secp256k1(crate::secp256k1::Secp256k1PrivateKey::new(bytes)?)
253                }
254                #[cfg(feature = "secp256r1")]
255                SignatureScheme::Secp256r1 => {
256                    let bytes: [u8; crate::secp256r1::Secp256r1PrivateKey::LENGTH] =
257                        key.try_into().map_err(|_: Vec<u8>| {
258                            SignatureError::from_source(
259                                "suipriv key has invalid length for secp256r1",
260                            )
261                        })?;
262                    InnerKeypair::Secp256r1(crate::secp256r1::Secp256r1PrivateKey::new(bytes))
263                }
264                other => {
265                    return Err(SignatureError::from_source(format!(
266                        "unsupported scheme `{}` in suipriv encoding",
267                        other.name(),
268                    )));
269                }
270            };
271            Ok(Self { inner })
272        }
273
274        #[cfg(feature = "bech32")]
275        #[cfg_attr(doc_cfg, doc(cfg(feature = "bech32")))]
276        /// Encode this private key as a Bech32 `suiprivkey` string.
277        pub fn to_suiprivkey(&self) -> Result<String, SignatureError> {
278            match &self.inner {
279                #[cfg(feature = "ed25519")]
280                InnerKeypair::Ed25519(private_key) => private_key.to_suiprivkey(),
281                #[cfg(feature = "secp256k1")]
282                InnerKeypair::Secp256k1(private_key) => private_key.to_suiprivkey(),
283                #[cfg(feature = "secp256r1")]
284                InnerKeypair::Secp256r1(private_key) => private_key.to_suiprivkey(),
285            }
286        }
287    }
288
289    impl Signer<SimpleSignature> for SimpleKeypair {
290        fn try_sign(&self, message: &[u8]) -> Result<SimpleSignature, SignatureError> {
291            match &self.inner {
292                #[cfg(feature = "ed25519")]
293                InnerKeypair::Ed25519(private_key) => private_key.try_sign(message),
294                #[cfg(feature = "secp256k1")]
295                InnerKeypair::Secp256k1(private_key) => private_key.try_sign(message),
296                #[cfg(feature = "secp256r1")]
297                InnerKeypair::Secp256r1(private_key) => private_key.try_sign(message),
298            }
299        }
300    }
301
302    impl Signer<UserSignature> for SimpleKeypair {
303        fn try_sign(&self, msg: &[u8]) -> Result<UserSignature, SignatureError> {
304            <Self as Signer<SimpleSignature>>::try_sign(self, msg).map(UserSignature::Simple)
305        }
306    }
307
308    #[cfg(feature = "ed25519")]
309    #[cfg_attr(doc_cfg, doc(cfg(feature = "ed25519")))]
310    impl From<crate::ed25519::Ed25519PrivateKey> for SimpleKeypair {
311        fn from(private_key: crate::ed25519::Ed25519PrivateKey) -> Self {
312            Self {
313                inner: InnerKeypair::Ed25519(private_key),
314            }
315        }
316    }
317
318    #[cfg(feature = "secp256r1")]
319    #[cfg_attr(doc_cfg, doc(cfg(feature = "secp256r1")))]
320    impl From<crate::secp256r1::Secp256r1PrivateKey> for SimpleKeypair {
321        fn from(private_key: crate::secp256r1::Secp256r1PrivateKey) -> Self {
322            Self {
323                inner: InnerKeypair::Secp256r1(private_key),
324            }
325        }
326    }
327
328    #[cfg(feature = "secp256k1")]
329    #[cfg_attr(doc_cfg, doc(cfg(feature = "secp256k1")))]
330    impl From<crate::secp256k1::Secp256k1PrivateKey> for SimpleKeypair {
331        fn from(private_key: crate::secp256k1::Secp256k1PrivateKey) -> Self {
332            Self {
333                inner: InnerKeypair::Secp256k1(private_key),
334            }
335        }
336    }
337
338    #[derive(Debug, Clone, Eq, PartialEq)]
339    pub struct SimpleVerifiyingKey {
340        inner: InnerVerifyingKey,
341    }
342
343    #[derive(Debug, Clone, Eq, PartialEq)]
344    enum InnerVerifyingKey {
345        #[cfg(feature = "ed25519")]
346        Ed25519(crate::ed25519::Ed25519VerifyingKey),
347        #[cfg(feature = "secp256k1")]
348        Secp256k1(crate::secp256k1::Secp256k1VerifyingKey),
349        #[cfg(feature = "secp256r1")]
350        Secp256r1(crate::secp256r1::Secp256r1VerifyingKey),
351    }
352
353    impl SimpleVerifiyingKey {
354        pub fn scheme(&self) -> SignatureScheme {
355            match &self.inner {
356                #[cfg(feature = "ed25519")]
357                InnerVerifyingKey::Ed25519(verifying_key) => verifying_key.public_key().scheme(),
358                #[cfg(feature = "secp256k1")]
359                InnerVerifyingKey::Secp256k1(verifying_key) => verifying_key.public_key().scheme(),
360                #[cfg(feature = "secp256r1")]
361                InnerVerifyingKey::Secp256r1(verifying_key) => verifying_key.public_key().scheme(),
362            }
363        }
364
365        pub fn public_key(&self) -> MultisigMemberPublicKey {
366            match &self.inner {
367                #[cfg(feature = "ed25519")]
368                InnerVerifyingKey::Ed25519(verifying_key) => {
369                    MultisigMemberPublicKey::Ed25519(verifying_key.public_key())
370                }
371                #[cfg(feature = "secp256k1")]
372                InnerVerifyingKey::Secp256k1(verifying_key) => {
373                    MultisigMemberPublicKey::Secp256k1(verifying_key.public_key())
374                }
375                #[cfg(feature = "secp256r1")]
376                InnerVerifyingKey::Secp256r1(verifying_key) => {
377                    MultisigMemberPublicKey::Secp256r1(verifying_key.public_key())
378                }
379            }
380        }
381
382        #[cfg(feature = "pem")]
383        #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
384        /// Deserialize public key from ASN.1 DER-encoded data (binary format).
385        pub fn from_der(bytes: &[u8]) -> Result<Self, SignatureError> {
386            let public_key = pkcs8::SubjectPublicKeyInfoRef::try_from(bytes)
387                .map_err(SignatureError::from_source)?;
388
389            match public_key
390                .algorithm
391                .oids()
392                .map_err(SignatureError::from_source)?
393            {
394                #[cfg(feature = "ed25519")]
395                (ed25519_dalek::pkcs8::ALGORITHM_OID, None) => public_key
396                    .try_into()
397                    .map(crate::ed25519::Ed25519VerifyingKey::from_dalek)
398                    .map(InnerVerifyingKey::Ed25519)
399                    .map_err(SignatureError::from_source),
400
401                #[cfg(feature = "secp256r1")]
402                (
403                    p256::elliptic_curve::ALGORITHM_OID,
404                    Some(<p256::NistP256 as pkcs8::AssociatedOid>::OID),
405                ) => public_key
406                    .try_into()
407                    .map(crate::secp256r1::Secp256r1VerifyingKey::from_p256)
408                    .map(InnerVerifyingKey::Secp256r1)
409                    .map_err(SignatureError::from_source),
410
411                #[cfg(feature = "secp256k1")]
412                (
413                    k256::elliptic_curve::ALGORITHM_OID,
414                    Some(<k256::Secp256k1 as pkcs8::AssociatedOid>::OID),
415                ) => public_key
416                    .try_into()
417                    .map(crate::secp256k1::Secp256k1VerifyingKey::from_k256)
418                    .map(InnerVerifyingKey::Secp256k1)
419                    .map_err(SignatureError::from_source),
420
421                _ => Err(SignatureError::from_source(
422                    "unsupported or invalid public key type",
423                )),
424            }
425            .map(|inner| Self { inner })
426        }
427
428        #[cfg(feature = "pem")]
429        #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
430        /// Serialize this public key as DER-encoded data
431        pub fn to_der(&self) -> Result<Vec<u8>, SignatureError> {
432            match &self.inner {
433                #[cfg(feature = "ed25519")]
434                InnerVerifyingKey::Ed25519(verifying_key) => verifying_key.to_der(),
435                #[cfg(feature = "secp256k1")]
436                InnerVerifyingKey::Secp256k1(verifying_key) => verifying_key.to_der(),
437                #[cfg(feature = "secp256r1")]
438                InnerVerifyingKey::Secp256r1(verifying_key) => verifying_key.to_der(),
439            }
440        }
441
442        #[cfg(feature = "pem")]
443        #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
444        /// Deserialize public key from PEM.
445        pub fn from_pem(s: &str) -> Result<Self, SignatureError> {
446            use pkcs8::der::pem::PemLabel;
447
448            let (label, doc) = pkcs8::Document::from_pem(s).map_err(SignatureError::from_source)?;
449            pkcs8::SubjectPublicKeyInfoRef::validate_pem_label(label)
450                .map_err(SignatureError::from_source)?;
451            Self::from_der(doc.as_bytes())
452        }
453
454        #[cfg(feature = "pem")]
455        #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
456        /// Serialize this public key as PEM
457        pub fn to_pem(&self) -> Result<String, SignatureError> {
458            match &self.inner {
459                #[cfg(feature = "ed25519")]
460                InnerVerifyingKey::Ed25519(verifying_key) => verifying_key.to_pem(),
461                #[cfg(feature = "secp256k1")]
462                InnerVerifyingKey::Secp256k1(verifying_key) => verifying_key.to_pem(),
463                #[cfg(feature = "secp256r1")]
464                InnerVerifyingKey::Secp256r1(verifying_key) => verifying_key.to_pem(),
465            }
466        }
467    }
468
469    impl Verifier<SimpleSignature> for SimpleVerifiyingKey {
470        fn verify(
471            &self,
472            message: &[u8],
473            signature: &SimpleSignature,
474        ) -> Result<(), SignatureError> {
475            match &self.inner {
476                #[cfg(feature = "ed25519")]
477                InnerVerifyingKey::Ed25519(verifying_key) => {
478                    verifying_key.verify(message, signature)
479                }
480                #[cfg(feature = "secp256k1")]
481                InnerVerifyingKey::Secp256k1(verifying_key) => {
482                    verifying_key.verify(message, signature)
483                }
484                #[cfg(feature = "secp256r1")]
485                InnerVerifyingKey::Secp256r1(verifying_key) => {
486                    verifying_key.verify(message, signature)
487                }
488            }
489        }
490    }
491
492    impl Verifier<UserSignature> for SimpleVerifiyingKey {
493        fn verify(&self, message: &[u8], signature: &UserSignature) -> Result<(), SignatureError> {
494            let UserSignature::Simple(signature) = signature else {
495                return Err(SignatureError::from_source("not a simple signature"));
496            };
497
498            <Self as Verifier<SimpleSignature>>::verify(self, message, signature)
499        }
500    }
501
502    #[cfg(feature = "ed25519")]
503    #[cfg_attr(doc_cfg, doc(cfg(feature = "ed25519")))]
504    impl From<crate::ed25519::Ed25519VerifyingKey> for SimpleVerifiyingKey {
505        fn from(verifying_key: crate::ed25519::Ed25519VerifyingKey) -> Self {
506            Self {
507                inner: InnerVerifyingKey::Ed25519(verifying_key),
508            }
509        }
510    }
511
512    #[cfg(feature = "secp256r1")]
513    #[cfg_attr(doc_cfg, doc(cfg(feature = "secp256r1")))]
514    impl From<crate::secp256r1::Secp256r1VerifyingKey> for SimpleVerifiyingKey {
515        fn from(verifying_key: crate::secp256r1::Secp256r1VerifyingKey) -> Self {
516            Self {
517                inner: InnerVerifyingKey::Secp256r1(verifying_key),
518            }
519        }
520    }
521
522    #[cfg(feature = "secp256k1")]
523    #[cfg_attr(doc_cfg, doc(cfg(feature = "secp256k1")))]
524    impl From<crate::secp256k1::Secp256k1VerifyingKey> for SimpleVerifiyingKey {
525        fn from(verifying_key: crate::secp256k1::Secp256k1VerifyingKey) -> Self {
526            Self {
527                inner: InnerVerifyingKey::Secp256k1(verifying_key),
528            }
529        }
530    }
531}
532
533#[cfg(test)]
534mod test {
535    use super::*;
536    use crate::ed25519::Ed25519PrivateKey;
537    use crate::ed25519::Ed25519VerifyingKey;
538    use crate::secp256k1::Secp256k1PrivateKey;
539    use crate::secp256k1::Secp256k1VerifyingKey;
540    use crate::secp256r1::Secp256r1PrivateKey;
541    use crate::secp256r1::Secp256r1VerifyingKey;
542    use test_strategy::proptest;
543
544    #[cfg(target_arch = "wasm32")]
545    use wasm_bindgen_test::wasm_bindgen_test as test;
546
547    #[proptest]
548    fn ed25519_pem_der(signer: Ed25519PrivateKey) {
549        //
550        // Private Key
551        //
552        let public_key = signer.public_key();
553        let ed25519_der = signer.to_der().unwrap();
554        let ed25519_pem = signer.to_pem().unwrap();
555
556        // der and pem round-trip
557        let from_der = Ed25519PrivateKey::from_der(&ed25519_der).unwrap();
558        assert_eq!(from_der.public_key(), public_key);
559        let from_pem = Ed25519PrivateKey::from_pem(&ed25519_pem).unwrap();
560        assert_eq!(from_pem.public_key(), public_key);
561
562        // der and pem bytes don't convert to secp256r1 or secp256k1
563        Secp256r1PrivateKey::from_der(&ed25519_der).unwrap_err();
564        Secp256r1PrivateKey::from_pem(&ed25519_pem).unwrap_err();
565        Secp256k1PrivateKey::from_der(&ed25519_der).unwrap_err();
566        Secp256k1PrivateKey::from_pem(&ed25519_pem).unwrap_err();
567
568        // SimpleKeypair parses
569        let keypair_from_der = SimpleKeypair::from_der(&ed25519_der).unwrap();
570        assert_eq!(ed25519_der, keypair_from_der.to_der().unwrap());
571        let keypair_from_pem = SimpleKeypair::from_pem(&ed25519_pem).unwrap();
572        assert_eq!(ed25519_pem, keypair_from_pem.to_pem().unwrap());
573
574        //
575        // Verifying Key
576        //
577        let verifying_key = signer.verifying_key();
578        let der = verifying_key.to_der().unwrap();
579        let pem = verifying_key.to_pem().unwrap();
580
581        // der and pem round-trip
582        let from_der = Ed25519VerifyingKey::from_der(&der).unwrap();
583        assert_eq!(from_der.public_key(), public_key);
584        let from_pem = Ed25519VerifyingKey::from_pem(&pem).unwrap();
585        assert_eq!(from_pem.public_key(), public_key);
586
587        // der and pem bytes don't convert to secp256r1 or secp256k1
588        Secp256r1VerifyingKey::from_der(&der).unwrap_err();
589        Secp256r1VerifyingKey::from_pem(&pem).unwrap_err();
590        Secp256k1VerifyingKey::from_der(&der).unwrap_err();
591        Secp256k1VerifyingKey::from_pem(&pem).unwrap_err();
592
593        // SimpleKeypair parses
594        let from_der = SimpleVerifiyingKey::from_der(&der).unwrap();
595        assert_eq!(der, from_der.to_der().unwrap());
596        let from_pem = SimpleVerifiyingKey::from_pem(&pem).unwrap();
597        assert_eq!(pem, from_pem.to_pem().unwrap());
598    }
599
600    #[proptest]
601    fn secp256r1_pem_der(signer: Secp256r1PrivateKey) {
602        //
603        // Private Key
604        //
605        let public_key = signer.public_key();
606        let secp256r1_der = signer.to_der().unwrap();
607        let secp256r1_pem = signer.to_pem().unwrap();
608
609        // der and pem round-trip
610        let from_der = Secp256r1PrivateKey::from_der(&secp256r1_der).unwrap();
611        assert_eq!(from_der.public_key(), public_key);
612        let from_pem = Secp256r1PrivateKey::from_pem(&secp256r1_pem).unwrap();
613        assert_eq!(from_pem.public_key(), public_key);
614
615        // der and pem bytes don't convert to ed25519 or secp256k1
616        Ed25519PrivateKey::from_der(&secp256r1_der).unwrap_err();
617        Ed25519PrivateKey::from_pem(&secp256r1_pem).unwrap_err();
618        Secp256k1PrivateKey::from_der(&secp256r1_der).unwrap_err();
619        Secp256k1PrivateKey::from_pem(&secp256r1_pem).unwrap_err();
620
621        // SimpleKeypair parses
622        let keypair_from_der = SimpleKeypair::from_der(&secp256r1_der).unwrap();
623        assert_eq!(secp256r1_der, keypair_from_der.to_der().unwrap());
624        let keypair_from_pem = SimpleKeypair::from_pem(&secp256r1_pem).unwrap();
625        assert_eq!(secp256r1_pem, keypair_from_pem.to_pem().unwrap());
626
627        //
628        // Verifying Key
629        //
630        let verifying_key = signer.verifying_key();
631        let der = verifying_key.to_der().unwrap();
632        let pem = verifying_key.to_pem().unwrap();
633
634        // der and pem round-trip
635        let from_der = Secp256r1VerifyingKey::from_der(&der).unwrap();
636        assert_eq!(from_der.public_key(), public_key);
637        let from_pem = Secp256r1VerifyingKey::from_pem(&pem).unwrap();
638        assert_eq!(from_pem.public_key(), public_key);
639
640        // der and pem bytes don't convert to ed25519 or secp256k1
641        Ed25519VerifyingKey::from_der(&der).unwrap_err();
642        Ed25519VerifyingKey::from_pem(&pem).unwrap_err();
643        Secp256k1VerifyingKey::from_der(&der).unwrap_err();
644        Secp256k1VerifyingKey::from_pem(&pem).unwrap_err();
645
646        // SimpleKeypair parses
647        let from_der = SimpleVerifiyingKey::from_der(&der).unwrap();
648        assert_eq!(der, from_der.to_der().unwrap());
649        let from_pem = SimpleVerifiyingKey::from_pem(&pem).unwrap();
650        assert_eq!(pem, from_pem.to_pem().unwrap());
651    }
652
653    #[proptest]
654    fn secp256k1_pem_der(signer: Secp256k1PrivateKey) {
655        //
656        // Private Key
657        //
658        let public_key = signer.public_key();
659        let secp256k1_der = signer.to_der().unwrap();
660        let secp256k1_pem = signer.to_pem().unwrap();
661
662        // der and pem round-trip
663        let from_der = Secp256k1PrivateKey::from_der(&secp256k1_der).unwrap();
664        assert_eq!(from_der.public_key(), public_key);
665        let from_pem = Secp256k1PrivateKey::from_pem(&secp256k1_pem).unwrap();
666        assert_eq!(from_pem.public_key(), public_key);
667
668        // der and pem bytes don't convert to secp256r1 or ed25519
669        Ed25519PrivateKey::from_der(&secp256k1_der).unwrap_err();
670        Ed25519PrivateKey::from_pem(&secp256k1_pem).unwrap_err();
671        Secp256r1PrivateKey::from_der(&secp256k1_der).unwrap_err();
672        Secp256r1PrivateKey::from_pem(&secp256k1_pem).unwrap_err();
673
674        // SimpleKeypair parses
675        let keypair_from_der = SimpleKeypair::from_der(&secp256k1_der).unwrap();
676        assert_eq!(secp256k1_der, keypair_from_der.to_der().unwrap());
677        let keypair_from_pem = SimpleKeypair::from_pem(&secp256k1_pem).unwrap();
678        assert_eq!(secp256k1_pem, keypair_from_pem.to_pem().unwrap());
679
680        //
681        // Verifying Key
682        //
683        let verifying_key = signer.verifying_key();
684        let der = verifying_key.to_der().unwrap();
685        let pem = verifying_key.to_pem().unwrap();
686
687        // der and pem round-trip
688        let from_der = Secp256k1VerifyingKey::from_der(&der).unwrap();
689        assert_eq!(from_der.public_key(), public_key);
690        let from_pem = Secp256k1VerifyingKey::from_pem(&pem).unwrap();
691        assert_eq!(from_pem.public_key(), public_key);
692
693        // der and pem bytes don't convert to ed25519 or secp256r1
694        Ed25519VerifyingKey::from_der(&der).unwrap_err();
695        Ed25519VerifyingKey::from_pem(&pem).unwrap_err();
696        Secp256r1VerifyingKey::from_der(&der).unwrap_err();
697        Secp256r1VerifyingKey::from_pem(&pem).unwrap_err();
698
699        // SimpleKeypair parses
700        let from_der = SimpleVerifiyingKey::from_der(&der).unwrap();
701        assert_eq!(der, from_der.to_der().unwrap());
702        let from_pem = SimpleVerifiyingKey::from_pem(&pem).unwrap();
703        assert_eq!(pem, from_pem.to_pem().unwrap());
704    }
705
706    // Round-trip and rejection tests for the suiprivkey Bech32 format.
707    //
708    // These mirror the format produced by the Sui CLI and the upstream
709    // `sui-types` crate. `EXPECTED_ED25519_VECTOR` is taken directly from
710    // `crates/sui-types/src/unit_tests/crypto_tests.rs` in the main sui repo
711    // and is included as a regression vector against any future encoding
712    // drift.
713    #[cfg(feature = "bech32")]
714    mod bech32 {
715        use super::*;
716        use sui_sdk_types::SignatureScheme;
717
718        #[cfg(target_arch = "wasm32")]
719        use wasm_bindgen_test::wasm_bindgen_test as test;
720
721        // Upstream test vector: `Ed25519KeyPair::generate(&mut StdRng::from_seed([0; 32]))`
722        // encoded with `SuiKeyPair::encode()` produces this string. The leading
723        // flag byte is 0x00 (Ed25519); the remaining 32 bytes are the private
724        // key.
725        const UPSTREAM_ED25519_SUIPRIVKEY: &str =
726            "suiprivkey1qzdlfxn2qa2lj5uprl8pyhexs02sg2wrhdy7qaq50cqgnffw4c2477kg9h3";
727
728        #[proptest]
729        fn ed25519_round_trip(signer: Ed25519PrivateKey) {
730            let encoded = signer.to_suiprivkey().unwrap();
731            let decoded = Ed25519PrivateKey::from_suiprivkey(&encoded).unwrap();
732            assert_eq!(decoded.public_key(), signer.public_key());
733
734            // SimpleKeypair dispatch agrees.
735            let keypair = SimpleKeypair::from_suiprivkey(&encoded).unwrap();
736            assert_eq!(keypair.scheme(), signer.scheme());
737            assert_eq!(encoded, keypair.to_suiprivkey().unwrap());
738        }
739
740        #[proptest]
741        fn secp256k1_round_trip(signer: Secp256k1PrivateKey) {
742            let encoded = signer.to_suiprivkey().unwrap();
743            let decoded = Secp256k1PrivateKey::from_suiprivkey(&encoded).unwrap();
744            assert_eq!(decoded.public_key(), signer.public_key());
745
746            let keypair = SimpleKeypair::from_suiprivkey(&encoded).unwrap();
747            assert_eq!(keypair.scheme(), signer.scheme());
748            assert_eq!(encoded, keypair.to_suiprivkey().unwrap());
749        }
750
751        #[proptest]
752        fn secp256r1_round_trip(signer: Secp256r1PrivateKey) {
753            let encoded = signer.to_suiprivkey().unwrap();
754            let decoded = Secp256r1PrivateKey::from_suiprivkey(&encoded).unwrap();
755            assert_eq!(decoded.public_key(), signer.public_key());
756
757            let keypair = SimpleKeypair::from_suiprivkey(&encoded).unwrap();
758            assert_eq!(keypair.scheme(), signer.scheme());
759            assert_eq!(encoded, keypair.to_suiprivkey().unwrap());
760        }
761
762        #[test]
763        fn upstream_ed25519_vector_round_trips() {
764            let keypair = SimpleKeypair::from_suiprivkey(UPSTREAM_ED25519_SUIPRIVKEY).unwrap();
765            assert_eq!(keypair.scheme(), SignatureScheme::Ed25519);
766            assert_eq!(
767                keypair.to_suiprivkey().unwrap(),
768                UPSTREAM_ED25519_SUIPRIVKEY
769            );
770
771            // Per-scheme decoder accepts it too.
772            Ed25519PrivateKey::from_suiprivkey(UPSTREAM_ED25519_SUIPRIVKEY).unwrap();
773            // Wrong-scheme per-scheme decoders reject it.
774            Secp256k1PrivateKey::from_suiprivkey(UPSTREAM_ED25519_SUIPRIVKEY).unwrap_err();
775            Secp256r1PrivateKey::from_suiprivkey(UPSTREAM_ED25519_SUIPRIVKEY).unwrap_err();
776        }
777
778        #[test]
779        fn rejects_wrong_hrp() {
780            // Same payload as the upstream Ed25519 vector but encoded with a
781            // different HRP — must fail.
782            let bytes = ::bech32::primitives::decode::CheckedHrpstring::new::<::bech32::Bech32>(
783                UPSTREAM_ED25519_SUIPRIVKEY,
784            )
785            .unwrap()
786            .byte_iter()
787            .collect::<Vec<_>>();
788            let wrong_hrp = ::bech32::Hrp::parse("notsui").unwrap();
789            let encoded = ::bech32::encode::<::bech32::Bech32>(wrong_hrp, &bytes).unwrap();
790
791            SimpleKeypair::from_suiprivkey(&encoded).unwrap_err();
792            Ed25519PrivateKey::from_suiprivkey(&encoded).unwrap_err();
793        }
794
795        #[test]
796        fn rejects_bech32m_checksum() {
797            // Re-encode the upstream Ed25519 payload using the Bech32m
798            // checksum variant. A correctly-implemented decoder must reject
799            // this, since the suipriv format uses BIP-173 Bech32 only.
800            let bytes = ::bech32::primitives::decode::CheckedHrpstring::new::<::bech32::Bech32>(
801                UPSTREAM_ED25519_SUIPRIVKEY,
802            )
803            .unwrap()
804            .byte_iter()
805            .collect::<Vec<_>>();
806            let hrp = ::bech32::Hrp::parse("suiprivkey").unwrap();
807            let bech32m = ::bech32::encode::<::bech32::Bech32m>(hrp, &bytes).unwrap();
808            assert_ne!(bech32m, UPSTREAM_ED25519_SUIPRIVKEY);
809
810            SimpleKeypair::from_suiprivkey(&bech32m).unwrap_err();
811            Ed25519PrivateKey::from_suiprivkey(&bech32m).unwrap_err();
812        }
813    }
814}