sui_sdk_types/crypto/
multisig.rs

1use super::zklogin::ZkLoginAuthenticator;
2use super::zklogin::ZkLoginPublicIdentifier;
3use super::Ed25519PublicKey;
4use super::Ed25519Signature;
5use super::PasskeyAuthenticator;
6use super::PasskeyPublicKey;
7use super::Secp256k1PublicKey;
8use super::Secp256k1Signature;
9use super::Secp256r1PublicKey;
10use super::Secp256r1Signature;
11use super::SignatureScheme;
12
13pub type WeightUnit = u8;
14pub type ThresholdUnit = u16;
15pub type BitmapUnit = u16;
16
17const MAX_COMMITTEE_SIZE: usize = 10;
18// TODO validate sigs
19// const MAX_BITMAP_VALUE: BitmapUnit = 0b1111111111;
20
21/// Enum of valid public keys for multisig committee members
22///
23/// # BCS
24///
25/// The BCS serialized form for this type is defined by the following ABNF:
26///
27/// ```text
28/// multisig-member-public-key = ed25519-multisig-member-public-key /
29///                              secp256k1-multisig-member-public-key /
30///                              secp256r1-multisig-member-public-key /
31///                              zklogin-multisig-member-public-key
32///
33/// ed25519-multisig-member-public-key   = %x00 ed25519-public-key
34/// secp256k1-multisig-member-public-key = %x01 secp256k1-public-key
35/// secp256r1-multisig-member-public-key = %x02 secp256r1-public-key
36/// zklogin-multisig-member-public-key   = %x03 zklogin-public-identifier
37/// ```
38///
39/// There is also a legacy encoding for this type defined as:
40///
41/// ```text
42/// legacy-multisig-member-public-key = string ; which is valid base64 encoded
43///                                            ; and the decoded bytes are defined
44///                                            ; by legacy-public-key
45/// legacy-public-key = (ed25519-flag ed25519-public-key) /
46///                     (secp256k1-flag secp256k1-public-key) /
47///                     (secp256r1-flag secp256r1-public-key)
48/// ```
49#[derive(Clone, Debug, PartialEq, Eq)]
50#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
51pub enum MultisigMemberPublicKey {
52    Ed25519(Ed25519PublicKey),
53    Secp256k1(Secp256k1PublicKey),
54    Secp256r1(Secp256r1PublicKey),
55    ZkLogin(ZkLoginPublicIdentifier),
56    Passkey(PasskeyPublicKey),
57}
58
59/// A member in a multisig committee
60///
61/// # BCS
62///
63/// The BCS serialized form for this type is defined by the following ABNF:
64///
65/// ```text
66/// multisig-member = multisig-member-public-key
67///                   u8    ; weight
68/// ```
69///
70/// There is also a legacy encoding for this type defined as:
71///
72/// ```text
73/// legacy-multisig-member = legacy-multisig-member-public-key
74///                          u8     ; weight
75/// ```
76#[derive(Clone, Debug, PartialEq, Eq)]
77#[cfg_attr(
78    feature = "serde",
79    derive(serde_derive::Serialize, serde_derive::Deserialize)
80)]
81#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
82pub struct MultisigMember {
83    public_key: MultisigMemberPublicKey,
84    weight: WeightUnit,
85}
86
87impl MultisigMember {
88    /// Construct a new member from a `MultisigMemberPublicKey` and a `weight`.
89    pub fn new(public_key: MultisigMemberPublicKey, weight: WeightUnit) -> Self {
90        Self { public_key, weight }
91    }
92
93    /// This member's public key.
94    pub fn public_key(&self) -> &MultisigMemberPublicKey {
95        &self.public_key
96    }
97
98    /// Weight of this member's signature.
99    pub fn weight(&self) -> WeightUnit {
100        self.weight
101    }
102}
103
104/// A multisig committee
105///
106/// A `MultisigCommittee` is a set of members who collectively control a single `Address` on the
107/// Sui blockchain. The number of required signautres to authorize the execution of a transaction
108/// is determined by `(signature_0_weight + signature_1_weight ..) >= threshold`.
109///
110/// # BCS
111///
112/// The BCS serialized form for this type is defined by the following ABNF:
113///
114/// ```text
115/// multisig-committee = (vector multisig-member)
116///                      u16    ; threshold
117/// ```
118///
119/// There is also a legacy encoding for this type defined as:
120///
121/// ```text
122/// legacy-multisig-committee = (vector legacy-multisig-member)
123///                             u16     ; threshold
124/// ```
125#[derive(Debug, Clone, PartialEq, Eq)]
126#[cfg_attr(
127    feature = "serde",
128    derive(serde_derive::Serialize, serde_derive::Deserialize)
129)]
130#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
131pub struct MultisigCommittee {
132    /// A list of committee members and their corresponding weight.
133    #[cfg_attr(feature = "proptest", any(proptest::collection::size_range(0..=10).lift()))]
134    members: Vec<MultisigMember>,
135
136    /// If the total weight of the public keys corresponding to verified signatures is larger than
137    /// threshold, the Multisig is verified.
138    threshold: ThresholdUnit,
139}
140
141impl MultisigCommittee {
142    /// Construct a new committee from a list of `MultisigMember`s and a `threshold`.
143    ///
144    /// Note that the order of the members is significant towards deriving the `Address` governed
145    /// by this committee.
146    pub fn new(members: Vec<MultisigMember>, threshold: ThresholdUnit) -> Self {
147        Self { members, threshold }
148    }
149
150    /// The members of the committee
151    pub fn members(&self) -> &[MultisigMember] {
152        &self.members
153    }
154
155    /// The total signature weight required to authorize a transaction for the address
156    /// corresponding to this `MultisigCommittee`.
157    pub fn threshold(&self) -> ThresholdUnit {
158        self.threshold
159    }
160
161    /// Return the flag for this signature scheme
162    pub fn scheme(&self) -> SignatureScheme {
163        SignatureScheme::Multisig
164    }
165
166    /// Checks if the Committee is valid.
167    ///
168    /// A valid committee is one that:
169    ///  - Has a nonzero threshold
170    ///  - Has at least one member
171    ///  - Has at most ten members
172    ///  - No member has weight 0
173    ///  - the sum of the weights of all members must be larger than the threshold
174    ///  - contains no duplicate members
175    pub fn is_valid(&self) -> bool {
176        self.threshold != 0
177            && !self.members.is_empty()
178            && self.members.len() <= MAX_COMMITTEE_SIZE
179            && !self.members.iter().any(|member| member.weight == 0)
180            && self
181                .members
182                .iter()
183                .map(|member| member.weight as ThresholdUnit)
184                .sum::<ThresholdUnit>()
185                >= self.threshold
186            && !self.members.iter().enumerate().any(|(i, member)| {
187                self.members
188                    .iter()
189                    .skip(i + 1)
190                    .any(|m| member.public_key == m.public_key)
191            })
192    }
193}
194
195/// Aggregated signature from members of a multisig committee.
196///
197/// # BCS
198///
199/// The BCS serialized form for this type is defined by the following ABNF:
200///
201/// ```text
202/// multisig-aggregated-signature = (vector multisig-member-signature)
203///                                 u16     ; bitmap
204///                                 multisig-committee
205/// ```
206///
207/// There is also a legacy encoding for this type defined as:
208///
209/// ```text
210/// legacy-multisig-aggregated-signature = (vector multisig-member-signature)
211///                                        roaring-bitmap   ; bitmap
212///                                        legacy-multisig-committee
213/// roaring-bitmap = bytes  ; where the contents of the bytes are valid
214///                         ; according to the serialized spec for
215///                         ; roaring bitmaps
216/// ```
217///
218/// See [here](https://github.com/RoaringBitmap/RoaringFormatSpec) for the specification for the
219/// serialized format of RoaringBitmaps.
220#[derive(Debug, Clone)]
221#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
222pub struct MultisigAggregatedSignature {
223    /// The plain signature encoded with signature scheme.
224    ///
225    /// The signatures must be in the same order as they are listed in the committee.
226    #[cfg_attr(feature = "proptest", any(proptest::collection::size_range(0..=10).lift()))]
227    signatures: Vec<MultisigMemberSignature>,
228    /// A bitmap that indicates the position of which public key the signature should be
229    /// authenticated with.
230    bitmap: BitmapUnit,
231    /// Legacy encoding for the bitmap.
232    //TODO implement a strategy for legacy bitmap
233    #[cfg_attr(feature = "proptest", strategy(proptest::strategy::Just(None)))]
234    legacy_bitmap: Option<roaring::RoaringBitmap>,
235    /// The public key encoded with each public key with its signature scheme used along with the
236    /// corresponding weight.
237    committee: MultisigCommittee,
238}
239
240impl MultisigAggregatedSignature {
241    /// Construct a new aggregated multisig signature.
242    ///
243    /// Since the list of signatures doesn't contain sufficient information to identify which
244    /// committee member provided the signature, it is up to the caller to ensure that the provided
245    /// signature list is in the same order as it's corresponding member in the provided committee
246    /// and that it's position in the provided bitmap is set.
247    pub fn new(
248        committee: MultisigCommittee,
249        signatures: Vec<MultisigMemberSignature>,
250        bitmap: BitmapUnit,
251    ) -> Self {
252        Self {
253            signatures,
254            bitmap,
255            legacy_bitmap: None,
256            committee,
257        }
258    }
259
260    /// The list of signatures from committee members
261    pub fn signatures(&self) -> &[MultisigMemberSignature] {
262        &self.signatures
263    }
264
265    /// The bitmap that indicates which committee members provided their signature.
266    pub fn bitmap(&self) -> BitmapUnit {
267        self.bitmap
268    }
269
270    /// The legacy roaring bitmap, if this is a legacy formatted signature
271    pub fn legacy_bitmap(&self) -> Option<&roaring::RoaringBitmap> {
272        self.legacy_bitmap.as_ref()
273    }
274
275    /// Configure with a legacy roaring bitmap
276    pub fn with_legacy_bitmap(&mut self, legacy_bitmap: roaring::RoaringBitmap) {
277        self.legacy_bitmap = Some(legacy_bitmap);
278    }
279
280    /// The committee for this aggregated signature
281    pub fn committee(&self) -> &MultisigCommittee {
282        &self.committee
283    }
284}
285
286impl PartialEq for MultisigAggregatedSignature {
287    fn eq(&self, other: &Self) -> bool {
288        // Skip comparing the legacy bitmap since we always convert to the new bitmap form
289        self.bitmap == other.bitmap
290            && self.signatures == other.signatures
291            && self.committee == other.committee
292    }
293}
294
295impl Eq for MultisigAggregatedSignature {}
296
297/// Convert a roaring bitmap to plain bitmap.
298#[cfg(feature = "serde")]
299fn roaring_bitmap_to_u16(roaring: &roaring::RoaringBitmap) -> Result<BitmapUnit, &'static str> {
300    let mut val = 0;
301    for i in roaring.iter() {
302        if i >= MAX_COMMITTEE_SIZE as u32 {
303            return Err("invalid bitmap");
304        }
305        val |= 1 << i as u8;
306    }
307    Ok(val)
308}
309
310/// A signature from a member of a multisig committee.
311///
312/// # BCS
313///
314/// The BCS serialized form for this type is defined by the following ABNF:
315///
316/// ```text
317/// multisig-member-signature = ed25519-multisig-member-signature /
318///                             secp256k1-multisig-member-signature /
319///                             secp256r1-multisig-member-signature /
320///                             zklogin-multisig-member-signature
321///
322/// ed25519-multisig-member-signature   = %x00 ed25519-signature
323/// secp256k1-multisig-member-signature = %x01 secp256k1-signature
324/// secp256r1-multisig-member-signature = %x02 secp256r1-signature
325/// zklogin-multisig-member-signature   = %x03 zklogin-authenticator
326/// ```
327#[derive(Debug, Clone, PartialEq, Eq)]
328#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
329pub enum MultisigMemberSignature {
330    Ed25519(Ed25519Signature),
331    Secp256k1(Secp256k1Signature),
332    Secp256r1(Secp256r1Signature),
333    ZkLogin(Box<ZkLoginAuthenticator>),
334    Passkey(PasskeyAuthenticator),
335}
336
337#[cfg(feature = "serde")]
338#[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
339mod serialization {
340    use super::*;
341    use crate::crypto::Base64Array33;
342    use crate::crypto::Base64Array34;
343    use crate::Ed25519PublicKey;
344    use crate::PasskeyPublicKey;
345    use crate::Secp256k1PublicKey;
346    use crate::Secp256r1PublicKey;
347    use crate::SignatureScheme;
348    use base64ct::Base64;
349    use base64ct::Encoding;
350    use serde::Deserialize;
351    use serde::Deserializer;
352    use serde::Serialize;
353    use serde::Serializer;
354    use serde_with::Bytes;
355    use serde_with::DeserializeAs;
356    use serde_with::SerializeAs;
357    use std::borrow::Cow;
358
359    pub struct Base64MultisigMemberPublicKey;
360
361    impl SerializeAs<MultisigMemberPublicKey> for Base64MultisigMemberPublicKey {
362        fn serialize_as<S>(
363            source: &MultisigMemberPublicKey,
364            serializer: S,
365        ) -> Result<S::Ok, S::Error>
366        where
367            S: Serializer,
368        {
369            match source {
370                MultisigMemberPublicKey::Ed25519(public_key) => {
371                    let mut buf = [0; 1 + Ed25519PublicKey::LENGTH];
372                    buf[0] = SignatureScheme::Ed25519 as u8;
373                    buf[1..].copy_from_slice(public_key.as_ref());
374                    Base64Array33::serialize_as(&buf, serializer)
375                }
376                MultisigMemberPublicKey::Secp256k1(public_key) => {
377                    let mut buf = [0; 1 + Secp256k1PublicKey::LENGTH];
378                    buf[0] = SignatureScheme::Secp256k1 as u8;
379                    buf[1..].copy_from_slice(public_key.as_ref());
380                    Base64Array34::serialize_as(&buf, serializer)
381                }
382                MultisigMemberPublicKey::Secp256r1(public_key) => {
383                    let mut buf = [0; 1 + Secp256r1PublicKey::LENGTH];
384                    buf[0] = SignatureScheme::Secp256r1 as u8;
385                    buf[1..].copy_from_slice(public_key.as_ref());
386                    Base64Array34::serialize_as(&buf, serializer)
387                }
388                MultisigMemberPublicKey::ZkLogin(_) => Err(serde::ser::Error::custom(
389                    "zklogin not supported in legacy multisig",
390                )),
391                MultisigMemberPublicKey::Passkey(_) => Err(serde::ser::Error::custom(
392                    "passkey not supported in legacy multisig",
393                )),
394            }
395        }
396    }
397
398    impl<'de> DeserializeAs<'de, MultisigMemberPublicKey> for Base64MultisigMemberPublicKey {
399        fn deserialize_as<D>(deserializer: D) -> Result<MultisigMemberPublicKey, D::Error>
400        where
401            D: Deserializer<'de>,
402        {
403            let b64: Cow<'de, str> = Deserialize::deserialize(deserializer)?;
404            let bytes = Base64::decode_vec(&b64).map_err(serde::de::Error::custom)?;
405            let flag = SignatureScheme::from_byte(
406                *bytes
407                    .first()
408                    .ok_or_else(|| serde::de::Error::custom("missing signature scheme falg"))?,
409            )
410            .map_err(serde::de::Error::custom)?;
411            let public_key_bytes = &bytes[1..];
412            match flag {
413                SignatureScheme::Ed25519 => {
414                    let public_key = Ed25519PublicKey::from_bytes(public_key_bytes)
415                        .map_err(serde::de::Error::custom)?;
416                    Ok(MultisigMemberPublicKey::Ed25519(public_key))
417                }
418                SignatureScheme::Secp256k1 => {
419                    let public_key = Secp256k1PublicKey::from_bytes(public_key_bytes)
420                        .map_err(serde::de::Error::custom)?;
421                    Ok(MultisigMemberPublicKey::Secp256k1(public_key))
422                }
423                SignatureScheme::Secp256r1 => {
424                    let public_key = Secp256r1PublicKey::from_bytes(public_key_bytes)
425                        .map_err(serde::de::Error::custom)?;
426                    Ok(MultisigMemberPublicKey::Secp256r1(public_key))
427                }
428                SignatureScheme::Multisig
429                | SignatureScheme::Bls12381
430                | SignatureScheme::ZkLogin
431                | SignatureScheme::Passkey => {
432                    Err(serde::de::Error::custom("invalid public key type"))
433                }
434            }
435        }
436    }
437
438    pub struct LegacyMultisigMember;
439
440    impl SerializeAs<MultisigMember> for LegacyMultisigMember {
441        fn serialize_as<S>(source: &MultisigMember, serializer: S) -> Result<S::Ok, S::Error>
442        where
443            S: Serializer,
444        {
445            #[derive(serde_derive::Serialize)]
446            struct LegacyMember<'a> {
447                #[serde(with = "::serde_with::As::<Base64MultisigMemberPublicKey>")]
448                public_key: &'a MultisigMemberPublicKey,
449                weight: WeightUnit,
450            }
451
452            let legacy = LegacyMember {
453                public_key: &source.public_key,
454                weight: source.weight,
455            };
456
457            legacy.serialize(serializer)
458        }
459    }
460
461    impl<'de> DeserializeAs<'de, MultisigMember> for LegacyMultisigMember {
462        fn deserialize_as<D>(deserializer: D) -> Result<MultisigMember, D::Error>
463        where
464            D: Deserializer<'de>,
465        {
466            #[derive(serde_derive::Deserialize)]
467            struct LegacyMember {
468                #[serde(with = "::serde_with::As::<Base64MultisigMemberPublicKey>")]
469                public_key: MultisigMemberPublicKey,
470                weight: WeightUnit,
471            }
472
473            let legacy = LegacyMember::deserialize(deserializer)?;
474
475            Ok(MultisigMember {
476                public_key: legacy.public_key,
477                weight: legacy.weight,
478            })
479        }
480    }
481
482    #[derive(serde_derive::Deserialize)]
483    pub struct Multisig {
484        signatures: Vec<MultisigMemberSignature>,
485        bitmap: BitmapUnit,
486        committee: MultisigCommittee,
487    }
488
489    #[derive(serde_derive::Serialize)]
490    pub struct MultisigRef<'a> {
491        signatures: &'a [MultisigMemberSignature],
492        bitmap: BitmapUnit,
493        committee: &'a MultisigCommittee,
494    }
495
496    #[derive(serde_derive::Deserialize)]
497    pub struct LegacyMultisig {
498        signatures: Vec<MultisigMemberSignature>,
499        #[serde(with = "::serde_with::As::<crate::_serde::BinaryRoaringBitmap>")]
500        bitmap: roaring::RoaringBitmap,
501        committee: LegacyMultisigCommittee,
502    }
503
504    #[derive(serde_derive::Serialize)]
505    pub struct LegacyMultisigRef<'a> {
506        signatures: &'a [MultisigMemberSignature],
507        #[serde(with = "::serde_with::As::<crate::_serde::BinaryRoaringBitmap>")]
508        bitmap: &'a roaring::RoaringBitmap,
509        committee: LegacyMultisigCommitteeRef<'a>,
510    }
511
512    #[derive(serde_derive::Deserialize)]
513    struct LegacyMultisigCommittee {
514        #[serde(with = "::serde_with::As::<Vec<LegacyMultisigMember>>")]
515        members: Vec<MultisigMember>,
516        threshold: ThresholdUnit,
517    }
518
519    #[derive(serde_derive::Serialize)]
520    struct LegacyMultisigCommitteeRef<'a> {
521        #[serde(with = "::serde_with::As::<&[LegacyMultisigMember]>")]
522        members: &'a [MultisigMember],
523        threshold: ThresholdUnit,
524    }
525
526    #[derive(serde_derive::Deserialize)]
527    struct ReadableMultisigAggregatedSignature {
528        signatures: Vec<MultisigMemberSignature>,
529        bitmap: BitmapUnit,
530        #[serde(default)]
531        #[serde(with = "::serde_with::As::<Option<crate::_serde::Base64RoaringBitmap>>")]
532        legacy_bitmap: Option<roaring::RoaringBitmap>,
533        committee: MultisigCommittee,
534    }
535
536    #[derive(serde_derive::Serialize)]
537    struct ReadableMultisigAggregatedSignatureRef<'a> {
538        signatures: &'a [MultisigMemberSignature],
539        bitmap: BitmapUnit,
540        #[serde(skip_serializing_if = "Option::is_none")]
541        #[serde(with = "::serde_with::As::<Option<crate::_serde::Base64RoaringBitmap>>")]
542        legacy_bitmap: &'a Option<roaring::RoaringBitmap>,
543        committee: &'a MultisigCommittee,
544    }
545
546    impl Serialize for MultisigAggregatedSignature {
547        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
548        where
549            S: Serializer,
550        {
551            if serializer.is_human_readable() {
552                let readable = ReadableMultisigAggregatedSignatureRef {
553                    signatures: &self.signatures,
554                    bitmap: self.bitmap,
555                    legacy_bitmap: &self.legacy_bitmap,
556                    committee: &self.committee,
557                };
558                readable.serialize(serializer)
559            } else {
560                let bytes = self.to_bytes();
561                serializer.serialize_bytes(&bytes)
562            }
563        }
564    }
565
566    impl<'de> Deserialize<'de> for MultisigAggregatedSignature {
567        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
568        where
569            D: Deserializer<'de>,
570        {
571            if deserializer.is_human_readable() {
572                let readable = ReadableMultisigAggregatedSignature::deserialize(deserializer)?;
573                Ok(Self {
574                    signatures: readable.signatures,
575                    bitmap: readable.bitmap,
576                    legacy_bitmap: readable.legacy_bitmap,
577                    committee: readable.committee,
578                })
579            } else {
580                let bytes: Cow<'de, [u8]> = Bytes::deserialize_as(deserializer)?;
581                Self::from_serialized_bytes(bytes)
582            }
583        }
584    }
585
586    impl MultisigAggregatedSignature {
587        pub(crate) fn to_bytes(&self) -> Vec<u8> {
588            let mut buf = Vec::new();
589            buf.push(SignatureScheme::Multisig as u8);
590
591            if let Some(bitmap) = &self.legacy_bitmap {
592                let legacy = LegacyMultisigRef {
593                    signatures: &self.signatures,
594                    bitmap,
595                    committee: LegacyMultisigCommitteeRef {
596                        members: &self.committee.members,
597                        threshold: self.committee.threshold,
598                    },
599                };
600
601                bcs::serialize_into(&mut buf, &legacy).expect("serialization cannot fail");
602            } else {
603                let multisig = MultisigRef {
604                    signatures: &self.signatures,
605                    bitmap: self.bitmap,
606                    committee: &self.committee,
607                };
608                bcs::serialize_into(&mut buf, &multisig).expect("serialization cannot fail");
609            }
610            buf
611        }
612
613        pub(crate) fn from_serialized_bytes<T: AsRef<[u8]>, E: serde::de::Error>(
614            bytes: T,
615        ) -> Result<Self, E> {
616            let bytes = bytes.as_ref();
617            let flag = SignatureScheme::from_byte(
618                *bytes
619                    .first()
620                    .ok_or_else(|| serde::de::Error::custom("missing signature scheme falg"))?,
621            )
622            .map_err(serde::de::Error::custom)?;
623            if flag != SignatureScheme::Multisig {
624                return Err(serde::de::Error::custom("invalid multisig flag"));
625            }
626            let bcs_bytes = &bytes[1..];
627
628            // Unfortunately we have no information in the serialized form of a Multisig to be
629            // able to determine if its a Legacy format or the new standard format so we just
630            // need to try each.
631            //
632            // We'll start with the newer format as that should be more prevalent.
633            if let Ok(multisig) = bcs::from_bytes::<Multisig>(bcs_bytes) {
634                Ok(Self {
635                    signatures: multisig.signatures,
636                    bitmap: multisig.bitmap,
637                    legacy_bitmap: None,
638                    committee: multisig.committee,
639                })
640            } else if let Ok(legacy) = bcs::from_bytes::<LegacyMultisig>(bcs_bytes) {
641                Ok(Self {
642                    signatures: legacy.signatures,
643                    bitmap: roaring_bitmap_to_u16(&legacy.bitmap)
644                        .map_err(serde::de::Error::custom)?,
645                    legacy_bitmap: Some(legacy.bitmap),
646                    committee: MultisigCommittee {
647                        members: legacy.committee.members,
648                        threshold: legacy.committee.threshold,
649                    },
650                })
651            } else {
652                Err(serde::de::Error::custom("invalid multisig"))
653            }
654        }
655    }
656
657    #[derive(serde_derive::Serialize, serde_derive::Deserialize)]
658    enum MemberPublicKey {
659        Ed25519(Ed25519PublicKey),
660        Secp256k1(Secp256k1PublicKey),
661        Secp256r1(Secp256r1PublicKey),
662        ZkLogin(ZkLoginPublicIdentifier),
663        Passkey(PasskeyPublicKey),
664    }
665
666    #[derive(serde_derive::Serialize, serde_derive::Deserialize)]
667    #[serde(tag = "scheme", rename_all = "lowercase")]
668    #[serde(rename = "MultisigMemberPublicKey")]
669    enum ReadableMemberPublicKey {
670        Ed25519 { public_key: Ed25519PublicKey },
671        Secp256k1 { public_key: Secp256k1PublicKey },
672        Secp256r1 { public_key: Secp256r1PublicKey },
673        ZkLogin(ZkLoginPublicIdentifier),
674        Passkey { public_key: PasskeyPublicKey },
675    }
676
677    impl Serialize for MultisigMemberPublicKey {
678        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
679        where
680            S: Serializer,
681        {
682            if serializer.is_human_readable() {
683                let readable = match self {
684                    MultisigMemberPublicKey::Ed25519(public_key) => {
685                        ReadableMemberPublicKey::Ed25519 {
686                            public_key: *public_key,
687                        }
688                    }
689                    MultisigMemberPublicKey::Secp256k1(public_key) => {
690                        ReadableMemberPublicKey::Secp256k1 {
691                            public_key: *public_key,
692                        }
693                    }
694                    MultisigMemberPublicKey::Secp256r1(public_key) => {
695                        ReadableMemberPublicKey::Secp256r1 {
696                            public_key: *public_key,
697                        }
698                    }
699                    MultisigMemberPublicKey::ZkLogin(public_id) => {
700                        ReadableMemberPublicKey::ZkLogin(public_id.clone())
701                    }
702                    MultisigMemberPublicKey::Passkey(public_key) => {
703                        ReadableMemberPublicKey::Passkey {
704                            public_key: *public_key,
705                        }
706                    }
707                };
708                readable.serialize(serializer)
709            } else {
710                let binary = match self {
711                    MultisigMemberPublicKey::Ed25519(public_key) => {
712                        MemberPublicKey::Ed25519(*public_key)
713                    }
714                    MultisigMemberPublicKey::Secp256k1(public_key) => {
715                        MemberPublicKey::Secp256k1(*public_key)
716                    }
717                    MultisigMemberPublicKey::Secp256r1(public_key) => {
718                        MemberPublicKey::Secp256r1(*public_key)
719                    }
720                    MultisigMemberPublicKey::ZkLogin(public_id) => {
721                        MemberPublicKey::ZkLogin(public_id.clone())
722                    }
723                    MultisigMemberPublicKey::Passkey(public_key) => {
724                        MemberPublicKey::Passkey(*public_key)
725                    }
726                };
727                binary.serialize(serializer)
728            }
729        }
730    }
731
732    impl<'de> Deserialize<'de> for MultisigMemberPublicKey {
733        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
734        where
735            D: Deserializer<'de>,
736        {
737            if deserializer.is_human_readable() {
738                let readable = ReadableMemberPublicKey::deserialize(deserializer)?;
739                Ok(match readable {
740                    ReadableMemberPublicKey::Ed25519 { public_key } => Self::Ed25519(public_key),
741                    ReadableMemberPublicKey::Secp256k1 { public_key } => {
742                        Self::Secp256k1(public_key)
743                    }
744                    ReadableMemberPublicKey::Secp256r1 { public_key } => {
745                        Self::Secp256r1(public_key)
746                    }
747                    ReadableMemberPublicKey::ZkLogin(public_id) => Self::ZkLogin(public_id),
748                    ReadableMemberPublicKey::Passkey { public_key } => Self::Passkey(public_key),
749                })
750            } else {
751                let binary = MemberPublicKey::deserialize(deserializer)?;
752                Ok(match binary {
753                    MemberPublicKey::Ed25519(public_key) => Self::Ed25519(public_key),
754                    MemberPublicKey::Secp256k1(public_key) => Self::Secp256k1(public_key),
755                    MemberPublicKey::Secp256r1(public_key) => Self::Secp256r1(public_key),
756                    MemberPublicKey::ZkLogin(public_id) => Self::ZkLogin(public_id),
757                    MemberPublicKey::Passkey(public_key) => Self::Passkey(public_key),
758                })
759            }
760        }
761    }
762
763    #[derive(serde_derive::Serialize, serde_derive::Deserialize)]
764    enum MemberSignature {
765        Ed25519(Ed25519Signature),
766        Secp256k1(Secp256k1Signature),
767        Secp256r1(Secp256r1Signature),
768        ZkLogin(Box<ZkLoginAuthenticator>),
769        Passkey(PasskeyAuthenticator),
770    }
771
772    #[derive(serde_derive::Serialize, serde_derive::Deserialize)]
773    #[serde(tag = "scheme", rename_all = "lowercase")]
774    #[serde(rename = "MultisigMemberSignature")]
775    enum ReadableMemberSignature {
776        Ed25519 { signature: Ed25519Signature },
777        Secp256k1 { signature: Secp256k1Signature },
778        Secp256r1 { signature: Secp256r1Signature },
779        ZkLogin(Box<ZkLoginAuthenticator>),
780        Passkey(PasskeyAuthenticator),
781    }
782
783    impl Serialize for MultisigMemberSignature {
784        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
785        where
786            S: Serializer,
787        {
788            if serializer.is_human_readable() {
789                let readable = match self {
790                    MultisigMemberSignature::Ed25519(signature) => {
791                        ReadableMemberSignature::Ed25519 {
792                            signature: *signature,
793                        }
794                    }
795                    MultisigMemberSignature::Secp256k1(signature) => {
796                        ReadableMemberSignature::Secp256k1 {
797                            signature: *signature,
798                        }
799                    }
800                    MultisigMemberSignature::Secp256r1(signature) => {
801                        ReadableMemberSignature::Secp256r1 {
802                            signature: *signature,
803                        }
804                    }
805                    MultisigMemberSignature::ZkLogin(authenticator) => {
806                        ReadableMemberSignature::ZkLogin(authenticator.clone())
807                    }
808                    MultisigMemberSignature::Passkey(authenticator) => {
809                        ReadableMemberSignature::Passkey(authenticator.clone())
810                    }
811                };
812                readable.serialize(serializer)
813            } else {
814                let binary = match self {
815                    MultisigMemberSignature::Ed25519(signature) => {
816                        MemberSignature::Ed25519(*signature)
817                    }
818                    MultisigMemberSignature::Secp256k1(signature) => {
819                        MemberSignature::Secp256k1(*signature)
820                    }
821                    MultisigMemberSignature::Secp256r1(signature) => {
822                        MemberSignature::Secp256r1(*signature)
823                    }
824                    MultisigMemberSignature::ZkLogin(authenticator) => {
825                        MemberSignature::ZkLogin(authenticator.clone())
826                    }
827                    MultisigMemberSignature::Passkey(authenticator) => {
828                        MemberSignature::Passkey(authenticator.clone())
829                    }
830                };
831                binary.serialize(serializer)
832            }
833        }
834    }
835
836    impl<'de> Deserialize<'de> for MultisigMemberSignature {
837        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
838        where
839            D: Deserializer<'de>,
840        {
841            if deserializer.is_human_readable() {
842                let readable = ReadableMemberSignature::deserialize(deserializer)?;
843                Ok(match readable {
844                    ReadableMemberSignature::Ed25519 { signature } => Self::Ed25519(signature),
845                    ReadableMemberSignature::Secp256k1 { signature } => Self::Secp256k1(signature),
846                    ReadableMemberSignature::Secp256r1 { signature } => Self::Secp256r1(signature),
847                    ReadableMemberSignature::ZkLogin(authenticator) => Self::ZkLogin(authenticator),
848                    ReadableMemberSignature::Passkey(authenticator) => Self::Passkey(authenticator),
849                })
850            } else {
851                let binary = MemberSignature::deserialize(deserializer)?;
852                Ok(match binary {
853                    MemberSignature::Ed25519(signature) => Self::Ed25519(signature),
854                    MemberSignature::Secp256k1(signature) => Self::Secp256k1(signature),
855                    MemberSignature::Secp256r1(signature) => Self::Secp256r1(signature),
856                    MemberSignature::ZkLogin(authenticator) => Self::ZkLogin(authenticator),
857                    MemberSignature::Passkey(authenticator) => Self::Passkey(authenticator),
858                })
859            }
860        }
861    }
862}