1use super::{
6 Ed25519PublicKey, Ed25519Signature, MultisigAggregatedSignature, PasskeyAuthenticator,
7 Secp256k1PublicKey, Secp256k1Signature, Secp256r1PublicKey, Secp256r1Signature,
8 ZkLoginAuthenticator,
9};
10
11#[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 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#[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, ZkLogin = 0x05,
226 Passkey = 0x06,
227}
228
229impl SignatureScheme {
230 crate::def_is!(
231 Ed25519, Secp256k1, Secp256r1, Multisig, Bls12381, ZkLogin, Passkey,
232 );
233
234 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 pub fn to_u8(self) -> u8 {
250 self as u8
251 }
252}
253
254impl super::ZkLoginPublicIdentifier {
255 pub fn scheme(&self) -> SignatureScheme {
257 SignatureScheme::ZkLogin
258 }
259}
260
261impl super::PasskeyPublicKey {
262 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#[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 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}