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