Skip to content

Commit 5b61c62

Browse files
committed
sui-sdk-types: add support for passkeys in multisigs
1 parent 4b66232 commit 5b61c62

File tree

4 files changed

+72
-3
lines changed

4 files changed

+72
-3
lines changed

crates/sui-sdk-types/src/crypto/multisig.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ use super::zklogin::ZkLoginAuthenticator;
22
use super::zklogin::ZkLoginPublicIdentifier;
33
use super::Ed25519PublicKey;
44
use super::Ed25519Signature;
5+
use super::PasskeyAuthenticator;
6+
use super::PasskeyPublicKey;
57
use super::Secp256k1PublicKey;
68
use super::Secp256k1Signature;
79
use super::Secp256r1PublicKey;
@@ -51,6 +53,7 @@ pub enum MultisigMemberPublicKey {
5153
Secp256k1(Secp256k1PublicKey),
5254
Secp256r1(Secp256r1PublicKey),
5355
ZkLogin(ZkLoginPublicIdentifier),
56+
Passkey(PasskeyPublicKey),
5457
}
5558

5659
/// A member in a multisig committee
@@ -328,6 +331,7 @@ pub enum MultisigMemberSignature {
328331
Secp256k1(Secp256k1Signature),
329332
Secp256r1(Secp256r1Signature),
330333
ZkLogin(Box<ZkLoginAuthenticator>),
334+
Passkey(PasskeyAuthenticator),
331335
}
332336

333337
#[cfg(feature = "serde")]
@@ -337,6 +341,7 @@ mod serialization {
337341
use crate::crypto::Base64Array33;
338342
use crate::crypto::Base64Array34;
339343
use crate::Ed25519PublicKey;
344+
use crate::PasskeyPublicKey;
340345
use crate::Secp256k1PublicKey;
341346
use crate::Secp256r1PublicKey;
342347
use crate::SignatureScheme;
@@ -383,6 +388,9 @@ mod serialization {
383388
MultisigMemberPublicKey::ZkLogin(_) => Err(serde::ser::Error::custom(
384389
"zklogin not supported in legacy multisig",
385390
)),
391+
MultisigMemberPublicKey::Passkey(_) => Err(serde::ser::Error::custom(
392+
"passkey not supported in legacy multisig",
393+
)),
386394
}
387395
}
388396
}
@@ -652,6 +660,7 @@ mod serialization {
652660
Secp256k1(Secp256k1PublicKey),
653661
Secp256r1(Secp256r1PublicKey),
654662
ZkLogin(ZkLoginPublicIdentifier),
663+
Passkey(PasskeyPublicKey),
655664
}
656665

657666
#[derive(serde_derive::Serialize, serde_derive::Deserialize)]
@@ -662,6 +671,7 @@ mod serialization {
662671
Secp256k1 { public_key: Secp256k1PublicKey },
663672
Secp256r1 { public_key: Secp256r1PublicKey },
664673
ZkLogin(ZkLoginPublicIdentifier),
674+
Passkey { public_key: PasskeyPublicKey },
665675
}
666676

667677
impl Serialize for MultisigMemberPublicKey {
@@ -689,6 +699,11 @@ mod serialization {
689699
MultisigMemberPublicKey::ZkLogin(public_id) => {
690700
ReadableMemberPublicKey::ZkLogin(public_id.clone())
691701
}
702+
MultisigMemberPublicKey::Passkey(public_key) => {
703+
ReadableMemberPublicKey::Passkey {
704+
public_key: *public_key,
705+
}
706+
}
692707
};
693708
readable.serialize(serializer)
694709
} else {
@@ -705,6 +720,9 @@ mod serialization {
705720
MultisigMemberPublicKey::ZkLogin(public_id) => {
706721
MemberPublicKey::ZkLogin(public_id.clone())
707722
}
723+
MultisigMemberPublicKey::Passkey(public_key) => {
724+
MemberPublicKey::Passkey(*public_key)
725+
}
708726
};
709727
binary.serialize(serializer)
710728
}
@@ -727,6 +745,7 @@ mod serialization {
727745
Self::Secp256r1(public_key)
728746
}
729747
ReadableMemberPublicKey::ZkLogin(public_id) => Self::ZkLogin(public_id),
748+
ReadableMemberPublicKey::Passkey { public_key } => Self::Passkey(public_key),
730749
})
731750
} else {
732751
let binary = MemberPublicKey::deserialize(deserializer)?;
@@ -735,6 +754,7 @@ mod serialization {
735754
MemberPublicKey::Secp256k1(public_key) => Self::Secp256k1(public_key),
736755
MemberPublicKey::Secp256r1(public_key) => Self::Secp256r1(public_key),
737756
MemberPublicKey::ZkLogin(public_id) => Self::ZkLogin(public_id),
757+
MemberPublicKey::Passkey(public_key) => Self::Passkey(public_key),
738758
})
739759
}
740760
}
@@ -746,6 +766,7 @@ mod serialization {
746766
Secp256k1(Secp256k1Signature),
747767
Secp256r1(Secp256r1Signature),
748768
ZkLogin(Box<ZkLoginAuthenticator>),
769+
Passkey(PasskeyAuthenticator),
749770
}
750771

