1use crate::base_types::{AuthorityName, ConciseableName, SuiAddress};
4use crate::committee::CommitteeTrait;
5use crate::committee::{Committee, EpochId, StakeUnit};
6use crate::error::{SuiError, SuiErrorKind, SuiResult};
7use crate::signature::GenericSignature;
8use crate::sui_serde::{Readable, SuiBitmap};
9use anyhow::{Error, anyhow};
10use derive_more::{AsMut, AsRef, From};
11pub use enum_dispatch::enum_dispatch;
12use eyre::eyre;
13use fastcrypto::bls12381::min_sig::{
14 BLS12381AggregateSignature, BLS12381AggregateSignatureAsBytes, BLS12381KeyPair,
15 BLS12381PrivateKey, BLS12381PublicKey, BLS12381Signature,
16};
17use fastcrypto::ed25519::{
18 Ed25519KeyPair, Ed25519PrivateKey, Ed25519PublicKey, Ed25519PublicKeyAsBytes, Ed25519Signature,
19 Ed25519SignatureAsBytes,
20};
21use fastcrypto::encoding::{Base64, Bech32, Encoding, Hex};
22use fastcrypto::error::{FastCryptoError, FastCryptoResult};
23use fastcrypto::hash::{Blake2b256, HashFunction};
24use fastcrypto::secp256k1::{
25 Secp256k1KeyPair, Secp256k1PublicKey, Secp256k1PublicKeyAsBytes, Secp256k1Signature,
26 Secp256k1SignatureAsBytes,
27};
28use fastcrypto::secp256r1::{
29 Secp256r1KeyPair, Secp256r1PublicKey, Secp256r1PublicKeyAsBytes, Secp256r1Signature,
30 Secp256r1SignatureAsBytes,
31};
32pub use fastcrypto::traits::KeyPair as KeypairTraits;
33pub use fastcrypto::traits::Signer;
34pub use fastcrypto::traits::{
35 AggregateAuthenticator, Authenticator, EncodeDecodeBase64, SigningKey, ToFromBytes,
36 VerifyingKey,
37};
38use fastcrypto_zkp::bn254::zk_login::ZkLoginInputs;
39use fastcrypto_zkp::zk_login_utils::Bn254FrElement;
40use rand::SeedableRng;
41use rand::rngs::{OsRng, StdRng};
42use roaring::RoaringBitmap;
43use schemars::JsonSchema;
44use serde::ser::Serializer;
45use serde::{Deserialize, Deserializer, Serialize};
46use serde_with::{Bytes, DeserializeAs, serde_as};
47use shared_crypto::intent::{Intent, IntentMessage, IntentScope};
48use std::collections::BTreeMap;
49use std::fmt::Debug;
50use std::fmt::{self, Display, Formatter};
51use std::hash::{Hash, Hasher};
52use std::str::FromStr;
53use strum::EnumString;
54use tracing::{instrument, warn};
55
56#[cfg(test)]
57#[path = "unit_tests/crypto_tests.rs"]
58mod crypto_tests;
59
60#[cfg(test)]
61#[path = "unit_tests/intent_tests.rs"]
62mod intent_tests;
63
64pub type AuthorityKeyPair = BLS12381KeyPair;
66pub type AuthorityPublicKey = BLS12381PublicKey;
67pub type AuthorityPrivateKey = BLS12381PrivateKey;
68pub type AuthoritySignature = BLS12381Signature;
69pub type AggregateAuthoritySignature = BLS12381AggregateSignature;
70pub type AggregateAuthoritySignatureAsBytes = BLS12381AggregateSignatureAsBytes;
71
72pub type AccountKeyPair = Ed25519KeyPair;
74pub type AccountPublicKey = Ed25519PublicKey;
75pub type AccountPrivateKey = Ed25519PrivateKey;
76
77pub type NetworkKeyPair = Ed25519KeyPair;
78pub type NetworkPublicKey = Ed25519PublicKey;
79pub type NetworkPrivateKey = Ed25519PrivateKey;
80
81pub type DefaultHash = Blake2b256;
82
83pub const DEFAULT_EPOCH_ID: EpochId = 0;
84pub const SUI_PRIV_KEY_PREFIX: &str = "suiprivkey";
85
86pub fn generate_proof_of_possession(
93 keypair: &AuthorityKeyPair,
94 address: SuiAddress,
95) -> AuthoritySignature {
96 let mut msg: Vec<u8> = Vec::new();
97 msg.extend_from_slice(keypair.public().as_bytes());
98 msg.extend_from_slice(address.as_ref());
99 AuthoritySignature::new_secure(
100 &IntentMessage::new(Intent::sui_app(IntentScope::ProofOfPossession), msg),
101 &DEFAULT_EPOCH_ID,
102 keypair,
103 )
104}
105
106pub fn verify_proof_of_possession(
109 pop: &AuthoritySignature,
110 protocol_pubkey: &AuthorityPublicKey,
111 sui_address: SuiAddress,
112) -> Result<(), SuiError> {
113 protocol_pubkey
114 .validate()
115 .map_err(|_| SuiErrorKind::InvalidSignature {
116 error: "Fail to validate pubkey".to_string(),
117 })?;
118 let mut msg = protocol_pubkey.as_bytes().to_vec();
119 msg.extend_from_slice(sui_address.as_ref());
120 pop.verify_secure(
121 &IntentMessage::new(Intent::sui_app(IntentScope::ProofOfPossession), msg),
122 DEFAULT_EPOCH_ID,
123 protocol_pubkey.into(),
124 )
125}
126#[allow(clippy::large_enum_variant)]
135#[derive(Debug, From, PartialEq, Eq)]
136pub enum SuiKeyPair {
137 Ed25519(Ed25519KeyPair),
138 Secp256k1(Secp256k1KeyPair),
139 Secp256r1(Secp256r1KeyPair),
140}
141
142impl SuiKeyPair {
143 pub fn public(&self) -> PublicKey {
144 match self {
145 SuiKeyPair::Ed25519(kp) => PublicKey::Ed25519(kp.public().into()),
146 SuiKeyPair::Secp256k1(kp) => PublicKey::Secp256k1(kp.public().into()),
147 SuiKeyPair::Secp256r1(kp) => PublicKey::Secp256r1(kp.public().into()),
148 }
149 }
150
151 pub fn copy(&self) -> Self {
152 match self {
153 SuiKeyPair::Ed25519(kp) => kp.copy().into(),
154 SuiKeyPair::Secp256k1(kp) => kp.copy().into(),
155 SuiKeyPair::Secp256r1(kp) => kp.copy().into(),
156 }
157 }
158}
159
160impl Signer<Signature> for SuiKeyPair {
161 fn sign(&self, msg: &[u8]) -> Signature {
162 match self {
163 SuiKeyPair::Ed25519(kp) => kp.sign(msg),
164 SuiKeyPair::Secp256k1(kp) => kp.sign(msg),
165 SuiKeyPair::Secp256r1(kp) => kp.sign(msg),
166 }
167 }
168}
169
170impl EncodeDecodeBase64 for SuiKeyPair {
171 fn encode_base64(&self) -> String {
172 Base64::encode(self.to_bytes())
173 }
174
175 fn decode_base64(value: &str) -> FastCryptoResult<Self> {
176 let bytes = Base64::decode(value)?;
177 Self::from_bytes(&bytes).map_err(|_| FastCryptoError::InvalidInput)
178 }
179}
180impl SuiKeyPair {
181 pub fn to_bytes(&self) -> Vec<u8> {
182 let mut bytes: Vec<u8> = Vec::new();
183 bytes.push(self.public().flag());
184
185 match self {
186 SuiKeyPair::Ed25519(kp) => {
187 bytes.extend_from_slice(kp.as_bytes());
188 }
189 SuiKeyPair::Secp256k1(kp) => {
190 bytes.extend_from_slice(kp.as_bytes());
191 }
192 SuiKeyPair::Secp256r1(kp) => {
193 bytes.extend_from_slice(kp.as_bytes());
194 }
195 }
196 bytes
197 }
198
199 pub fn from_bytes(bytes: &[u8]) -> Result<Self, eyre::Report> {
200 match SignatureScheme::from_flag_byte(bytes.first().ok_or_else(|| eyre!("Invalid length"))?)
201 {
202 Ok(x) => match x {
203 SignatureScheme::ED25519 => Ok(SuiKeyPair::Ed25519(Ed25519KeyPair::from_bytes(
204 bytes.get(1..).ok_or_else(|| eyre!("Invalid length"))?,
205 )?)),
206 SignatureScheme::Secp256k1 => {
207 Ok(SuiKeyPair::Secp256k1(Secp256k1KeyPair::from_bytes(
208 bytes.get(1..).ok_or_else(|| eyre!("Invalid length"))?,
209 )?))
210 }
211 SignatureScheme::Secp256r1 => {
212 Ok(SuiKeyPair::Secp256r1(Secp256r1KeyPair::from_bytes(
213 bytes.get(1..).ok_or_else(|| eyre!("Invalid length"))?,
214 )?))
215 }
216 _ => Err(eyre!("Invalid flag byte")),
217 },
218 _ => Err(eyre!("Invalid bytes")),
219 }
220 }
221
222 pub fn to_bytes_no_flag(&self) -> Vec<u8> {
223 match self {
224 SuiKeyPair::Ed25519(kp) => kp.as_bytes().to_vec(),
225 SuiKeyPair::Secp256k1(kp) => kp.as_bytes().to_vec(),
226 SuiKeyPair::Secp256r1(kp) => kp.as_bytes().to_vec(),
227 }
228 }
229
230 pub fn encode(&self) -> Result<String, eyre::Report> {
232 Bech32::encode(self.to_bytes(), SUI_PRIV_KEY_PREFIX).map_err(|e| eyre!(e))
233 }
234
235 pub fn decode(value: &str) -> Result<Self, eyre::Report> {
237 let bytes = Bech32::decode(value, SUI_PRIV_KEY_PREFIX)?;
238 Self::from_bytes(&bytes)
239 }
240}
241
242impl Serialize for SuiKeyPair {
243 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
244 where
245 S: Serializer,
246 {
247 let s = self.encode_base64();
248 serializer.serialize_str(&s)
249 }
250}
251
252impl<'de> Deserialize<'de> for SuiKeyPair {
253 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
254 where
255 D: Deserializer<'de>,
256 {
257 use serde::de::Error;
258 let s = String::deserialize(deserializer)?;
259 SuiKeyPair::decode_base64(&s).map_err(|e| Error::custom(e.to_string()))
260 }
261}
262
263#[derive(Clone, Debug, PartialEq, Eq, JsonSchema, Serialize, Deserialize)]
264pub enum PublicKey {
265 Ed25519(Ed25519PublicKeyAsBytes),
266 Secp256k1(Secp256k1PublicKeyAsBytes),
267 Secp256r1(Secp256r1PublicKeyAsBytes),
268 ZkLogin(ZkLoginPublicIdentifier),
269 Passkey(Secp256r1PublicKeyAsBytes),
270}
271
272#[derive(Clone, Debug, PartialEq, Eq, JsonSchema, Serialize, Deserialize)]
275pub struct ZkLoginPublicIdentifier(#[schemars(with = "Base64")] pub Vec<u8>);
276
277impl ZkLoginPublicIdentifier {
278 pub fn new(iss: &str, address_seed: &Bn254FrElement) -> SuiResult<Self> {
280 let mut bytes = Vec::new();
281 let iss_bytes = iss.as_bytes();
282 bytes.extend([iss_bytes.len() as u8]);
283 bytes.extend(iss_bytes);
284 bytes.extend(address_seed.padded());
285
286 Ok(Self(bytes))
287 }
288
289 pub fn validate(&self) -> SuiResult<()> {
291 let bytes = &self.0;
292
293 let iss_len = *bytes
295 .first()
296 .ok_or_else(|| SuiErrorKind::InvalidSignature {
297 error: "invalid zklogin pk".to_string(),
298 })? as usize;
299 let iss_bytes =
300 bytes
301 .get(1..1 + iss_len)
302 .ok_or_else(|| SuiErrorKind::InvalidSignature {
303 error: "invalid zklogin pk iss length".to_string(),
304 })?;
305
306 std::str::from_utf8(iss_bytes).map_err(|e| SuiErrorKind::InvalidSignature {
308 error: format!("zkLogin pk issuer is not valid: {}", e),
309 })?;
310
311 let address_seed_bytes =
313 bytes
314 .get(1 + iss_len..)
315 .ok_or_else(|| SuiErrorKind::InvalidSignature {
316 error: "zkLogin pk has no address seed".to_string(),
317 })?;
318
319 if address_seed_bytes.len() > 32 {
320 return Err(SuiErrorKind::InvalidSignature {
321 error: format!(
322 "address seed must be at most 32 bytes, got {}",
323 address_seed_bytes.len()
324 ),
325 }
326 .into());
327 }
328
329 Ok(())
330 }
331}
332impl AsRef<[u8]> for PublicKey {
333 fn as_ref(&self) -> &[u8] {
334 match self {
335 PublicKey::Ed25519(pk) => &pk.0,
336 PublicKey::Secp256k1(pk) => &pk.0,
337 PublicKey::Secp256r1(pk) => &pk.0,
338 PublicKey::ZkLogin(z) => &z.0,
339 PublicKey::Passkey(pk) => &pk.0,
340 }
341 }
342}
343
344impl EncodeDecodeBase64 for PublicKey {
345 fn encode_base64(&self) -> String {
346 let mut bytes: Vec<u8> = Vec::new();
347 bytes.extend_from_slice(&[self.flag()]);
348 bytes.extend_from_slice(self.as_ref());
349 Base64::encode(&bytes[..])
350 }
351
352 fn decode_base64(value: &str) -> FastCryptoResult<Self> {
353 let bytes = Base64::decode(value)?;
354 match bytes.first() {
355 Some(x) => {
356 if x == &SignatureScheme::ED25519.flag() {
357 let pk: Ed25519PublicKey =
358 Ed25519PublicKey::from_bytes(bytes.get(1..).ok_or(
359 FastCryptoError::InputLengthWrong(Ed25519PublicKey::LENGTH + 1),
360 )?)?;
361 Ok(PublicKey::Ed25519((&pk).into()))
362 } else if x == &SignatureScheme::Secp256k1.flag() {
363 let pk = Secp256k1PublicKey::from_bytes(bytes.get(1..).ok_or(
364 FastCryptoError::InputLengthWrong(Secp256k1PublicKey::LENGTH + 1),
365 )?)?;
366 Ok(PublicKey::Secp256k1((&pk).into()))
367 } else if x == &SignatureScheme::Secp256r1.flag() {
368 let pk = Secp256r1PublicKey::from_bytes(bytes.get(1..).ok_or(
369 FastCryptoError::InputLengthWrong(Secp256r1PublicKey::LENGTH + 1),
370 )?)?;
371 Ok(PublicKey::Secp256r1((&pk).into()))
372 } else if x == &SignatureScheme::PasskeyAuthenticator.flag() {
373 let pk = Secp256r1PublicKey::from_bytes(bytes.get(1..).ok_or(
374 FastCryptoError::InputLengthWrong(Secp256r1PublicKey::LENGTH + 1),
375 )?)?;
376 Ok(PublicKey::Passkey((&pk).into()))
377 } else {
378 Err(FastCryptoError::InvalidInput)
379 }
380 }
381 _ => Err(FastCryptoError::InvalidInput),
382 }
383 }
384}
385
386impl PublicKey {
387 pub fn flag(&self) -> u8 {
388 self.scheme().flag()
389 }
390
391 pub fn try_from_bytes(
392 curve: SignatureScheme,
393 key_bytes: &[u8],
394 ) -> Result<PublicKey, eyre::Report> {
395 match curve {
396 SignatureScheme::ED25519 => Ok(PublicKey::Ed25519(
397 (&Ed25519PublicKey::from_bytes(key_bytes)?).into(),
398 )),
399 SignatureScheme::Secp256k1 => Ok(PublicKey::Secp256k1(
400 (&Secp256k1PublicKey::from_bytes(key_bytes)?).into(),
401 )),
402 SignatureScheme::Secp256r1 => Ok(PublicKey::Secp256r1(
403 (&Secp256r1PublicKey::from_bytes(key_bytes)?).into(),
404 )),
405 SignatureScheme::PasskeyAuthenticator => Ok(PublicKey::Passkey(
406 (&Secp256r1PublicKey::from_bytes(key_bytes)?).into(),
407 )),
408 _ => Err(eyre!("Unsupported curve")),
409 }
410 }
411
412 pub fn scheme(&self) -> SignatureScheme {
413 match self {
414 PublicKey::Ed25519(_) => Ed25519SuiSignature::SCHEME,
415 PublicKey::Secp256k1(_) => Secp256k1SuiSignature::SCHEME,
416 PublicKey::Secp256r1(_) => Secp256r1SuiSignature::SCHEME,
417 PublicKey::ZkLogin(_) => SignatureScheme::ZkLoginAuthenticator,
418 PublicKey::Passkey(_) => SignatureScheme::PasskeyAuthenticator,
419 }
420 }
421
422 pub fn from_zklogin_inputs(inputs: &ZkLoginInputs) -> SuiResult<Self> {
423 Ok(PublicKey::ZkLogin(ZkLoginPublicIdentifier::new(
424 inputs.get_iss(),
425 inputs.get_address_seed(),
426 )?))
427 }
428}
429
430#[serde_as]
433#[derive(
434 Copy,
435 Clone,
436 PartialEq,
437 Eq,
438 Hash,
439 PartialOrd,
440 Ord,
441 Serialize,
442 Deserialize,
443 schemars::JsonSchema,
444 AsRef,
445)]
446#[as_ref(forward)]
447pub struct AuthorityPublicKeyBytes(
448 #[schemars(with = "Base64")]
449 #[serde_as(as = "Readable<Base64, Bytes>")]
450 pub [u8; AuthorityPublicKey::LENGTH],
451);
452
453impl AuthorityPublicKeyBytes {
454 fn fmt_impl(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
455 let s = Hex::encode(self.0);
456 write!(f, "k#{}", s)?;
457 Ok(())
458 }
459}
460
461impl<'a> ConciseableName<'a> for AuthorityPublicKeyBytes {
462 type ConciseTypeRef = ConciseAuthorityPublicKeyBytesRef<'a>;
463 type ConciseType = ConciseAuthorityPublicKeyBytes;
464
465 fn concise(&'a self) -> ConciseAuthorityPublicKeyBytesRef<'a> {
470 ConciseAuthorityPublicKeyBytesRef(self)
471 }
472
473 fn concise_owned(&self) -> ConciseAuthorityPublicKeyBytes {
474 ConciseAuthorityPublicKeyBytes(*self)
475 }
476}
477
478pub struct ConciseAuthorityPublicKeyBytesRef<'a>(&'a AuthorityPublicKeyBytes);
480
481impl Debug for ConciseAuthorityPublicKeyBytesRef<'_> {
482 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
483 let s = Hex::encode(self.0.0.get(0..4).ok_or(std::fmt::Error)?);
484 write!(f, "k#{}..", s)
485 }
486}
487
488impl Display for ConciseAuthorityPublicKeyBytesRef<'_> {
489 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
490 Debug::fmt(self, f)
491 }
492}
493
494#[derive(Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, schemars::JsonSchema)]
496pub struct ConciseAuthorityPublicKeyBytes(AuthorityPublicKeyBytes);
497
498impl Debug for ConciseAuthorityPublicKeyBytes {
499 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
500 let s = Hex::encode(self.0.0.get(0..4).ok_or(std::fmt::Error)?);
501 write!(f, "k#{}..", s)
502 }
503}
504
505impl Display for ConciseAuthorityPublicKeyBytes {
506 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
507 Debug::fmt(self, f)
508 }
509}
510
511impl TryFrom<AuthorityPublicKeyBytes> for AuthorityPublicKey {
512 type Error = FastCryptoError;
513
514 fn try_from(bytes: AuthorityPublicKeyBytes) -> Result<AuthorityPublicKey, Self::Error> {
515 AuthorityPublicKey::from_bytes(bytes.as_ref())
516 }
517}
518
519impl From<&AuthorityPublicKey> for AuthorityPublicKeyBytes {
520 fn from(pk: &AuthorityPublicKey) -> AuthorityPublicKeyBytes {
521 AuthorityPublicKeyBytes::from_bytes(pk.as_ref()).unwrap()
522 }
523}
524
525impl Debug for AuthorityPublicKeyBytes {
526 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
527 self.fmt_impl(f)
528 }
529}
530
531impl Display for AuthorityPublicKeyBytes {
532 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
533 self.fmt_impl(f)
534 }
535}
536
537impl ToFromBytes for AuthorityPublicKeyBytes {
538 fn from_bytes(bytes: &[u8]) -> Result<Self, fastcrypto::error::FastCryptoError> {
539 let bytes: [u8; AuthorityPublicKey::LENGTH] = bytes
540 .try_into()
541 .map_err(|_| fastcrypto::error::FastCryptoError::InvalidInput)?;
542 Ok(AuthorityPublicKeyBytes(bytes))
543 }
544}
545
546impl AuthorityPublicKeyBytes {
547 pub const ZERO: Self = Self::new([0u8; AuthorityPublicKey::LENGTH]);
548
549 pub const fn new(bytes: [u8; AuthorityPublicKey::LENGTH]) -> AuthorityPublicKeyBytes
551where {
552 AuthorityPublicKeyBytes(bytes)
553 }
554}
555
556impl FromStr for AuthorityPublicKeyBytes {
557 type Err = Error;
558
559 fn from_str(s: &str) -> Result<Self, Self::Err> {
560 let value = Hex::decode(s).map_err(|e| anyhow!(e))?;
561 Self::from_bytes(&value[..]).map_err(|e| anyhow!(e))
562 }
563}
564
565impl Default for AuthorityPublicKeyBytes {
566 fn default() -> Self {
567 Self::ZERO
568 }
569}
570
571pub trait SuiAuthoritySignature {
576 fn verify_secure<T>(
577 &self,
578 value: &IntentMessage<T>,
579 epoch_id: EpochId,
580 author: AuthorityPublicKeyBytes,
581 ) -> Result<(), SuiError>
582 where
583 T: Serialize;
584
585 fn new_secure<T>(
586 value: &IntentMessage<T>,
587 epoch_id: &EpochId,
588 secret: &dyn Signer<Self>,
589 ) -> Self
590 where
591 T: Serialize;
592}
593
594impl SuiAuthoritySignature for AuthoritySignature {
595 #[instrument(level = "trace", skip_all)]
596 fn new_secure<T>(value: &IntentMessage<T>, epoch: &EpochId, secret: &dyn Signer<Self>) -> Self
597 where
598 T: Serialize,
599 {
600 let mut intent_msg_bytes =
601 bcs::to_bytes(&value).expect("Message serialization should not fail");
602 epoch.write(&mut intent_msg_bytes);
603 secret.sign(&intent_msg_bytes)
604 }
605
606 #[instrument(level = "trace", skip_all)]
607 fn verify_secure<T>(
608 &self,
609 value: &IntentMessage<T>,
610 epoch: EpochId,
611 author: AuthorityPublicKeyBytes,
612 ) -> Result<(), SuiError>
613 where
614 T: Serialize,
615 {
616 let mut message = bcs::to_bytes(&value).expect("Message serialization should not fail");
617 epoch.write(&mut message);
618
619 let public_key = AuthorityPublicKey::try_from(author).map_err(|_| {
620 SuiErrorKind::KeyConversionError(
621 "Failed to serialize public key bytes to valid public key".to_string(),
622 )
623 })?;
624 public_key.verify(&message[..], self).map_err(|e| {
625 SuiErrorKind::InvalidSignature {
626 error: format!(
627 "Fail to verify auth sig {} epoch: {} author: {}",
628 e,
629 epoch,
630 author.concise()
631 ),
632 }
633 .into()
634 })
635 }
636}
637
638pub fn get_key_pair<KP: KeypairTraits>() -> (SuiAddress, KP)
641where
642 <KP as KeypairTraits>::PubKey: SuiPublicKey,
643{
644 get_key_pair_from_rng(&mut OsRng)
645}
646
647pub fn random_committee_key_pairs_of_size(size: usize) -> Vec<AuthorityKeyPair> {
649 let mut rng = StdRng::from_seed([0; 32]);
650 (0..size)
651 .map(|_| {
652 let key_pair = get_key_pair_from_rng::<AuthorityKeyPair, _>(&mut rng);
658 get_key_pair_from_rng::<AuthorityKeyPair, _>(&mut rng);
659 get_key_pair_from_rng::<AccountKeyPair, _>(&mut rng);
660 get_key_pair_from_rng::<AccountKeyPair, _>(&mut rng);
661 key_pair.1
662 })
663 .collect()
664}
665
666pub fn deterministic_random_account_key() -> (SuiAddress, AccountKeyPair) {
667 let mut rng = StdRng::from_seed([0; 32]);
668 get_key_pair_from_rng(&mut rng)
669}
670
671pub fn get_account_key_pair() -> (SuiAddress, AccountKeyPair) {
672 get_key_pair()
673}
674
675pub fn get_authority_key_pair() -> (SuiAddress, AuthorityKeyPair) {
676 get_key_pair()
677}
678
679pub fn get_key_pair_from_rng<KP: KeypairTraits, R>(csprng: &mut R) -> (SuiAddress, KP)
681where
682 R: rand::CryptoRng + rand::RngCore,
683 <KP as KeypairTraits>::PubKey: SuiPublicKey,
684{
685 let kp = KP::generate(&mut StdRng::from_rng(csprng).unwrap());
686 (kp.public().into(), kp)
687}
688
689pub fn get_key_pair_from_bytes<KP: KeypairTraits>(bytes: &[u8]) -> SuiResult<(SuiAddress, KP)>
691where
692 <KP as KeypairTraits>::PubKey: SuiPublicKey,
693{
694 let priv_length = <KP as KeypairTraits>::PrivKey::LENGTH;
695 let pub_key_length = <KP as KeypairTraits>::PubKey::LENGTH;
696 if bytes.len() != priv_length + pub_key_length {
697 return Err(SuiErrorKind::KeyConversionError(format!(
698 "Invalid input byte length, expected {}: {}",
699 priv_length,
700 bytes.len()
701 ))
702 .into());
703 }
704 let sk = <KP as KeypairTraits>::PrivKey::from_bytes(
705 bytes
706 .get(..priv_length)
707 .ok_or(SuiErrorKind::InvalidPrivateKey)?,
708 )
709 .map_err(|_| SuiErrorKind::InvalidPrivateKey)?;
710 let kp: KP = sk.into();
711 Ok((kp.public().into(), kp))
712}
713
714#[enum_dispatch]
720#[derive(Clone, JsonSchema, Debug, PartialEq, Eq, Hash)]
721pub enum Signature {
722 Ed25519SuiSignature,
723 Secp256k1SuiSignature,
724 Secp256r1SuiSignature,
725}
726
727impl Serialize for Signature {
728 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
729 where
730 S: Serializer,
731 {
732 let bytes = self.as_ref();
733
734 if serializer.is_human_readable() {
735 let s = Base64::encode(bytes);
736 serializer.serialize_str(&s)
737 } else {
738 serializer.serialize_bytes(bytes)
739 }
740 }
741}
742
743impl<'de> Deserialize<'de> for Signature {
744 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
745 where
746 D: Deserializer<'de>,
747 {
748 use serde::de::Error;
749
750 let bytes = if deserializer.is_human_readable() {
751 let s = String::deserialize(deserializer)?;
752 Base64::decode(&s).map_err(|e| Error::custom(e.to_string()))?
753 } else {
754 Bytes::deserialize_as(deserializer)?
755 };
756
757 Self::from_bytes(&bytes).map_err(|e| Error::custom(e.to_string()))
758 }
759}
760
761impl Signature {
762 pub fn new_hashed(hashed_msg: &[u8], secret: &dyn Signer<Signature>) -> Self {
764 Signer::sign(secret, hashed_msg)
765 }
766
767 pub fn new_secure<T>(value: &IntentMessage<T>, secret: &dyn Signer<Signature>) -> Self
768 where
769 T: Serialize,
770 {
771 let mut hasher = DefaultHash::default();
776 bcs::serialize_into(&mut hasher, &value).expect("Message serialization should not fail");
777
778 Signer::sign(secret, &hasher.finalize().digest)
779 }
780}
781
782impl AsRef<[u8]> for Signature {
783 fn as_ref(&self) -> &[u8] {
784 match self {
785 Signature::Ed25519SuiSignature(sig) => sig.as_ref(),
786 Signature::Secp256k1SuiSignature(sig) => sig.as_ref(),
787 Signature::Secp256r1SuiSignature(sig) => sig.as_ref(),
788 }
789 }
790}
791impl AsMut<[u8]> for Signature {
792 fn as_mut(&mut self) -> &mut [u8] {
793 match self {
794 Signature::Ed25519SuiSignature(sig) => sig.as_mut(),
795 Signature::Secp256k1SuiSignature(sig) => sig.as_mut(),
796 Signature::Secp256r1SuiSignature(sig) => sig.as_mut(),
797 }
798 }
799}
800
801impl ToFromBytes for Signature {
802 fn from_bytes(bytes: &[u8]) -> Result<Self, FastCryptoError> {
803 match bytes.first() {
804 Some(x) => {
805 if x == &Ed25519SuiSignature::SCHEME.flag() {
806 Ok(<Ed25519SuiSignature as ToFromBytes>::from_bytes(bytes)?.into())
807 } else if x == &Secp256k1SuiSignature::SCHEME.flag() {
808 Ok(<Secp256k1SuiSignature as ToFromBytes>::from_bytes(bytes)?.into())
809 } else if x == &Secp256r1SuiSignature::SCHEME.flag() {
810 Ok(<Secp256r1SuiSignature as ToFromBytes>::from_bytes(bytes)?.into())
811 } else {
812 Err(FastCryptoError::InvalidInput)
813 }
814 }
815 _ => Err(FastCryptoError::InvalidInput),
816 }
817 }
818}
819
820impl SuiPublicKey for BLS12381PublicKey {
825 const SIGNATURE_SCHEME: SignatureScheme = SignatureScheme::BLS12381;
826}
827
828#[serde_as]
833#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, AsRef, AsMut)]
834#[as_ref(forward)]
835#[as_mut(forward)]
836pub struct Ed25519SuiSignature(
837 #[schemars(with = "Base64")]
838 #[serde_as(as = "Readable<Base64, Bytes>")]
839 [u8; Ed25519PublicKey::LENGTH + Ed25519Signature::LENGTH + 1],
840);
841
842impl Default for Ed25519SuiSignature {
844 fn default() -> Self {
845 Self([0; Ed25519PublicKey::LENGTH + Ed25519Signature::LENGTH + 1])
846 }
847}
848
849impl SuiSignatureInner for Ed25519SuiSignature {
850 type Sig = Ed25519Signature;
851 type PubKey = Ed25519PublicKey;
852 type KeyPair = Ed25519KeyPair;
853 const LENGTH: usize = Ed25519PublicKey::LENGTH + Ed25519Signature::LENGTH + 1;
854}
855
856impl SuiPublicKey for Ed25519PublicKey {
857 const SIGNATURE_SCHEME: SignatureScheme = SignatureScheme::ED25519;
858}
859
860impl ToFromBytes for Ed25519SuiSignature {
861 fn from_bytes(bytes: &[u8]) -> Result<Self, FastCryptoError> {
862 if bytes.len() != Self::LENGTH {
863 return Err(FastCryptoError::InputLengthWrong(Self::LENGTH));
864 }
865 let mut sig_bytes = [0; Self::LENGTH];
866 sig_bytes.copy_from_slice(bytes);
867 Ok(Self(sig_bytes))
868 }
869}
870
871impl Signer<Signature> for Ed25519KeyPair {
872 fn sign(&self, msg: &[u8]) -> Signature {
873 Ed25519SuiSignature::new(self, msg).into()
874 }
875}
876
877#[serde_as]
881#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, AsRef, AsMut)]
882#[as_ref(forward)]
883#[as_mut(forward)]
884pub struct Secp256k1SuiSignature(
885 #[schemars(with = "Base64")]
886 #[serde_as(as = "Readable<Base64, Bytes>")]
887 [u8; Secp256k1PublicKey::LENGTH + Secp256k1Signature::LENGTH + 1],
888);
889
890impl SuiSignatureInner for Secp256k1SuiSignature {
891 type Sig = Secp256k1Signature;
892 type PubKey = Secp256k1PublicKey;
893 type KeyPair = Secp256k1KeyPair;
894 const LENGTH: usize = Secp256k1PublicKey::LENGTH + Secp256k1Signature::LENGTH + 1;
895}
896
897impl SuiPublicKey for Secp256k1PublicKey {
898 const SIGNATURE_SCHEME: SignatureScheme = SignatureScheme::Secp256k1;
899}
900
901impl ToFromBytes for Secp256k1SuiSignature {
902 fn from_bytes(bytes: &[u8]) -> Result<Self, FastCryptoError> {
903 if bytes.len() != Self::LENGTH {
904 return Err(FastCryptoError::InputLengthWrong(Self::LENGTH));
905 }
906 let mut sig_bytes = [0; Self::LENGTH];
907 sig_bytes.copy_from_slice(bytes);
908 Ok(Self(sig_bytes))
909 }
910}
911
912impl Signer<Signature> for Secp256k1KeyPair {
913 fn sign(&self, msg: &[u8]) -> Signature {
914 Secp256k1SuiSignature::new(self, msg).into()
915 }
916}
917
918#[serde_as]
922#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, AsRef, AsMut)]
923#[as_ref(forward)]
924#[as_mut(forward)]
925pub struct Secp256r1SuiSignature(
926 #[schemars(with = "Base64")]
927 #[serde_as(as = "Readable<Base64, Bytes>")]
928 [u8; Secp256r1PublicKey::LENGTH + Secp256r1Signature::LENGTH + 1],
929);
930
931impl SuiSignatureInner for Secp256r1SuiSignature {
932 type Sig = Secp256r1Signature;
933 type PubKey = Secp256r1PublicKey;
934 type KeyPair = Secp256r1KeyPair;
935 const LENGTH: usize = Secp256r1PublicKey::LENGTH + Secp256r1Signature::LENGTH + 1;
936}
937
938impl SuiPublicKey for Secp256r1PublicKey {
939 const SIGNATURE_SCHEME: SignatureScheme = SignatureScheme::Secp256r1;
940}
941
942impl ToFromBytes for Secp256r1SuiSignature {
943 fn from_bytes(bytes: &[u8]) -> Result<Self, FastCryptoError> {
944 if bytes.len() != Self::LENGTH {
945 return Err(FastCryptoError::InputLengthWrong(Self::LENGTH));
946 }
947 let mut sig_bytes = [0; Self::LENGTH];
948 sig_bytes.copy_from_slice(bytes);
949 Ok(Self(sig_bytes))
950 }
951}
952
953impl Signer<Signature> for Secp256r1KeyPair {
954 fn sign(&self, msg: &[u8]) -> Signature {
955 Secp256r1SuiSignature::new(self, msg).into()
956 }
957}
958
959pub trait SuiSignatureInner: Sized + ToFromBytes + PartialEq + Eq + Hash {
963 type Sig: Authenticator<PubKey = Self::PubKey>;
964 type PubKey: VerifyingKey<Sig = Self::Sig> + SuiPublicKey;
965 type KeyPair: KeypairTraits<PubKey = Self::PubKey, Sig = Self::Sig>;
966
967 const LENGTH: usize = Self::Sig::LENGTH + Self::PubKey::LENGTH + 1;
968 const SCHEME: SignatureScheme = Self::PubKey::SIGNATURE_SCHEME;
969
970 fn get_verification_inputs(&self) -> SuiResult<(Self::Sig, Self::PubKey)> {
972 let pk = Self::PubKey::from_bytes(self.public_key_bytes())
973 .map_err(|_| SuiErrorKind::KeyConversionError("Invalid public key".to_string()))?;
974
975 let signature = Self::Sig::from_bytes(self.signature_bytes()).map_err(|_| {
977 SuiErrorKind::InvalidSignature {
978 error: "Fail to get pubkey and sig".to_string(),
979 }
980 })?;
981
982 Ok((signature, pk))
983 }
984
985 fn new(kp: &Self::KeyPair, message: &[u8]) -> Self {
986 let sig = Signer::sign(kp, message);
987
988 let mut signature_bytes: Vec<u8> = Vec::new();
989 signature_bytes
990 .extend_from_slice(&[<Self::PubKey as SuiPublicKey>::SIGNATURE_SCHEME.flag()]);
991 signature_bytes.extend_from_slice(sig.as_ref());
992 signature_bytes.extend_from_slice(kp.public().as_ref());
993 Self::from_bytes(&signature_bytes[..])
994 .expect("Serialized signature did not have expected size")
995 }
996}
997
998pub trait SuiPublicKey: VerifyingKey {
999 const SIGNATURE_SCHEME: SignatureScheme;
1000}
1001
1002#[enum_dispatch(Signature)]
1003pub trait SuiSignature: Sized + ToFromBytes {
1004 fn signature_bytes(&self) -> &[u8];
1005 fn public_key_bytes(&self) -> &[u8];
1006 fn scheme(&self) -> SignatureScheme;
1007
1008 fn verify_secure<T>(
1009 &self,
1010 value: &IntentMessage<T>,
1011 author: SuiAddress,
1012 scheme: SignatureScheme,
1013 ) -> SuiResult<()>
1014 where
1015 T: Serialize;
1016}
1017
1018impl<S: SuiSignatureInner + Sized> SuiSignature for S {
1019 fn signature_bytes(&self) -> &[u8] {
1020 &self.as_ref()[1..1 + S::Sig::LENGTH]
1023 }
1024
1025 fn public_key_bytes(&self) -> &[u8] {
1026 &self.as_ref()[S::Sig::LENGTH + 1..]
1029 }
1030
1031 fn scheme(&self) -> SignatureScheme {
1032 S::PubKey::SIGNATURE_SCHEME
1033 }
1034
1035 fn verify_secure<T>(
1036 &self,
1037 value: &IntentMessage<T>,
1038 author: SuiAddress,
1039 scheme: SignatureScheme,
1040 ) -> Result<(), SuiError>
1041 where
1042 T: Serialize,
1043 {
1044 let mut hasher = DefaultHash::default();
1045 bcs::serialize_into(&mut hasher, &value).expect("Message serialization should not fail");
1046 let digest = hasher.finalize().digest;
1047
1048 let (sig, pk) = &self.get_verification_inputs()?;
1049 match scheme {
1050 SignatureScheme::ZkLoginAuthenticator => {} _ => {
1052 let address = SuiAddress::from(pk);
1053 if author != address {
1054 return Err(SuiErrorKind::IncorrectSigner {
1055 error: format!(
1056 "Incorrect signer, expected {:?}, got {:?}",
1057 author, address
1058 ),
1059 }
1060 .into());
1061 }
1062 }
1063 }
1064
1065 pk.verify(&digest, sig).map_err(|e| {
1066 SuiErrorKind::InvalidSignature {
1067 error: format!("Fail to verify user sig {}", e),
1068 }
1069 .into()
1070 })
1071 }
1072}
1073
1074pub trait AuthoritySignInfoTrait: private::SealedAuthoritySignInfoTrait {
1080 fn verify_secure<T: Serialize>(
1081 &self,
1082 data: &T,
1083 intent: Intent,
1084 committee: &Committee,
1085 ) -> SuiResult;
1086
1087 fn add_to_verification_obligation<'a>(
1088 &self,
1089 committee: &'a Committee,
1090 obligation: &mut VerificationObligation<'a>,
1091 message_index: usize,
1092 ) -> SuiResult<()>;
1093}
1094
1095#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
1096pub struct EmptySignInfo {}
1097impl AuthoritySignInfoTrait for EmptySignInfo {
1098 fn verify_secure<T: Serialize>(
1099 &self,
1100 _data: &T,
1101 _intent: Intent,
1102 _committee: &Committee,
1103 ) -> SuiResult {
1104 Ok(())
1105 }
1106
1107 fn add_to_verification_obligation<'a>(
1108 &self,
1109 _committee: &'a Committee,
1110 _obligation: &mut VerificationObligation<'a>,
1111 _message_index: usize,
1112 ) -> SuiResult<()> {
1113 Ok(())
1114 }
1115}
1116
1117#[derive(Clone, Debug, Eq, Serialize, Deserialize)]
1118pub struct AuthoritySignInfo {
1119 pub epoch: EpochId,
1120 pub authority: AuthorityName,
1121 pub signature: AuthoritySignature,
1122}
1123
1124impl AuthoritySignInfoTrait for AuthoritySignInfo {
1125 fn verify_secure<T: Serialize>(
1126 &self,
1127 data: &T,
1128 intent: Intent,
1129 committee: &Committee,
1130 ) -> SuiResult<()> {
1131 let mut obligation = VerificationObligation::default();
1132 let idx = obligation.add_message(data, self.epoch, intent);
1133 self.add_to_verification_obligation(committee, &mut obligation, idx)?;
1134 obligation.verify_all()?;
1135 Ok(())
1136 }
1137
1138 fn add_to_verification_obligation<'a>(
1139 &self,
1140 committee: &'a Committee,
1141 obligation: &mut VerificationObligation<'a>,
1142 message_index: usize,
1143 ) -> SuiResult<()> {
1144 fp_ensure!(
1145 self.epoch == committee.epoch(),
1146 SuiErrorKind::WrongEpoch {
1147 expected_epoch: committee.epoch(),
1148 actual_epoch: self.epoch,
1149 }
1150 .into()
1151 );
1152 let weight = committee.weight(&self.authority);
1153 fp_ensure!(
1154 weight > 0,
1155 SuiErrorKind::UnknownSigner {
1156 signer: Some(self.authority.concise().to_string()),
1157 index: None,
1158 committee: Box::new(committee.clone())
1159 }
1160 .into()
1161 );
1162
1163 obligation
1164 .public_keys
1165 .get_mut(message_index)
1166 .ok_or(SuiErrorKind::InvalidAddress)?
1167 .push(committee.public_key(&self.authority)?);
1168 obligation
1169 .signatures
1170 .get_mut(message_index)
1171 .ok_or(SuiErrorKind::InvalidAddress)?
1172 .add_signature(self.signature.clone())
1173 .map_err(|_| SuiErrorKind::InvalidSignature {
1174 error: "Fail to aggregator auth sig".to_string(),
1175 })?;
1176 Ok(())
1177 }
1178}
1179
1180impl AuthoritySignInfo {
1181 pub fn new<T>(
1182 epoch: EpochId,
1183 value: &T,
1184 intent: Intent,
1185 name: AuthorityName,
1186 secret: &dyn Signer<AuthoritySignature>,
1187 ) -> Self
1188 where
1189 T: Serialize,
1190 {
1191 Self {
1192 epoch,
1193 authority: name,
1194 signature: AuthoritySignature::new_secure(
1195 &IntentMessage::new(intent, value),
1196 &epoch,
1197 secret,
1198 ),
1199 }
1200 }
1201}
1202
1203impl Hash for AuthoritySignInfo {
1204 fn hash<H: Hasher>(&self, state: &mut H) {
1205 self.epoch.hash(state);
1206 self.authority.hash(state);
1207 }
1208}
1209
1210impl Display for AuthoritySignInfo {
1211 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1212 write!(
1213 f,
1214 "AuthoritySignInfo {{ epoch: {:?}, authority: {} }}",
1215 self.epoch, self.authority,
1216 )
1217 }
1218}
1219
1220impl PartialEq for AuthoritySignInfo {
1221 fn eq(&self, other: &Self) -> bool {
1222 self.epoch == other.epoch && self.authority == other.authority
1225 }
1226}
1227
1228#[serde_as]
1235#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
1236pub struct AuthorityQuorumSignInfo<const STRONG_THRESHOLD: bool> {
1237 pub epoch: EpochId,
1238 #[schemars(with = "Base64")]
1239 pub signature: AggregateAuthoritySignature,
1240 #[schemars(with = "Base64")]
1241 #[serde_as(as = "SuiBitmap")]
1242 pub signers_map: RoaringBitmap,
1243}
1244
1245pub type AuthorityStrongQuorumSignInfo = AuthorityQuorumSignInfo<true>;
1246
1247#[serde_as]
1250#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
1251pub struct SuiAuthorityStrongQuorumSignInfo {
1252 pub epoch: EpochId,
1253 pub signature: AggregateAuthoritySignatureAsBytes,
1254 #[schemars(with = "Base64")]
1255 #[serde_as(as = "SuiBitmap")]
1256 pub signers_map: RoaringBitmap,
1257}
1258
1259impl From<&AuthorityStrongQuorumSignInfo> for SuiAuthorityStrongQuorumSignInfo {
1260 fn from(info: &AuthorityStrongQuorumSignInfo) -> Self {
1261 Self {
1262 epoch: info.epoch,
1263 signature: (&info.signature).into(),
1264 signers_map: info.signers_map.clone(),
1265 }
1266 }
1267}
1268
1269impl TryFrom<&SuiAuthorityStrongQuorumSignInfo> for AuthorityStrongQuorumSignInfo {
1270 type Error = FastCryptoError;
1271
1272 fn try_from(info: &SuiAuthorityStrongQuorumSignInfo) -> Result<Self, Self::Error> {
1273 Ok(Self {
1274 epoch: info.epoch,
1275 signature: (&info.signature).try_into()?,
1276 signers_map: info.signers_map.clone(),
1277 })
1278 }
1279}
1280
1281static_assertions::assert_not_impl_any!(AuthorityStrongQuorumSignInfo: Hash, Eq, PartialEq);
1292
1293impl<const STRONG_THRESHOLD: bool> AuthoritySignInfoTrait
1294 for AuthorityQuorumSignInfo<STRONG_THRESHOLD>
1295{
1296 fn verify_secure<T: Serialize>(
1297 &self,
1298 data: &T,
1299 intent: Intent,
1300 committee: &Committee,
1301 ) -> SuiResult {
1302 let mut obligation = VerificationObligation::default();
1303 let idx = obligation.add_message(data, self.epoch, intent);
1304 self.add_to_verification_obligation(committee, &mut obligation, idx)?;
1305 obligation.verify_all()?;
1306 Ok(())
1307 }
1308
1309 fn add_to_verification_obligation<'a>(
1310 &self,
1311 committee: &'a Committee,
1312 obligation: &mut VerificationObligation<'a>,
1313 message_index: usize,
1314 ) -> SuiResult<()> {
1315 fp_ensure!(
1317 self.epoch == committee.epoch(),
1318 SuiErrorKind::WrongEpoch {
1319 expected_epoch: committee.epoch(),
1320 actual_epoch: self.epoch,
1321 }
1322 .into()
1323 );
1324
1325 let mut weight = 0;
1326
1327 obligation
1329 .signatures
1330 .get_mut(message_index)
1331 .ok_or(SuiErrorKind::InvalidAuthenticator)?
1332 .add_aggregate(self.signature.clone())
1333 .map_err(|_| SuiErrorKind::InvalidSignature {
1334 error: "Signature Aggregation failed".to_string(),
1335 })?;
1336
1337 let selected_public_keys = obligation
1338 .public_keys
1339 .get_mut(message_index)
1340 .ok_or(SuiErrorKind::InvalidAuthenticator)?;
1341
1342 let mut seen = std::collections::BTreeSet::new();
1343 for authority_index in self.signers_map.iter() {
1344 if !seen.insert(authority_index) {
1345 continue;
1346 }
1347
1348 let authority = committee
1350 .authority_by_index(authority_index)
1351 .ok_or_else(|| SuiErrorKind::UnknownSigner {
1352 signer: None,
1353 index: Some(authority_index),
1354 committee: Box::new(committee.clone()),
1355 })?;
1356 let voting_rights = committee.weight(authority);
1357 fp_ensure!(
1358 voting_rights > 0,
1359 SuiErrorKind::UnknownSigner {
1360 signer: Some(authority.concise().to_string()),
1361 index: Some(authority_index),
1362 committee: Box::new(committee.clone()),
1363 }
1364 .into()
1365 );
1366 weight += voting_rights;
1367
1368 selected_public_keys.push(committee.public_key(authority)?);
1369 }
1370
1371 fp_ensure!(
1372 weight >= Self::quorum_threshold(committee),
1373 SuiErrorKind::CertificateRequiresQuorum.into()
1374 );
1375
1376 Ok(())
1377 }
1378}
1379
1380impl<const STRONG_THRESHOLD: bool> AuthorityQuorumSignInfo<STRONG_THRESHOLD> {
1381 pub fn new_from_auth_sign_infos(
1382 auth_sign_infos: Vec<AuthoritySignInfo>,
1383 committee: &Committee,
1384 ) -> SuiResult<Self> {
1385 fp_ensure!(
1386 auth_sign_infos.iter().all(|a| a.epoch == committee.epoch),
1387 SuiErrorKind::InvalidSignature {
1388 error: "All signatures must be from the same epoch as the committee".to_string()
1389 }
1390 .into()
1391 );
1392 let total_stake: StakeUnit = auth_sign_infos
1393 .iter()
1394 .map(|a| committee.weight(&a.authority))
1395 .sum();
1396 fp_ensure!(
1397 total_stake >= Self::quorum_threshold(committee),
1398 SuiErrorKind::InvalidSignature {
1399 error: "Signatures don't have enough stake to form a quorum".to_string()
1400 }
1401 .into()
1402 );
1403
1404 let signatures: BTreeMap<_, _> = auth_sign_infos
1405 .into_iter()
1406 .map(|a| (a.authority, a.signature))
1407 .collect();
1408 let mut map = RoaringBitmap::new();
1409 for pk in signatures.keys() {
1410 map.insert(committee.authority_index(pk).ok_or_else(|| {
1411 SuiErrorKind::UnknownSigner {
1412 signer: Some(pk.concise().to_string()),
1413 index: None,
1414 committee: Box::new(committee.clone()),
1415 }
1416 })?);
1417 }
1418 let sigs: Vec<AuthoritySignature> = signatures.into_values().collect();
1419
1420 Ok(AuthorityQuorumSignInfo {
1421 epoch: committee.epoch,
1422 signature: AggregateAuthoritySignature::aggregate(&sigs).map_err(|e| {
1423 SuiErrorKind::InvalidSignature {
1424 error: e.to_string(),
1425 }
1426 })?,
1427 signers_map: map,
1428 })
1429 }
1430
1431 pub fn authorities<'a>(
1432 &'a self,
1433 committee: &'a Committee,
1434 ) -> impl Iterator<Item = SuiResult<&'a AuthorityName>> {
1435 self.signers_map.iter().map(|i| {
1436 committee
1437 .authority_by_index(i)
1438 .ok_or(SuiErrorKind::InvalidAuthenticator.into())
1439 })
1440 }
1441
1442 pub fn quorum_threshold(committee: &Committee) -> StakeUnit {
1443 committee.threshold::<STRONG_THRESHOLD>()
1444 }
1445
1446 pub fn len(&self) -> u64 {
1447 self.signers_map.len()
1448 }
1449
1450 pub fn is_empty(&self) -> bool {
1451 self.signers_map.is_empty()
1452 }
1453}
1454
1455impl<const S: bool> Display for AuthorityQuorumSignInfo<S> {
1456 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1457 writeln!(
1458 f,
1459 "{} {{ epoch: {:?}, signers_map: {:?} }}",
1460 if S {
1461 "AuthorityStrongQuorumSignInfo"
1462 } else {
1463 "AuthorityWeakQuorumSignInfo"
1464 },
1465 self.epoch,
1466 self.signers_map,
1467 )?;
1468 Ok(())
1469 }
1470}
1471
1472mod private {
1473 pub trait SealedAuthoritySignInfoTrait {}
1474 impl SealedAuthoritySignInfoTrait for super::EmptySignInfo {}
1475 impl SealedAuthoritySignInfoTrait for super::AuthoritySignInfo {}
1476 impl<const S: bool> SealedAuthoritySignInfoTrait for super::AuthorityQuorumSignInfo<S> {}
1477}
1478
1479pub trait Signable<W> {
1481 fn write(&self, writer: &mut W);
1482}
1483
1484pub trait SignableBytes
1485where
1486 Self: Sized,
1487{
1488 fn from_signable_bytes(bytes: &[u8]) -> Result<Self, Error>;
1489}
1490
1491mod bcs_signable {
1502
1503 pub trait BcsSignable: serde::Serialize + serde::de::DeserializeOwned {}
1504 impl BcsSignable for crate::committee::Committee {}
1505 impl BcsSignable for crate::messages_checkpoint::CheckpointSummary {}
1506 impl BcsSignable for crate::messages_checkpoint::CheckpointContents {}
1507
1508 impl BcsSignable for crate::effects::TransactionEffects {}
1509 impl BcsSignable for crate::effects::TransactionEvents {}
1510 impl BcsSignable for crate::transaction::TransactionData {}
1511 impl BcsSignable for crate::transaction::SenderSignedData {}
1512 impl BcsSignable for crate::object::ObjectInner {}
1513
1514 impl BcsSignable for crate::global_state_hash::GlobalStateHash {}
1515
1516 impl BcsSignable for super::bcs_signable_test::Foo {}
1517 #[cfg(test)]
1518 impl BcsSignable for super::bcs_signable_test::Bar {}
1519}
1520
1521impl<T, W> Signable<W> for T
1522where
1523 T: bcs_signable::BcsSignable,
1524 W: std::io::Write,
1525{
1526 fn write(&self, writer: &mut W) {
1527 let name = serde_name::trace_name::<Self>().expect("Self must be a struct or an enum");
1528 write!(writer, "{}::", name).expect("Hasher should not fail");
1530 bcs::serialize_into(writer, &self).expect("Message serialization should not fail");
1531 }
1532}
1533
1534impl<W> Signable<W> for EpochId
1535where
1536 W: std::io::Write,
1537{
1538 fn write(&self, writer: &mut W) {
1539 bcs::serialize_into(writer, &self).expect("Message serialization should not fail");
1540 }
1541}
1542
1543impl<T> SignableBytes for T
1544where
1545 T: bcs_signable::BcsSignable,
1546{
1547 fn from_signable_bytes(bytes: &[u8]) -> Result<Self, Error> {
1548 let name = serde_name::trace_name::<Self>().expect("Self should be a struct or an enum");
1550 let name_byte_len = format!("{}::", name).bytes().len();
1551 Ok(bcs::from_bytes(bytes.get(name_byte_len..).ok_or_else(
1552 || anyhow!("Failed to deserialize to {name}."),
1553 )?)?)
1554 }
1555}
1556
1557fn hash<S: Signable<H>, H: HashFunction<DIGEST_SIZE>, const DIGEST_SIZE: usize>(
1558 signable: &S,
1559) -> [u8; DIGEST_SIZE] {
1560 let mut digest = H::default();
1561 signable.write(&mut digest);
1562 let hash = digest.finalize();
1563 hash.into()
1564}
1565
1566pub fn default_hash<S: Signable<DefaultHash>>(signable: &S) -> [u8; 32] {
1567 hash::<S, DefaultHash, 32>(signable)
1568}
1569
1570#[derive(Default)]
1571pub struct VerificationObligation<'a> {
1572 pub messages: Vec<Vec<u8>>,
1573 pub signatures: Vec<AggregateAuthoritySignature>,
1574 pub public_keys: Vec<Vec<&'a AuthorityPublicKey>>,
1575}
1576
1577impl<'a> VerificationObligation<'a> {
1578 pub fn new() -> VerificationObligation<'a> {
1579 VerificationObligation::default()
1580 }
1581
1582 pub fn add_message<T>(&mut self, message_value: &T, epoch: EpochId, intent: Intent) -> usize
1585 where
1586 T: Serialize,
1587 {
1588 let intent_msg = IntentMessage::new(intent, message_value);
1589 let mut intent_msg_bytes =
1590 bcs::to_bytes(&intent_msg).expect("Message serialization should not fail");
1591 epoch.write(&mut intent_msg_bytes);
1592 self.signatures.push(AggregateAuthoritySignature::default());
1593 self.public_keys.push(Vec::new());
1594 self.messages.push(intent_msg_bytes);
1595 self.messages.len() - 1
1596 }
1597
1598 pub fn add_signature_and_public_key(
1600 &mut self,
1601 signature: &AuthoritySignature,
1602 public_key: &'a AuthorityPublicKey,
1603 idx: usize,
1604 ) -> SuiResult<()> {
1605 self.public_keys
1606 .get_mut(idx)
1607 .ok_or(SuiErrorKind::InvalidAuthenticator)?
1608 .push(public_key);
1609 self.signatures
1610 .get_mut(idx)
1611 .ok_or(SuiErrorKind::InvalidAuthenticator)?
1612 .add_signature(signature.clone())
1613 .map_err(|_| SuiErrorKind::InvalidSignature {
1614 error: "Failed to add signature to obligation".to_string(),
1615 })?;
1616 Ok(())
1617 }
1618
1619 pub fn verify_all(self) -> SuiResult<()> {
1620 let mut pks = Vec::with_capacity(self.public_keys.len());
1621 for pk in self.public_keys.clone() {
1622 pks.push(pk.into_iter());
1623 }
1624 AggregateAuthoritySignature::batch_verify(
1625 &self.signatures.iter().collect::<Vec<_>>()[..],
1626 pks,
1627 &self.messages.iter().map(|x| &x[..]).collect::<Vec<_>>()[..],
1628 )
1629 .map_err(|e| {
1630 let message = format!(
1631 "pks: {:?}, messages: {:?}, sigs: {:?}",
1632 &self.public_keys,
1633 self.messages
1634 .iter()
1635 .map(Base64::encode)
1636 .collect::<Vec<String>>(),
1637 &self
1638 .signatures
1639 .iter()
1640 .map(|s| Base64::encode(s.as_ref()))
1641 .collect::<Vec<String>>()
1642 );
1643
1644 let chunk_size = 2048;
1645
1646 for (i, chunk) in message
1649 .as_bytes()
1650 .chunks(chunk_size)
1651 .map(std::str::from_utf8)
1652 .enumerate()
1653 {
1654 warn!(
1655 "Failed to batch verify aggregated auth sig: {} (chunk {}): {}",
1656 e,
1657 i,
1658 chunk.unwrap()
1659 );
1660 }
1661
1662 SuiErrorKind::InvalidSignature {
1663 error: format!("Failed to batch verify aggregated auth sig: {}", e),
1664 }
1665 })?;
1666 Ok(())
1667 }
1668}
1669
1670pub mod bcs_signable_test {
1671 use serde::{Deserialize, Serialize};
1672
1673 #[derive(Clone, Serialize, Deserialize)]
1674 pub struct Foo(pub String);
1675
1676 #[cfg(test)]
1677 #[derive(Serialize, Deserialize)]
1678 pub struct Bar(pub String);
1679
1680 #[cfg(test)]
1681 use super::VerificationObligation;
1682
1683 #[cfg(test)]
1684 pub fn get_obligation_input<T>(value: &T) -> (VerificationObligation<'_>, usize)
1685 where
1686 T: super::bcs_signable::BcsSignable,
1687 {
1688 use shared_crypto::intent::{Intent, IntentScope};
1689
1690 let mut obligation = VerificationObligation::default();
1691 let idx = obligation.add_message(
1693 value,
1694 0,
1695 Intent::sui_app(IntentScope::SenderSignedTransaction),
1696 );
1697 (obligation, idx)
1698 }
1699}
1700
1701#[derive(
1702 Clone,
1703 Copy,
1704 Deserialize,
1705 Serialize,
1706 JsonSchema,
1707 Debug,
1708 EnumString,
1709 strum_macros::Display,
1710 PartialEq,
1711 Eq,
1712)]
1713#[strum(serialize_all = "lowercase")]
1714pub enum SignatureScheme {
1715 ED25519,
1716 Secp256k1,
1717 Secp256r1,
1718 BLS12381, MultiSig,
1720 ZkLoginAuthenticator,
1721 PasskeyAuthenticator,
1722}
1723
1724impl SignatureScheme {
1725 pub fn flag(&self) -> u8 {
1726 match self {
1727 SignatureScheme::ED25519 => 0x00,
1728 SignatureScheme::Secp256k1 => 0x01,
1729 SignatureScheme::Secp256r1 => 0x02,
1730 SignatureScheme::MultiSig => 0x03,
1731 SignatureScheme::BLS12381 => 0x04, SignatureScheme::ZkLoginAuthenticator => 0x05,
1733 SignatureScheme::PasskeyAuthenticator => 0x06,
1734 }
1735 }
1736
1737 pub fn from_flag(flag: &str) -> Result<SignatureScheme, SuiError> {
1738 let byte_int = flag
1739 .parse::<u8>()
1740 .map_err(|_| SuiErrorKind::KeyConversionError("Invalid key scheme".to_string()))?;
1741 Self::from_flag_byte(&byte_int)
1742 }
1743
1744 pub fn from_flag_byte(byte_int: &u8) -> Result<SignatureScheme, SuiError> {
1745 match byte_int {
1746 0x00 => Ok(SignatureScheme::ED25519),
1747 0x01 => Ok(SignatureScheme::Secp256k1),
1748 0x02 => Ok(SignatureScheme::Secp256r1),
1749 0x03 => Ok(SignatureScheme::MultiSig),
1750 0x04 => Ok(SignatureScheme::BLS12381),
1751 0x05 => Ok(SignatureScheme::ZkLoginAuthenticator),
1752 0x06 => Ok(SignatureScheme::PasskeyAuthenticator),
1753 _ => Err(SuiErrorKind::KeyConversionError("Invalid key scheme".to_string()).into()),
1754 }
1755 }
1756}
1757#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
1759pub enum CompressedSignature {
1760 Ed25519(Ed25519SignatureAsBytes),
1761 Secp256k1(Secp256k1SignatureAsBytes),
1762 Secp256r1(Secp256r1SignatureAsBytes),
1763 ZkLogin(ZkLoginAuthenticatorAsBytes),
1764 Passkey(PasskeyAuthenticatorAsBytes),
1765}
1766
1767#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
1768pub struct ZkLoginAuthenticatorAsBytes(#[schemars(with = "Base64")] pub Vec<u8>);
1769
1770#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
1771pub struct PasskeyAuthenticatorAsBytes(#[schemars(with = "Base64")] pub Vec<u8>);
1772
1773impl AsRef<[u8]> for CompressedSignature {
1774 fn as_ref(&self) -> &[u8] {
1775 match self {
1776 CompressedSignature::Ed25519(sig) => &sig.0,
1777 CompressedSignature::Secp256k1(sig) => &sig.0,
1778 CompressedSignature::Secp256r1(sig) => &sig.0,
1779 CompressedSignature::ZkLogin(sig) => &sig.0,
1780 CompressedSignature::Passkey(sig) => &sig.0,
1781 }
1782 }
1783}
1784
1785impl FromStr for Signature {
1786 type Err = eyre::Report;
1787 fn from_str(s: &str) -> Result<Self, Self::Err> {
1788 Self::decode_base64(s).map_err(|e| eyre!("Fail to decode base64 {}", e.to_string()))
1789 }
1790}
1791
1792impl FromStr for PublicKey {
1793 type Err = eyre::Report;
1794 fn from_str(s: &str) -> Result<Self, Self::Err> {
1795 Self::decode_base64(s).map_err(|e| eyre!("Fail to decode base64 {}", e.to_string()))
1796 }
1797}
1798
1799impl FromStr for GenericSignature {
1800 type Err = eyre::Report;
1801 fn from_str(s: &str) -> Result<Self, Self::Err> {
1802 Self::decode_base64(s).map_err(|e| eyre!("Fail to decode base64 {}", e.to_string()))
1803 }
1804}
1805
1806pub type RandomnessSignature = fastcrypto_tbls::types::Signature;
1810pub type RandomnessPartialSignature = fastcrypto_tbls::tbls::PartialSignature<RandomnessSignature>;
1811pub type RandomnessPrivateKey =
1812 fastcrypto_tbls::ecies_v1::PrivateKey<fastcrypto::groups::bls12381::G2Element>;
1813
1814#[derive(Clone, Copy, Hash, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord)]
1816pub struct RandomnessRound(pub u64);
1817
1818impl Display for RandomnessRound {
1819 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1820 write!(f, "{}", self.0)
1821 }
1822}
1823
1824impl std::ops::Add for RandomnessRound {
1825 type Output = Self;
1826 fn add(self, other: Self) -> Self {
1827 Self(self.0 + other.0)
1828 }
1829}
1830
1831impl std::ops::Add<u64> for RandomnessRound {
1832 type Output = Self;
1833 fn add(self, other: u64) -> Self {
1834 Self(self.0 + other)
1835 }
1836}
1837
1838impl std::ops::Sub for RandomnessRound {
1839 type Output = Self;
1840 fn sub(self, other: Self) -> Self {
1841 Self(self.0 - other.0)
1842 }
1843}
1844
1845impl std::ops::Sub<u64> for RandomnessRound {
1846 type Output = Self;
1847 fn sub(self, other: u64) -> Self {
1848 Self(self.0 - other)
1849 }
1850}
1851
1852impl RandomnessRound {
1853 pub fn new(round: u64) -> Self {
1854 Self(round)
1855 }
1856
1857 pub fn checked_add(self, rhs: u64) -> Option<Self> {
1858 self.0.checked_add(rhs).map(Self)
1859 }
1860
1861 pub fn signature_message(&self) -> Vec<u8> {
1862 "random_beacon round "
1863 .as_bytes()
1864 .iter()
1865 .cloned()
1866 .chain(bcs::to_bytes(&self.0).expect("serialization should not fail"))
1867 .collect()
1868 }
1869}