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        /// Build a keypair from the scheme flag and key bytes of a decoded
225        /// `flag || private_key` payload.
226        ///
227        /// Only the simple schemes (Ed25519, Secp256k1, Secp256r1) are
228        /// accepted, matching the upstream `sui-types` parser.
229        fn from_flagged_key_bytes(
230            scheme: SignatureScheme,
231            key: Vec<u8>,
232        ) -> Result<Self, SignatureError> {
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                                "private 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                                "private 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                                "private 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 private key 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        /// Decode a Bech32 `suiprivkey` string produced by the Sui CLI.
277        ///
278        /// The leading flag byte selects the scheme. Only the simple schemes
279        /// (Ed25519, Secp256k1, Secp256r1) are accepted, matching the
280        /// upstream `sui-types` parser.
281        pub fn from_suiprivkey(s: &str) -> Result<Self, SignatureError> {
282            let (scheme, key) = crate::suipriv::decode(s)?;
283            Self::from_flagged_key_bytes(scheme, key)
284        }
285
286        #[cfg(feature = "bech32")]
287        #[cfg_attr(doc_cfg, doc(cfg(feature = "bech32")))]
288        /// Encode this private key as a Bech32 `suiprivkey` string.
289        pub fn to_suiprivkey(&self) -> Result<String, SignatureError> {
290            match &self.inner {
291                #[cfg(feature = "ed25519")]
292                InnerKeypair::Ed25519(private_key) => private_key.to_suiprivkey(),
293                #[cfg(feature = "secp256k1")]
294                InnerKeypair::Secp256k1(private_key) => private_key.to_suiprivkey(),
295                #[cfg(feature = "secp256r1")]
296                InnerKeypair::Secp256r1(private_key) => private_key.to_suiprivkey(),
297            }
298        }
299
300        /// Decode a Base64 `flag || private_key` string, the legacy keystore
301        /// format used for entries of the Sui CLI's `sui.keystore` file.
302        ///
303        /// The leading flag byte selects the scheme. Only the simple schemes
304        /// (Ed25519, Secp256k1, Secp256r1) are accepted, matching the
305        /// upstream `sui-types` parser.
306        pub fn from_base64(s: &str) -> Result<Self, SignatureError> {
307            let (scheme, key) = crate::suipriv::decode_base64(s)?;
308            Self::from_flagged_key_bytes(scheme, key)
309        }
310
311        /// Encode this private key as a Base64 `flag || private_key` string,
312        /// the legacy keystore format used for entries of the Sui CLI's
313        /// `sui.keystore` file.
314        pub fn to_base64(&self) -> String {
315            match &self.inner {
316                #[cfg(feature = "ed25519")]
317                InnerKeypair::Ed25519(private_key) => private_key.to_base64(),
318                #[cfg(feature = "secp256k1")]
319                InnerKeypair::Secp256k1(private_key) => private_key.to_base64(),
320                #[cfg(feature = "secp256r1")]
321                InnerKeypair::Secp256r1(private_key) => private_key.to_base64(),
322            }
323        }
324    }
325
326    impl Signer<SimpleSignature> for SimpleKeypair {
327        fn try_sign(&self, message: &[u8]) -> Result<SimpleSignature, SignatureError> {
328            match &self.inner {
329                #[cfg(feature = "ed25519")]
330                InnerKeypair::Ed25519(private_key) => private_key.try_sign(message),
331                #[cfg(feature = "secp256k1")]
332                InnerKeypair::Secp256k1(private_key) => private_key.try_sign(message),
333                #[cfg(feature = "secp256r1")]
334                InnerKeypair::Secp256r1(private_key) => private_key.try_sign(message),
335            }
336        }
337    }
338
339    impl Signer<UserSignature> for SimpleKeypair {
340        fn try_sign(&self, msg: &[u8]) -> Result<UserSignature, SignatureError> {
341            <Self as Signer<SimpleSignature>>::try_sign(self, msg).map(UserSignature::Simple)
342        }
343    }
344
345    #[cfg(feature = "ed25519")]
346    #[cfg_attr(doc_cfg, doc(cfg(feature = "ed25519")))]
347    impl From<crate::ed25519::Ed25519PrivateKey> for SimpleKeypair {
348        fn from(private_key: crate::ed25519::Ed25519PrivateKey) -> Self {
349            Self {
350                inner: InnerKeypair::Ed25519(private_key),
351            }
352        }
353    }
354
355    #[cfg(feature = "secp256r1")]
356    #[cfg_attr(doc_cfg, doc(cfg(feature = "secp256r1")))]
357    impl From<crate::secp256r1::Secp256r1PrivateKey> for SimpleKeypair {
358        fn from(private_key: crate::secp256r1::Secp256r1PrivateKey) -> Self {
359            Self {
360                inner: InnerKeypair::Secp256r1(private_key),
361            }
362        }
363    }
364
365    #[cfg(feature = "secp256k1")]
366    #[cfg_attr(doc_cfg, doc(cfg(feature = "secp256k1")))]
367    impl From<crate::secp256k1::Secp256k1PrivateKey> for SimpleKeypair {
368        fn from(private_key: crate::secp256k1::Secp256k1PrivateKey) -> Self {
369            Self {
370                inner: InnerKeypair::Secp256k1(private_key),
371            }
372        }
373    }
374
375    #[derive(Debug, Clone, Eq, PartialEq)]
376    pub struct SimpleVerifiyingKey {
377        inner: InnerVerifyingKey,
378    }
379
380    #[derive(Debug, Clone, Eq, PartialEq)]
381    enum InnerVerifyingKey {
382        #[cfg(feature = "ed25519")]
383        Ed25519(crate::ed25519::Ed25519VerifyingKey),
384        #[cfg(feature = "secp256k1")]
385        Secp256k1(crate::secp256k1::Secp256k1VerifyingKey),
386        #[cfg(feature = "secp256r1")]
387        Secp256r1(crate::secp256r1::Secp256r1VerifyingKey),
388    }
389
390    impl SimpleVerifiyingKey {
391        pub fn scheme(&self) -> SignatureScheme {
392            match &self.inner {
393                #[cfg(feature = "ed25519")]
394                InnerVerifyingKey::Ed25519(verifying_key) => verifying_key.public_key().scheme(),
395                #[cfg(feature = "secp256k1")]
396                InnerVerifyingKey::Secp256k1(verifying_key) => verifying_key.public_key().scheme(),
397                #[cfg(feature = "secp256r1")]
398                InnerVerifyingKey::Secp256r1(verifying_key) => verifying_key.public_key().scheme(),
399            }
400        }
401
402        pub fn public_key(&self) -> MultisigMemberPublicKey {
403            match &self.inner {
404                #[cfg(feature = "ed25519")]
405                InnerVerifyingKey::Ed25519(verifying_key) => {
406                    MultisigMemberPublicKey::Ed25519(verifying_key.public_key())
407                }
408                #[cfg(feature = "secp256k1")]
409                InnerVerifyingKey::Secp256k1(verifying_key) => {
410                    MultisigMemberPublicKey::Secp256k1(verifying_key.public_key())
411                }
412                #[cfg(feature = "secp256r1")]
413                InnerVerifyingKey::Secp256r1(verifying_key) => {
414                    MultisigMemberPublicKey::Secp256r1(verifying_key.public_key())
415                }
416            }
417        }
418
419        /// Derive the `Address` that corresponds to this public key.
420        pub fn derive_address(&self) -> sui_sdk_types::Address {
421            match &self.inner {
422                #[cfg(feature = "ed25519")]
423                InnerVerifyingKey::Ed25519(verifying_key) => {
424                    verifying_key.public_key().derive_address()
425                }
426                #[cfg(feature = "secp256k1")]
427                InnerVerifyingKey::Secp256k1(verifying_key) => {
428                    verifying_key.public_key().derive_address()
429                }
430                #[cfg(feature = "secp256r1")]
431                InnerVerifyingKey::Secp256r1(verifying_key) => {
432                    verifying_key.public_key().derive_address()
433                }
434            }
435        }
436
437        #[cfg(feature = "pem")]
438        #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
439        /// Deserialize public key from ASN.1 DER-encoded data (binary format).
440        pub fn from_der(bytes: &[u8]) -> Result<Self, SignatureError> {
441            let public_key = pkcs8::SubjectPublicKeyInfoRef::try_from(bytes)
442                .map_err(SignatureError::from_source)?;
443
444            match public_key
445                .algorithm
446                .oids()
447                .map_err(SignatureError::from_source)?
448            {
449                #[cfg(feature = "ed25519")]
450                (ed25519_dalek::pkcs8::ALGORITHM_OID, None) => public_key
451                    .try_into()
452                    .map(crate::ed25519::Ed25519VerifyingKey::from_dalek)
453                    .map(InnerVerifyingKey::Ed25519)
454                    .map_err(SignatureError::from_source),
455
456                #[cfg(feature = "secp256r1")]
457                (
458                    p256::elliptic_curve::ALGORITHM_OID,
459                    Some(<p256::NistP256 as pkcs8::AssociatedOid>::OID),
460                ) => public_key
461                    .try_into()
462                    .map(crate::secp256r1::Secp256r1VerifyingKey::from_p256)
463                    .map(InnerVerifyingKey::Secp256r1)
464                    .map_err(SignatureError::from_source),
465
466                #[cfg(feature = "secp256k1")]
467                (
468                    k256::elliptic_curve::ALGORITHM_OID,
469                    Some(<k256::Secp256k1 as pkcs8::AssociatedOid>::OID),
470                ) => public_key
471                    .try_into()
472                    .map(crate::secp256k1::Secp256k1VerifyingKey::from_k256)
473                    .map(InnerVerifyingKey::Secp256k1)
474                    .map_err(SignatureError::from_source),
475
476                _ => Err(SignatureError::from_source(
477                    "unsupported or invalid public key type",
478                )),
479            }
480            .map(|inner| Self { inner })
481        }
482
483        #[cfg(feature = "pem")]
484        #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
485        /// Serialize this public key as DER-encoded data
486        pub fn to_der(&self) -> Result<Vec<u8>, SignatureError> {
487            match &self.inner {
488                #[cfg(feature = "ed25519")]
489                InnerVerifyingKey::Ed25519(verifying_key) => verifying_key.to_der(),
490                #[cfg(feature = "secp256k1")]
491                InnerVerifyingKey::Secp256k1(verifying_key) => verifying_key.to_der(),
492                #[cfg(feature = "secp256r1")]
493                InnerVerifyingKey::Secp256r1(verifying_key) => verifying_key.to_der(),
494            }
495        }
496
497        #[cfg(feature = "pem")]
498        #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
499        /// Deserialize public key from PEM.
500        pub fn from_pem(s: &str) -> Result<Self, SignatureError> {
501            use pkcs8::der::pem::PemLabel;
502
503            let (label, doc) = pkcs8::Document::from_pem(s).map_err(SignatureError::from_source)?;
504            pkcs8::SubjectPublicKeyInfoRef::validate_pem_label(label)
505                .map_err(SignatureError::from_source)?;
506            Self::from_der(doc.as_bytes())
507        }
508
509        #[cfg(feature = "pem")]
510        #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
511        /// Serialize this public key as PEM
512        pub fn to_pem(&self) -> Result<String, SignatureError> {
513            match &self.inner {
514                #[cfg(feature = "ed25519")]
515                InnerVerifyingKey::Ed25519(verifying_key) => verifying_key.to_pem(),
516                #[cfg(feature = "secp256k1")]
517                InnerVerifyingKey::Secp256k1(verifying_key) => verifying_key.to_pem(),
518                #[cfg(feature = "secp256r1")]
519                InnerVerifyingKey::Secp256r1(verifying_key) => verifying_key.to_pem(),
520            }
521        }
522    }
523
524    impl Verifier<SimpleSignature> for SimpleVerifiyingKey {
525        fn verify(
526            &self,
527            message: &[u8],
528            signature: &SimpleSignature,
529        ) -> Result<(), SignatureError> {
530            match &self.inner {
531                #[cfg(feature = "ed25519")]
532                InnerVerifyingKey::Ed25519(verifying_key) => {
533                    verifying_key.verify(message, signature)
534                }
535                #[cfg(feature = "secp256k1")]
536                InnerVerifyingKey::Secp256k1(verifying_key) => {
537                    verifying_key.verify(message, signature)
538                }
539                #[cfg(feature = "secp256r1")]
540                InnerVerifyingKey::Secp256r1(verifying_key) => {
541                    verifying_key.verify(message, signature)
542                }
543            }
544        }
545    }
546
547    impl Verifier<UserSignature> for SimpleVerifiyingKey {
548        fn verify(&self, message: &[u8], signature: &UserSignature) -> Result<(), SignatureError> {
549            let UserSignature::Simple(signature) = signature else {
550                return Err(SignatureError::from_source("not a simple signature"));
551            };
552
553            <Self as Verifier<SimpleSignature>>::verify(self, message, signature)
554        }
555    }
556
557    #[cfg(feature = "ed25519")]
558    #[cfg_attr(doc_cfg, doc(cfg(feature = "ed25519")))]
559    impl From<crate::ed25519::Ed25519VerifyingKey> for SimpleVerifiyingKey {
560        fn from(verifying_key: crate::ed25519::Ed25519VerifyingKey) -> Self {
561            Self {
562                inner: InnerVerifyingKey::Ed25519(verifying_key),
563            }
564        }
565    }
566
567    #[cfg(feature = "secp256r1")]
568    #[cfg_attr(doc_cfg, doc(cfg(feature = "secp256r1")))]
569    impl From<crate::secp256r1::Secp256r1VerifyingKey> for SimpleVerifiyingKey {
570        fn from(verifying_key: crate::secp256r1::Secp256r1VerifyingKey) -> Self {
571            Self {
572                inner: InnerVerifyingKey::Secp256r1(verifying_key),
573            }
574        }
575    }
576
577    #[cfg(feature = "secp256k1")]
578    #[cfg_attr(doc_cfg, doc(cfg(feature = "secp256k1")))]
579    impl From<crate::secp256k1::Secp256k1VerifyingKey> for SimpleVerifiyingKey {
580        fn from(verifying_key: crate::secp256k1::Secp256k1VerifyingKey) -> Self {
581            Self {
582                inner: InnerVerifyingKey::Secp256k1(verifying_key),
583            }
584        }
585    }
586}
587
588#[cfg(test)]
589mod test {
590    use super::*;
591    use crate::ed25519::Ed25519PrivateKey;
592    use crate::ed25519::Ed25519VerifyingKey;
593    use crate::secp256k1::Secp256k1PrivateKey;
594    use crate::secp256k1::Secp256k1VerifyingKey;
595    use crate::secp256r1::Secp256r1PrivateKey;
596    use crate::secp256r1::Secp256r1VerifyingKey;
597    use test_strategy::proptest;
598
599    #[cfg(target_arch = "wasm32")]
600    use wasm_bindgen_test::wasm_bindgen_test as test;
601
602    #[proptest]
603    fn ed25519_pem_der(signer: Ed25519PrivateKey) {
604        //
605        // Private Key
606        //
607        let public_key = signer.public_key();
608        let ed25519_der = signer.to_der().unwrap();
609        let ed25519_pem = signer.to_pem().unwrap();
610
611        // der and pem round-trip
612        let from_der = Ed25519PrivateKey::from_der(&ed25519_der).unwrap();
613        assert_eq!(from_der.public_key(), public_key);
614        let from_pem = Ed25519PrivateKey::from_pem(&ed25519_pem).unwrap();
615        assert_eq!(from_pem.public_key(), public_key);
616
617        // der and pem bytes don't convert to secp256r1 or secp256k1
618        Secp256r1PrivateKey::from_der(&ed25519_der).unwrap_err();
619        Secp256r1PrivateKey::from_pem(&ed25519_pem).unwrap_err();
620        Secp256k1PrivateKey::from_der(&ed25519_der).unwrap_err();
621        Secp256k1PrivateKey::from_pem(&ed25519_pem).unwrap_err();
622
623        // SimpleKeypair parses
624        let keypair_from_der = SimpleKeypair::from_der(&ed25519_der).unwrap();
625        assert_eq!(ed25519_der, keypair_from_der.to_der().unwrap());
626        let keypair_from_pem = SimpleKeypair::from_pem(&ed25519_pem).unwrap();
627        assert_eq!(ed25519_pem, keypair_from_pem.to_pem().unwrap());
628
629        //
630        // Verifying Key
631        //
632        let verifying_key = signer.verifying_key();
633        let der = verifying_key.to_der().unwrap();
634        let pem = verifying_key.to_pem().unwrap();
635
636        // der and pem round-trip
637        let from_der = Ed25519VerifyingKey::from_der(&der).unwrap();
638        assert_eq!(from_der.public_key(), public_key);
639        let from_pem = Ed25519VerifyingKey::from_pem(&pem).unwrap();
640        assert_eq!(from_pem.public_key(), public_key);
641
642        // der and pem bytes don't convert to secp256r1 or secp256k1
643        Secp256r1VerifyingKey::from_der(&der).unwrap_err();
644        Secp256r1VerifyingKey::from_pem(&pem).unwrap_err();
645        Secp256k1VerifyingKey::from_der(&der).unwrap_err();
646        Secp256k1VerifyingKey::from_pem(&pem).unwrap_err();
647
648        // SimpleKeypair parses
649        let from_der = SimpleVerifiyingKey::from_der(&der).unwrap();
650        assert_eq!(der, from_der.to_der().unwrap());
651        let from_pem = SimpleVerifiyingKey::from_pem(&pem).unwrap();
652        assert_eq!(pem, from_pem.to_pem().unwrap());
653    }
654
655    #[proptest]
656    fn secp256r1_pem_der(signer: Secp256r1PrivateKey) {
657        //
658        // Private Key
659        //
660        let public_key = signer.public_key();
661        let secp256r1_der = signer.to_der().unwrap();
662        let secp256r1_pem = signer.to_pem().unwrap();
663
664        // der and pem round-trip
665        let from_der = Secp256r1PrivateKey::from_der(&secp256r1_der).unwrap();
666        assert_eq!(from_der.public_key(), public_key);
667        let from_pem = Secp256r1PrivateKey::from_pem(&secp256r1_pem).unwrap();
668        assert_eq!(from_pem.public_key(), public_key);
669
670        // der and pem bytes don't convert to ed25519 or secp256k1
671        Ed25519PrivateKey::from_der(&secp256r1_der).unwrap_err();
672        Ed25519PrivateKey::from_pem(&secp256r1_pem).unwrap_err();
673        Secp256k1PrivateKey::from_der(&secp256r1_der).unwrap_err();
674        Secp256k1PrivateKey::from_pem(&secp256r1_pem).unwrap_err();
675
676        // SimpleKeypair parses
677        let keypair_from_der = SimpleKeypair::from_der(&secp256r1_der).unwrap();
678        assert_eq!(secp256r1_der, keypair_from_der.to_der().unwrap());
679        let keypair_from_pem = SimpleKeypair::from_pem(&secp256r1_pem).unwrap();
680        assert_eq!(secp256r1_pem, keypair_from_pem.to_pem().unwrap());
681
682        //
683        // Verifying Key
684        //
685        let verifying_key = signer.verifying_key();
686        let der = verifying_key.to_der().unwrap();
687        let pem = verifying_key.to_pem().unwrap();
688
689        // der and pem round-trip
690        let from_der = Secp256r1VerifyingKey::from_der(&der).unwrap();
691        assert_eq!(from_der.public_key(), public_key);
692        let from_pem = Secp256r1VerifyingKey::from_pem(&pem).unwrap();
693        assert_eq!(from_pem.public_key(), public_key);
694
695        // der and pem bytes don't convert to ed25519 or secp256k1
696        Ed25519VerifyingKey::from_der(&der).unwrap_err();
697        Ed25519VerifyingKey::from_pem(&pem).unwrap_err();
698        Secp256k1VerifyingKey::from_der(&der).unwrap_err();
699        Secp256k1VerifyingKey::from_pem(&pem).unwrap_err();
700
701        // SimpleKeypair parses
702        let from_der = SimpleVerifiyingKey::from_der(&der).unwrap();
703        assert_eq!(der, from_der.to_der().unwrap());
704        let from_pem = SimpleVerifiyingKey::from_pem(&pem).unwrap();
705        assert_eq!(pem, from_pem.to_pem().unwrap());
706    }
707
708    #[proptest]
709    fn secp256k1_pem_der(signer: Secp256k1PrivateKey) {
710        //
711        // Private Key
712        //
713        let public_key = signer.public_key();
714        let secp256k1_der = signer.to_der().unwrap();
715        let secp256k1_pem = signer.to_pem().unwrap();
716
717        // der and pem round-trip
718        let from_der = Secp256k1PrivateKey::from_der(&secp256k1_der).unwrap();
719        assert_eq!(from_der.public_key(), public_key);
720        let from_pem = Secp256k1PrivateKey::from_pem(&secp256k1_pem).unwrap();
721        assert_eq!(from_pem.public_key(), public_key);
722
723        // der and pem bytes don't convert to secp256r1 or ed25519
724        Ed25519PrivateKey::from_der(&secp256k1_der).unwrap_err();
725        Ed25519PrivateKey::from_pem(&secp256k1_pem).unwrap_err();
726        Secp256r1PrivateKey::from_der(&secp256k1_der).unwrap_err();
727        Secp256r1PrivateKey::from_pem(&secp256k1_pem).unwrap_err();
728
729        // SimpleKeypair parses
730        let keypair_from_der = SimpleKeypair::from_der(&secp256k1_der).unwrap();
731        assert_eq!(secp256k1_der, keypair_from_der.to_der().unwrap());
732        let keypair_from_pem = SimpleKeypair::from_pem(&secp256k1_pem).unwrap();
733        assert_eq!(secp256k1_pem, keypair_from_pem.to_pem().unwrap());
734
735        //
736        // Verifying Key
737        //
738        let verifying_key = signer.verifying_key();
739        let der = verifying_key.to_der().unwrap();
740        let pem = verifying_key.to_pem().unwrap();
741
742        // der and pem round-trip
743        let from_der = Secp256k1VerifyingKey::from_der(&der).unwrap();
744        assert_eq!(from_der.public_key(), public_key);
745        let from_pem = Secp256k1VerifyingKey::from_pem(&pem).unwrap();
746        assert_eq!(from_pem.public_key(), public_key);
747
748        // der and pem bytes don't convert to ed25519 or secp256r1
749        Ed25519VerifyingKey::from_der(&der).unwrap_err();
750        Ed25519VerifyingKey::from_pem(&pem).unwrap_err();
751        Secp256r1VerifyingKey::from_der(&der).unwrap_err();
752        Secp256r1VerifyingKey::from_pem(&pem).unwrap_err();
753
754        // SimpleKeypair parses
755        let from_der = SimpleVerifiyingKey::from_der(&der).unwrap();
756        assert_eq!(der, from_der.to_der().unwrap());
757        let from_pem = SimpleVerifiyingKey::from_pem(&pem).unwrap();
758        assert_eq!(pem, from_pem.to_pem().unwrap());
759    }
760
761    #[proptest]
762    fn simple_verifying_key_derives_matching_address(
763        ed25519: Ed25519PrivateKey,
764        secp256k1: Secp256k1PrivateKey,
765        secp256r1: Secp256r1PrivateKey,
766    ) {
767        // SimpleVerifiyingKey::derive_address must agree with the address
768        // derived from the scheme-specific public key.
769        let expected = ed25519.public_key().derive_address();
770        let keypair = SimpleKeypair::from(ed25519);
771        assert_eq!(keypair.verifying_key().derive_address(), expected);
772
773        let expected = secp256k1.public_key().derive_address();
774        let keypair = SimpleKeypair::from(secp256k1);
775        assert_eq!(keypair.verifying_key().derive_address(), expected);
776
777        let expected = secp256r1.public_key().derive_address();
778        let keypair = SimpleKeypair::from(secp256r1);
779        assert_eq!(keypair.verifying_key().derive_address(), expected);
780    }
781
782    // Round-trip and rejection tests for the suiprivkey Bech32 format.
783    //
784    // These mirror the format produced by the Sui CLI and the upstream
785    // `sui-types` crate. `EXPECTED_ED25519_VECTOR` is taken directly from
786    // `crates/sui-types/src/unit_tests/crypto_tests.rs` in the main sui repo
787    // and is included as a regression vector against any future encoding
788    // drift.
789    #[cfg(feature = "bech32")]
790    mod bech32 {
791        use super::*;
792        use sui_sdk_types::SignatureScheme;
793
794        #[cfg(target_arch = "wasm32")]
795        use wasm_bindgen_test::wasm_bindgen_test as test;
796
797        // Upstream test vector: `Ed25519KeyPair::generate(&mut StdRng::from_seed([0; 32]))`
798        // encoded with `SuiKeyPair::encode()` produces this string. The leading
799        // flag byte is 0x00 (Ed25519); the remaining 32 bytes are the private
800        // key.
801        const UPSTREAM_ED25519_SUIPRIVKEY: &str =
802            "suiprivkey1qzdlfxn2qa2lj5uprl8pyhexs02sg2wrhdy7qaq50cqgnffw4c2477kg9h3";
803
804        #[proptest]
805        fn ed25519_round_trip(signer: Ed25519PrivateKey) {
806            let encoded = signer.to_suiprivkey().unwrap();
807            let decoded = Ed25519PrivateKey::from_suiprivkey(&encoded).unwrap();
808            assert_eq!(decoded.public_key(), signer.public_key());
809
810            // SimpleKeypair dispatch agrees.
811            let keypair = SimpleKeypair::from_suiprivkey(&encoded).unwrap();
812            assert_eq!(keypair.scheme(), signer.scheme());
813            assert_eq!(encoded, keypair.to_suiprivkey().unwrap());
814        }
815
816        #[proptest]
817        fn secp256k1_round_trip(signer: Secp256k1PrivateKey) {
818            let encoded = signer.to_suiprivkey().unwrap();
819            let decoded = Secp256k1PrivateKey::from_suiprivkey(&encoded).unwrap();
820            assert_eq!(decoded.public_key(), signer.public_key());
821
822            let keypair = SimpleKeypair::from_suiprivkey(&encoded).unwrap();
823            assert_eq!(keypair.scheme(), signer.scheme());
824            assert_eq!(encoded, keypair.to_suiprivkey().unwrap());
825        }
826
827        #[proptest]
828        fn secp256r1_round_trip(signer: Secp256r1PrivateKey) {
829            let encoded = signer.to_suiprivkey().unwrap();
830            let decoded = Secp256r1PrivateKey::from_suiprivkey(&encoded).unwrap();
831            assert_eq!(decoded.public_key(), signer.public_key());
832
833            let keypair = SimpleKeypair::from_suiprivkey(&encoded).unwrap();
834            assert_eq!(keypair.scheme(), signer.scheme());
835            assert_eq!(encoded, keypair.to_suiprivkey().unwrap());
836        }
837
838        #[test]
839        fn upstream_ed25519_vector_round_trips() {
840            let keypair = SimpleKeypair::from_suiprivkey(UPSTREAM_ED25519_SUIPRIVKEY).unwrap();
841            assert_eq!(keypair.scheme(), SignatureScheme::Ed25519);
842            assert_eq!(
843                keypair.to_suiprivkey().unwrap(),
844                UPSTREAM_ED25519_SUIPRIVKEY
845            );
846
847            // Per-scheme decoder accepts it too.
848            Ed25519PrivateKey::from_suiprivkey(UPSTREAM_ED25519_SUIPRIVKEY).unwrap();
849            // Wrong-scheme per-scheme decoders reject it.
850            Secp256k1PrivateKey::from_suiprivkey(UPSTREAM_ED25519_SUIPRIVKEY).unwrap_err();
851            Secp256r1PrivateKey::from_suiprivkey(UPSTREAM_ED25519_SUIPRIVKEY).unwrap_err();
852        }
853
854        #[test]
855        fn rejects_wrong_hrp() {
856            // Same payload as the upstream Ed25519 vector but encoded with a
857            // different HRP — must fail.
858            let bytes = ::bech32::primitives::decode::CheckedHrpstring::new::<::bech32::Bech32>(
859                UPSTREAM_ED25519_SUIPRIVKEY,
860            )
861            .unwrap()
862            .byte_iter()
863            .collect::<Vec<_>>();
864            let wrong_hrp = ::bech32::Hrp::parse("notsui").unwrap();
865            let encoded = ::bech32::encode::<::bech32::Bech32>(wrong_hrp, &bytes).unwrap();
866
867            SimpleKeypair::from_suiprivkey(&encoded).unwrap_err();
868            Ed25519PrivateKey::from_suiprivkey(&encoded).unwrap_err();
869        }
870
871        #[test]
872        fn rejects_bech32m_checksum() {
873            // Re-encode the upstream Ed25519 payload using the Bech32m
874            // checksum variant. A correctly-implemented decoder must reject
875            // this, since the suipriv format uses BIP-173 Bech32 only.
876            let bytes = ::bech32::primitives::decode::CheckedHrpstring::new::<::bech32::Bech32>(
877                UPSTREAM_ED25519_SUIPRIVKEY,
878            )
879            .unwrap()
880            .byte_iter()
881            .collect::<Vec<_>>();
882            let hrp = ::bech32::Hrp::parse("suiprivkey").unwrap();
883            let bech32m = ::bech32::encode::<::bech32::Bech32m>(hrp, &bytes).unwrap();
884            assert_ne!(bech32m, UPSTREAM_ED25519_SUIPRIVKEY);
885
886            SimpleKeypair::from_suiprivkey(&bech32m).unwrap_err();
887            Ed25519PrivateKey::from_suiprivkey(&bech32m).unwrap_err();
888        }
889    }
890
891    // Round-trip and rejection tests for the legacy Base64 keystore format.
892    //
893    // The payload is the same `flag || private_key` bytes as the Bech32
894    // `suiprivkey` format, encoded as plain Base64 instead. This is the
895    // encoding used for entries of the Sui CLI's `sui.keystore` file.
896    mod base64 {
897        use super::*;
898        use sui_sdk_types::SignatureScheme;
899
900        #[cfg(target_arch = "wasm32")]
901        use wasm_bindgen_test::wasm_bindgen_test as test;
902
903        // The same payload as the bech32 module's upstream Ed25519 vector
904        // (`Ed25519KeyPair::generate(&mut StdRng::from_seed([0; 32]))`),
905        // Base64-encoded: 0x00 flag byte followed by the 32 private key
906        // bytes.
907        const UPSTREAM_ED25519_BASE64: &str = "AJv0mmoHVflTgR/OEl8mg9UEKcO7SeB0FH4AiaUurhVf";
908
909        #[proptest]
910        fn ed25519_round_trip(signer: Ed25519PrivateKey) {
911            let encoded = signer.to_base64();
912            let decoded = Ed25519PrivateKey::from_base64(&encoded).unwrap();
913            assert_eq!(decoded.public_key(), signer.public_key());
914
915            // SimpleKeypair dispatch agrees.
916            let keypair = SimpleKeypair::from_base64(&encoded).unwrap();
917            assert_eq!(keypair.scheme(), signer.scheme());
918            assert_eq!(encoded, keypair.to_base64());
919        }
920
921        #[proptest]
922        fn secp256k1_round_trip(signer: Secp256k1PrivateKey) {
923            let encoded = signer.to_base64();
924            let decoded = Secp256k1PrivateKey::from_base64(&encoded).unwrap();
925            assert_eq!(decoded.public_key(), signer.public_key());
926
927            let keypair = SimpleKeypair::from_base64(&encoded).unwrap();
928            assert_eq!(keypair.scheme(), signer.scheme());
929            assert_eq!(encoded, keypair.to_base64());
930        }
931
932        #[proptest]
933        fn secp256r1_round_trip(signer: Secp256r1PrivateKey) {
934            let encoded = signer.to_base64();
935            let decoded = Secp256r1PrivateKey::from_base64(&encoded).unwrap();
936            assert_eq!(decoded.public_key(), signer.public_key());
937
938            let keypair = SimpleKeypair::from_base64(&encoded).unwrap();
939            assert_eq!(keypair.scheme(), signer.scheme());
940            assert_eq!(encoded, keypair.to_base64());
941        }
942
943        #[test]
944        fn upstream_ed25519_vector_round_trips() {
945            let keypair = SimpleKeypair::from_base64(UPSTREAM_ED25519_BASE64).unwrap();
946            assert_eq!(keypair.scheme(), SignatureScheme::Ed25519);
947            assert_eq!(keypair.to_base64(), UPSTREAM_ED25519_BASE64);
948
949            // Per-scheme decoder accepts it too.
950            Ed25519PrivateKey::from_base64(UPSTREAM_ED25519_BASE64).unwrap();
951            // Wrong-scheme per-scheme decoders reject it.
952            Secp256k1PrivateKey::from_base64(UPSTREAM_ED25519_BASE64).unwrap_err();
953            Secp256r1PrivateKey::from_base64(UPSTREAM_ED25519_BASE64).unwrap_err();
954        }
955
956        #[cfg(feature = "bech32")]
957        #[test]
958        fn agrees_with_suiprivkey_encoding() {
959            // Both encodings carry the same payload, so converting between
960            // them must be lossless.
961            let keypair = SimpleKeypair::from_base64(UPSTREAM_ED25519_BASE64).unwrap();
962            let suiprivkey = keypair.to_suiprivkey().unwrap();
963            let round_tripped = SimpleKeypair::from_suiprivkey(&suiprivkey).unwrap();
964            assert_eq!(round_tripped.to_base64(), UPSTREAM_ED25519_BASE64);
965        }
966
967        #[test]
968        fn rejects_invalid_input() {
969            // Not Base64 at all.
970            SimpleKeypair::from_base64("not base64!").unwrap_err();
971            Ed25519PrivateKey::from_base64("not base64!").unwrap_err();
972
973            // Valid Base64 but an empty payload (no flag byte).
974            SimpleKeypair::from_base64("").unwrap_err();
975
976            // Valid Base64 but an unknown scheme flag (0xff).
977            use base64ct::Encoding;
978            let payload = base64ct::Base64::decode_vec(UPSTREAM_ED25519_BASE64).unwrap();
979            let mut bad_flag_payload = payload.clone();
980            bad_flag_payload[0] = 0xff;
981            let bad_flag = base64ct::Base64::encode_string(&bad_flag_payload);
982            SimpleKeypair::from_base64(&bad_flag).unwrap_err();
983
984            // Valid Base64 and flag but truncated key bytes.
985            let truncated = base64ct::Base64::encode_string(&payload[..16]);
986            SimpleKeypair::from_base64(&truncated).unwrap_err();
987        }
988    }
989}