751772
#[derive(serde_derive::Serialize, serde_derive::Deserialize)]
@@ -756,6 +777,7 @@ mod serialization {
756777
Secp256k1 { signature: Secp256k1Signature },
757778
Secp256r1 { signature: Secp256r1Signature },
758779
ZkLogin(Box<ZkLoginAuthenticator>),
780+
Passkey(PasskeyAuthenticator),
759781
}
760782

761783
impl Serialize for MultisigMemberSignature {
@@ -783,6 +805,9 @@ mod serialization {
783805
MultisigMemberSignature::ZkLogin(authenticator) => {
784806
ReadableMemberSignature::ZkLogin(authenticator.clone())
785807
}
808+
MultisigMemberSignature::Passkey(authenticator) => {
809+
ReadableMemberSignature::Passkey(authenticator.clone())
810+
}
786811
};
787812
readable.serialize(serializer)
788813
} else {
@@ -799,6 +824,9 @@ mod serialization {
799824
MultisigMemberSignature::ZkLogin(authenticator) => {
800825
MemberSignature::ZkLogin(authenticator.clone())
801826
}
827+
MultisigMemberSignature::Passkey(authenticator) => {
828+
MemberSignature::Passkey(authenticator.clone())
829+
}
802830
};
803831
binary.serialize(serializer)
804832
}
@@ -817,6 +845,7 @@ mod serialization {
817845
ReadableMemberSignature::Secp256k1 { signature } => Self::Secp256k1(signature),
818846
ReadableMemberSignature::Secp256r1 { signature } => Self::Secp256r1(signature),
819847
ReadableMemberSignature::ZkLogin(authenticator) => Self::ZkLogin(authenticator),
848+
ReadableMemberSignature::Passkey(authenticator) => Self::Passkey(authenticator),
820849
})
821850
} else {
822851
let binary = MemberSignature::deserialize(deserializer)?;
@@ -825,6 +854,7 @@ mod serialization {
825854
MemberSignature::Secp256k1(signature) => Self::Secp256k1(signature),
826855
MemberSignature::Secp256r1(signature) => Self::Secp256r1(signature),
827856
MemberSignature::ZkLogin(authenticator) => Self::ZkLogin(authenticator),
857+
MemberSignature::Passkey(authenticator) => Self::Passkey(authenticator),
828858
})
829859
}
830860
}

crates/sui-sdk-types/src/crypto/passkey.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,12 +93,21 @@ impl PasskeyAuthenticator {
9393
/// The BCS serialized form for this type is defined by the following ABNF:
9494
///
9595
/// ```text
96-
/// passkey-public-key = passkey-flag secp256r1-public-key
96+
/// passkey-public-key = secp256r1-public-key
9797
/// ```
98-
#[derive(Debug, Clone, PartialEq, Eq)]
98+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
99+
#[cfg_attr(
100+
feature = "serde",
101+
derive(serde_derive::Serialize, serde_derive::Deserialize)
102+
)]
103+
#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
99104
pub struct PasskeyPublicKey(Secp256r1PublicKey);
100105

