1use super::Ed25519PublicKey;
2use super::Ed25519Signature;
3use super::MultisigAggregatedSignature;
4use super::PasskeyAuthenticator;
5use super::Secp256k1PublicKey;
6use super::Secp256k1Signature;
7use super::Secp256r1PublicKey;
8use super::Secp256r1Signature;
9use super::ZkLoginAuthenticator;
10
11#[derive(Clone, Debug, PartialEq, Eq, Hash)]
32#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
33pub enum SimpleSignature {
34 Ed25519 {
35 signature: Ed25519Signature,
36 public_key: Ed25519PublicKey,
37 },
38 Secp256k1 {
39 signature: Secp256k1Signature,
40 public_key: Secp256k1PublicKey,
41 },
42 Secp256r1 {
43 signature: Secp256r1Signature,
44 public_key: Secp256r1PublicKey,
45 },
46}
47
48impl SimpleSignature {
49 pub fn scheme(&self) -> SignatureScheme {
51 match self {
52 SimpleSignature::Ed25519 { .. } => SignatureScheme::Ed25519,
53 SimpleSignature::Secp256k1 { .. } => SignatureScheme::Secp256k1,
54 SimpleSignature::Secp256r1 { .. } => SignatureScheme::Secp256r1,
55 }
56 }
57}
58
59impl SimpleSignature {
60 #[cfg(feature = "serde")]
61 #[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
62 fn to_bytes(&self) -> Vec<u8> {
63 let mut buf = Vec::new();
64 match self {
65 SimpleSignature::Ed25519 {
66 signature,
67 public_key,
68 } => {
69 buf.push(SignatureScheme::Ed25519 as u8);
70 buf.extend_from_slice(signature.as_ref());
71 buf.extend_from_slice(public_key.as_ref());
72 }
73 SimpleSignature::Secp256k1 {
74 signature,
75 public_key,
76 } => {
77 buf.push(SignatureScheme::Secp256k1 as u8);
78 buf.extend_from_slice(signature.as_ref());
79 buf.extend_from_slice(public_key.as_ref());
80 }
81 SimpleSignature::Secp256r1 {
82 signature,
83 public_key,
84 } => {
85 buf.push(SignatureScheme::Secp256r1 as u8);
86 buf.extend_from_slice(signature.as_ref());
87 buf.extend_from_slice(public_key.as_ref());
88 }
89 }
90
91 buf
92 }
93
94 #[cfg(feature = "serde")]
95 #[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
96 fn from_serialized_bytes<T: AsRef<[u8]>, E: serde::de::Error>(bytes: T) -> Result<Self, E> {
97 let bytes = bytes.as_ref();
98 let flag = SignatureScheme::from_byte(
99 *bytes
100 .first()
101 .ok_or_else(|| serde::de::Error::custom("missing signature scheme falg"))?,
102 )
103 .map_err(serde::de::Error::custom)?;
104 match flag {
105 SignatureScheme::Ed25519 => {
106 let expected_length = 1 + Ed25519Signature::LENGTH + Ed25519PublicKey::LENGTH;
107
108 if bytes.len() != expected_length {
109 return Err(serde::de::Error::custom("invalid ed25519 signature"));
110 }
111
112 let mut signature = [0; Ed25519Signature::LENGTH];
113 signature.copy_from_slice(&bytes[1..(1 + Ed25519Signature::LENGTH)]);
114
115 let mut public_key = [0; Ed25519PublicKey::LENGTH];
116 public_key.copy_from_slice(&bytes[(1 + Ed25519Signature::LENGTH)..]);
117
118 Ok(SimpleSignature::Ed25519 {
119 signature: Ed25519Signature::new(signature),
120 public_key: Ed25519PublicKey::new(public_key),
121 })
122 }
123 SignatureScheme::Secp256k1 => {
124 let expected_length = 1 + Secp256k1Signature::LENGTH + Secp256k1PublicKey::LENGTH;
125
126 if bytes.len() != expected_length {
127 return Err(serde::de::Error::custom("invalid secp25k1 signature"));
128 }
129
130 let mut signature = [0; Secp256k1Signature::LENGTH];
131 signature.copy_from_slice(&bytes[1..(1 + Secp256k1Signature::LENGTH)]);
132
133 let mut public_key = [0; Secp256k1PublicKey::LENGTH];
134 public_key.copy_from_slice(&bytes[(1 + Secp256k1Signature::LENGTH)..]);
135
136 Ok(SimpleSignature::Secp256k1 {
137 signature: Secp256k1Signature::new(signature),
138 public_key: Secp256k1PublicKey::new(public_key),
139 })
140 }
141 SignatureScheme::Secp256r1 => {
142 let expected_length = 1 + Secp256r1Signature::LENGTH + Secp256r1PublicKey::LENGTH;
143
144 if bytes.len() != expected_length {
145 return Err(serde::de::Error::custom("invalid secp25r1 signature"));
146 }
147
148 let mut signature = [0; Secp256r1Signature::LENGTH];
149 signature.copy_from_slice(&bytes[1..(1 + Secp256r1Signature::LENGTH)]);
150
151 let mut public_key = [0; Secp256r1PublicKey::LENGTH];
152 public_key.copy_from_slice(&bytes[(1 + Secp256r1Signature::LENGTH)..]);
153
154 Ok(SimpleSignature::Secp256r1 {
155 signature: Secp256r1Signature::new(signature),
156 public_key: Secp256r1PublicKey::new(public_key),
157 })
158 }
159 SignatureScheme::Multisig
160 | SignatureScheme::Bls12381
161 | SignatureScheme::ZkLogin
162 | SignatureScheme::Passkey => Err(serde::de::Error::custom("invalid signature scheme")),
163 }
164 }
165}
166
167#[cfg(feature = "serde")]
168#[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
169impl serde::Serialize for SimpleSignature {
170 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
171 where
172 S: serde::Serializer,
173 {
174 #[derive(serde_derive::Serialize)]
175 #[serde(tag = "scheme")]
176 #[serde(rename_all = "lowercase")]
177 enum Sig<'a> {
178 Ed25519 {
179 signature: &'a Ed25519Signature,
180 public_key: &'a Ed25519PublicKey,
181 },
182 Secp256k1 {
183 signature: &'a Secp256k1Signature,
184 public_key: &'a Secp256k1PublicKey,
185 },
186 Secp256r1 {
187 signature: &'a Secp256r1Signature,
188 public_key: &'a Secp256r1PublicKey,
189 },
190 }
191
192 if serializer.is_human_readable() {
193 let sig = match self {
194 SimpleSignature::Ed25519 {
195 signature,
196 public_key,
197 } => Sig::Ed25519 {
198 signature,
199 public_key,
200 },
201 SimpleSignature::Secp256k1 {
202 signature,
203 public_key,
204 } => Sig::Secp256k1 {
205 signature,
206 public_key,
207 },
208 SimpleSignature::Secp256r1 {
209 signature,
210 public_key,
211 } => Sig::Secp256r1 {
212 signature,
213 public_key,
214 },
215 };
216
217 sig.serialize(serializer)
218 } else {
219 match self {
220 SimpleSignature::Ed25519 {
221 signature,
222 public_key,
223 } => {
224 let mut buf = [0; 1 + Ed25519Signature::LENGTH + Ed25519PublicKey::LENGTH];
225 buf[0] = SignatureScheme::Ed25519 as u8;
226 buf[1..(1 + Ed25519Signature::LENGTH)].copy_from_slice(signature.as_ref());
227 buf[(1 + Ed25519Signature::LENGTH)..].copy_from_slice(public_key.as_ref());
228
229 serializer.serialize_bytes(&buf)
230 }
231 SimpleSignature::Secp256k1 {
232 signature,
233 public_key,
234 } => {
235 let mut buf = [0; 1 + Secp256k1Signature::LENGTH + Secp256k1PublicKey::LENGTH];
236 buf[0] = SignatureScheme::Secp256k1 as u8;
237 buf[1..(1 + Secp256k1Signature::LENGTH)].copy_from_slice(signature.as_ref());
238 buf[(1 + Secp256k1Signature::LENGTH)..].copy_from_slice(public_key.as_ref());
239
240 serializer.serialize_bytes(&buf)
241 }
242 SimpleSignature::Secp256r1 {
243 signature,
244 public_key,
245 } => {
246 let mut buf = [0; 1 + Secp256r1Signature::LENGTH + Secp256r1PublicKey::LENGTH];
247 buf[0] = SignatureScheme::Secp256r1 as u8;
248 buf[1..(1 + Secp256r1Signature::LENGTH)].copy_from_slice(signature.as_ref());
249 buf[(1 + Secp256r1Signature::LENGTH)..].copy_from_slice(public_key.as_ref());
250
251 serializer.serialize_bytes(&buf)
252 }
253 }
254 }
255 }
256}
257
258#[cfg(feature = "serde")]
259#[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
260impl<'de> serde::Deserialize<'de> for SimpleSignature {
261 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
262 where
263 D: serde::Deserializer<'de>,
264 {
265 #[derive(serde_derive::Deserialize)]
266 #[serde(tag = "scheme")]
267 #[serde(rename_all = "lowercase")]
268 enum Sig {
269 Ed25519 {
270 signature: Ed25519Signature,
271 public_key: Ed25519PublicKey,
272 },
273 Secp256k1 {
274 signature: Secp256k1Signature,
275 public_key: Secp256k1PublicKey,
276 },
277 Secp256r1 {
278 signature: Secp256r1Signature,
279 public_key: Secp256r1PublicKey,
280 },
281 }
282
283 if deserializer.is_human_readable() {
284 let sig = Sig::deserialize(deserializer)?;
285 Ok(match sig {
286 Sig::Ed25519 {
287 signature,
288 public_key,
289 } => SimpleSignature::Ed25519 {
290 signature,
291 public_key,
292 },
293 Sig::Secp256k1 {
294 signature,
295 public_key,
296 } => SimpleSignature::Secp256k1 {
297 signature,
298 public_key,
299 },
300 Sig::Secp256r1 {
301 signature,
302 public_key,
303 } => SimpleSignature::Secp256r1 {
304 signature,
305 public_key,
306 },
307 })
308 } else {
309 let bytes: std::borrow::Cow<'de, [u8]> = std::borrow::Cow::deserialize(deserializer)?;
310 Self::from_serialized_bytes(bytes)
311 }
312 }
313}
314
315#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
333#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
334#[repr(u8)]
335pub enum SignatureScheme {
336 Ed25519 = 0x00,
337 Secp256k1 = 0x01,
338 Secp256r1 = 0x02,
339 Multisig = 0x03,
340 Bls12381 = 0x04, ZkLogin = 0x05,
342 Passkey = 0x06,
343}
344
345impl SignatureScheme {
346 pub fn name(self) -> &'static str {
348 match self {
349 SignatureScheme::Ed25519 => "ed25519",
350 SignatureScheme::Secp256k1 => "secp256k1",
351 SignatureScheme::Secp256r1 => "secp256r1",
352 SignatureScheme::Multisig => "multisig",
353 SignatureScheme::Bls12381 => "bls12381",
354 SignatureScheme::ZkLogin => "zklogin",
355 SignatureScheme::Passkey => "passkey",
356 }
357 }
358
359 pub fn from_byte(flag: u8) -> Result<Self, InvalidSignatureScheme> {
361 match flag {
362 0x00 => Ok(Self::Ed25519),
363 0x01 => Ok(Self::Secp256k1),
364 0x02 => Ok(Self::Secp256r1),
365 0x03 => Ok(Self::Multisig),
366 0x04 => Ok(Self::Bls12381),
367 0x05 => Ok(Self::ZkLogin),
368 0x06 => Ok(Self::Passkey),
369 invalid => Err(InvalidSignatureScheme(invalid)),
370 }
371 }
372
373 pub fn to_u8(self) -> u8 {
375 self as u8
376 }
377}
378
379impl Ed25519PublicKey {
380 pub fn scheme(&self) -> SignatureScheme {
382 SignatureScheme::Ed25519
383 }
384}
385
386impl Secp256k1PublicKey {
387 pub fn scheme(&self) -> SignatureScheme {
389 SignatureScheme::Secp256k1
390 }
391}
392
393impl Secp256r1PublicKey {
394 pub fn scheme(&self) -> SignatureScheme {
396 SignatureScheme::Secp256r1
397 }
398}
399
400impl super::ZkLoginPublicIdentifier {
401 pub fn scheme(&self) -> SignatureScheme {
403 SignatureScheme::ZkLogin
404 }
405}
406
407impl super::PasskeyPublicKey {
408 pub fn scheme(&self) -> SignatureScheme {
410 SignatureScheme::Passkey
411 }
412}
413
414#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
415pub struct InvalidSignatureScheme(u8);
416
417impl std::fmt::Display for InvalidSignatureScheme {
418 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
419 write!(f, "invalid signature scheme: {:02x}", self.0)
420 }
421}
422
423#[derive(Clone, Debug, PartialEq, Eq)]
442#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
443pub enum UserSignature {
444 Simple(SimpleSignature),
445 Multisig(MultisigAggregatedSignature),
446 ZkLogin(Box<ZkLoginAuthenticator>),
447 Passkey(PasskeyAuthenticator),
448}
449
450impl UserSignature {
451 pub fn scheme(&self) -> SignatureScheme {
453 match self {
454 UserSignature::Simple(simple) => simple.scheme(),
455 UserSignature::Multisig(_) => SignatureScheme::Multisig,
456 UserSignature::ZkLogin(_) => SignatureScheme::ZkLogin,
457 UserSignature::Passkey(_) => SignatureScheme::Passkey,
458 }
459 }
460}
461
462#[cfg(feature = "serde")]
463#[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
464mod serialization {
465 use super::*;
466
467 impl UserSignature {
468 pub fn to_bytes(&self) -> Vec<u8> {
469 match self {
470 UserSignature::Simple(s) => s.to_bytes(),
471 UserSignature::Multisig(m) => m.to_bytes(),
472 UserSignature::ZkLogin(z) => z.to_bytes(),
473 UserSignature::Passkey(p) => p.to_bytes(),
474 }
475 }
476
477 pub fn to_base64(&self) -> String {
478 use base64ct::Encoding;
479
480 base64ct::Base64::encode_string(&self.to_bytes())
481 }
482
483 fn from_serialized_bytes<T: AsRef<[u8]>, E: serde::de::Error>(bytes: T) -> Result<Self, E> {
484 let bytes = bytes.as_ref();
485
486 let flag = SignatureScheme::from_byte(
487 *bytes
488 .first()
489 .ok_or_else(|| serde::de::Error::custom("missing signature scheme falg"))?,
490 )
491 .map_err(serde::de::Error::custom)?;
492 match flag {
493 SignatureScheme::Ed25519
494 | SignatureScheme::Secp256k1
495 | SignatureScheme::Secp256r1 => {
496 let simple = SimpleSignature::from_serialized_bytes(bytes)?;
497 Ok(Self::Simple(simple))
498 }
499 SignatureScheme::Multisig => {
500 let multisig = MultisigAggregatedSignature::from_serialized_bytes(bytes)?;
501 Ok(Self::Multisig(multisig))
502 }
503 SignatureScheme::Bls12381 => Err(serde::de::Error::custom(
504 "bls not supported for user signatures",
505 )),
506 SignatureScheme::ZkLogin => {
507 let zklogin = ZkLoginAuthenticator::from_serialized_bytes(bytes)?;
508 Ok(Self::ZkLogin(Box::new(zklogin)))
509 }
510 SignatureScheme::Passkey => {
511 let passkey = PasskeyAuthenticator::from_serialized_bytes(bytes)?;
512 Ok(Self::Passkey(passkey))
513 }
514 }
515 }
516
517 pub fn from_bytes(bytes: &[u8]) -> Result<Self, bcs::Error> {
518 Self::from_serialized_bytes(bytes)
519 }
520
521 pub fn from_base64(s: &str) -> Result<Self, bcs::Error> {
522 use base64ct::Encoding;
523 use serde::de::Error;
524
525 let bytes = base64ct::Base64::decode_vec(s).map_err(bcs::Error::custom)?;
526 Self::from_bytes(&bytes)
527 }
528 }
529
530 #[derive(serde_derive::Serialize)]
531 #[serde(tag = "scheme", rename_all = "lowercase")]
532 enum ReadableUserSignatureRef<'a> {
533 Ed25519 {
534 signature: &'a Ed25519Signature,
535 public_key: &'a Ed25519PublicKey,
536 },
537 Secp256k1 {
538 signature: &'a Secp256k1Signature,
539 public_key: &'a Secp256k1PublicKey,
540 },
541 Secp256r1 {
542 signature: &'a Secp256r1Signature,
543 public_key: &'a Secp256r1PublicKey,
544 },
545 Multisig(&'a MultisigAggregatedSignature),
546 ZkLogin(&'a ZkLoginAuthenticator),
547 Passkey(&'a PasskeyAuthenticator),
548 }
549
550 #[derive(serde_derive::Deserialize)]
551 #[serde(tag = "scheme", rename_all = "lowercase")]
552 #[serde(rename = "UserSignature")]
553 enum ReadableUserSignature {
554 Ed25519 {
555 signature: Ed25519Signature,
556 public_key: Ed25519PublicKey,
557 },
558 Secp256k1 {
559 signature: Secp256k1Signature,
560 public_key: Secp256k1PublicKey,
561 },
562 Secp256r1 {
563 signature: Secp256r1Signature,
564 public_key: Secp256r1PublicKey,
565 },
566 Multisig(MultisigAggregatedSignature),
567 ZkLogin(Box<ZkLoginAuthenticator>),
568 Passkey(PasskeyAuthenticator),
569 }
570
571 impl serde::Serialize for UserSignature {
572 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
573 where
574 S: serde::Serializer,
575 {
576 if serializer.is_human_readable() {
577 let readable = match self {
578 UserSignature::Simple(SimpleSignature::Ed25519 {
579 signature,
580 public_key,
581 }) => ReadableUserSignatureRef::Ed25519 {
582 signature,
583 public_key,
584 },
585 UserSignature::Simple(SimpleSignature::Secp256k1 {
586 signature,
587 public_key,
588 }) => ReadableUserSignatureRef::Secp256k1 {
589 signature,
590 public_key,
591 },
592 UserSignature::Simple(SimpleSignature::Secp256r1 {
593 signature,
594 public_key,
595 }) => ReadableUserSignatureRef::Secp256r1 {
596 signature,
597 public_key,
598 },
599 UserSignature::Multisig(multisig) => {
600 ReadableUserSignatureRef::Multisig(multisig)
601 }
602 UserSignature::ZkLogin(zklogin) => ReadableUserSignatureRef::ZkLogin(zklogin),
603 UserSignature::Passkey(passkey) => ReadableUserSignatureRef::Passkey(passkey),
604 };
605 readable.serialize(serializer)
606 } else {
607 match self {
608 UserSignature::Simple(simple) => simple.serialize(serializer),
609 UserSignature::Multisig(multisig) => multisig.serialize(serializer),
610 UserSignature::ZkLogin(zklogin) => zklogin.serialize(serializer),
611 UserSignature::Passkey(passkey) => passkey.serialize(serializer),
612 }
613 }
614 }
615 }
616
617 impl<'de> serde::Deserialize<'de> for UserSignature {
618 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
619 where
620 D: serde::Deserializer<'de>,
621 {
622 if deserializer.is_human_readable() {
623 let readable = ReadableUserSignature::deserialize(deserializer)?;
624 Ok(match readable {
625 ReadableUserSignature::Ed25519 {
626 signature,
627 public_key,
628 } => Self::Simple(SimpleSignature::Ed25519 {
629 signature,
630 public_key,
631 }),
632 ReadableUserSignature::Secp256k1 {
633 signature,
634 public_key,
635 } => Self::Simple(SimpleSignature::Secp256k1 {
636 signature,
637 public_key,
638 }),
639 ReadableUserSignature::Secp256r1 {
640 signature,
641 public_key,
642 } => Self::Simple(SimpleSignature::Secp256r1 {
643 signature,
644 public_key,
645 }),
646 ReadableUserSignature::Multisig(multisig) => Self::Multisig(multisig),
647 ReadableUserSignature::ZkLogin(zklogin) => Self::ZkLogin(zklogin),
648 ReadableUserSignature::Passkey(passkey) => Self::Passkey(passkey),
649 })
650 } else {
651 use serde_with::DeserializeAs;
652
653 let bytes: std::borrow::Cow<'de, [u8]> =
654 serde_with::Bytes::deserialize_as(deserializer)?;
655 Self::from_serialized_bytes(bytes)
656 }
657 }
658 }
659
660 #[cfg(test)]
661 mod test {
662 use super::*;
663 use base64ct::Base64;
664 use base64ct::Encoding;
665 use test_strategy::proptest;
666
667 #[cfg(target_arch = "wasm32")]
668 use wasm_bindgen_test::wasm_bindgen_test as test;
669
670 #[proptest]
671 fn roundtrip_signature_scheme(scheme: SignatureScheme) {
672 assert_eq!(Ok(scheme), SignatureScheme::from_byte(scheme.to_u8()));
673 }
674
675 #[test]
676 fn simple_fixtures() {
677 const FIXTURES: &[(SignatureScheme, &str)] = &[
678 (SignatureScheme::Ed25519, "YQDaeO4w2ULMy5eqHBzP0oalr1YhDX/9uJS9MntKnW3d55q4aqZYYnoEloaBmXKc6FoD5bTwONdwS9CwdMQGhIcPDX2rNYyNrapO+gBJp1sHQ2VVsQo2ghm7aA9wVxNJ13U="),
679 (SignatureScheme::Secp256k1, "YgErcT6WUSQXGD1DaIwls5rWq648akDMlvL41ugUUhyIPWnqURl+daQLG+ILNemARKHYVNOikKJJ8jqu+HzlRa5rAg4XzVk55GsZZkGWjNdZkQuiV34n+nP944dtub7FvOsr"),
680 (SignatureScheme::Secp256r1, "YgLp1p4K9dSQTt2AeR05yK1MkXmtLm6Sieb9yfkpW1gOBiqnO9ZKZiWUrLJQav2Mxw64zM37g3IVdsB/To6qfl8IA0f7ryPwOKvEwwiicRF6Kkz/rt28X/gcdRe8bHSn7bQw"),
681 ];
682
683 for (scheme, fixture) in FIXTURES {
684 let bcs = Base64::decode_vec(fixture).unwrap();
685
686 let sig: UserSignature = bcs::from_bytes(&bcs).unwrap();
687 assert_eq!(*scheme, sig.scheme());
688 let bytes = bcs::to_bytes(&sig).unwrap();
689 assert_eq!(bcs, bytes);
690
691 let json = serde_json::to_string_pretty(&sig).unwrap();
692 println!("{json}");
693 assert_eq!(sig, serde_json::from_str(&json).unwrap());
694 }
695 }
696
697 #[test]
698 fn legacy_multisig_fixtures() {
699 const FIXTURE1: &str = "rgIDAgAnwUSyrALP8m0eEPZE6aPggBELk72n1u3LU+i4nx5kqzhahcICbskEYzHJrbarvFr/RQITgDMoorqpDhN8dgsKATyrN3CD8g37D60dYiGW6sOBqIcf3E1mdMsKvX2pbOZsYQv8VNL+2Jz3vnMXcwEZF32PplKjcnmyUGRhV11M7n4UOjAAAAEAAAAAAAEAEAAAAAAAAQADLEFBMTlxeldNamEycVR2b0FTYWRiQjBObFZiRUtOb0ladTJnUGNGY1RTZGQxATBBUUlPRjgxWk9lUnJHV1pCbG96WFdaRUxvbGQrSi9wei9lT0hiYm0reGJ6ckt3PT0BMEFnTkgrNjhqOERpcnhNTUlvbkVSZWlwTS82N2R2Ri80SEhVWHZHeDBwKzIwTUE9PQECAA==";
700
701 const FIXTURE2: &str = "8QIDAwDYAAra4KQGp2Oq1TCOgWfH8IxC4UA5wJB/NqOcNmMh54Y5d5pnVQfTlqgq4J17a8+W+y3+jk9h4YMB9LzPDYcLAaJJBH+WLPfPaQ7T3Cv8nqpZ1TbPrT8E61FrSgeIbN4OTJeijjguv1pd3ImvTeo4AMYZczf5OH6+5yBaur7R6YACiooT5J36agjUk0TpVcTKMGwykIwD7NBkZ0gbinHxuVJwdi1tSbqhMpqvNgP+CFO6F7FSTe+xiHh0MDOKyYQItxY6MAAAAQAAAAAAAgAQAAAAAAABAAIAAyxBQTE5cXpXTWphMnFUdm9BU2FkYkIwTmxWYkVLTm9JWnUyZ1BjRmNUU2RkMQEwQVFJT0Y4MVpPZVJyR1daQmxvelhXWkVMb2xkK0ovcHovZU9IYmJtK3hienJLdz09ATBBZ05IKzY4ajhEaXJ4TU1Jb25FUmVpcE0vNjdkdkYvNEhIVVh2R3gwcCsyME1BPT0BAgA=";
702
703 for fixture in [FIXTURE1, FIXTURE2] {
704 let bcs = Base64::decode_vec(fixture).unwrap();
705
706 let sig: UserSignature = bcs::from_bytes(&bcs).unwrap();
707 assert_eq!(SignatureScheme::Multisig, sig.scheme());
708 let bytes = bcs::to_bytes(&sig).unwrap();
709 assert_eq!(bcs, bytes);
710
711 let json = serde_json::to_string_pretty(&sig).unwrap();
712 println!("{json}");
713 assert_eq!(sig, serde_json::from_str(&json).unwrap());
714 }
715 }
716
717 #[test]
718 fn multisig_fixtures() {
719 const FIXTURE1: &str = "sgIDAwCTLgVngjC4yeuvpAGKVkgcvIKVFUJnL1r6oFZScQVE5DNIz6kfxAGDRcVUczE9CUb7/sN/EuFJ8ot86Sdb8pAFASoQ91stRHXdW5dLy0BQ6v+7XWptawy2ItMyPk508p+PHdtZcm2aKl3lZGIvXe6MPY73E+1Hakv/xJbTYsw5SPMC5dx3gBwxds2GV12c7VUSqkyXamliSF1W/QBMufqrlmdIOZ1ox9gbsvIPtXYahfvKm8ozA7rsZWwRv8atsnyfYgcAAwANfas1jI2tqk76AEmnWwdDZVWxCjaCGbtoD3BXE0nXdQEBAg4XzVk55GsZZkGWjNdZkQuiV34n+nP944dtub7FvOsrAQIDR/uvI/A4q8TDCKJxEXoqTP+u3bxf+Bx1F7xsdKfttDABAgA=";
720
721 const FIXTURE2: &str = "8QEDAgBMW4Oq7XMjO5c6HLgTBJrWDZsCEcZF2EPOf68fdf1aY3e3pvA3cmk0tjMmXFB9+A6J2NohCpTFb/CsXEBjtCcMAfraaMMOMzG815145jlrY44Rbp0d1JQJOJ3hjgEe2xVBFP3QR94IVZk6ssyYxsecpBA+re5eqVRacvZGSobNPkMDAAMADX2rNYyNrapO+gBJp1sHQ2VVsQo2ghm7aA9wVxNJ13UBAQIOF81ZOeRrGWZBlozXWZELold+J/pz/eOHbbm+xbzrKwECA0f7ryPwOKvEwwiicRF6Kkz/rt28X/gcdRe8bHSn7bQwAQIA";
722
723 for fixture in [FIXTURE1, FIXTURE2] {
724 let bcs = Base64::decode_vec(fixture).unwrap();
725
726 let sig: UserSignature = bcs::from_bytes(&bcs).unwrap();
727 assert_eq!(SignatureScheme::Multisig, sig.scheme());
728 let bytes = bcs::to_bytes(&sig).unwrap();
729 assert_eq!(bcs, bytes);
730
731 let json = serde_json::to_string_pretty(&sig).unwrap();
732 println!("{json}");
733 assert_eq!(sig, serde_json::from_str(&json).unwrap());
734 }
735 }
736
737 #[test]
738 fn mutisig_with_zklogin() {
739 const FIXTURE: &str = "xwgDAQOWBwUDTDYyNzM5OTI5NDQyODI2NTYyNDE2NDMyNDk5Njc1NDY0MzY0MTU2ODM1MzgzMzAwNzMzMDkwMzgyOTUwOTAwMjA0MzcwMzI3MzQ0MTdNMTM5MjUxMzE5MTUzODM4NDMwOTkzODU1NTU2MjYyNzIwMzI5NjE5MjM3MjY1ODAyMjY2OTcwMTUzMTkxOTcxMzIxODkxMTg2MDUyNTcBMQMCTDc3MDQwMDc2MTQxMjAyNDQ0MjgyMDMyMzQwMzI3NzQ2ODkwODEwNzg2Mzg4NjkzMTcyNDM1NTEyNTMwMTA3MjYzMzg1MTA0MzYxMjdMNDczMzY5MTU2NjAwODE5MTIwNDAxMjcwNTc5OTA2MjI3NTk2MjY0NzMwMTUyNDU3MDIxMjM0MzczMjc1MTE3MTQyMjY2MzEzNTc1MgJMOTYzMjExNjUzNzQxMTQ3Mjk4MTQ2NDE0NzY0MDM5MzkxNzQxODQyMDI4NzgwOTUxODYyMTk5OTM0MjIwNjc2ODgzMjg0NzY5NTg5Nkw4NDM2Mjg3MTUwMzIxMjE2NTUwOTIxNTQ4ODg0MjI2MDM4MjczMTk0MjAyNDQwNTc0NzI5MDM4MTk2NDAxNDAzMDI0Mzg0MTEzODk4AgExATADTDUxNzIxODQyMDU0ODkxNDg4MzEwNTgxODkxNDIwNjI3Njc1NTM3MjMxMDkzNzIyMDk4NzI0NDAxMzA1MTg0MzYzODQxNzUxMjY1MjRMNTE1MTQzMjA2NjEzODc0NzIwOTEyMDY4NzUyMjIwODU1NDA0MTU2NDgyNzA4MDc5NzA1MDcxNjkyNzc2OTY0MzQ0NzQyMjEyMzI3MAExMXdpYVhOeklqb2lhSFIwY0hNNkx5OXBaQzUwZDJsMFkyZ3VkSFl2YjJGMWRHZ3lJaXcCMmV5SmhiR2NpT2lKU1V6STFOaUlzSW5SNWNDSTZJa3BYVkNJc0ltdHBaQ0k2SWpFaWZRTTIwNjg3NjQyNTE3NjMwNzMzMjczNjg3Nzk1NDc2MjQ3NDM3NzQzODM0NjAxMTAxNTY2Njg0OTY3OTY3NzA1ODA5OTg1MjQxMDY1NTM5CgAAAAAAAABhANFnRWP0VWDZA6kp8ltYtndCLMp70+CQMkW4CKPMOF5fGqTuUIKzqHJysBK8jS3rgHHBc5ZDqn0YUG0W2SH5gQC5xu4WMO8+cRFEpkjbBruyKE9ydM++5T/87lA8waSSAAgABAANfas1jI2tqk76AEmnWwdDZVWxCjaCGbtoD3BXE0nXdQEBAg4XzVk55GsZZkGWjNdZkQuiV34n+nP944dtub7FvOsrAQIDR/uvI/A4q8TDCKJxEXoqTP+u3bxf+Bx1F7xsdKfttDABAzwbaHR0cHM6Ly9pZC50d2l0Y2gudHYvb2F1dGgyLbzKbLI5Mq4c7y9X5gf73CthASNbTN9llO2Okr5TqEMBAQA=";
740
741 let bcs = Base64::decode_vec(FIXTURE).unwrap();
742
743 let sig: UserSignature = bcs::from_bytes(&bcs).unwrap();
744 assert_eq!(SignatureScheme::Multisig, sig.scheme());
745 let bytes = bcs::to_bytes(&sig).unwrap();
746 assert_eq!(bcs, bytes);
747
748 let json = serde_json::to_string_pretty(&sig).unwrap();
749 println!("{json}");
750 assert_eq!(sig, serde_json::from_str(&json).unwrap());
751 }
752
753 #[test]
754 fn zklogin_fixtures() {
755 const FIXTURES: &[&str] = &[
756 "mAcFA00yMTM0MzA3MTg2NDQ3ODc4NTU1OTU1OTY2Njg3NDQ3Njg0MzYyODQxNjA4OTQ4ODEyMTk4MjQ0OTY0ODk4OTg3OTkxMTI1MTY2OTA2N0w1MzYyMzAzOTQxMzk3NzQ1MTk2MTQxNjgxNjA5MDk0MDI4MTg3NzgxMzY2ODc3ODA5NTA2NTU0NzA3MjQ4MzcwNzM4OTcwOTI5MzYwATEDAk0xOTAzMjkyNDMyMDAxODEyNjcyNzEyMDYzMjYzMzM2OTE1NTg2MDc4NDA0NjY2MDcyMzIzMjU0MTAwMjQyODAxODA4ODQ4MTI3MzA5N0sxOTM0MDEzODQwOTcyNjc5OTM0MzgxMTI2ODg3OTQ2MTk1NDk5NTczMjY3NTE5ODAxNDA4MzQ2MzA3NDA2NzI3NjIxNzI0MTA4ODUCTDQxMTc0OTU3NjIwNzc2NjE4OTk2Njk5ODU1MTUzMzc2MDcwMTkzNTgwMjc2MjUxNTc4MDQwMTc0NTI2OTM1MTY5ODY1MDU1NDcyMTdNMTI3MDM0MzkzNTYyNTQ3NTM4NDA5NzAxMjA3MDAxMjM5MjcxOTU1OTI4OTE0MDgxMzY5NzQ0ODkwMzkzMzgyOTgzODYwODQxODYyNzYCATEBMANMNjAyNTg2MDg4MjI2OTUxNTE2NDY3MjY1NjU3OTU4MDE1OTMyMTI2ODY4MDM1NjU0NTkxOTA1NDkwNzkzNTM4MzY1NDYwNzA5MTIyOE0xNTUxNzY4ODA2NDc3NTgzMDI3NzAwNjY2NzE2OTM2NzAxNjU4Nzk5NDIyNjc1MTQ0Nzg5ODMzNjg0MDk5NjU4MDczNzg0NDY0NDExNQExMXdpYVhOeklqb2lhSFIwY0hNNkx5OXBaQzUwZDJsMFkyZ3VkSFl2YjJGMWRHZ3lJaXcCMmV5SmhiR2NpT2lKU1V6STFOaUlzSW5SNWNDSTZJa3BYVkNJc0ltdHBaQ0k2SWpFaWZRTDIwMjIzNjc3MTc2ODYwNzEyNzk5MTIwNjA0MTY1NTc3MDEyMjMyOTk3NTc0MjQwNjg2MDUwMzc1OTc1MTI1NzUzNDA0NDU0MTY4MTAKAAAAAAAAAGICUv1c+GW7/G0rKAO5QgQrqs3ujZALi4GWTkqgEjfTqMs53H1MeeRJdWzJW104/97F1VJyjm01ozKRasbRJGSsRwKi14vTFJZpnOkPlaKtNt4cGpY4PpaoeXb289IzLDx1Gg==",
757 "mwcFA00xMDE2MjI2MTYwOTg0NDYxNDI1OTY3MjA3OTg1MTYyNzUxNTQyNjEzMzM1OTEzMTc5NDQ3ODc4MDgzNDA3NTkxNDc5ODcxNzMzNzUzNU0xNjUwMTEzNTg2OTk2NDUwMDk1Njk2MDE2NzI0NzgwMzY3MzkyNDI4NDI0NTU3MDIyODMyODc4MDYxNjE4NzE0MzY2MzgzNzA0MjMyNAExAwJMNjAyMjIxMDk3ODA0MDA5MTgyMjQ1MDM2NjM2NjkyMzE1Mjg2NDAzMDQzNjY2ODg5NTUzNzYwNTM5MTM4MDA3OTAxMzIzMjE5OTk2NU0xNjEwNjE0MDY4NzEwMDc3MzQyNDIyNTI0NjEyNzM3ODIyNTgwOTIxMTQxMTYwMjQzMTIwMzI3NDM2MjM1NjEwOTI5NDk5Mjg2MjM4NgJMNzQwNDE3NTg3NDgyOTU3NDM0NTk1NDk1MTU0NDkxODY2ODI5ODQ0OTYxNjMzMDAyMzE4MzE4MzcwMTgxNjEwOTg3OTAwOTY5MTcxMUw3MzAwNzMwODk0MDQzNjM0NjI0NzIwNzkzNDIxNTM1NTUxODI3NDU4NjE4NzU5NjE2OTEzMjU0ODY4MzUzODE1MzM5ODg3MjIzMTA5AgExATADTTExNDA2NTA2NzUyNTkyODQ5NDk4MzcyNzYxODIyNzM4MjA2NTY0ODc4ODM3NTE3NzkxNTY2MzQ3NDk0NDkyNDQyMTI4MDExMTQwMzU3TTE1Njk5MzYzODA5ODg4MDc3MDcxNjM1NTg1MTA2NzA2MjE0NTcxMDI3NDU3ODE5MTE4NTE1NTk2MjA4MDgzODUzODcyOTM3NzQxNDczATExd2lhWE56SWpvaWFIUjBjSE02THk5cFpDNTBkMmwwWTJndWRIWXZiMkYxZEdneUlpdwIyZXlKaGJHY2lPaUpTVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0lzSW10cFpDSTZJakVpZlFNMTc1NzI2MTY4NDgyNzU4OTMzODIyMTc0ODE3OTM5MTkwMDYzNjYzNzY4NTk4MTcwNDA1NDYwNDk4MzU5NTgxODc0NjEyOTg2NjkyNzAKAAAAAAAAAGICl9lwjktCQkH7GqGGV6EdbjHv4Go6MIDmr6EIvtg/2h5IuXKJF5GoVLuykxWwkSdNr9iRUZaz3Z0p/Z9nPJlW/gNaiwdVCMdfShJHSZgqfSH4DZpfaJPkGp6VX+TIIeDevg==",
758 "mgcFA00xOTUwNDI1NDE5MzgxMzM3OTA5NDA1MzkyODkyNTQwMjAxMjIxMTg4ODY5MDAzOTQ3ODM0MjYzOTk4OTcwMjA4MjAxNjY2MDkyNzg4MU0xODEwMjYxODU0NjY0NjY3MDgyMjI5MjczMjIwMDgzMzU0OTk4NDAxMTkxMDI1MDY2MjQ4Mjk5MjMzODgzNjA1NTc1MzMyNTUyMTUzMwExAwJMNTI0MzA1OTQ2MTI1NDQxOTM0NzgzOTMxMjI4ODQ5NjY4OTI0Njk4NzIyMTMyMDcxMDcyNzc2NzgzNzc3NDc4ODI4Mzc1NjgzMTAyOE0xMjA3MDIwMzk2MzAzNjY0NTY2NjAyMzUwNDMyNDM3NDY1OTYwMTY1NzY2NDAzOTU4MzE0MDU2Njc2MDExOTcwMTA3MjI5MjA0NzkxMQJNMTYzNjc2NDUxMTMxNzA1OTkxMTgwNzc1NjgxOTUyMjA5ODY1NjcxNjE0ODk2MDcyNDI1NzQ2ODg5ODQ0NzI4NTk0MzE2Mzk4MzQxNzhMNTg5MTQ4MzY3MjI1MTQyMzgzODE5NTQxNDg0NjEwNTY0Nzk4MDE2NjAyODIyNjcwMzE2ODE1Njg2MzkzNjUxNjk1OTkzMjE4MzExNQIBMQEwA0w2NDc2MTA0MzAwODgxNTQ2NTk3NjUwODk0NjEzNTUyMDc1NDg4Mjk5NjA4NjM5MTY4MzE3MjgzNTg2ODI3MDA3MTUzODg5MjI1MTI2TDQ3NjgzNjQxMTE1NjM0NzI0MDI1NzA4NDE0ODEyMDMzMTgzMDQzMTQ1MDQ4NjcxMzk1NzQ0MzAzODI2NzA4MDcwMTkwNDgxMTQyNzEBMTF3aWFYTnpJam9pYUhSMGNITTZMeTlwWkM1MGQybDBZMmd1ZEhZdmIyRjFkR2d5SWl3AjJleUpoYkdjaU9pSlNVekkxTmlJc0luUjVjQ0k2SWtwWFZDSXNJbXRwWkNJNklqRWlmUU0xMDc0MzE4MDg0MjY5ODE2Mzk0ODQ5NzAyMjkwMDE0Mzc4NjI0MTEwOTYyMzMyMDgzNzYxNzUzMDY5NzUxNDA1MzIwODA1NjEwNzgzNAoAAAAAAAAAYgLL7Jn3QV4USqVbuv97w4LqA12BAwU95fsUrvymgAUPtiepsG6kCVnX903PFZBusNM07tgWJ4/5ypb5mbJQhijJA+3BG7HM6kM2jZ0NPldx4AR5zvu+l4ZXRC4lo39h/K5s",
759 "mgcFA0wxNjY4NTEwOTQ1NDY2OTQ2OTYyODUxODAzOTg1MTA3Mjk2NTM1OTM3MzI1NzI5OTMzNDE1MzAzOTcwNjI2MjE3NzAwOTM0NjE4MjY1TDc5ODAxMjUwNTYxMTA2NzczMjY0NjA1MjI0MjgyNTk1OTM4NzQzOTg5MjE3Nzg1Mzk1MTUxODY3MTkwMzk3OTc1MTQ0NDA4ODQ1NTEBMQMCTTEyODA2ODY2NjkyMTUxODMxMTI1MzExMTk3Nzc1NTAxNDU1MTIwNzQwNjg2Mzk2OTQ4NDIxMjAyODI0MjkwODMwNzQzMzM4NTE1MjMxTTE4NzY2Mzc4MTcwNzE4MDMzMzk0ODQxMTYxMTU0MjA0NDA2ODc0MDM0ODk4NjA1NTk4MTgzMDM5NjM2NjQ1NjU3Mjk3NTIzMTU4ODU1Ak0xNzYyNTIzNTA0NzgxNDg2NDg1OTY1NTA1MTkyNTUyMzYxNjkwNzg2MDk3MjM3ODE1OTU1NjA4NDMyNDM5NTQxODk5MzI4NzQwMzk0M00xNjQ3MTA2MDIyOTUzMDIyNjEwOTk0Mzc3MTU3NzQ1NjIzMDM2NTM5NTMxNzM0NDk3OTAwNjAwMTE1NTgxNzM5ODE1NjczMjIwMjcxMwIBMQEwA00xODU1NzU4NTE1MjgxMTk5Mzk1MTY2NDY4NDA1ODg4MTg0NDE2MjY4NTk1NzAxMDY1MzIyNjg5ODkyOTgwNjA1Njc4NjMyMzg5MzA0M0wyNDQ2NDI2NDg4NTQwNzcwNzE5NTIyMjk1NTY3Njc2OTU3MzYzNjIxNTQ0MDUwMTg5OTAxMTk0MTY3NDY1NDE3OTA0Njk2NDQ3NDA1ATExd2lhWE56SWpvaWFIUjBjSE02THk5cFpDNTBkMmwwWTJndWRIWXZiMkYxZEdneUlpdwIyZXlKaGJHY2lPaUpTVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0lzSW10cFpDSTZJakVpZlFMODQ2ODk2NzMyOTAyOTgzNjU0MjM3MzIzMjc4Njc3NzgyNDA5MTgyOTM1OTA4MjczNzA5MjQ3MjM1NDEwODEzNTkwOTE0MTM4MjEwNAoAAAAAAAAAYgEaWZZP7C934LS3vgsXYQk85BBiG6E285TY0C6U59qaUxlCUQWACVbxyEej193U4uIIP71lZ6KwvfT7lqOsUUIvAoa8xwWZ68Qgs7iXfsxg5ZS7VnSb6qVi1/gKm9//yqod",
760 "lgcFA0w2MjczOTkyOTQ0MjgyNjU2MjQxNjQzMjQ5OTY3NTQ2NDM2NDE1NjgzNTM4MzMwMDczMzA5MDM4Mjk1MDkwMDIwNDM3MDMyNzM0NDE3TTEzOTI1MTMxOTE1MzgzODQzMDk5Mzg1NTU1NjI2MjcyMDMyOTYxOTIzNzI2NTgwMjI2Njk3MDE1MzE5MTk3MTMyMTg5MTE4NjA1MjU3ATEDAkw3NzA0MDA3NjE0MTIwMjQ0NDI4MjAzMjM0MDMyNzc0Njg5MDgxMDc4NjM4ODY5MzE3MjQzNTUxMjUzMDEwNzI2MzM4NTEwNDM2MTI3TDQ3MzM2OTE1NjYwMDgxOTEyMDQwMTI3MDU3OTkwNjIyNzU5NjI2NDczMDE1MjQ1NzAyMTIzNDM3MzI3NTExNzE0MjI2NjMxMzU3NTICTDk2MzIxMTY1Mzc0MTE0NzI5ODE0NjQxNDc2NDAzOTM5MTc0MTg0MjAyODc4MDk1MTg2MjE5OTkzNDIyMDY3Njg4MzI4NDc2OTU4OTZMODQzNjI4NzE1MDMyMTIxNjU1MDkyMTU0ODg4NDIyNjAzODI3MzE5NDIwMjQ0MDU3NDcyOTAzODE5NjQwMTQwMzAyNDM4NDExMzg5OAIBMQEwA0w1MTcyMTg0MjA1NDg5MTQ4ODMxMDU4MTg5MTQyMDYyNzY3NTUzNzIzMTA5MzcyMjA5ODcyNDQwMTMwNTE4NDM2Mzg0MTc1MTI2NTI0TDUxNTE0MzIwNjYxMzg3NDcyMDkxMjA2ODc1MjIyMDg1NTQwNDE1NjQ4MjcwODA3OTcwNTA3MTY5Mjc3Njk2NDM0NDc0MjIxMjMyNzABMTF3aWFYTnpJam9pYUhSMGNITTZMeTlwWkM1MGQybDBZMmd1ZEhZdmIyRjFkR2d5SWl3AjJleUpoYkdjaU9pSlNVekkxTmlJc0luUjVjQ0k2SWtwWFZDSXNJbXRwWkNJNklqRWlmUU0yMDY4NzY0MjUxNzYzMDczMzI3MzY4Nzc5NTQ3NjI0NzQzNzc0MzgzNDYwMTEwMTU2NjY4NDk2Nzk2NzcwNTgwOTk4NTI0MTA2NTUzOQoAAAAAAAAAYQBn1v6x7RD9EyaiubLQ8qQkJSNI2Mr1GFHXZyOUJ+eCphFkwjYKBo44TMAbryd405BY+MHYTFLZOD06UTycKHgKucbuFjDvPnERRKZI2wa7sihPcnTPvuU//O5QPMGkkgA=",
761 ];
762
763 for fixture in FIXTURES {
764 let bcs = Base64::decode_vec(fixture).unwrap();
765
766 let sig: UserSignature = bcs::from_bytes(&bcs).unwrap();
767 assert_eq!(SignatureScheme::ZkLogin, sig.scheme());
768 let bytes = bcs::to_bytes(&sig).unwrap();
769 assert_eq!(bcs, bytes);
770
771 let json = serde_json::to_string_pretty(&sig).unwrap();
772 println!("{json}");
773 assert_eq!(sig, serde_json::from_str(&json).unwrap());
774 }
775 }
776
777 #[test]
778 fn passkey_fixtures() {
779 const FIXTURES: &[&str] = &[
780 "lgIGJUmWDeWIDoxodDQXD2R2YFuP5K65ooYyx5lc87qDHZdjHQAAAACKAXsidHlwZSI6IndlYmF1dGhuLmdldCIsImNoYWxsZW5nZSI6IkFBQUF0X21qSUIxdmJWcFlNNldWNllfb2l4Nko4YU5fOXNiOFNLRmJ1a0JmaVF3Iiwib3JpZ2luIjoiaHR0cDovL2xvY2FsaG9zdDo1MTczIiwiY3Jvc3NPcmlnaW4iOmZhbHNlfWICmOyQv1fJ+inKD0C/sxKtxyFKl9aoBign6p9Ih3iA2ahDVg2CPZqUOlEhur2S2GbIZjbn6TbgWtbXXg8SjLkL7wM9Fw4JO0AKLdnLC1nhQguHBX5K6Hv2ta1sqoOqEFDDEw==",
781 ];
782
783 for fixture in FIXTURES {
784 let bcs = Base64::decode_vec(fixture).unwrap();
785
786 let sig: UserSignature = bcs::from_bytes(&bcs).unwrap();
787 assert_eq!(SignatureScheme::Passkey, sig.scheme());
788 let bytes = bcs::to_bytes(&sig).unwrap();
789 assert_eq!(bcs, bytes);
790
791 let json = serde_json::to_string_pretty(&sig).unwrap();
792 println!("{json}");
793 assert_eq!(sig, serde_json::from_str(&json).unwrap());
794 }
795 }
796 }
797}