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, 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 let data: Vec<u8> = Vec::deserialize(deserializer)?;
755 data
756 };
757
758 Self::from_bytes(&bytes).map_err(|e| Error::custom(e.to_string()))
759 }
760}
761
762impl Signature {
763 pub fn new_hashed(hashed_msg: &[u8], secret: &dyn Signer<Signature>) -> Self {
765 Signer::sign(secret, hashed_msg)
766 }
767
768 pub fn new_secure<T>(value: &IntentMessage<T>, secret: &dyn Signer<Signature>) -> Self
769 where
770 T: Serialize,
771 {
772 let mut hasher = DefaultHash::default();
777 hasher.update(bcs::to_bytes(&value).expect("Message serialization should not fail"));
778
779 Signer::sign(secret, &hasher.finalize().digest)
780 }
781}
782
783impl AsRef<[u8]> for Signature {
784 fn as_ref(&self) -> &[u8] {
785 match self {
786 Signature::Ed25519SuiSignature(sig) => sig.as_ref(),
787 Signature::Secp256k1SuiSignature(sig) => sig.as_ref(),
788 Signature::Secp256r1SuiSignature(sig) => sig.as_ref(),
789 }
790 }
791}
792impl AsMut<[u8]> for Signature {
793 fn as_mut(&mut self) -> &mut [u8] {
794 match self {
795 Signature::Ed25519SuiSignature(sig) => sig.as_mut(),
796 Signature::Secp256k1SuiSignature(sig) => sig.as_mut(),
797 Signature::Secp256r1SuiSignature(sig) => sig.as_mut(),
798 }
799 }
800}
801
802impl ToFromBytes for Signature {
803 fn from_bytes(bytes: &[u8]) -> Result<Self, FastCryptoError> {
804 match bytes.first() {
805 Some(x) => {
806 if x == &Ed25519SuiSignature::SCHEME.flag() {
807 Ok(<Ed25519SuiSignature as ToFromBytes>::from_bytes(bytes)?.into())
808 } else if x == &Secp256k1SuiSignature::SCHEME.flag() {
809 Ok(<Secp256k1SuiSignature as ToFromBytes>::from_bytes(bytes)?.into())
810 } else if x == &Secp256r1SuiSignature::SCHEME.flag() {
811 Ok(<Secp256r1SuiSignature as ToFromBytes>::from_bytes(bytes)?.into())
812 } else {
813 Err(FastCryptoError::InvalidInput)
814 }
815 }
816 _ => Err(FastCryptoError::InvalidInput),
817 }
818 }
819}
820
821impl SuiPublicKey for BLS12381PublicKey {
826 const SIGNATURE_SCHEME: SignatureScheme = SignatureScheme::BLS12381;
827}
828
829#[serde_as]
834#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, AsRef, AsMut)]
835#[as_ref(forward)]
836#[as_mut(forward)]
837pub struct Ed25519SuiSignature(
838 #[schemars(with = "Base64")]
839 #[serde_as(as = "Readable<Base64, Bytes>")]
840 [u8; Ed25519PublicKey::LENGTH + Ed25519Signature::LENGTH + 1],
841);
842
843impl Default for Ed25519SuiSignature {
845 fn default() -> Self {
846 Self([0; Ed25519PublicKey::LENGTH + Ed25519Signature::LENGTH + 1])
847 }
848}
849
850impl SuiSignatureInner for Ed25519SuiSignature {
851 type Sig = Ed25519Signature;
852 type PubKey = Ed25519PublicKey;
853 type KeyPair = Ed25519KeyPair;
854 const LENGTH: usize = Ed25519PublicKey::LENGTH + Ed25519Signature::LENGTH + 1;
855}
856
857impl SuiPublicKey for Ed25519PublicKey {
858 const SIGNATURE_SCHEME: SignatureScheme = SignatureScheme::ED25519;
859}
860
861impl ToFromBytes for Ed25519SuiSignature {
862 fn from_bytes(bytes: &[u8]) -> Result<Self, FastCryptoError> {
863 if bytes.len() != Self::LENGTH {
864 return Err(FastCryptoError::InputLengthWrong(Self::LENGTH));
865 }
866 let mut sig_bytes = [0; Self::LENGTH];
867 sig_bytes.copy_from_slice(bytes);
868 Ok(Self(sig_bytes))
869 }
870}
871
872impl Signer<Signature> for Ed25519KeyPair {
873 fn sign(&self, msg: &[u8]) -> Signature {
874 Ed25519SuiSignature::new(self, msg).into()
875 }
876}
877
878#[serde_as]
882#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, AsRef, AsMut)]
883#[as_ref(forward)]
884#[as_mut(forward)]
885pub struct Secp256k1SuiSignature(
886 #[schemars(with = "Base64")]
887 #[serde_as(as = "Readable<Base64, Bytes>")]
888 [u8; Secp256k1PublicKey::LENGTH + Secp256k1Signature::LENGTH + 1],
889);
890
891impl SuiSignatureInner for Secp256k1SuiSignature {
892 type Sig = Secp256k1Signature;
893 type PubKey = Secp256k1PublicKey;
894 type KeyPair = Secp256k1KeyPair;
895 const LENGTH: usize = Secp256k1PublicKey::LENGTH + Secp256k1Signature::LENGTH + 1;
896}
897
898impl SuiPublicKey for Secp256k1PublicKey {
899 const SIGNATURE_SCHEME: SignatureScheme = SignatureScheme::Secp256k1;
900}
901
902impl ToFromBytes for Secp256k1SuiSignature {
903 fn from_bytes(bytes: &[u8]) -> Result<Self, FastCryptoError> {
904 if bytes.len() != Self::LENGTH {
905 return Err(FastCryptoError::InputLengthWrong(Self::LENGTH));
906 }
907 let mut sig_bytes = [0; Self::LENGTH];
908 sig_bytes.copy_from_slice(bytes);
909 Ok(Self(sig_bytes))
910 }
911}
912
913impl Signer<Signature> for Secp256k1KeyPair {
914 fn sign(&self, msg: &[u8]) -> Signature {
915 Secp256k1SuiSignature::new(self, msg).into()
916 }
917}
918
919#[serde_as]
923#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, AsRef, AsMut)]
924#[as_ref(forward)]
925#[as_mut(forward)]
926pub struct Secp256r1SuiSignature(
927 #[schemars(with = "Base64")]
928 #[serde_as(as = "Readable<Base64, Bytes>")]
929 [u8; Secp256r1PublicKey::LENGTH + Secp256r1Signature::LENGTH + 1],
930);
931
932impl SuiSignatureInner for Secp256r1SuiSignature {
933 type Sig = Secp256r1Signature;
934 type PubKey = Secp256r1PublicKey;
935 type KeyPair = Secp256r1KeyPair;
936 const LENGTH: usize = Secp256r1PublicKey::LENGTH + Secp256r1Signature::LENGTH + 1;
937}
938
939impl SuiPublicKey for Secp256r1PublicKey {
940 const SIGNATURE_SCHEME: SignatureScheme = SignatureScheme::Secp256r1;
941}
942
943impl ToFromBytes for Secp256r1SuiSignature {
944 fn from_bytes(bytes: &[u8]) -> Result<Self, FastCryptoError> {
945 if bytes.len() != Self::LENGTH {
946 return Err(FastCryptoError::InputLengthWrong(Self::LENGTH));
947 }
948 let mut sig_bytes = [0; Self::LENGTH];
949 sig_bytes.copy_from_slice(bytes);
950 Ok(Self(sig_bytes))
951 }
952}
953
954impl Signer<Signature> for Secp256r1KeyPair {
955 fn sign(&self, msg: &[u8]) -> Signature {
956 Secp256r1SuiSignature::new(self, msg).into()
957 }
958}
959
960pub trait SuiSignatureInner: Sized + ToFromBytes + PartialEq + Eq + Hash {
964 type Sig: Authenticator<PubKey = Self::PubKey>;
965 type PubKey: VerifyingKey<Sig = Self::Sig> + SuiPublicKey;
966 type KeyPair: KeypairTraits<PubKey = Self::PubKey, Sig = Self::Sig>;
967
968 const LENGTH: usize = Self::Sig::LENGTH + Self::PubKey::LENGTH + 1;
969 const SCHEME: SignatureScheme = Self::PubKey::SIGNATURE_SCHEME;
970
971 fn get_verification_inputs(&self) -> SuiResult<(Self::Sig, Self::PubKey)> {
973 let pk = Self::PubKey::from_bytes(self.public_key_bytes())
974 .map_err(|_| SuiErrorKind::KeyConversionError("Invalid public key".to_string()))?;
975
976 let signature = Self::Sig::from_bytes(self.signature_bytes()).map_err(|_| {
978 SuiErrorKind::InvalidSignature {
979 error: "Fail to get pubkey and sig".to_string(),
980 }
981 })?;
982
983 Ok((signature, pk))
984 }
985
986 fn new(kp: &Self::KeyPair, message: &[u8]) -> Self {
987 let sig = Signer::sign(kp, message);
988
989 let mut signature_bytes: Vec<u8> = Vec::new();
990 signature_bytes
991 .extend_from_slice(&[<Self::PubKey as SuiPublicKey>::SIGNATURE_SCHEME.flag()]);
992 signature_bytes.extend_from_slice(sig.as_ref());
993 signature_bytes.extend_from_slice(kp.public().as_ref());
994 Self::from_bytes(&signature_bytes[..])
995 .expect("Serialized signature did not have expected size")
996 }
997}
998
999pub trait SuiPublicKey: VerifyingKey {
1000 const SIGNATURE_SCHEME: SignatureScheme;
1001}
1002
1003#[enum_dispatch(Signature)]
1004pub trait SuiSignature: Sized + ToFromBytes {
1005 fn signature_bytes(&self) -> &[u8];
1006 fn public_key_bytes(&self) -> &[u8];
1007 fn scheme(&self) -> SignatureScheme;
1008
1009 fn verify_secure<T>(
1010 &self,
1011 value: &IntentMessage<T>,
1012 author: SuiAddress,
1013 scheme: SignatureScheme,
1014 ) -> SuiResult<()>
1015 where
1016 T: Serialize;
1017}
1018
1019impl<S: SuiSignatureInner + Sized> SuiSignature for S {
1020 fn signature_bytes(&self) -> &[u8] {
1021 &self.as_ref()[1..1 + S::Sig::LENGTH]
1024 }
1025
1026 fn public_key_bytes(&self) -> &[u8] {
1027 &self.as_ref()[S::Sig::LENGTH + 1..]
1030 }
1031
1032 fn scheme(&self) -> SignatureScheme {
1033 S::PubKey::SIGNATURE_SCHEME
1034 }
1035
1036 fn verify_secure<T>(
1037 &self,
1038 value: &IntentMessage<T>,
1039 author: SuiAddress,
1040 scheme: SignatureScheme,
1041 ) -> Result<(), SuiError>
1042 where
1043 T: Serialize,
1044 {
1045 let mut hasher = DefaultHash::default();
1046 hasher.update(bcs::to_bytes(&value).expect("Message serialization should not fail"));
1047 let digest = hasher.finalize().digest;
1048
1049 let (sig, pk) = &self.get_verification_inputs()?;
1050 match scheme {
1051 SignatureScheme::ZkLoginAuthenticator => {} _ => {
1053 let address = SuiAddress::from(pk);
1054 if author != address {
1055 return Err(SuiErrorKind::IncorrectSigner {
1056 error: format!(
1057 "Incorrect signer, expected {:?}, got {:?}",
1058 author, address
1059 ),
1060 }
1061 .into());
1062 }
1063 }
1064 }
1065
1066 pk.verify(&digest, sig).map_err(|e| {
1067 SuiErrorKind::InvalidSignature {
1068 error: format!("Fail to verify user sig {}", e),
1069 }
1070 .into()
1071 })
1072 }
1073}
1074
1075pub trait AuthoritySignInfoTrait: private::SealedAuthoritySignInfoTrait {
1081 fn verify_secure<T: Serialize>(
1082 &self,
1083 data: &T,
1084 intent: Intent,
1085 committee: &Committee,
1086 ) -> SuiResult;
1087
1088 fn add_to_verification_obligation<'a>(
1089 &self,
1090 committee: &'a Committee,
1091 obligation: &mut VerificationObligation<'a>,
1092 message_index: usize,
1093 ) -> SuiResult<()>;
1094}
1095
1096#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
1097pub struct EmptySignInfo {}
1098impl AuthoritySignInfoTrait for EmptySignInfo {
1099 fn verify_secure<T: Serialize>(
1100 &self,
1101 _data: &T,
1102 _intent: Intent,
1103 _committee: &Committee,
1104 ) -> SuiResult {
1105 Ok(())
1106 }
1107
1108 fn add_to_verification_obligation<'a>(
1109 &self,
1110 _committee: &'a Committee,
1111 _obligation: &mut VerificationObligation<'a>,
1112 _message_index: usize,
1113 ) -> SuiResult<()> {
1114 Ok(())
1115 }
1116}
1117
1118#[derive(Clone, Debug, Eq, Serialize, Deserialize)]
1119pub struct AuthoritySignInfo {
1120 pub epoch: EpochId,
1121 pub authority: AuthorityName,
1122 pub signature: AuthoritySignature,
1123}
1124
1125impl AuthoritySignInfoTrait for AuthoritySignInfo {
1126 fn verify_secure<T: Serialize>(
1127 &self,
1128 data: &T,
1129 intent: Intent,
1130 committee: &Committee,
1131 ) -> SuiResult<()> {
1132 let mut obligation = VerificationObligation::default();
1133 let idx = obligation.add_message(data, self.epoch, intent);
1134 self.add_to_verification_obligation(committee, &mut obligation, idx)?;
1135 obligation.verify_all()?;
1136 Ok(())
1137 }
1138
1139 fn add_to_verification_obligation<'a>(
1140 &self,
1141 committee: &'a Committee,
1142 obligation: &mut VerificationObligation<'a>,
1143 message_index: usize,
1144 ) -> SuiResult<()> {
1145 fp_ensure!(
1146 self.epoch == committee.epoch(),
1147 SuiErrorKind::WrongEpoch {
1148 expected_epoch: committee.epoch(),
1149 actual_epoch: self.epoch,
1150 }
1151 .into()
1152 );
1153 let weight = committee.weight(&self.authority);
1154 fp_ensure!(
1155 weight > 0,
1156 SuiErrorKind::UnknownSigner {
1157 signer: Some(self.authority.concise().to_string()),
1158 index: None,
1159 committee: Box::new(committee.clone())
1160 }
1161 .into()
1162 );
1163
1164 obligation
1165 .public_keys
1166 .get_mut(message_index)
1167 .ok_or(SuiErrorKind::InvalidAddress)?
1168 .push(committee.public_key(&self.authority)?);
1169 obligation
1170 .signatures
1171 .get_mut(message_index)
1172 .ok_or(SuiErrorKind::InvalidAddress)?
1173 .add_signature(self.signature.clone())
1174 .map_err(|_| SuiErrorKind::InvalidSignature {
1175 error: "Fail to aggregator auth sig".to_string(),
1176 })?;
1177 Ok(())
1178 }
1179}
1180
1181impl AuthoritySignInfo {
1182 pub fn new<T>(
1183 epoch: EpochId,
1184 value: &T,
1185 intent: Intent,
1186 name: AuthorityName,
1187 secret: &dyn Signer<AuthoritySignature>,
1188 ) -> Self
1189 where
1190 T: Serialize,
1191 {
1192 Self {
1193 epoch,
1194 authority: name,
1195 signature: AuthoritySignature::new_secure(
1196 &IntentMessage::new(intent, value),
1197 &epoch,
1198 secret,
1199 ),
1200 }
1201 }
1202}
1203
1204impl Hash for AuthoritySignInfo {
1205 fn hash<H: Hasher>(&self, state: &mut H) {
1206 self.epoch.hash(state);
1207 self.authority.hash(state);
1208 }
1209}
1210
1211impl Display for AuthoritySignInfo {
1212 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1213 write!(
1214 f,
1215 "AuthoritySignInfo {{ epoch: {:?}, authority: {} }}",
1216 self.epoch, self.authority,
1217 )
1218 }
1219}
1220
1221impl PartialEq for AuthoritySignInfo {
1222 fn eq(&self, other: &Self) -> bool {
1223 self.epoch == other.epoch && self.authority == other.authority
1226 }
1227}
1228
1229#[serde_as]
1236#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
1237pub struct AuthorityQuorumSignInfo<const STRONG_THRESHOLD: bool> {
1238 pub epoch: EpochId,
1239 #[schemars(with = "Base64")]
1240 pub signature: AggregateAuthoritySignature,
1241 #[schemars(with = "Base64")]
1242 #[serde_as(as = "SuiBitmap")]
1243 pub signers_map: RoaringBitmap,
1244}
1245
1246pub type AuthorityStrongQuorumSignInfo = AuthorityQuorumSignInfo<true>;
1247
1248#[serde_as]
1251#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
1252pub struct SuiAuthorityStrongQuorumSignInfo {
1253 pub epoch: EpochId,
1254 pub signature: AggregateAuthoritySignatureAsBytes,
1255 #[schemars(with = "Base64")]
1256 #[serde_as(as = "SuiBitmap")]
1257 pub signers_map: RoaringBitmap,
1258}
1259
1260impl From<&AuthorityStrongQuorumSignInfo> for SuiAuthorityStrongQuorumSignInfo {
1261 fn from(info: &AuthorityStrongQuorumSignInfo) -> Self {
1262 Self {
1263 epoch: info.epoch,
1264 signature: (&info.signature).into(),
1265 signers_map: info.signers_map.clone(),
1266 }
1267 }
1268}
1269
1270impl TryFrom<&SuiAuthorityStrongQuorumSignInfo> for AuthorityStrongQuorumSignInfo {
1271 type Error = FastCryptoError;
1272
1273 fn try_from(info: &SuiAuthorityStrongQuorumSignInfo) -> Result<Self, Self::Error> {
1274 Ok(Self {
1275 epoch: info.epoch,
1276 signature: (&info.signature).try_into()?,
1277 signers_map: info.signers_map.clone(),
1278 })
1279 }
1280}
1281
1282static_assertions::assert_not_impl_any!(AuthorityStrongQuorumSignInfo: Hash, Eq, PartialEq);
1293
1294impl<const STRONG_THRESHOLD: bool> AuthoritySignInfoTrait
1295 for AuthorityQuorumSignInfo<STRONG_THRESHOLD>
1296{
1297 fn verify_secure<T: Serialize>(
1298 &self,
1299 data: &T,
1300 intent: Intent,
1301 committee: &Committee,
1302 ) -> SuiResult {
1303 let mut obligation = VerificationObligation::default();
1304 let idx = obligation.add_message(data, self.epoch, intent);
1305 self.add_to_verification_obligation(committee, &mut obligation, idx)?;
1306 obligation.verify_all()?;
1307 Ok(())
1308 }
1309
1310 fn add_to_verification_obligation<'a>(
1311 &self,
1312 committee: &'a Committee,
1313 obligation: &mut VerificationObligation<'a>,
1314 message_index: usize,
1315 ) -> SuiResult<()> {
1316 fp_ensure!(
1318 self.epoch == committee.epoch(),
1319 SuiErrorKind::WrongEpoch {
1320 expected_epoch: committee.epoch(),
1321 actual_epoch: self.epoch,
1322 }
1323 .into()
1324 );
1325
1326 let mut weight = 0;
1327
1328 obligation
1330 .signatures
1331 .get_mut(message_index)
1332 .ok_or(SuiErrorKind::InvalidAuthenticator)?
1333 .add_aggregate(self.signature.clone())
1334 .map_err(|_| SuiErrorKind::InvalidSignature {
1335 error: "Signature Aggregation failed".to_string(),
1336 })?;
1337
1338 let selected_public_keys = obligation
1339 .public_keys
1340 .get_mut(message_index)
1341 .ok_or(SuiErrorKind::InvalidAuthenticator)?;
1342
1343 let mut seen = std::collections::BTreeSet::new();
1344 for authority_index in self.signers_map.iter() {
1345 if !seen.insert(authority_index) {
1346 continue;
1347 }
1348
1349 let authority = committee
1351 .authority_by_index(authority_index)
1352 .ok_or_else(|| SuiErrorKind::UnknownSigner {
1353 signer: None,
1354 index: Some(authority_index),
1355 committee: Box::new(committee.clone()),
1356 })?;
1357 let voting_rights = committee.weight(authority);
1358 fp_ensure!(
1359 voting_rights > 0,
1360 SuiErrorKind::UnknownSigner {
1361 signer: Some(authority.concise().to_string()),
1362 index: Some(authority_index),
1363 committee: Box::new(committee.clone()),
1364 }
1365 .into()
1366 );
1367 weight += voting_rights;
1368
1369 selected_public_keys.push(committee.public_key(authority)?);
1370 }
1371
1372 fp_ensure!(
1373 weight >= Self::quorum_threshold(committee),
1374 SuiErrorKind::CertificateRequiresQuorum.into()
1375 );
1376
1377 Ok(())
1378 }
1379}
1380
1381impl<const STRONG_THRESHOLD: bool> AuthorityQuorumSignInfo<STRONG_THRESHOLD> {
1382 pub fn new_from_auth_sign_infos(
1383 auth_sign_infos: Vec<AuthoritySignInfo>,
1384 committee: &Committee,
1385 ) -> SuiResult<Self> {
1386 fp_ensure!(
1387 auth_sign_infos.iter().all(|a| a.epoch == committee.epoch),
1388 SuiErrorKind::InvalidSignature {
1389 error: "All signatures must be from the same epoch as the committee".to_string()
1390 }
1391 .into()
1392 );
1393 let total_stake: StakeUnit = auth_sign_infos
1394 .iter()
1395 .map(|a| committee.weight(&a.authority))
1396 .sum();
1397 fp_ensure!(
1398 total_stake >= Self::quorum_threshold(committee),
1399 SuiErrorKind::InvalidSignature {
1400 error: "Signatures don't have enough stake to form a quorum".to_string()
1401 }
1402 .into()
1403 );
1404
1405 let signatures: BTreeMap<_, _> = auth_sign_infos
1406 .into_iter()
1407 .map(|a| (a.authority, a.signature))
1408 .collect();
1409 let mut map = RoaringBitmap::new();
1410 for pk in signatures.keys() {
1411 map.insert(committee.authority_index(pk).ok_or_else(|| {
1412 SuiErrorKind::UnknownSigner {
1413 signer: Some(pk.concise().to_string()),
1414 index: None,
1415 committee: Box::new(committee.clone()),
1416 }
1417 })?);
1418 }
1419 let sigs: Vec<AuthoritySignature> = signatures.into_values().collect();
1420
1421 Ok(AuthorityQuorumSignInfo {
1422 epoch: committee.epoch,
1423 signature: AggregateAuthoritySignature::aggregate(&sigs).map_err(|e| {
1424 SuiErrorKind::InvalidSignature {
1425 error: e.to_string(),
1426 }
1427 })?,
1428 signers_map: map,
1429 })
1430 }
1431
1432 pub fn authorities<'a>(
1433 &'a self,
1434 committee: &'a Committee,
1435 ) -> impl Iterator<Item = SuiResult<&'a AuthorityName>> {
1436 self.signers_map.iter().map(|i| {
1437 committee
1438 .authority_by_index(i)
1439 .ok_or(SuiErrorKind::InvalidAuthenticator.into())
1440 })
1441 }
1442
1443 pub fn quorum_threshold(committee: &Committee) -> StakeUnit {
1444 committee.threshold::<STRONG_THRESHOLD>()
1445 }
1446
1447 pub fn len(&self) -> u64 {
1448 self.signers_map.len()
1449 }
1450
1451 pub fn is_empty(&self) -> bool {
1452 self.signers_map.is_empty()
1453 }
1454}
1455
1456impl<const S: bool> Display for AuthorityQuorumSignInfo<S> {
1457 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1458 writeln!(
1459 f,
1460 "{} {{ epoch: {:?}, signers_map: {:?} }}",
1461 if S {
1462 "AuthorityStrongQuorumSignInfo"
1463 } else {
1464 "AuthorityWeakQuorumSignInfo"
1465 },
1466 self.epoch,
1467 self.signers_map,
1468 )?;
1469 Ok(())
1470 }
1471}
1472
1473mod private {
1474 pub trait SealedAuthoritySignInfoTrait {}
1475 impl SealedAuthoritySignInfoTrait for super::EmptySignInfo {}
1476 impl SealedAuthoritySignInfoTrait for super::AuthoritySignInfo {}
1477 impl<const S: bool> SealedAuthoritySignInfoTrait for super::AuthorityQuorumSignInfo<S> {}
1478}
1479
1480pub trait Signable<W> {
1482 fn write(&self, writer: &mut W);
1483}
1484
1485pub trait SignableBytes
1486where
1487 Self: Sized,
1488{
1489 fn from_signable_bytes(bytes: &[u8]) -> Result<Self, Error>;
1490}
1491
1492mod bcs_signable {
1503
1504 pub trait BcsSignable: serde::Serialize + serde::de::DeserializeOwned {}
1505 impl BcsSignable for crate::committee::Committee {}
1506 impl BcsSignable for crate::messages_checkpoint::CheckpointSummary {}
1507 impl BcsSignable for crate::messages_checkpoint::CheckpointContents {}
1508
1509 impl BcsSignable for crate::effects::TransactionEffects {}
1510 impl BcsSignable for crate::effects::TransactionEvents {}
1511 impl BcsSignable for crate::transaction::TransactionData {}
1512 impl BcsSignable for crate::transaction::SenderSignedData {}
1513 impl BcsSignable for crate::object::ObjectInner {}
1514
1515 impl BcsSignable for crate::global_state_hash::GlobalStateHash {}
1516
1517 impl BcsSignable for super::bcs_signable_test::Foo {}
1518 #[cfg(test)]
1519 impl BcsSignable for super::bcs_signable_test::Bar {}
1520}
1521
1522impl<T, W> Signable<W> for T
1523where
1524 T: bcs_signable::BcsSignable,
1525 W: std::io::Write,
1526{
1527 fn write(&self, writer: &mut W) {
1528 let name = serde_name::trace_name::<Self>().expect("Self must be a struct or an enum");
1529 write!(writer, "{}::", name).expect("Hasher should not fail");
1531 bcs::serialize_into(writer, &self).expect("Message serialization should not fail");
1532 }
1533}
1534
1535impl<W> Signable<W> for EpochId
1536where
1537 W: std::io::Write,
1538{
1539 fn write(&self, writer: &mut W) {
1540 bcs::serialize_into(writer, &self).expect("Message serialization should not fail");
1541 }
1542}
1543
1544impl<T> SignableBytes for T
1545where
1546 T: bcs_signable::BcsSignable,
1547{
1548 fn from_signable_bytes(bytes: &[u8]) -> Result<Self, Error> {
1549 let name = serde_name::trace_name::<Self>().expect("Self should be a struct or an enum");
1551 let name_byte_len = format!("{}::", name).bytes().len();
1552 Ok(bcs::from_bytes(bytes.get(name_byte_len..).ok_or_else(
1553 || anyhow!("Failed to deserialize to {name}."),
1554 )?)?)
1555 }
1556}
1557
1558fn hash<S: Signable<H>, H: HashFunction<DIGEST_SIZE>, const DIGEST_SIZE: usize>(
1559 signable: &S,
1560) -> [u8; DIGEST_SIZE] {
1561 let mut digest = H::default();
1562 signable.write(&mut digest);
1563 let hash = digest.finalize();
1564 hash.into()
1565}
1566
1567pub fn default_hash<S: Signable<DefaultHash>>(signable: &S) -> [u8; 32] {
1568 hash::<S, DefaultHash, 32>(signable)
1569}
1570
1571#[derive(Default)]
1572pub struct VerificationObligation<'a> {
1573 pub messages: Vec<Vec<u8>>,
1574 pub signatures: Vec<AggregateAuthoritySignature>,
1575 pub public_keys: Vec<Vec<&'a AuthorityPublicKey>>,
1576}
1577
1578impl<'a> VerificationObligation<'a> {
1579 pub fn new() -> VerificationObligation<'a> {
1580 VerificationObligation::default()
1581 }
1582
1583 pub fn add_message<T>(&mut self, message_value: &T, epoch: EpochId, intent: Intent) -> usize
1586 where
1587 T: Serialize,
1588 {
1589 let intent_msg = IntentMessage::new(intent, message_value);
1590 let mut intent_msg_bytes =
1591 bcs::to_bytes(&intent_msg).expect("Message serialization should not fail");
1592 epoch.write(&mut intent_msg_bytes);
1593 self.signatures.push(AggregateAuthoritySignature::default());
1594 self.public_keys.push(Vec::new());
1595 self.messages.push(intent_msg_bytes);
1596 self.messages.len() - 1
1597 }
1598
1599 pub fn add_signature_and_public_key(
1601 &mut self,
1602 signature: &AuthoritySignature,
1603 public_key: &'a AuthorityPublicKey,
1604 idx: usize,
1605 ) -> SuiResult<()> {
1606 self.public_keys
1607 .get_mut(idx)
1608 .ok_or(SuiErrorKind::InvalidAuthenticator)?
1609 .push(public_key);
1610 self.signatures
1611 .get_mut(idx)
1612 .ok_or(SuiErrorKind::InvalidAuthenticator)?
1613 .add_signature(signature.clone())
1614 .map_err(|_| SuiErrorKind::InvalidSignature {
1615 error: "Failed to add signature to obligation".to_string(),
1616 })?;
1617 Ok(())
1618 }
1619
1620 pub fn verify_all(self) -> SuiResult<()> {
1621 let mut pks = Vec::with_capacity(self.public_keys.len());
1622 for pk in self.public_keys.clone() {
1623 pks.push(pk.into_iter());
1624 }
1625 AggregateAuthoritySignature::batch_verify(
1626 &self.signatures.iter().collect::<Vec<_>>()[..],
1627 pks,
1628 &self.messages.iter().map(|x| &x[..]).collect::<Vec<_>>()[..],
1629 )
1630 .map_err(|e| {
1631 let message = format!(
1632 "pks: {:?}, messages: {:?}, sigs: {:?}",
1633 &self.public_keys,
1634 self.messages
1635 .iter()
1636 .map(Base64::encode)
1637 .collect::<Vec<String>>(),
1638 &self
1639 .signatures
1640 .iter()
1641 .map(|s| Base64::encode(s.as_ref()))
1642 .collect::<Vec<String>>()
1643 );
1644
1645 let chunk_size = 2048;
1646
1647 for (i, chunk) in message
1650 .as_bytes()
1651 .chunks(chunk_size)
1652 .map(std::str::from_utf8)
1653 .enumerate()
1654 {
1655 warn!(
1656 "Failed to batch verify aggregated auth sig: {} (chunk {}): {}",
1657 e,
1658 i,
1659 chunk.unwrap()
1660 );
1661 }
1662
1663 SuiErrorKind::InvalidSignature {
1664 error: format!("Failed to batch verify aggregated auth sig: {}", e),
1665 }
1666 })?;
1667 Ok(())
1668 }
1669}
1670
1671pub mod bcs_signable_test {
1672 use serde::{Deserialize, Serialize};
1673
1674 #[derive(Clone, Serialize, Deserialize)]
1675 pub struct Foo(pub String);
1676
1677 #[cfg(test)]
1678 #[derive(Serialize, Deserialize)]
1679 pub struct Bar(pub String);
1680
1681 #[cfg(test)]
1682 use super::VerificationObligation;
1683
1684 #[cfg(test)]
1685 pub fn get_obligation_input<T>(value: &T) -> (VerificationObligation<'_>, usize)
1686 where
1687 T: super::bcs_signable::BcsSignable,
1688 {
1689 use shared_crypto::intent::{Intent, IntentScope};
1690
1691 let mut obligation = VerificationObligation::default();
1692 let idx = obligation.add_message(
1694 value,
1695 0,
1696 Intent::sui_app(IntentScope::SenderSignedTransaction),
1697 );
1698 (obligation, idx)
1699 }
1700}
1701
1702#[derive(
1703 Clone,
1704 Copy,
1705 Deserialize,
1706 Serialize,
1707 JsonSchema,
1708 Debug,
1709 EnumString,
1710 strum_macros::Display,
1711 PartialEq,
1712 Eq,
1713)]
1714#[strum(serialize_all = "lowercase")]
1715pub enum SignatureScheme {
1716 ED25519,
1717 Secp256k1,
1718 Secp256r1,
1719 BLS12381, MultiSig,
1721 ZkLoginAuthenticator,
1722 PasskeyAuthenticator,
1723}
1724
1725impl SignatureScheme {
1726 pub fn flag(&self) -> u8 {
1727 match self {
1728 SignatureScheme::ED25519 => 0x00,
1729 SignatureScheme::Secp256k1 => 0x01,
1730 SignatureScheme::Secp256r1 => 0x02,
1731 SignatureScheme::MultiSig => 0x03,
1732 SignatureScheme::BLS12381 => 0x04, SignatureScheme::ZkLoginAuthenticator => 0x05,
1734 SignatureScheme::PasskeyAuthenticator => 0x06,
1735 }
1736 }
1737
1738 pub fn from_flag(flag: &str) -> Result<SignatureScheme, SuiError> {
1739 let byte_int = flag
1740 .parse::<u8>()
1741 .map_err(|_| SuiErrorKind::KeyConversionError("Invalid key scheme".to_string()))?;
1742 Self::from_flag_byte(&byte_int)
1743 }
1744
1745 pub fn from_flag_byte(byte_int: &u8) -> Result<SignatureScheme, SuiError> {
1746 match byte_int {
1747 0x00 => Ok(SignatureScheme::ED25519),
1748 0x01 => Ok(SignatureScheme::Secp256k1),
1749 0x02 => Ok(SignatureScheme::Secp256r1),
1750 0x03 => Ok(SignatureScheme::MultiSig),
1751 0x04 => Ok(SignatureScheme::BLS12381),
1752 0x05 => Ok(SignatureScheme::ZkLoginAuthenticator),
1753 0x06 => Ok(SignatureScheme::PasskeyAuthenticator),
1754 _ => Err(SuiErrorKind::KeyConversionError("Invalid key scheme".to_string()).into()),
1755 }
1756 }
1757}
1758#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
1760pub enum CompressedSignature {
1761 Ed25519(Ed25519SignatureAsBytes),
1762 Secp256k1(Secp256k1SignatureAsBytes),
1763 Secp256r1(Secp256r1SignatureAsBytes),
1764 ZkLogin(ZkLoginAuthenticatorAsBytes),
1765 Passkey(PasskeyAuthenticatorAsBytes),
1766}
1767
1768#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
1769pub struct ZkLoginAuthenticatorAsBytes(#[schemars(with = "Base64")] pub Vec<u8>);
1770
1771#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
1772pub struct PasskeyAuthenticatorAsBytes(#[schemars(with = "Base64")] pub Vec<u8>);
1773
1774impl AsRef<[u8]> for CompressedSignature {
1775 fn as_ref(&self) -> &[u8] {
1776 match self {
1777 CompressedSignature::Ed25519(sig) => &sig.0,
1778 CompressedSignature::Secp256k1(sig) => &sig.0,
1779 CompressedSignature::Secp256r1(sig) => &sig.0,
1780 CompressedSignature::ZkLogin(sig) => &sig.0,
1781 CompressedSignature::Passkey(sig) => &sig.0,
1782 }
1783 }
1784}
1785
1786impl FromStr for Signature {
1787 type Err = eyre::Report;
1788 fn from_str(s: &str) -> Result<Self, Self::Err> {
1789 Self::decode_base64(s).map_err(|e| eyre!("Fail to decode base64 {}", e.to_string()))
1790 }
1791}
1792
1793impl FromStr for PublicKey {
1794 type Err = eyre::Report;
1795 fn from_str(s: &str) -> Result<Self, Self::Err> {
1796 Self::decode_base64(s).map_err(|e| eyre!("Fail to decode base64 {}", e.to_string()))
1797 }
1798}
1799
1800impl FromStr for GenericSignature {
1801 type Err = eyre::Report;
1802 fn from_str(s: &str) -> Result<Self, Self::Err> {
1803 Self::decode_base64(s).map_err(|e| eyre!("Fail to decode base64 {}", e.to_string()))
1804 }
1805}
1806
1807pub type RandomnessSignature = fastcrypto_tbls::types::Signature;
1811pub type RandomnessPartialSignature = fastcrypto_tbls::tbls::PartialSignature<RandomnessSignature>;
1812pub type RandomnessPrivateKey =
1813 fastcrypto_tbls::ecies_v1::PrivateKey<fastcrypto::groups::bls12381::G2Element>;
1814
1815#[derive(Clone, Copy, Hash, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord)]
1817pub struct RandomnessRound(pub u64);
1818
1819impl Display for RandomnessRound {
1820 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1821 write!(f, "{}", self.0)
1822 }
1823}
1824
1825impl std::ops::Add for RandomnessRound {
1826 type Output = Self;
1827 fn add(self, other: Self) -> Self {
1828 Self(self.0 + other.0)
1829 }
1830}
1831
1832impl std::ops::Add<u64> for RandomnessRound {
1833 type Output = Self;
1834 fn add(self, other: u64) -> Self {
1835 Self(self.0 + other)
1836 }
1837}
1838
1839impl std::ops::Sub for RandomnessRound {
1840 type Output = Self;
1841 fn sub(self, other: Self) -> Self {
1842 Self(self.0 - other.0)
1843 }
1844}
1845
1846impl std::ops::Sub<u64> for RandomnessRound {
1847 type Output = Self;
1848 fn sub(self, other: u64) -> Self {
1849 Self(self.0 - other)
1850 }
1851}
1852
1853impl RandomnessRound {
1854 pub fn new(round: u64) -> Self {
1855 Self(round)
1856 }
1857
1858 pub fn checked_add(self, rhs: u64) -> Option<Self> {
1859 self.0.checked_add(rhs).map(Self)
1860 }
1861
1862 pub fn signature_message(&self) -> Vec<u8> {
1863 "random_beacon round "
1864 .as_bytes()
1865 .iter()
1866 .cloned()
1867 .chain(bcs::to_bytes(&self.0).expect("serialization should not fail"))
1868 .collect()
1869 }
1870}