101106
impl PasskeyPublicKey {
107+
pub fn new(public_key: Secp256r1PublicKey) -> Self {
108+
Self(public_key)
109+
}
110+
102111
/// The underlying `Secp256r1PublicKey` for this passkey.
103112
pub fn inner(&self) -> &Secp256r1PublicKey {
104113
&self.0

crates/sui-sdk-types/src/crypto/signature.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -793,5 +793,34 @@ mod serialization {
793793
assert_eq!(sig, serde_json::from_str(&json).unwrap());
794794
}
795795
}
796+
797+
#[test]
798+
fn mutisig_with_passkey() {
799+
const FIXTURE: &str = "4wMDAQSPAgYlWA5npzp6kvrYZs+ZuUq2Z1mil2S1cYIfq64uix17NuQdAAAAAIMBeyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoieEtoSGhUU1o4TVJTNjAtLTZNbjBreC1vSW1RWUs1RjNFMmtzQm9iRkk3OCIsIm9yaWdpbiI6Imh0dHBzOi8vd3d3LnN1aS5pbyIsImNyb3NzT3JpZ2luIjpmYWxzZX1iAj6cOZNgD7buVIny/mQVv0gt87gEpo/V6yFusFHc0ED0XBdBXIRO8cDcoKDOPeKpNOwyMn4JvCwh/bA9Z27vBcID4FVY2uPg1vTXoKTq74rVS0uaUzafqn5emXJEfpzp9osQAAUADX2rNYyNrapO+gBJp1sHQ2VVsQo2ghm7aA9wVxNJ13UBAQIOF81ZOeRrGWZBlozXWZELold+J/pz/eOHbbm+xbzrKwECA0f7ryPwOKvEwwiicRF6Kkz/rt28X/gcdRe8bHSn7bQwAQM8G2h0dHBzOi8vaWQudHdpdGNoLnR2L29hdXRoMgVuAvSJovCe0hhp6n7cBfcDd20d7RhhkODYMqLqqMIDAQQD4FVY2uPg1vTXoKTq74rVS0uaUzafqn5emXJEfpzp9osBAQA=";
800+
801+
let bcs = Base64::decode_vec(FIXTURE).unwrap();
802+
803+
let sig: UserSignature = bcs::from_bytes(&bcs).unwrap();
804+
assert_eq!(SignatureScheme::Multisig, sig.scheme());
805+
806+
let committee = match &sig {
807+
UserSignature::Multisig(multisig) => multisig.committee(),
808+
_ => panic!("not a multisig"),
809+
};
810+
assert_eq!(
811+
committee.derive_address(),
812+
crate::Address::from_hex(
813+
"0x10f58251fa90d7fd5510f99787ac5c5874fe29c033524ba0275f1ed793ed8598"
814+
)
815+
.unwrap()
816+
);
817+
818+
let bytes = bcs::to_bytes(&sig).unwrap();
819+
assert_eq!(bcs, bytes);
820+
821+
let json = serde_json::to_string_pretty(&sig).unwrap();
822+
println!("{json}");
823+
assert_eq!(sig, serde_json::from_str(&json).unwrap());
824+
}
796825
}
797826
}

crates/sui-sdk-types/src/hash.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ impl crate::PasskeyPublicKey {
220220
/// `Secp256r1PublicKey` that corresponds to this passkey prefixed with the Passkey
221221
/// `SignatureScheme` flag (`0x06`).
222222
///
223-
/// `hash( 0x06 || 33-byte secp256r1 public key)`
223+
/// `hash( 0x06 || 33-byte secp256r1-public-key)`
224224
pub fn derive_address(&self) -> Address {
225225
let mut hasher = Hasher::new();
226226
self.write_into_hasher(&mut hasher);
@@ -265,6 +265,7 @@ impl crate::MultisigCommittee {
265265
Secp256k1(p) => p.write_into_hasher(&mut hasher),
266266
Secp256r1(p) => p.write_into_hasher(&mut hasher),
267267
ZkLogin(p) => p.write_into_hasher_padded(&mut hasher),
268+
Passkey(p) => p.write_into_hasher(&mut hasher),
268269
}
269270

270271
hasher.update(member.weight().to_le_bytes());

0 commit comments

Comments
 (0)