iota_sdk_types/crypto/
signature.rs

1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2025 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5use super::{
6    Ed25519PublicKey, Ed25519Signature, MultisigAggregatedSignature, PasskeyAuthenticator,
7    Secp256k1PublicKey, Secp256k1Signature, Secp256r1PublicKey, Secp256r1Signature,
8    ZkLoginAuthenticator,
9};
10
11/// A basic signature
12///
13/// This enumeration defines the set of simple or basic signature schemes
14/// supported by IOTA. Most signature schemes supported by IOTA end up
15/// comprising of a at least one simple signature scheme.
16///
17/// # BCS
18///
19/// The BCS serialized form for this type is defined by the following ABNF:
20///
21/// ```text
22/// simple-signature-bcs = bytes ; where the contents of the bytes are defined by <simple-signature>
23/// simple-signature = (ed25519-flag ed25519-signature ed25519-public-key) /
24///                    (secp256k1-flag secp256k1-signature secp256k1-public-key) /
25///                    (secp256r1-flag secp256r1-signature secp256r1-public-key)
26/// ```
27///
28/// Note: Due to historical reasons, signatures are serialized slightly
29/// different from the majority of the types in IOTA. In particular if a
30/// signature is ever embedded in another structure it generally is serialized
31/// as `bytes` meaning it has a length prefix that defines the length of
32/// the completely serialized signature.
33#[derive(Clone, Debug, PartialEq, Eq, Hash)]
34#[cfg_attr(
35    feature = "schemars",
36    derive(schemars::JsonSchema),
37    schemars(tag = "scheme", rename_all = "lowercase")
38)]
39#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
40pub enum SimpleSignature {
41    Ed25519 {
42        signature: Ed25519Signature,
43        public_key: Ed25519PublicKey,
44    },
45    Secp256k1 {
46        signature: Secp256k1Signature,
47        public_key: Secp256k1PublicKey,
48    },
49    Secp256r1 {
50        signature: Secp256r1Signature,
51        public_key: Secp256r1PublicKey,
52    },
53}
54
55impl SimpleSignature {
56    crate::def_is!(Ed25519, Secp256k1, Secp256r1);
57
58    pub fn as_ed25519_sig_opt(&self) -> Option<&Ed25519Signature> {
59        if let Self::Ed25519 { signature, .. } = self {
60            Some(signature)
61        } else {
62            None
63        }
64    }
65
66    pub fn as_ed25519_sig(&self) -> &Ed25519Signature {
67        self.as_ed25519_sig_opt().expect("not an ed25519 signature")
68    }
69
70    pub fn as_ed25519_pub_key_opt(&self) -> Option<&Ed25519PublicKey> {
71        if let Self::Ed25519 { public_key, .. } = self {
72            Some(public_key)
73        } else {
74            None
75        }
76    }
77
78    pub fn as_ed25519_pub_key(&self) -> &Ed25519PublicKey {
79        self.as_ed25519_pub_key_opt()
80            .expect("not an ed25519 public key")
81    }
82
83    pub fn into_ed25519_opt(self) -> Option<(Ed25519Signature, Ed25519PublicKey)> {
84        if let Self::Ed25519 {
85            signature,
86            public_key,
87            ..
88        } = self
89        {
90            Some((signature, public_key))
91        } else {
92            None
93        }
94    }
95
96    pub fn into_ed25519(self) -> (Ed25519Signature, Ed25519PublicKey) {
97        self.into_ed25519_opt().expect("not an ed25519 signature")
98    }
99
100    pub fn as_secp256k1_sig_opt(&self) -> Option<&Secp256k1Signature> {
101        if let Self::Secp256k1 { signature, .. } = self {
102            Some(signature)
103        } else {
104            None
105        }
106    }
107
108    pub fn as_secp256k1_sig(&self) -> &Secp256k1Signature {
109        self.as_secp256k1_sig_opt()
110            .expect("not an secp256k1 signature")
111    }
112
113    pub fn as_secp256k1_pub_key_opt(&self) -> Option<&Secp256k1PublicKey> {
114        if let Self::Secp256k1 { public_key, .. } = self {
115            Some(public_key)
116        } else {
117            None
118        }
119    }
120
121    pub fn as_secp256k1_pub_key(&self) -> &Secp256k1PublicKey {
122        self.as_secp256k1_pub_key_opt()
123            .expect("not an secp256k1 public key")
124    }
125
126    pub fn into_secp256k1_opt(self) -> Option<(Secp256k1Signature, Secp256k1PublicKey)> {
127        if let Self::Secp256k1 {
128            signature,
129            public_key,
130            ..
131        } = self
132        {
133            Some((signature, public_key))
134        } else {
135            None
136        }
137    }
138
139    pub fn into_secp256k1(self) -> (Secp256k1Signature, Secp256k1PublicKey) {
140        self.into_secp256k1_opt()
141            .expect("not an secp256k1 signature")
142    }
143
144    pub fn as_secp256r1_sig_opt(&self) -> Option<&Secp256r1Signature> {
145        if let Self::Secp256r1 { signature, .. } = self {
146            Some(signature)
147        } else {
148            None
149        }
150    }
151
152    pub fn as_secp256r1_sig(&self) -> &Secp256r1Signature {
153        self.as_secp256r1_sig_opt()
154            .expect("not an secp256r1 signature")
155    }
156
157    pub fn as_secp256r1_pub_key_opt(&self) -> Option<&Secp256r1PublicKey> {
158        if let Self::Secp256r1 { public_key, .. } = self {
159            Some(public_key)
160        } else {
161            None
162        }
163    }
164
165    pub fn as_secp256r1_pub_key(&self) -> &Secp256r1PublicKey {
166        self.as_secp256r1_pub_key_opt()
167            .expect("not an secp256r1 public key")
168    }
169
170    pub fn into_secp256r1_opt(self) -> Option<(Secp256r1Signature, Secp256r1PublicKey)> {
171        if let Self::Secp256r1 {
172            signature,
173            public_key,
174            ..
175        } = self
176        {
177            Some((signature, public_key))
178        } else {
179            None
180        }
181    }
182
183    pub fn into_secp256r1(self) -> (Secp256r1Signature, Secp256r1PublicKey) {
184        self.into_secp256r1_opt()
185            .expect("not an secp256r1 signature")
186    }
187
188    /// Return the flag for this signature scheme
189    pub fn scheme(&self) -> SignatureScheme {
190        match self {
191            SimpleSignature::Ed25519 { .. } => SignatureScheme::Ed25519,
192            SimpleSignature::Secp256k1 { .. } => SignatureScheme::Secp256k1,
193            SimpleSignature::Secp256r1 { .. } => SignatureScheme::Secp256r1,
194        }
195    }
196}
197
198/// Flag use to disambiguate the signature schemes supported by IOTA.
199///
200/// # BCS
201///
202/// The BCS serialized form for this type is defined by the following ABNF:
203///
204/// ```text
205/// signature-scheme = ed25519-flag / secp256k1-flag / secp256r1-flag /
206///                    multisig-flag / bls-flag / zklogin-flag / passkey-flag
207/// ed25519-flag     = %x00
208/// secp256k1-flag   = %x01
209/// secp256r1-flag   = %x02
210/// multisig-flag    = %x03
211/// bls-flag         = %x04
212/// zklogin-flag     = %x05
213/// passkey-flag     = %x06
214/// ```
215#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, strum::Display)]
216#[strum(serialize_all = "lowercase")]
217#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
218#[repr(u8)]
219pub enum SignatureScheme {
220    Ed25519 = 0x00,
221    Secp256k1 = 0x01,
222    Secp256r1 = 0x02,
223    Multisig = 0x03,
224    Bls12381 = 0x04, // This is currently not supported for user addresses
225    ZkLogin = 0x05,
226    Passkey = 0x06,
227}
228
229impl SignatureScheme {
230    crate::def_is!(
231        Ed25519, Secp256k1, Secp256r1, Multisig, Bls12381, ZkLogin, Passkey,
232    );
233
234    /// Try constructing from a byte flag
235    pub fn from_byte(flag: u8) -> Result<Self, InvalidSignatureScheme> {
236        match flag {
237            0x00 => Ok(Self::Ed25519),
238            0x01 => Ok(Self::Secp256k1),
239            0x02 => Ok(Self::Secp256r1),
240            0x03 => Ok(Self::Multisig),
241            0x04 => Ok(Self::Bls12381),
242            0x05 => Ok(Self::ZkLogin),
243            0x06 => Ok(Self::Passkey),
244            invalid => Err(InvalidSignatureScheme(invalid)),
245        }
246    }
247
248    /// Convert to a byte flag
249    pub fn to_u8(self) -> u8 {
250        self as u8
251    }
252}
253
254impl super::ZkLoginPublicIdentifier {
255    /// Return the flag for this signature scheme
256    pub fn scheme(&self) -> SignatureScheme {
257        SignatureScheme::ZkLogin
258    }
259}
260
261impl super::PasskeyPublicKey {
262    /// Return the flag for this signature scheme
263    pub fn scheme(&self) -> SignatureScheme {
264        SignatureScheme::Passkey
265    }
266}
267
268#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
269pub struct InvalidSignatureScheme(u8);
270
271impl std::fmt::Display for InvalidSignatureScheme {
272    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
273        write!(f, "invalid signature scheme: {:02x}", self.0)
274    }
275}
276
277/// A signature from a user
278///
279/// A `UserSignature` is most commonly used to authorize the execution and
280/// inclusion of a transaction to the blockchain.
281///
282/// # BCS
283///
284/// The BCS serialized form for this type is defined by the following ABNF:
285///
286/// ```text
287/// user-signature-bcs = bytes ; where the contents of the bytes are defined by <user-signature>
288/// user-signature = simple-signature / multisig / multisig-legacy / zklogin / passkey
289/// ```
290///
291/// Note: Due to historical reasons, signatures are serialized slightly
292/// different from the majority of the types in IOTA. In particular if a
293/// signature is ever embedded in another structure it generally is serialized
294/// as `bytes` meaning it has a length prefix that defines the length of
295/// the completely serialized signature.
296#[derive(Clone, Debug, PartialEq, Eq)]
297#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
298pub enum UserSignature {
299    Simple(SimpleSignature),
300    Multisig(MultisigAggregatedSignature),
301    ZkLogin(Box<ZkLoginAuthenticator>),
302    Passkey(PasskeyAuthenticator),
303}
304
305impl UserSignature {
306    crate::def_is_as_into_opt!(
307        Simple(SimpleSignature),
308        Multisig(MultisigAggregatedSignature),
309        Passkey(PasskeyAuthenticator)
310    );
311
312    pub fn is_zklogin(&self) -> bool {
313        matches!(self, Self::ZkLogin(_))
314    }
315
316    pub fn as_zklogin_opt(&self) -> Option<&ZkLoginAuthenticator> {
317        if let Self::ZkLogin(auth) = self {
318            Some(auth)
319        } else {
320            None
321        }
322    }
323
324    pub fn as_zklogin(&self) -> &ZkLoginAuthenticator {
325        self.as_zklogin_opt().expect("not a ZkLogin authenticator")
326    }
327
328    pub fn into_zklogin_opt(self) -> Option<ZkLoginAuthenticator> {
329        if let Self::ZkLogin(auth) = self {
330            Some(*auth)
331        } else {
332            None
333        }
334    }
335
336    pub fn into_zklogin(self) -> ZkLoginAuthenticator {
337        self.into_zklogin_opt()
338            .expect("not a ZkLogin authenticator")
339    }
340
341    /// Return the flag for this signature scheme
342    pub fn scheme(&self) -> SignatureScheme {
343        match self {
344            UserSignature::Simple(simple) => simple.scheme(),
345            UserSignature::Multisig(_) => SignatureScheme::Multisig,
346            UserSignature::ZkLogin(_) => SignatureScheme::ZkLogin,
347            UserSignature::Passkey(_) => SignatureScheme::Passkey,
348        }
349    }
350}
351
352#[cfg(feature = "serde")]
353#[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
354mod serialization {
355    use super::*;
356    use crate::crypto::SignatureFromBytesError;
357
358    impl SimpleSignature {
359        pub fn to_bytes(&self) -> Vec<u8> {
360            let mut buf = Vec::new();
361            match self {
362                SimpleSignature::Ed25519 {
363                    signature,
364                    public_key,
365                } => {
366                    buf.push(SignatureScheme::Ed25519 as u8);
367                    buf.extend_from_slice(signature.as_ref());
368                    buf.extend_from_slice(public_key.as_ref());
369                }
370                SimpleSignature::Secp256k1 {
371                    signature,
372                    public_key,
373                } => {
374                    buf.push(SignatureScheme::Secp256k1 as u8);
375                    buf.extend_from_slice(signature.as_ref());
376                    buf.extend_from_slice(public_key.as_ref());
377                }
378                SimpleSignature::Secp256r1 {
379                    signature,
380                    public_key,
381                } => {
382                    buf.push(SignatureScheme::Secp256r1 as u8);
383                    buf.extend_from_slice(signature.as_ref());
384                    buf.extend_from_slice(public_key.as_ref());
385                }
386            }
387
388            buf
389        }
390
391        pub fn from_serialized_bytes(
392            bytes: impl AsRef<[u8]>,
393        ) -> Result<Self, SignatureFromBytesError> {
394            let bytes = bytes.as_ref();
395            let flag =
396                SignatureScheme::from_byte(*bytes.first().ok_or_else(|| {
397                    SignatureFromBytesError::new("missing signature scheme flag")
398                })?)
399                .map_err(SignatureFromBytesError::new)?;
400            match flag {
401                SignatureScheme::Ed25519 => {
402                    let expected_length = 1 + Ed25519Signature::LENGTH + Ed25519PublicKey::LENGTH;
403
404                    if bytes.len() != expected_length {
405                        return Err(SignatureFromBytesError::new("invalid ed25519 signature"));
406                    }
407
408                    let mut signature = [0; Ed25519Signature::LENGTH];
409                    signature.copy_from_slice(&bytes[1..(1 + Ed25519Signature::LENGTH)]);
410
411                    let mut public_key = [0; Ed25519PublicKey::LENGTH];
412                    public_key.copy_from_slice(&bytes[(1 + Ed25519Signature::LENGTH)..]);
413
414                    Ok(SimpleSignature::Ed25519 {
415                        signature: Ed25519Signature::new(signature),
416                        public_key: Ed25519PublicKey::new(public_key),
417                    })
418                }
419                SignatureScheme::Secp256k1 => {
420                    let expected_length =
421                        1 + Secp256k1Signature::LENGTH + Secp256k1PublicKey::LENGTH;
422
423                    if bytes.len() != expected_length {
424                        return Err(SignatureFromBytesError::new("invalid secp25k1 signature"));
425                    }
426
427                    let mut signature = [0; Secp256k1Signature::LENGTH];
428                    signature.copy_from_slice(&bytes[1..(1 + Secp256k1Signature::LENGTH)]);
429
430                    let mut public_key = [0; Secp256k1PublicKey::LENGTH];
431                    public_key.copy_from_slice(&bytes[(1 + Secp256k1Signature::LENGTH)..]);
432
433                    Ok(SimpleSignature::Secp256k1 {
434                        signature: Secp256k1Signature::new(signature),
435                        public_key: Secp256k1PublicKey::new(public_key),
436                    })
437                }
438                SignatureScheme::Secp256r1 => {
439                    let expected_length =
440                        1 + Secp256r1Signature::LENGTH + Secp256r1PublicKey::LENGTH;
441
442                    if bytes.len() != expected_length {
443                        return Err(SignatureFromBytesError::new("invalid secp25r1 signature"));
444                    }
445
446                    let mut signature = [0; Secp256r1Signature::LENGTH];
447                    signature.copy_from_slice(&bytes[1..(1 + Secp256r1Signature::LENGTH)]);
448
449                    let mut public_key = [0; Secp256r1PublicKey::LENGTH];
450                    public_key.copy_from_slice(&bytes[(1 + Secp256r1Signature::LENGTH)..]);
451
452                    Ok(SimpleSignature::Secp256r1 {
453                        signature: Secp256r1Signature::new(signature),
454                        public_key: Secp256r1PublicKey::new(public_key),
455                    })
456                }
457                SignatureScheme::Multisig
458                | SignatureScheme::Bls12381
459                | SignatureScheme::ZkLogin
460                | SignatureScheme::Passkey => {
461                    Err(SignatureFromBytesError::new("invalid signature scheme"))
462                }
463            }
464        }
465    }
466
467    impl serde::Serialize for SimpleSignature {
468        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
469        where
470            S: serde::Serializer,
471        {
472            #[derive(serde::Serialize)]
473            #[serde(tag = "scheme")]
474            #[serde(rename_all = "lowercase")]
475            enum Sig<'a> {
476                Ed25519 {
477                    signature: &'a Ed25519Signature,
478                    public_key: &'a Ed25519PublicKey,
479                },
480                Secp256k1 {
481                    signature: &'a Secp256k1Signature,
482                    public_key: &'a Secp256k1PublicKey,
483                },
484                Secp256r1 {
485                    signature: &'a Secp256r1Signature,
486                    public_key: &'a Secp256r1PublicKey,
487                },
488            }
489
490            if serializer.is_human_readable() {
491                let sig = match self {
492                    SimpleSignature::Ed25519 {
493                        signature,
494                        public_key,
495                    } => Sig::Ed25519 {
496                        signature,
497                        public_key,
498                    },
499                    SimpleSignature::Secp256k1 {
500                        signature,
501                        public_key,
502                    } => Sig::Secp256k1 {
503                        signature,
504                        public_key,
505                    },
506                    SimpleSignature::Secp256r1 {
507                        signature,
508                        public_key,
509                    } => Sig::Secp256r1 {
510                        signature,
511                        public_key,
512                    },
513                };
514
515                sig.serialize(serializer)
516            } else {
517                match self {
518                    SimpleSignature::Ed25519 {
519                        signature,
520                        public_key,
521                    } => {
522                        let mut buf = [0; 1 + Ed25519Signature::LENGTH + Ed25519PublicKey::LENGTH];
523                        buf[0] = SignatureScheme::Ed25519 as u8;
524                        buf[1..(1 + Ed25519Signature::LENGTH)].copy_from_slice(signature.as_ref());
525                        buf[(1 + Ed25519Signature::LENGTH)..].copy_from_slice(public_key.as_ref());
526
527                        serializer.serialize_bytes(&buf)
528                    }
529                    SimpleSignature::Secp256k1 {
530                        signature,
531                        public_key,
532                    } => {
533                        let mut buf =
534                            [0; 1 + Secp256k1Signature::LENGTH + Secp256k1PublicKey::LENGTH];
535                        buf[0] = SignatureScheme::Secp256k1 as u8;
536                        buf[1..(1 + Secp256k1Signature::LENGTH)]
537                            .copy_from_slice(signature.as_ref());
538                        buf[(1 + Secp256k1Signature::LENGTH)..]
539                            .copy_from_slice(public_key.as_ref());
540
541                        serializer.serialize_bytes(&buf)
542                    }
543                    SimpleSignature::Secp256r1 {
544                        signature,
545                        public_key,
546                    } => {
547                        let mut buf =
548                            [0; 1 + Secp256r1Signature::LENGTH + Secp256r1PublicKey::LENGTH];
549                        buf[0] = SignatureScheme::Secp256r1 as u8;
550                        buf[1..(1 + Secp256r1Signature::LENGTH)]
551                            .copy_from_slice(signature.as_ref());
552                        buf[(1 + Secp256r1Signature::LENGTH)..]
553                            .copy_from_slice(public_key.as_ref());
554
555                        serializer.serialize_bytes(&buf)
556                    }
557                }
558            }
559        }
560    }
561
562    impl<'de> serde::Deserialize<'de> for SimpleSignature {
563        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
564        where
565            D: serde::Deserializer<'de>,
566        {
567            #[derive(serde::Deserialize)]
568            #[serde(tag = "scheme")]
569            #[serde(rename_all = "lowercase")]
570            enum Sig {
571                Ed25519 {
572                    signature: Ed25519Signature,
573                    public_key: Ed25519PublicKey,
574                },
575                Secp256k1 {
576                    signature: Secp256k1Signature,
577                    public_key: Secp256k1PublicKey,
578                },
579                Secp256r1 {
580                    signature: Secp256r1Signature,
581                    public_key: Secp256r1PublicKey,
582                },
583            }
584
585            if deserializer.is_human_readable() {
586                let sig = Sig::deserialize(deserializer)?;
587                Ok(match sig {
588                    Sig::Ed25519 {
589                        signature,
590                        public_key,
591                    } => SimpleSignature::Ed25519 {
592                        signature,
593                        public_key,
594                    },
595                    Sig::Secp256k1 {
596                        signature,
597                        public_key,
598                    } => SimpleSignature::Secp256k1 {
599                        signature,
600                        public_key,
601                    },
602                    Sig::Secp256r1 {
603                        signature,
604                        public_key,
605                    } => SimpleSignature::Secp256r1 {
606                        signature,
607                        public_key,
608                    },
609                })
610            } else {
611                let bytes: std::borrow::Cow<'de, [u8]> =
612                    std::borrow::Cow::deserialize(deserializer)?;
613                Self::from_serialized_bytes(bytes).map_err(serde::de::Error::custom)
614            }
615        }
616    }
617
618    impl UserSignature {
619        pub fn to_bytes(&self) -> Vec<u8> {
620            match self {
621                UserSignature::Simple(s) => s.to_bytes(),
622                UserSignature::Multisig(m) => m.to_bytes(),
623                UserSignature::ZkLogin(z) => z.to_bytes(),
624                UserSignature::Passkey(p) => p.to_bytes(),
625            }
626        }
627
628        pub fn to_base64(&self) -> String {
629            use base64ct::Encoding;
630
631            base64ct::Base64::encode_string(&self.to_bytes())
632        }
633
634        fn from_serialized_bytes(bytes: impl AsRef<[u8]>) -> Result<Self, SignatureFromBytesError> {
635            let bytes = bytes.as_ref();
636
637            let flag =
638                SignatureScheme::from_byte(*bytes.first().ok_or_else(|| {
639                    SignatureFromBytesError::new("missing signature scheme flag")
640                })?)
641                .map_err(SignatureFromBytesError::new)?;
642            match flag {
643                SignatureScheme::Ed25519
644                | SignatureScheme::Secp256k1
645                | SignatureScheme::Secp256r1 => {
646                    let simple = SimpleSignature::from_serialized_bytes(bytes)?;
647                    Ok(Self::Simple(simple))
648                }
649                SignatureScheme::Multisig => {
650                    let multisig = MultisigAggregatedSignature::from_serialized_bytes(bytes)?;
651                    Ok(Self::Multisig(multisig))
652                }
653                SignatureScheme::Bls12381 => Err(SignatureFromBytesError::new(
654                    "bls not supported for user signatures",
655                )),
656                SignatureScheme::ZkLogin => {
657                    let zklogin = ZkLoginAuthenticator::from_serialized_bytes(bytes)?;
658                    Ok(Self::ZkLogin(Box::new(zklogin)))
659                }
660                SignatureScheme::Passkey => {
661                    let passkey = PasskeyAuthenticator::from_serialized_bytes(bytes)?;
662                    Ok(Self::Passkey(passkey))
663                }
664            }
665        }
666
667        pub fn from_bytes(bytes: &[u8]) -> Result<Self, bcs::Error> {
668            Self::from_serialized_bytes(bytes).map_err(serde::de::Error::custom)
669        }
670
671        pub fn from_base64(s: &str) -> Result<Self, bcs::Error> {
672            use base64ct::Encoding;
673            use serde::de::Error;
674
675            let bytes = base64ct::Base64::decode_vec(s).map_err(bcs::Error::custom)?;
676            Self::from_bytes(&bytes)
677        }
678    }
679
680    #[derive(serde::Serialize)]
681    #[serde(tag = "scheme", rename_all = "lowercase")]
682    enum ReadableUserSignatureRef<'a> {
683        Ed25519 {
684            signature: &'a Ed25519Signature,
685            public_key: &'a Ed25519PublicKey,
686        },
687        Secp256k1 {
688            signature: &'a Secp256k1Signature,
689            public_key: &'a Secp256k1PublicKey,
690        },
691        Secp256r1 {
692            signature: &'a Secp256r1Signature,
693            public_key: &'a Secp256r1PublicKey,
694        },
695        Multisig(&'a MultisigAggregatedSignature),
696        ZkLogin(&'a ZkLoginAuthenticator),
697        Passkey(&'a PasskeyAuthenticator),
698    }
699
700    #[derive(serde::Deserialize)]
701    #[serde(tag = "scheme", rename_all = "lowercase")]
702    #[serde(rename = "UserSignature")]
703    #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
704    enum ReadableUserSignature {
705        Ed25519 {
706            signature: Ed25519Signature,
707            public_key: Ed25519PublicKey,
708        },
709        Secp256k1 {
710            signature: Secp256k1Signature,
711            public_key: Secp256k1PublicKey,
712        },
713        Secp256r1 {
714            signature: Secp256r1Signature,
715            public_key: Secp256r1PublicKey,
716        },
717        Multisig(MultisigAggregatedSignature),
718        ZkLogin(Box<ZkLoginAuthenticator>),
719        Passkey(PasskeyAuthenticator),
720    }
721
722    #[cfg(feature = "schemars")]
723    impl schemars::JsonSchema for UserSignature {
724        fn schema_name() -> String {
725            ReadableUserSignature::schema_name()
726        }
727
728        fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
729            ReadableUserSignature::json_schema(gen)
730        }
731    }
732
733    impl serde::Serialize for UserSignature {
734        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
735        where
736            S: serde::Serializer,
737        {
738            if serializer.is_human_readable() {
739                let readable = match self {
740                    UserSignature::Simple(SimpleSignature::Ed25519 {
741                        signature,
742                        public_key,
743                    }) => ReadableUserSignatureRef::Ed25519 {
744                        signature,
745                        public_key,
746                    },
747                    UserSignature::Simple(SimpleSignature::Secp256k1 {
748                        signature,
749                        public_key,
750                    }) => ReadableUserSignatureRef::Secp256k1 {
751                        signature,
752                        public_key,
753                    },
754                    UserSignature::Simple(SimpleSignature::Secp256r1 {
755                        signature,
756                        public_key,
757                    }) => ReadableUserSignatureRef::Secp256r1 {
758                        signature,
759                        public_key,
760                    },
761                    UserSignature::Multisig(multisig) => {
762                        ReadableUserSignatureRef::Multisig(multisig)
763                    }
764                    UserSignature::ZkLogin(zklogin) => ReadableUserSignatureRef::ZkLogin(zklogin),
765                    UserSignature::Passkey(passkey) => ReadableUserSignatureRef::Passkey(passkey),
766                };
767                readable.serialize(serializer)
768            } else {
769                match self {
770                    UserSignature::Simple(simple) => simple.serialize(serializer),
771                    UserSignature::Multisig(multisig) => multisig.serialize(serializer),
772                    UserSignature::ZkLogin(zklogin) => zklogin.serialize(serializer),
773                    UserSignature::Passkey(passkey) => passkey.serialize(serializer),
774                }
775            }
776        }
777    }
778
779    impl<'de> serde::Deserialize<'de> for UserSignature {
780        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
781        where
782            D: serde::Deserializer<'de>,
783        {
784            if deserializer.is_human_readable() {
785                let readable = ReadableUserSignature::deserialize(deserializer)?;
786                Ok(match readable {
787                    ReadableUserSignature::Ed25519 {
788                        signature,
789                        public_key,
790                    } => Self::Simple(SimpleSignature::Ed25519 {
791                        signature,
792                        public_key,
793                    }),
794                    ReadableUserSignature::Secp256k1 {
795                        signature,
796                        public_key,
797                    } => Self::Simple(SimpleSignature::Secp256k1 {
798                        signature,
799                        public_key,
800                    }),
801                    ReadableUserSignature::Secp256r1 {
802                        signature,
803                        public_key,
804                    } => Self::Simple(SimpleSignature::Secp256r1 {
805                        signature,
806                        public_key,
807                    }),
808                    ReadableUserSignature::Multisig(multisig) => Self::Multisig(multisig),
809                    ReadableUserSignature::ZkLogin(zklogin) => Self::ZkLogin(zklogin),
810                    ReadableUserSignature::Passkey(passkey) => Self::Passkey(passkey),
811                })
812            } else {
813                use serde_with::DeserializeAs;
814
815                let bytes: std::borrow::Cow<'de, [u8]> =
816                    serde_with::Bytes::deserialize_as(deserializer)?;
817                Self::from_serialized_bytes(bytes).map_err(serde::de::Error::custom)
818            }
819        }
820    }
821
822    #[cfg(test)]
823    mod tests {
824        use base64ct::{Base64, Encoding};
825        use test_strategy::proptest;
826        #[cfg(target_arch = "wasm32")]
827        use wasm_bindgen_test::wasm_bindgen_test as test;
828
829        use super::*;
830
831        #[proptest]
832        fn roundtrip_signature_scheme(scheme: SignatureScheme) {
833            assert_eq!(Ok(scheme), SignatureScheme::from_byte(scheme.to_u8()));
834        }
835
836        #[test]
837        fn simple_fixtures() {
838            const FIXTURES: &[(SignatureScheme, &str)] = &[
839                (
840                    SignatureScheme::Ed25519,
841                    "YQDaeO4w2ULMy5eqHBzP0oalr1YhDX/9uJS9MntKnW3d55q4aqZYYnoEloaBmXKc6FoD5bTwONdwS9CwdMQGhIcPDX2rNYyNrapO+gBJp1sHQ2VVsQo2ghm7aA9wVxNJ13U=",
842                ),
843                (
844                    SignatureScheme::Secp256k1,
845                    "YgErcT6WUSQXGD1DaIwls5rWq648akDMlvL41ugUUhyIPWnqURl+daQLG+ILNemARKHYVNOikKJJ8jqu+HzlRa5rAg4XzVk55GsZZkGWjNdZkQuiV34n+nP944dtub7FvOsr",
846                ),
847                (
848                    SignatureScheme::Secp256r1,
849                    "YgLp1p4K9dSQTt2AeR05yK1MkXmtLm6Sieb9yfkpW1gOBiqnO9ZKZiWUrLJQav2Mxw64zM37g3IVdsB/To6qfl8IA0f7ryPwOKvEwwiicRF6Kkz/rt28X/gcdRe8bHSn7bQw",
850                ),
851            ];
852
853            for (scheme, fixture) in FIXTURES {
854                let bcs = Base64::decode_vec(fixture).unwrap();
855
856                let sig: UserSignature = bcs::from_bytes(&bcs).unwrap();
857                assert_eq!(*scheme, sig.scheme());
858                let bytes = bcs::to_bytes(&sig).unwrap();
859                assert_eq!(bcs, bytes);
860
861                let json = serde_json::to_string_pretty(&sig).unwrap();
862                println!("{json}");
863                assert_eq!(sig, serde_json::from_str(&json).unwrap());
864            }
865        }
866
867        #[test]
868        fn multisig_fixtures() {
869            const FIXTURE1: &str = "sgIDAwCTLgVngjC4yeuvpAGKVkgcvIKVFUJnL1r6oFZScQVE5DNIz6kfxAGDRcVUczE9CUb7/sN/EuFJ8ot86Sdb8pAFASoQ91stRHXdW5dLy0BQ6v+7XWptawy2ItMyPk508p+PHdtZcm2aKl3lZGIvXe6MPY73E+1Hakv/xJbTYsw5SPMC5dx3gBwxds2GV12c7VUSqkyXamliSF1W/QBMufqrlmdIOZ1ox9gbsvIPtXYahfvKm8ozA7rsZWwRv8atsnyfYgcAAwANfas1jI2tqk76AEmnWwdDZVWxCjaCGbtoD3BXE0nXdQEBAg4XzVk55GsZZkGWjNdZkQuiV34n+nP944dtub7FvOsrAQIDR/uvI/A4q8TDCKJxEXoqTP+u3bxf+Bx1F7xsdKfttDABAgA=";
870
871            const FIXTURE2: &str = "8QEDAgBMW4Oq7XMjO5c6HLgTBJrWDZsCEcZF2EPOf68fdf1aY3e3pvA3cmk0tjMmXFB9+A6J2NohCpTFb/CsXEBjtCcMAfraaMMOMzG815145jlrY44Rbp0d1JQJOJ3hjgEe2xVBFP3QR94IVZk6ssyYxsecpBA+re5eqVRacvZGSobNPkMDAAMADX2rNYyNrapO+gBJp1sHQ2VVsQo2ghm7aA9wVxNJ13UBAQIOF81ZOeRrGWZBlozXWZELold+J/pz/eOHbbm+xbzrKwECA0f7ryPwOKvEwwiicRF6Kkz/rt28X/gcdRe8bHSn7bQwAQIA";
872
873            for fixture in [FIXTURE1, FIXTURE2] {
874                let bcs = Base64::decode_vec(fixture).unwrap();
875
876                let sig: UserSignature = bcs::from_bytes(&bcs).unwrap();
877                assert_eq!(SignatureScheme::Multisig, sig.scheme());
878                let bytes = bcs::to_bytes(&sig).unwrap();
879                assert_eq!(bcs, bytes);
880
881                let json = serde_json::to_string_pretty(&sig).unwrap();
882                println!("{json}");
883                assert_eq!(sig, serde_json::from_str(&json).unwrap());
884            }
885        }
886
887        #[test]
888        fn mutisig_with_zklogin() {
889            const FIXTURE: &str = "xwgDAQOWBwUDTDYyNzM5OTI5NDQyODI2NTYyNDE2NDMyNDk5Njc1NDY0MzY0MTU2ODM1MzgzMzAwNzMzMDkwMzgyOTUwOTAwMjA0MzcwMzI3MzQ0MTdNMTM5MjUxMzE5MTUzODM4NDMwOTkzODU1NTU2MjYyNzIwMzI5NjE5MjM3MjY1ODAyMjY2OTcwMTUzMTkxOTcxMzIxODkxMTg2MDUyNTcBMQMCTDc3MDQwMDc2MTQxMjAyNDQ0MjgyMDMyMzQwMzI3NzQ2ODkwODEwNzg2Mzg4NjkzMTcyNDM1NTEyNTMwMTA3MjYzMzg1MTA0MzYxMjdMNDczMzY5MTU2NjAwODE5MTIwNDAxMjcwNTc5OTA2MjI3NTk2MjY0NzMwMTUyNDU3MDIxMjM0MzczMjc1MTE3MTQyMjY2MzEzNTc1MgJMOTYzMjExNjUzNzQxMTQ3Mjk4MTQ2NDE0NzY0MDM5MzkxNzQxODQyMDI4NzgwOTUxODYyMTk5OTM0MjIwNjc2ODgzMjg0NzY5NTg5Nkw4NDM2Mjg3MTUwMzIxMjE2NTUwOTIxNTQ4ODg0MjI2MDM4MjczMTk0MjAyNDQwNTc0NzI5MDM4MTk2NDAxNDAzMDI0Mzg0MTEzODk4AgExATADTDUxNzIxODQyMDU0ODkxNDg4MzEwNTgxODkxNDIwNjI3Njc1NTM3MjMxMDkzNzIyMDk4NzI0NDAxMzA1MTg0MzYzODQxNzUxMjY1MjRMNTE1MTQzMjA2NjEzODc0NzIwOTEyMDY4NzUyMjIwODU1NDA0MTU2NDgyNzA4MDc5NzA1MDcxNjkyNzc2OTY0MzQ0NzQyMjEyMzI3MAExMXdpYVhOeklqb2lhSFIwY0hNNkx5OXBaQzUwZDJsMFkyZ3VkSFl2YjJGMWRHZ3lJaXcCMmV5SmhiR2NpT2lKU1V6STFOaUlzSW5SNWNDSTZJa3BYVkNJc0ltdHBaQ0k2SWpFaWZRTTIwNjg3NjQyNTE3NjMwNzMzMjczNjg3Nzk1NDc2MjQ3NDM3NzQzODM0NjAxMTAxNTY2Njg0OTY3OTY3NzA1ODA5OTg1MjQxMDY1NTM5CgAAAAAAAABhANFnRWP0VWDZA6kp8ltYtndCLMp70+CQMkW4CKPMOF5fGqTuUIKzqHJysBK8jS3rgHHBc5ZDqn0YUG0W2SH5gQC5xu4WMO8+cRFEpkjbBruyKE9ydM++5T/87lA8waSSAAgABAANfas1jI2tqk76AEmnWwdDZVWxCjaCGbtoD3BXE0nXdQEBAg4XzVk55GsZZkGWjNdZkQuiV34n+nP944dtub7FvOsrAQIDR/uvI/A4q8TDCKJxEXoqTP+u3bxf+Bx1F7xsdKfttDABAzwbaHR0cHM6Ly9pZC50d2l0Y2gudHYvb2F1dGgyLbzKbLI5Mq4c7y9X5gf73CthASNbTN9llO2Okr5TqEMBAQA=";
890
891            let bcs = Base64::decode_vec(FIXTURE).unwrap();
892
893            let sig: UserSignature = bcs::from_bytes(&bcs).unwrap();
894            assert_eq!(SignatureScheme::Multisig, sig.scheme());
895            let bytes = bcs::to_bytes(&sig).unwrap();
896            assert_eq!(bcs, bytes);
897
898            let json = serde_json::to_string_pretty(&sig).unwrap();
899            println!("{json}");
900            assert_eq!(sig, serde_json::from_str(&json).unwrap());
901        }
902
903        #[test]
904        fn zklogin_fixtures() {
905            const FIXTURES: &[&str] = &[
906                "mAcFA00yMTM0MzA3MTg2NDQ3ODc4NTU1OTU1OTY2Njg3NDQ3Njg0MzYyODQxNjA4OTQ4ODEyMTk4MjQ0OTY0ODk4OTg3OTkxMTI1MTY2OTA2N0w1MzYyMzAzOTQxMzk3NzQ1MTk2MTQxNjgxNjA5MDk0MDI4MTg3NzgxMzY2ODc3ODA5NTA2NTU0NzA3MjQ4MzcwNzM4OTcwOTI5MzYwATEDAk0xOTAzMjkyNDMyMDAxODEyNjcyNzEyMDYzMjYzMzM2OTE1NTg2MDc4NDA0NjY2MDcyMzIzMjU0MTAwMjQyODAxODA4ODQ4MTI3MzA5N0sxOTM0MDEzODQwOTcyNjc5OTM0MzgxMTI2ODg3OTQ2MTk1NDk5NTczMjY3NTE5ODAxNDA4MzQ2MzA3NDA2NzI3NjIxNzI0MTA4ODUCTDQxMTc0OTU3NjIwNzc2NjE4OTk2Njk5ODU1MTUzMzc2MDcwMTkzNTgwMjc2MjUxNTc4MDQwMTc0NTI2OTM1MTY5ODY1MDU1NDcyMTdNMTI3MDM0MzkzNTYyNTQ3NTM4NDA5NzAxMjA3MDAxMjM5MjcxOTU1OTI4OTE0MDgxMzY5NzQ0ODkwMzkzMzgyOTgzODYwODQxODYyNzYCATEBMANMNjAyNTg2MDg4MjI2OTUxNTE2NDY3MjY1NjU3OTU4MDE1OTMyMTI2ODY4MDM1NjU0NTkxOTA1NDkwNzkzNTM4MzY1NDYwNzA5MTIyOE0xNTUxNzY4ODA2NDc3NTgzMDI3NzAwNjY2NzE2OTM2NzAxNjU4Nzk5NDIyNjc1MTQ0Nzg5ODMzNjg0MDk5NjU4MDczNzg0NDY0NDExNQExMXdpYVhOeklqb2lhSFIwY0hNNkx5OXBaQzUwZDJsMFkyZ3VkSFl2YjJGMWRHZ3lJaXcCMmV5SmhiR2NpT2lKU1V6STFOaUlzSW5SNWNDSTZJa3BYVkNJc0ltdHBaQ0k2SWpFaWZRTDIwMjIzNjc3MTc2ODYwNzEyNzk5MTIwNjA0MTY1NTc3MDEyMjMyOTk3NTc0MjQwNjg2MDUwMzc1OTc1MTI1NzUzNDA0NDU0MTY4MTAKAAAAAAAAAGICUv1c+GW7/G0rKAO5QgQrqs3ujZALi4GWTkqgEjfTqMs53H1MeeRJdWzJW104/97F1VJyjm01ozKRasbRJGSsRwKi14vTFJZpnOkPlaKtNt4cGpY4PpaoeXb289IzLDx1Gg==",
907                "mwcFA00xMDE2MjI2MTYwOTg0NDYxNDI1OTY3MjA3OTg1MTYyNzUxNTQyNjEzMzM1OTEzMTc5NDQ3ODc4MDgzNDA3NTkxNDc5ODcxNzMzNzUzNU0xNjUwMTEzNTg2OTk2NDUwMDk1Njk2MDE2NzI0NzgwMzY3MzkyNDI4NDI0NTU3MDIyODMyODc4MDYxNjE4NzE0MzY2MzgzNzA0MjMyNAExAwJMNjAyMjIxMDk3ODA0MDA5MTgyMjQ1MDM2NjM2NjkyMzE1Mjg2NDAzMDQzNjY2ODg5NTUzNzYwNTM5MTM4MDA3OTAxMzIzMjE5OTk2NU0xNjEwNjE0MDY4NzEwMDc3MzQyNDIyNTI0NjEyNzM3ODIyNTgwOTIxMTQxMTYwMjQzMTIwMzI3NDM2MjM1NjEwOTI5NDk5Mjg2MjM4NgJMNzQwNDE3NTg3NDgyOTU3NDM0NTk1NDk1MTU0NDkxODY2ODI5ODQ0OTYxNjMzMDAyMzE4MzE4MzcwMTgxNjEwOTg3OTAwOTY5MTcxMUw3MzAwNzMwODk0MDQzNjM0NjI0NzIwNzkzNDIxNTM1NTUxODI3NDU4NjE4NzU5NjE2OTEzMjU0ODY4MzUzODE1MzM5ODg3MjIzMTA5AgExATADTTExNDA2NTA2NzUyNTkyODQ5NDk4MzcyNzYxODIyNzM4MjA2NTY0ODc4ODM3NTE3NzkxNTY2MzQ3NDk0NDkyNDQyMTI4MDExMTQwMzU3TTE1Njk5MzYzODA5ODg4MDc3MDcxNjM1NTg1MTA2NzA2MjE0NTcxMDI3NDU3ODE5MTE4NTE1NTk2MjA4MDgzODUzODcyOTM3NzQxNDczATExd2lhWE56SWpvaWFIUjBjSE02THk5cFpDNTBkMmwwWTJndWRIWXZiMkYxZEdneUlpdwIyZXlKaGJHY2lPaUpTVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0lzSW10cFpDSTZJakVpZlFNMTc1NzI2MTY4NDgyNzU4OTMzODIyMTc0ODE3OTM5MTkwMDYzNjYzNzY4NTk4MTcwNDA1NDYwNDk4MzU5NTgxODc0NjEyOTg2NjkyNzAKAAAAAAAAAGICl9lwjktCQkH7GqGGV6EdbjHv4Go6MIDmr6EIvtg/2h5IuXKJF5GoVLuykxWwkSdNr9iRUZaz3Z0p/Z9nPJlW/gNaiwdVCMdfShJHSZgqfSH4DZpfaJPkGp6VX+TIIeDevg==",
908                "mgcFA00xOTUwNDI1NDE5MzgxMzM3OTA5NDA1MzkyODkyNTQwMjAxMjIxMTg4ODY5MDAzOTQ3ODM0MjYzOTk4OTcwMjA4MjAxNjY2MDkyNzg4MU0xODEwMjYxODU0NjY0NjY3MDgyMjI5MjczMjIwMDgzMzU0OTk4NDAxMTkxMDI1MDY2MjQ4Mjk5MjMzODgzNjA1NTc1MzMyNTUyMTUzMwExAwJMNTI0MzA1OTQ2MTI1NDQxOTM0NzgzOTMxMjI4ODQ5NjY4OTI0Njk4NzIyMTMyMDcxMDcyNzc2NzgzNzc3NDc4ODI4Mzc1NjgzMTAyOE0xMjA3MDIwMzk2MzAzNjY0NTY2NjAyMzUwNDMyNDM3NDY1OTYwMTY1NzY2NDAzOTU4MzE0MDU2Njc2MDExOTcwMTA3MjI5MjA0NzkxMQJNMTYzNjc2NDUxMTMxNzA1OTkxMTgwNzc1NjgxOTUyMjA5ODY1NjcxNjE0ODk2MDcyNDI1NzQ2ODg5ODQ0NzI4NTk0MzE2Mzk4MzQxNzhMNTg5MTQ4MzY3MjI1MTQyMzgzODE5NTQxNDg0NjEwNTY0Nzk4MDE2NjAyODIyNjcwMzE2ODE1Njg2MzkzNjUxNjk1OTkzMjE4MzExNQIBMQEwA0w2NDc2MTA0MzAwODgxNTQ2NTk3NjUwODk0NjEzNTUyMDc1NDg4Mjk5NjA4NjM5MTY4MzE3MjgzNTg2ODI3MDA3MTUzODg5MjI1MTI2TDQ3NjgzNjQxMTE1NjM0NzI0MDI1NzA4NDE0ODEyMDMzMTgzMDQzMTQ1MDQ4NjcxMzk1NzQ0MzAzODI2NzA4MDcwMTkwNDgxMTQyNzEBMTF3aWFYTnpJam9pYUhSMGNITTZMeTlwWkM1MGQybDBZMmd1ZEhZdmIyRjFkR2d5SWl3AjJleUpoYkdjaU9pSlNVekkxTmlJc0luUjVjQ0k2SWtwWFZDSXNJbXRwWkNJNklqRWlmUU0xMDc0MzE4MDg0MjY5ODE2Mzk0ODQ5NzAyMjkwMDE0Mzc4NjI0MTEwOTYyMzMyMDgzNzYxNzUzMDY5NzUxNDA1MzIwODA1NjEwNzgzNAoAAAAAAAAAYgLL7Jn3QV4USqVbuv97w4LqA12BAwU95fsUrvymgAUPtiepsG6kCVnX903PFZBusNM07tgWJ4/5ypb5mbJQhijJA+3BG7HM6kM2jZ0NPldx4AR5zvu+l4ZXRC4lo39h/K5s",
909                "mgcFA0wxNjY4NTEwOTQ1NDY2OTQ2OTYyODUxODAzOTg1MTA3Mjk2NTM1OTM3MzI1NzI5OTMzNDE1MzAzOTcwNjI2MjE3NzAwOTM0NjE4MjY1TDc5ODAxMjUwNTYxMTA2NzczMjY0NjA1MjI0MjgyNTk1OTM4NzQzOTg5MjE3Nzg1Mzk1MTUxODY3MTkwMzk3OTc1MTQ0NDA4ODQ1NTEBMQMCTTEyODA2ODY2NjkyMTUxODMxMTI1MzExMTk3Nzc1NTAxNDU1MTIwNzQwNjg2Mzk2OTQ4NDIxMjAyODI0MjkwODMwNzQzMzM4NTE1MjMxTTE4NzY2Mzc4MTcwNzE4MDMzMzk0ODQxMTYxMTU0MjA0NDA2ODc0MDM0ODk4NjA1NTk4MTgzMDM5NjM2NjQ1NjU3Mjk3NTIzMTU4ODU1Ak0xNzYyNTIzNTA0NzgxNDg2NDg1OTY1NTA1MTkyNTUyMzYxNjkwNzg2MDk3MjM3ODE1OTU1NjA4NDMyNDM5NTQxODk5MzI4NzQwMzk0M00xNjQ3MTA2MDIyOTUzMDIyNjEwOTk0Mzc3MTU3NzQ1NjIzMDM2NTM5NTMxNzM0NDk3OTAwNjAwMTE1NTgxNzM5ODE1NjczMjIwMjcxMwIBMQEwA00xODU1NzU4NTE1MjgxMTk5Mzk1MTY2NDY4NDA1ODg4MTg0NDE2MjY4NTk1NzAxMDY1MzIyNjg5ODkyOTgwNjA1Njc4NjMyMzg5MzA0M0wyNDQ2NDI2NDg4NTQwNzcwNzE5NTIyMjk1NTY3Njc2OTU3MzYzNjIxNTQ0MDUwMTg5OTAxMTk0MTY3NDY1NDE3OTA0Njk2NDQ3NDA1ATExd2lhWE56SWpvaWFIUjBjSE02THk5cFpDNTBkMmwwWTJndWRIWXZiMkYxZEdneUlpdwIyZXlKaGJHY2lPaUpTVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0lzSW10cFpDSTZJakVpZlFMODQ2ODk2NzMyOTAyOTgzNjU0MjM3MzIzMjc4Njc3NzgyNDA5MTgyOTM1OTA4MjczNzA5MjQ3MjM1NDEwODEzNTkwOTE0MTM4MjEwNAoAAAAAAAAAYgEaWZZP7C934LS3vgsXYQk85BBiG6E285TY0C6U59qaUxlCUQWACVbxyEej193U4uIIP71lZ6KwvfT7lqOsUUIvAoa8xwWZ68Qgs7iXfsxg5ZS7VnSb6qVi1/gKm9//yqod",
910                "lgcFA0w2MjczOTkyOTQ0MjgyNjU2MjQxNjQzMjQ5OTY3NTQ2NDM2NDE1NjgzNTM4MzMwMDczMzA5MDM4Mjk1MDkwMDIwNDM3MDMyNzM0NDE3TTEzOTI1MTMxOTE1MzgzODQzMDk5Mzg1NTU1NjI2MjcyMDMyOTYxOTIzNzI2NTgwMjI2Njk3MDE1MzE5MTk3MTMyMTg5MTE4NjA1MjU3ATEDAkw3NzA0MDA3NjE0MTIwMjQ0NDI4MjAzMjM0MDMyNzc0Njg5MDgxMDc4NjM4ODY5MzE3MjQzNTUxMjUzMDEwNzI2MzM4NTEwNDM2MTI3TDQ3MzM2OTE1NjYwMDgxOTEyMDQwMTI3MDU3OTkwNjIyNzU5NjI2NDczMDE1MjQ1NzAyMTIzNDM3MzI3NTExNzE0MjI2NjMxMzU3NTICTDk2MzIxMTY1Mzc0MTE0NzI5ODE0NjQxNDc2NDAzOTM5MTc0MTg0MjAyODc4MDk1MTg2MjE5OTkzNDIyMDY3Njg4MzI4NDc2OTU4OTZMODQzNjI4NzE1MDMyMTIxNjU1MDkyMTU0ODg4NDIyNjAzODI3MzE5NDIwMjQ0MDU3NDcyOTAzODE5NjQwMTQwMzAyNDM4NDExMzg5OAIBMQEwA0w1MTcyMTg0MjA1NDg5MTQ4ODMxMDU4MTg5MTQyMDYyNzY3NTUzNzIzMTA5MzcyMjA5ODcyNDQwMTMwNTE4NDM2Mzg0MTc1MTI2NTI0TDUxNTE0MzIwNjYxMzg3NDcyMDkxMjA2ODc1MjIyMDg1NTQwNDE1NjQ4MjcwODA3OTcwNTA3MTY5Mjc3Njk2NDM0NDc0MjIxMjMyNzABMTF3aWFYTnpJam9pYUhSMGNITTZMeTlwWkM1MGQybDBZMmd1ZEhZdmIyRjFkR2d5SWl3AjJleUpoYkdjaU9pSlNVekkxTmlJc0luUjVjQ0k2SWtwWFZDSXNJbXRwWkNJNklqRWlmUU0yMDY4NzY0MjUxNzYzMDczMzI3MzY4Nzc5NTQ3NjI0NzQzNzc0MzgzNDYwMTEwMTU2NjY4NDk2Nzk2NzcwNTgwOTk4NTI0MTA2NTUzOQoAAAAAAAAAYQBn1v6x7RD9EyaiubLQ8qQkJSNI2Mr1GFHXZyOUJ+eCphFkwjYKBo44TMAbryd405BY+MHYTFLZOD06UTycKHgKucbuFjDvPnERRKZI2wa7sihPcnTPvuU//O5QPMGkkgA=",
911            ];
912
913            for fixture in FIXTURES {
914                let bcs = Base64::decode_vec(fixture).unwrap();
915
916                let sig: UserSignature = bcs::from_bytes(&bcs).unwrap();
917                assert_eq!(SignatureScheme::ZkLogin, sig.scheme());
918                let bytes = bcs::to_bytes(&sig).unwrap();
919                assert_eq!(bcs, bytes);
920
921                let json = serde_json::to_string_pretty(&sig).unwrap();
922                println!("{json}");
923                assert_eq!(sig, serde_json::from_str(&json).unwrap());
924            }
925        }
926
927        #[test]
928        fn passkey_fixtures() {
929            const FIXTURES: &[&str] = &[
930                "lgIGJUmWDeWIDoxodDQXD2R2YFuP5K65ooYyx5lc87qDHZdjHQAAAACKAXsidHlwZSI6IndlYmF1dGhuLmdldCIsImNoYWxsZW5nZSI6IkFBQUF0X21qSUIxdmJWcFlNNldWNllfb2l4Nko4YU5fOXNiOFNLRmJ1a0JmaVF3Iiwib3JpZ2luIjoiaHR0cDovL2xvY2FsaG9zdDo1MTczIiwiY3Jvc3NPcmlnaW4iOmZhbHNlfWICmOyQv1fJ+inKD0C/sxKtxyFKl9aoBign6p9Ih3iA2ahDVg2CPZqUOlEhur2S2GbIZjbn6TbgWtbXXg8SjLkL7wM9Fw4JO0AKLdnLC1nhQguHBX5K6Hv2ta1sqoOqEFDDEw==",
931            ];
932
933            for fixture in FIXTURES {
934                let bcs = Base64::decode_vec(fixture).unwrap();
935
936                let sig: UserSignature = bcs::from_bytes(&bcs).unwrap();
937                assert_eq!(SignatureScheme::Passkey, sig.scheme());
938                let bytes = bcs::to_bytes(&sig).unwrap();
939                assert_eq!(bcs, bytes);
940
941                let json = serde_json::to_string_pretty(&sig).unwrap();
942                println!("{json}");
943                assert_eq!(sig, serde_json::from_str(&json).unwrap());
944            }
945        }
946    }
947}