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