sui_types/
crypto.rs

1// Copyright (c) Mysten Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3use crate::base_types::{AuthorityName, ConciseableName, SuiAddress};
4use crate::committee::CommitteeTrait;
5use crate::committee::{Committee, EpochId, StakeUnit};
6use crate::error::{SuiError, SuiErrorKind, SuiResult};
7use crate::signature::GenericSignature;
8use crate::sui_serde::{Readable, SuiBitmap};
9use anyhow::{Error, anyhow};
10use derive_more::{AsMut, AsRef, From};
11pub use enum_dispatch::enum_dispatch;
12use eyre::eyre;
13use fastcrypto::bls12381::min_sig::{
14    BLS12381AggregateSignature, BLS12381AggregateSignatureAsBytes, BLS12381KeyPair,
15    BLS12381PrivateKey, BLS12381PublicKey, BLS12381Signature,
16};
17use fastcrypto::ed25519::{
18    Ed25519KeyPair, Ed25519PrivateKey, Ed25519PublicKey, Ed25519PublicKeyAsBytes, Ed25519Signature,
19    Ed25519SignatureAsBytes,
20};
21use fastcrypto::encoding::{Base64, Bech32, Encoding, Hex};
22use fastcrypto::error::{FastCryptoError, FastCryptoResult};
23use fastcrypto::hash::{Blake2b256, HashFunction};
24use fastcrypto::secp256k1::{
25    Secp256k1KeyPair, Secp256k1PublicKey, Secp256k1PublicKeyAsBytes, Secp256k1Signature,
26    Secp256k1SignatureAsBytes,
27};
28use fastcrypto::secp256r1::{
29    Secp256r1KeyPair, Secp256r1PublicKey, Secp256r1PublicKeyAsBytes, Secp256r1Signature,
30    Secp256r1SignatureAsBytes,
31};
32pub use fastcrypto::traits::KeyPair as KeypairTraits;
33pub use fastcrypto::traits::Signer;
34pub use fastcrypto::traits::{
35    AggregateAuthenticator, Authenticator, EncodeDecodeBase64, SigningKey, ToFromBytes,
36    VerifyingKey,
37};
38use fastcrypto_zkp::bn254::zk_login::ZkLoginInputs;
39use fastcrypto_zkp::zk_login_utils::Bn254FrElement;
40use rand::SeedableRng;
41use rand::rngs::{OsRng, StdRng};
42use roaring::RoaringBitmap;
43use schemars::JsonSchema;
44use serde::ser::Serializer;
45use serde::{Deserialize, Deserializer, Serialize};
46use serde_with::{Bytes, DeserializeAs, serde_as};
47use shared_crypto::intent::{Intent, IntentMessage, IntentScope};
48use std::collections::BTreeMap;
49use std::fmt::Debug;
50use std::fmt::{self, Display, Formatter};
51use std::hash::{Hash, Hasher};
52use std::str::FromStr;
53use strum::EnumString;
54use tracing::{instrument, warn};
55
56#[cfg(test)]
57#[path = "unit_tests/crypto_tests.rs"]
58mod crypto_tests;
59
60#[cfg(test)]
61#[path = "unit_tests/intent_tests.rs"]
62mod intent_tests;
63
64// Authority Objects
65pub type AuthorityKeyPair = BLS12381KeyPair;
66pub type AuthorityPublicKey = BLS12381PublicKey;
67pub type AuthorityPrivateKey = BLS12381PrivateKey;
68pub type AuthoritySignature = BLS12381Signature;
69pub type AggregateAuthoritySignature = BLS12381AggregateSignature;
70pub type AggregateAuthoritySignatureAsBytes = BLS12381AggregateSignatureAsBytes;
71
72// TODO(joyqvq): prefix these types with Default, DefaultAccountKeyPair etc
73pub 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
86/// Creates a proof of that the authority account address is owned by the
87/// holder of authority protocol key, and also ensures that the authority
88/// protocol public key exists. A proof of possession is an authority
89/// signature committed over the intent message `intent || message || epoch` (See
90/// more at [struct IntentMessage] and [struct Intent]) where the message is
91/// constructed as `authority_pubkey_bytes || authority_account_address`.
92pub 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
106/// Verify proof of possession against the expected intent message,
107/// consisting of the protocol pubkey and the authority account address.
108pub 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///////////////////////////////////////////////
127// Account Keys
128//
129// * The following section defines the keypairs that are used by
130// * accounts to interact with Sui.
131// * Currently we support eddsa and ecdsa on Sui.
132//
133
134#[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    /// Encode a SuiKeyPair as `flag || privkey` in Bech32 starting with "suiprivkey" to a string. Note that the pubkey is not encoded.
231    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    /// Decode a SuiKeyPair from `flag || privkey` in Bech32 starting with "suiprivkey" to SuiKeyPair. The public key is computed directly from the private key bytes.
236    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/// A wrapper struct to retrofit in [enum PublicKey] for zkLogin.
273/// Useful to construct [struct MultiSigPublicKey].
274#[derive(Clone, Debug, PartialEq, Eq, JsonSchema, Serialize, Deserialize)]
275pub struct ZkLoginPublicIdentifier(#[schemars(with = "Base64")] pub Vec<u8>);
276
277impl ZkLoginPublicIdentifier {
278    /// Consists of iss_bytes_len || iss_bytes || padded_32_byte_address_seed.
279    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    /// Validates zkLogin public identifier structure: iss_len || iss || padded_32_byte_address_seed.
290    pub fn validate(&self) -> SuiResult<()> {
291        let bytes = &self.0;
292
293        // Parse issuer length and bytes.
294        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        // Validate issuer string.
307        std::str::from_utf8(iss_bytes).map_err(|e| SuiErrorKind::InvalidSignature {
308            error: format!("zkLogin pk issuer is not valid: {}", e),
309        })?;
310
311        // Validate address seed length <= 32 bytes.
312        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/// Defines the compressed version of the public key that we pass around
431/// in Sui
432#[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    /// Get a ConciseAuthorityPublicKeyBytesRef. Usage:
466    ///
467    ///   debug!(name = ?authority.concise());
468    ///   format!("{:?}", authority.concise());
469    fn concise(&'a self) -> ConciseAuthorityPublicKeyBytesRef<'a> {
470        ConciseAuthorityPublicKeyBytesRef(self)
471    }
472
473    fn concise_owned(&self) -> ConciseAuthorityPublicKeyBytes {
474        ConciseAuthorityPublicKeyBytes(*self)
475    }
476}
477
478/// A wrapper around AuthorityPublicKeyBytes that provides a concise Debug impl.
479pub 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/// A wrapper around AuthorityPublicKeyBytes but owns it.
495#[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    /// This ensures it's impossible to construct an instance with other than registered lengths
550    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
571//
572// Add helper calls for Authority Signature
573//
574
575pub 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
638// TODO: get_key_pair() and get_key_pair_from_bytes() should return KeyPair only.
639// TODO: rename to random_key_pair
640pub 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
647/// Generate a random committee key pairs with a given committee size
648pub 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            // TODO: We are generating the keys 4 times to match exactly as how we generate
653            // keys in ConfigBuilder::build (sui-config/src/network_config_builder). This is because
654            // we are using these key generation functions as fixtures and we call them
655            // independently in different paths and exact the results to be the same.
656            // We should eliminate them.
657            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
679/// Generate a keypair from the specified RNG (useful for testing with seedable rngs).
680pub 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
689// TODO: C-GETTER
690pub 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//
715// Account Signatures
716//
717
718// Enums for signature scheme signatures
719#[enum_dispatch]
720#[derive(Clone, JsonSchema, Debug, PartialEq, Eq, Hash)]
721pub enum Signature {
722    Ed25519SuiSignature,
723    Secp256k1SuiSignature,
724    Secp256r1SuiSignature,
725}
726
727impl Serialize for Signature {
728    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
729    where
730        S: Serializer,
731    {
732        let bytes = self.as_ref();
733
734        if serializer.is_human_readable() {
735            let s = Base64::encode(bytes);
736            serializer.serialize_str(&s)
737        } else {
738            serializer.serialize_bytes(bytes)
739        }
740    }
741}
742
743impl<'de> Deserialize<'de> for Signature {
744    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
745    where
746        D: Deserializer<'de>,
747    {
748        use serde::de::Error;
749
750        let bytes = if deserializer.is_human_readable() {
751            let s = String::deserialize(deserializer)?;
752            Base64::decode(&s).map_err(|e| Error::custom(e.to_string()))?
753        } else {
754            Bytes::deserialize_as(deserializer)?
755        };
756
757        Self::from_bytes(&bytes).map_err(|e| Error::custom(e.to_string()))
758    }
759}
760
761impl Signature {
762    /// The messaged passed in is already hashed form.
763    pub fn new_hashed(hashed_msg: &[u8], secret: &dyn Signer<Signature>) -> Self {
764        Signer::sign(secret, hashed_msg)
765    }
766
767    pub fn new_secure<T>(value: &IntentMessage<T>, secret: &dyn Signer<Signature>) -> Self
768    where
769        T: Serialize,
770    {
771        // Compute the BCS hash of the value in intent message. In the case of transaction data,
772        // this is the BCS hash of `struct TransactionData`, different from the transaction digest
773        // itself that computes the BCS hash of the Rust type prefix and `struct TransactionData`.
774        // (See `fn digest` in `impl Message for SenderSignedData`).
775        let mut hasher = DefaultHash::default();
776        bcs::serialize_into(&mut hasher, &value).expect("Message serialization should not fail");
777
778        Signer::sign(secret, &hasher.finalize().digest)
779    }
780}
781
782impl AsRef<[u8]> for Signature {
783    fn as_ref(&self) -> &[u8] {
784        match self {
785            Signature::Ed25519SuiSignature(sig) => sig.as_ref(),
786            Signature::Secp256k1SuiSignature(sig) => sig.as_ref(),
787            Signature::Secp256r1SuiSignature(sig) => sig.as_ref(),
788        }
789    }
790}
791impl AsMut<[u8]> for Signature {
792    fn as_mut(&mut self) -> &mut [u8] {
793        match self {
794            Signature::Ed25519SuiSignature(sig) => sig.as_mut(),
795            Signature::Secp256k1SuiSignature(sig) => sig.as_mut(),
796            Signature::Secp256r1SuiSignature(sig) => sig.as_mut(),
797        }
798    }
799}
800
801impl ToFromBytes for Signature {
802    fn from_bytes(bytes: &[u8]) -> Result<Self, FastCryptoError> {
803        match bytes.first() {
804            Some(x) => {
805                if x == &Ed25519SuiSignature::SCHEME.flag() {
806                    Ok(<Ed25519SuiSignature as ToFromBytes>::from_bytes(bytes)?.into())
807                } else if x == &Secp256k1SuiSignature::SCHEME.flag() {
808                    Ok(<Secp256k1SuiSignature as ToFromBytes>::from_bytes(bytes)?.into())
809                } else if x == &Secp256r1SuiSignature::SCHEME.flag() {
810                    Ok(<Secp256r1SuiSignature as ToFromBytes>::from_bytes(bytes)?.into())
811                } else {
812                    Err(FastCryptoError::InvalidInput)
813                }
814            }
815            _ => Err(FastCryptoError::InvalidInput),
816        }
817    }
818}
819
820//
821// BLS Port
822//
823
824impl SuiPublicKey for BLS12381PublicKey {
825    const SIGNATURE_SCHEME: SignatureScheme = SignatureScheme::BLS12381;
826}
827
828//
829// Ed25519 Sui Signature port
830//
831
832#[serde_as]
833#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, AsRef, AsMut)]
834#[as_ref(forward)]
835#[as_mut(forward)]
836pub struct Ed25519SuiSignature(
837    #[schemars(with = "Base64")]
838    #[serde_as(as = "Readable<Base64, Bytes>")]
839    [u8; Ed25519PublicKey::LENGTH + Ed25519Signature::LENGTH + 1],
840);
841
842// Implementation useful for simplify testing when mock signature is needed
843impl Default for Ed25519SuiSignature {
844    fn default() -> Self {
845        Self([0; Ed25519PublicKey::LENGTH + Ed25519Signature::LENGTH + 1])
846    }
847}
848
849impl SuiSignatureInner for Ed25519SuiSignature {
850    type Sig = Ed25519Signature;
851    type PubKey = Ed25519PublicKey;
852    type KeyPair = Ed25519KeyPair;
853    const LENGTH: usize = Ed25519PublicKey::LENGTH + Ed25519Signature::LENGTH + 1;
854}
855
856impl SuiPublicKey for Ed25519PublicKey {
857    const SIGNATURE_SCHEME: SignatureScheme = SignatureScheme::ED25519;
858}
859
860impl ToFromBytes for Ed25519SuiSignature {
861    fn from_bytes(bytes: &[u8]) -> Result<Self, FastCryptoError> {
862        if bytes.len() != Self::LENGTH {
863            return Err(FastCryptoError::InputLengthWrong(Self::LENGTH));
864        }
865        let mut sig_bytes = [0; Self::LENGTH];
866        sig_bytes.copy_from_slice(bytes);
867        Ok(Self(sig_bytes))
868    }
869}
870
871impl Signer<Signature> for Ed25519KeyPair {
872    fn sign(&self, msg: &[u8]) -> Signature {
873        Ed25519SuiSignature::new(self, msg).into()
874    }
875}
876
877//
878// Secp256k1 Sui Signature port
879//
880#[serde_as]
881#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, AsRef, AsMut)]
882#[as_ref(forward)]
883#[as_mut(forward)]
884pub struct Secp256k1SuiSignature(
885    #[schemars(with = "Base64")]
886    #[serde_as(as = "Readable<Base64, Bytes>")]
887    [u8; Secp256k1PublicKey::LENGTH + Secp256k1Signature::LENGTH + 1],
888);
889
890impl SuiSignatureInner for Secp256k1SuiSignature {
891    type Sig = Secp256k1Signature;
892    type PubKey = Secp256k1PublicKey;
893    type KeyPair = Secp256k1KeyPair;
894    const LENGTH: usize = Secp256k1PublicKey::LENGTH + Secp256k1Signature::LENGTH + 1;
895}
896
897impl SuiPublicKey for Secp256k1PublicKey {
898    const SIGNATURE_SCHEME: SignatureScheme = SignatureScheme::Secp256k1;
899}
900
901impl ToFromBytes for Secp256k1SuiSignature {
902    fn from_bytes(bytes: &[u8]) -> Result<Self, FastCryptoError> {
903        if bytes.len() != Self::LENGTH {
904            return Err(FastCryptoError::InputLengthWrong(Self::LENGTH));
905        }
906        let mut sig_bytes = [0; Self::LENGTH];
907        sig_bytes.copy_from_slice(bytes);
908        Ok(Self(sig_bytes))
909    }
910}
911
912impl Signer<Signature> for Secp256k1KeyPair {
913    fn sign(&self, msg: &[u8]) -> Signature {
914        Secp256k1SuiSignature::new(self, msg).into()
915    }
916}
917
918//
919// Secp256r1 Sui Signature port
920//
921#[serde_as]
922#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, AsRef, AsMut)]
923#[as_ref(forward)]
924#[as_mut(forward)]
925pub struct Secp256r1SuiSignature(
926    #[schemars(with = "Base64")]
927    #[serde_as(as = "Readable<Base64, Bytes>")]
928    [u8; Secp256r1PublicKey::LENGTH + Secp256r1Signature::LENGTH + 1],
929);
930
931impl SuiSignatureInner for Secp256r1SuiSignature {
932    type Sig = Secp256r1Signature;
933    type PubKey = Secp256r1PublicKey;
934    type KeyPair = Secp256r1KeyPair;
935    const LENGTH: usize = Secp256r1PublicKey::LENGTH + Secp256r1Signature::LENGTH + 1;
936}
937
938impl SuiPublicKey for Secp256r1PublicKey {
939    const SIGNATURE_SCHEME: SignatureScheme = SignatureScheme::Secp256r1;
940}
941
942impl ToFromBytes for Secp256r1SuiSignature {
943    fn from_bytes(bytes: &[u8]) -> Result<Self, FastCryptoError> {
944        if bytes.len() != Self::LENGTH {
945            return Err(FastCryptoError::InputLengthWrong(Self::LENGTH));
946        }
947        let mut sig_bytes = [0; Self::LENGTH];
948        sig_bytes.copy_from_slice(bytes);
949        Ok(Self(sig_bytes))
950    }
951}
952
953impl Signer<Signature> for Secp256r1KeyPair {
954    fn sign(&self, msg: &[u8]) -> Signature {
955        Secp256r1SuiSignature::new(self, msg).into()
956    }
957}
958
959//
960// This struct exists due to the limitations of the `enum_dispatch` library.
961//
962pub trait SuiSignatureInner: Sized + ToFromBytes + PartialEq + Eq + Hash {
963    type Sig: Authenticator<PubKey = Self::PubKey>;
964    type PubKey: VerifyingKey<Sig = Self::Sig> + SuiPublicKey;
965    type KeyPair: KeypairTraits<PubKey = Self::PubKey, Sig = Self::Sig>;
966
967    const LENGTH: usize = Self::Sig::LENGTH + Self::PubKey::LENGTH + 1;
968    const SCHEME: SignatureScheme = Self::PubKey::SIGNATURE_SCHEME;
969
970    /// Returns the deserialized signature and deserialized pubkey.
971    fn get_verification_inputs(&self) -> SuiResult<(Self::Sig, Self::PubKey)> {
972        let pk = Self::PubKey::from_bytes(self.public_key_bytes())
973            .map_err(|_| SuiErrorKind::KeyConversionError("Invalid public key".to_string()))?;
974
975        // deserialize the signature
976        let signature = Self::Sig::from_bytes(self.signature_bytes()).map_err(|_| {
977            SuiErrorKind::InvalidSignature {
978                error: "Fail to get pubkey and sig".to_string(),
979            }
980        })?;
981
982        Ok((signature, pk))
983    }
984
985    fn new(kp: &Self::KeyPair, message: &[u8]) -> Self {
986        let sig = Signer::sign(kp, message);
987
988        let mut signature_bytes: Vec<u8> = Vec::new();
989        signature_bytes
990            .extend_from_slice(&[<Self::PubKey as SuiPublicKey>::SIGNATURE_SCHEME.flag()]);
991        signature_bytes.extend_from_slice(sig.as_ref());
992        signature_bytes.extend_from_slice(kp.public().as_ref());
993        Self::from_bytes(&signature_bytes[..])
994            .expect("Serialized signature did not have expected size")
995    }
996}
997
998pub trait SuiPublicKey: VerifyingKey {
999    const SIGNATURE_SCHEME: SignatureScheme;
1000}
1001
1002#[enum_dispatch(Signature)]
1003pub trait SuiSignature: Sized + ToFromBytes {
1004    fn signature_bytes(&self) -> &[u8];
1005    fn public_key_bytes(&self) -> &[u8];
1006    fn scheme(&self) -> SignatureScheme;
1007
1008    fn verify_secure<T>(
1009        &self,
1010        value: &IntentMessage<T>,
1011        author: SuiAddress,
1012        scheme: SignatureScheme,
1013    ) -> SuiResult<()>
1014    where
1015        T: Serialize;
1016}
1017
1018impl<S: SuiSignatureInner + Sized> SuiSignature for S {
1019    fn signature_bytes(&self) -> &[u8] {
1020        // Access array slice is safe because the array bytes is initialized as
1021        // flag || signature || pubkey with its defined length.
1022        &self.as_ref()[1..1 + S::Sig::LENGTH]
1023    }
1024
1025    fn public_key_bytes(&self) -> &[u8] {
1026        // Access array slice is safe because the array bytes is initialized as
1027        // flag || signature || pubkey with its defined length.
1028        &self.as_ref()[S::Sig::LENGTH + 1..]
1029    }
1030
1031    fn scheme(&self) -> SignatureScheme {
1032        S::PubKey::SIGNATURE_SCHEME
1033    }
1034
1035    fn verify_secure<T>(
1036        &self,
1037        value: &IntentMessage<T>,
1038        author: SuiAddress,
1039        scheme: SignatureScheme,
1040    ) -> Result<(), SuiError>
1041    where
1042        T: Serialize,
1043    {
1044        let mut hasher = DefaultHash::default();
1045        bcs::serialize_into(&mut hasher, &value).expect("Message serialization should not fail");
1046        let digest = hasher.finalize().digest;
1047
1048        let (sig, pk) = &self.get_verification_inputs()?;
1049        match scheme {
1050            SignatureScheme::ZkLoginAuthenticator => {} // Pass this check because zk login does not derive address from pubkey.
1051            _ => {
1052                let address = SuiAddress::from(pk);
1053                if author != address {
1054                    return Err(SuiErrorKind::IncorrectSigner {
1055                        error: format!(
1056                            "Incorrect signer, expected {:?}, got {:?}",
1057                            author, address
1058                        ),
1059                    }
1060                    .into());
1061                }
1062            }
1063        }
1064
1065        pk.verify(&digest, sig).map_err(|e| {
1066            SuiErrorKind::InvalidSignature {
1067                error: format!("Fail to verify user sig {}", e),
1068            }
1069            .into()
1070        })
1071    }
1072}
1073
1074/// AuthoritySignInfoTrait is a trait used specifically for a few structs in messages.rs
1075/// to template on whether the struct is signed by an authority. We want to limit how
1076/// those structs can be instantiated on, hence the sealed trait.
1077/// TODO: We could also add the aggregated signature as another impl of the trait.
1078///       This will make CertifiedTransaction also an instance of the same struct.
1079pub trait AuthoritySignInfoTrait: private::SealedAuthoritySignInfoTrait {
1080    fn verify_secure<T: Serialize>(
1081        &self,
1082        data: &T,
1083        intent: Intent,
1084        committee: &Committee,
1085    ) -> SuiResult;
1086
1087    fn add_to_verification_obligation<'a>(
1088        &self,
1089        committee: &'a Committee,
1090        obligation: &mut VerificationObligation<'a>,
1091        message_index: usize,
1092    ) -> SuiResult<()>;
1093}
1094
1095#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
1096pub struct EmptySignInfo {}
1097impl AuthoritySignInfoTrait for EmptySignInfo {
1098    fn verify_secure<T: Serialize>(
1099        &self,
1100        _data: &T,
1101        _intent: Intent,
1102        _committee: &Committee,
1103    ) -> SuiResult {
1104        Ok(())
1105    }
1106
1107    fn add_to_verification_obligation<'a>(
1108        &self,
1109        _committee: &'a Committee,
1110        _obligation: &mut VerificationObligation<'a>,
1111        _message_index: usize,
1112    ) -> SuiResult<()> {
1113        Ok(())
1114    }
1115}
1116
1117#[derive(Clone, Debug, Eq, Serialize, Deserialize)]
1118pub struct AuthoritySignInfo {
1119    pub epoch: EpochId,
1120    pub authority: AuthorityName,
1121    pub signature: AuthoritySignature,
1122}
1123
1124impl AuthoritySignInfoTrait for AuthoritySignInfo {
1125    fn verify_secure<T: Serialize>(
1126        &self,
1127        data: &T,
1128        intent: Intent,
1129        committee: &Committee,
1130    ) -> SuiResult<()> {
1131        let mut obligation = VerificationObligation::default();
1132        let idx = obligation.add_message(data, self.epoch, intent);
1133        self.add_to_verification_obligation(committee, &mut obligation, idx)?;
1134        obligation.verify_all()?;
1135        Ok(())
1136    }
1137
1138    fn add_to_verification_obligation<'a>(
1139        &self,
1140        committee: &'a Committee,
1141        obligation: &mut VerificationObligation<'a>,
1142        message_index: usize,
1143    ) -> SuiResult<()> {
1144        fp_ensure!(
1145            self.epoch == committee.epoch(),
1146            SuiErrorKind::WrongEpoch {
1147                expected_epoch: committee.epoch(),
1148                actual_epoch: self.epoch,
1149            }
1150            .into()
1151        );
1152        let weight = committee.weight(&self.authority);
1153        fp_ensure!(
1154            weight > 0,
1155            SuiErrorKind::UnknownSigner {
1156                signer: Some(self.authority.concise().to_string()),
1157                index: None,
1158                committee: Box::new(committee.clone())
1159            }
1160            .into()
1161        );
1162
1163        obligation
1164            .public_keys
1165            .get_mut(message_index)
1166            .ok_or(SuiErrorKind::InvalidAddress)?
1167            .push(committee.public_key(&self.authority)?);
1168        obligation
1169            .signatures
1170            .get_mut(message_index)
1171            .ok_or(SuiErrorKind::InvalidAddress)?
1172            .add_signature(self.signature.clone())
1173            .map_err(|_| SuiErrorKind::InvalidSignature {
1174                error: "Fail to aggregator auth sig".to_string(),
1175            })?;
1176        Ok(())
1177    }
1178}
1179
1180impl AuthoritySignInfo {
1181    pub fn new<T>(
1182        epoch: EpochId,
1183        value: &T,
1184        intent: Intent,
1185        name: AuthorityName,
1186        secret: &dyn Signer<AuthoritySignature>,
1187    ) -> Self
1188    where
1189        T: Serialize,
1190    {
1191        Self {
1192            epoch,
1193            authority: name,
1194            signature: AuthoritySignature::new_secure(
1195                &IntentMessage::new(intent, value),
1196                &epoch,
1197                secret,
1198            ),
1199        }
1200    }
1201}
1202
1203impl Hash for AuthoritySignInfo {
1204    fn hash<H: Hasher>(&self, state: &mut H) {
1205        self.epoch.hash(state);
1206        self.authority.hash(state);
1207    }
1208}
1209
1210impl Display for AuthoritySignInfo {
1211    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1212        write!(
1213            f,
1214            "AuthoritySignInfo {{ epoch: {:?}, authority: {} }}",
1215            self.epoch, self.authority,
1216        )
1217    }
1218}
1219
1220impl PartialEq for AuthoritySignInfo {
1221    fn eq(&self, other: &Self) -> bool {
1222        // We do not compare the signature, because there can be multiple
1223        // valid signatures for the same epoch and authority.
1224        self.epoch == other.epoch && self.authority == other.authority
1225    }
1226}
1227
1228/// Represents at least a quorum (could be more) of authority signatures.
1229/// STRONG_THRESHOLD indicates whether to use the quorum threshold for quorum check.
1230/// When STRONG_THRESHOLD is true, the quorum is valid when the total stake is
1231/// at least the quorum threshold (2f+1) of the committee; when STRONG_THRESHOLD is false,
1232/// the quorum is valid when the total stake is at least the validity threshold (f+1) of
1233/// the committee.
1234#[serde_as]
1235#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
1236pub struct AuthorityQuorumSignInfo<const STRONG_THRESHOLD: bool> {
1237    pub epoch: EpochId,
1238    #[schemars(with = "Base64")]
1239    pub signature: AggregateAuthoritySignature,
1240    #[schemars(with = "Base64")]
1241    #[serde_as(as = "SuiBitmap")]
1242    pub signers_map: RoaringBitmap,
1243}
1244
1245pub type AuthorityStrongQuorumSignInfo = AuthorityQuorumSignInfo<true>;
1246
1247// Variant of [AuthorityStrongQuorumSignInfo] but with a serialized signature, to be used in
1248// external APIs.
1249#[serde_as]
1250#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
1251pub struct SuiAuthorityStrongQuorumSignInfo {
1252    pub epoch: EpochId,
1253    pub signature: AggregateAuthoritySignatureAsBytes,
1254    #[schemars(with = "Base64")]
1255    #[serde_as(as = "SuiBitmap")]
1256    pub signers_map: RoaringBitmap,
1257}
1258
1259impl From<&AuthorityStrongQuorumSignInfo> for SuiAuthorityStrongQuorumSignInfo {
1260    fn from(info: &AuthorityStrongQuorumSignInfo) -> Self {
1261        Self {
1262            epoch: info.epoch,
1263            signature: (&info.signature).into(),
1264            signers_map: info.signers_map.clone(),
1265        }
1266    }
1267}
1268
1269impl TryFrom<&SuiAuthorityStrongQuorumSignInfo> for AuthorityStrongQuorumSignInfo {
1270    type Error = FastCryptoError;
1271
1272    fn try_from(info: &SuiAuthorityStrongQuorumSignInfo) -> Result<Self, Self::Error> {
1273        Ok(Self {
1274            epoch: info.epoch,
1275            signature: (&info.signature).try_into()?,
1276            signers_map: info.signers_map.clone(),
1277        })
1278    }
1279}
1280
1281// Note: if you meet an error due to this line it may be because you need an Eq implementation for `CertifiedTransaction`,
1282// or one of the structs that include it, i.e. `ConfirmationTransaction`, `TransactionInfoResponse` or `ObjectInfoResponse`.
1283//
1284// Please note that any such implementation must be agnostic to the exact set of signatures in the certificate, as
1285// clients are allowed to equivocate on the exact nature of valid certificates they send to the system. This assertion
1286// is a simple tool to make sure certificates are accounted for correctly - should you remove it, you're on your own to
1287// maintain the invariant that valid certificates with distinct signatures are equivalent, but yet-unchecked
1288// certificates that differ on signers aren't.
1289//
1290// see also https://github.com/MystenLabs/sui/issues/266
1291static_assertions::assert_not_impl_any!(AuthorityStrongQuorumSignInfo: Hash, Eq, PartialEq);
1292
1293impl<const STRONG_THRESHOLD: bool> AuthoritySignInfoTrait
1294    for AuthorityQuorumSignInfo<STRONG_THRESHOLD>
1295{
1296    fn verify_secure<T: Serialize>(
1297        &self,
1298        data: &T,
1299        intent: Intent,
1300        committee: &Committee,
1301    ) -> SuiResult {
1302        let mut obligation = VerificationObligation::default();
1303        let idx = obligation.add_message(data, self.epoch, intent);
1304        self.add_to_verification_obligation(committee, &mut obligation, idx)?;
1305        obligation.verify_all()?;
1306        Ok(())
1307    }
1308
1309    fn add_to_verification_obligation<'a>(
1310        &self,
1311        committee: &'a Committee,
1312        obligation: &mut VerificationObligation<'a>,
1313        message_index: usize,
1314    ) -> SuiResult<()> {
1315        // Check epoch
1316        fp_ensure!(
1317            self.epoch == committee.epoch(),
1318            SuiErrorKind::WrongEpoch {
1319                expected_epoch: committee.epoch(),
1320                actual_epoch: self.epoch,
1321            }
1322            .into()
1323        );
1324
1325        let mut weight = 0;
1326
1327        // Create obligations for the committee signatures
1328        obligation
1329            .signatures
1330            .get_mut(message_index)
1331            .ok_or(SuiErrorKind::InvalidAuthenticator)?
1332            .add_aggregate(self.signature.clone())
1333            .map_err(|_| SuiErrorKind::InvalidSignature {
1334                error: "Signature Aggregation failed".to_string(),
1335            })?;
1336
1337        let selected_public_keys = obligation
1338            .public_keys
1339            .get_mut(message_index)
1340            .ok_or(SuiErrorKind::InvalidAuthenticator)?;
1341
1342        let mut seen = std::collections::BTreeSet::new();
1343        for authority_index in self.signers_map.iter() {
1344            if !seen.insert(authority_index) {
1345                continue;
1346            }
1347
1348            // Update weight when seeing the authority for the first time.
1349            let authority = committee
1350                .authority_by_index(authority_index)
1351                .ok_or_else(|| SuiErrorKind::UnknownSigner {
1352                    signer: None,
1353                    index: Some(authority_index),
1354                    committee: Box::new(committee.clone()),
1355                })?;
1356            let voting_rights = committee.weight(authority);
1357            fp_ensure!(
1358                voting_rights > 0,
1359                SuiErrorKind::UnknownSigner {
1360                    signer: Some(authority.concise().to_string()),
1361                    index: Some(authority_index),
1362                    committee: Box::new(committee.clone()),
1363                }
1364                .into()
1365            );
1366            weight += voting_rights;
1367
1368            selected_public_keys.push(committee.public_key(authority)?);
1369        }
1370
1371        fp_ensure!(
1372            weight >= Self::quorum_threshold(committee),
1373            SuiErrorKind::CertificateRequiresQuorum.into()
1374        );
1375
1376        Ok(())
1377    }
1378}
1379
1380impl<const STRONG_THRESHOLD: bool> AuthorityQuorumSignInfo<STRONG_THRESHOLD> {
1381    pub fn new_from_auth_sign_infos(
1382        auth_sign_infos: Vec<AuthoritySignInfo>,
1383        committee: &Committee,
1384    ) -> SuiResult<Self> {
1385        fp_ensure!(
1386            auth_sign_infos.iter().all(|a| a.epoch == committee.epoch),
1387            SuiErrorKind::InvalidSignature {
1388                error: "All signatures must be from the same epoch as the committee".to_string()
1389            }
1390            .into()
1391        );
1392        let total_stake: StakeUnit = auth_sign_infos
1393            .iter()
1394            .map(|a| committee.weight(&a.authority))
1395            .sum();
1396        fp_ensure!(
1397            total_stake >= Self::quorum_threshold(committee),
1398            SuiErrorKind::InvalidSignature {
1399                error: "Signatures don't have enough stake to form a quorum".to_string()
1400            }
1401            .into()
1402        );
1403
1404        let signatures: BTreeMap<_, _> = auth_sign_infos
1405            .into_iter()
1406            .map(|a| (a.authority, a.signature))
1407            .collect();
1408        let mut map = RoaringBitmap::new();
1409        for pk in signatures.keys() {
1410            map.insert(committee.authority_index(pk).ok_or_else(|| {
1411                SuiErrorKind::UnknownSigner {
1412                    signer: Some(pk.concise().to_string()),
1413                    index: None,
1414                    committee: Box::new(committee.clone()),
1415                }
1416            })?);
1417        }
1418        let sigs: Vec<AuthoritySignature> = signatures.into_values().collect();
1419
1420        Ok(AuthorityQuorumSignInfo {
1421            epoch: committee.epoch,
1422            signature: AggregateAuthoritySignature::aggregate(&sigs).map_err(|e| {
1423                SuiErrorKind::InvalidSignature {
1424                    error: e.to_string(),
1425                }
1426            })?,
1427            signers_map: map,
1428        })
1429    }
1430
1431    pub fn authorities<'a>(
1432        &'a self,
1433        committee: &'a Committee,
1434    ) -> impl Iterator<Item = SuiResult<&'a AuthorityName>> {
1435        self.signers_map.iter().map(|i| {
1436            committee
1437                .authority_by_index(i)
1438                .ok_or(SuiErrorKind::InvalidAuthenticator.into())
1439        })
1440    }
1441
1442    pub fn quorum_threshold(committee: &Committee) -> StakeUnit {
1443        committee.threshold::<STRONG_THRESHOLD>()
1444    }
1445
1446    pub fn len(&self) -> u64 {
1447        self.signers_map.len()
1448    }
1449
1450    pub fn is_empty(&self) -> bool {
1451        self.signers_map.is_empty()
1452    }
1453}
1454
1455impl<const S: bool> Display for AuthorityQuorumSignInfo<S> {
1456    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1457        writeln!(
1458            f,
1459            "{} {{ epoch: {:?}, signers_map: {:?} }}",
1460            if S {
1461                "AuthorityStrongQuorumSignInfo"
1462            } else {
1463                "AuthorityWeakQuorumSignInfo"
1464            },
1465            self.epoch,
1466            self.signers_map,
1467        )?;
1468        Ok(())
1469    }
1470}
1471
1472mod private {
1473    pub trait SealedAuthoritySignInfoTrait {}
1474    impl SealedAuthoritySignInfoTrait for super::EmptySignInfo {}
1475    impl SealedAuthoritySignInfoTrait for super::AuthoritySignInfo {}
1476    impl<const S: bool> SealedAuthoritySignInfoTrait for super::AuthorityQuorumSignInfo<S> {}
1477}
1478
1479/// Something that we know how to hash and sign.
1480pub trait Signable<W> {
1481    fn write(&self, writer: &mut W);
1482}
1483
1484pub trait SignableBytes
1485where
1486    Self: Sized,
1487{
1488    fn from_signable_bytes(bytes: &[u8]) -> Result<Self, Error>;
1489}
1490
1491/// Activate the blanket implementation of `Signable` based on serde and BCS.
1492/// * We use `serde_name` to extract a seed from the name of structs and enums.
1493/// * We use `BCS` to generate canonical bytes suitable for hashing and signing.
1494///
1495/// # Safety
1496/// We protect the access to this marker trait through a "sealed trait" pattern:
1497/// impls must be add added here (nowehre else) which lets us note those impls
1498/// MUST be on types that comply with the `serde_name` machinery
1499/// for the below implementations not to panic. One way to check they work is to write
1500/// a unit test for serialization to / deserialization from signable bytes.
1501mod bcs_signable {
1502
1503    pub trait BcsSignable: serde::Serialize + serde::de::DeserializeOwned {}
1504    impl BcsSignable for crate::committee::Committee {}
1505    impl BcsSignable for crate::messages_checkpoint::CheckpointSummary {}
1506    impl BcsSignable for crate::messages_checkpoint::CheckpointContents {}
1507
1508    impl BcsSignable for crate::effects::TransactionEffects {}
1509    impl BcsSignable for crate::effects::TransactionEvents {}
1510    impl BcsSignable for crate::transaction::TransactionData {}
1511    impl BcsSignable for crate::transaction::SenderSignedData {}
1512    impl BcsSignable for crate::object::ObjectInner {}
1513
1514    impl BcsSignable for crate::global_state_hash::GlobalStateHash {}
1515
1516    impl BcsSignable for super::bcs_signable_test::Foo {}
1517    #[cfg(test)]
1518    impl BcsSignable for super::bcs_signable_test::Bar {}
1519}
1520
1521impl<T, W> Signable<W> for T
1522where
1523    T: bcs_signable::BcsSignable,
1524    W: std::io::Write,
1525{
1526    fn write(&self, writer: &mut W) {
1527        let name = serde_name::trace_name::<Self>().expect("Self must be a struct or an enum");
1528        // Note: This assumes that names never contain the separator `::`.
1529        write!(writer, "{}::", name).expect("Hasher should not fail");
1530        bcs::serialize_into(writer, &self).expect("Message serialization should not fail");
1531    }
1532}
1533
1534impl<W> Signable<W> for EpochId
1535where
1536    W: std::io::Write,
1537{
1538    fn write(&self, writer: &mut W) {
1539        bcs::serialize_into(writer, &self).expect("Message serialization should not fail");
1540    }
1541}
1542
1543impl<T> SignableBytes for T
1544where
1545    T: bcs_signable::BcsSignable,
1546{
1547    fn from_signable_bytes(bytes: &[u8]) -> Result<Self, Error> {
1548        // Remove name tag before deserialization using BCS
1549        let name = serde_name::trace_name::<Self>().expect("Self should be a struct or an enum");
1550        let name_byte_len = format!("{}::", name).bytes().len();
1551        Ok(bcs::from_bytes(bytes.get(name_byte_len..).ok_or_else(
1552            || anyhow!("Failed to deserialize to {name}."),
1553        )?)?)
1554    }
1555}
1556
1557fn hash<S: Signable<H>, H: HashFunction<DIGEST_SIZE>, const DIGEST_SIZE: usize>(
1558    signable: &S,
1559) -> [u8; DIGEST_SIZE] {
1560    let mut digest = H::default();
1561    signable.write(&mut digest);
1562    let hash = digest.finalize();
1563    hash.into()
1564}
1565
1566pub fn default_hash<S: Signable<DefaultHash>>(signable: &S) -> [u8; 32] {
1567    hash::<S, DefaultHash, 32>(signable)
1568}
1569
1570#[derive(Default)]
1571pub struct VerificationObligation<'a> {
1572    pub messages: Vec<Vec<u8>>,
1573    pub signatures: Vec<AggregateAuthoritySignature>,
1574    pub public_keys: Vec<Vec<&'a AuthorityPublicKey>>,
1575}
1576
1577impl<'a> VerificationObligation<'a> {
1578    pub fn new() -> VerificationObligation<'a> {
1579        VerificationObligation::default()
1580    }
1581
1582    /// Add a new message to the list of messages to be verified.
1583    /// Returns the index of the message.
1584    pub fn add_message<T>(&mut self, message_value: &T, epoch: EpochId, intent: Intent) -> usize
1585    where
1586        T: Serialize,
1587    {
1588        let intent_msg = IntentMessage::new(intent, message_value);
1589        let mut intent_msg_bytes =
1590            bcs::to_bytes(&intent_msg).expect("Message serialization should not fail");
1591        epoch.write(&mut intent_msg_bytes);
1592        self.signatures.push(AggregateAuthoritySignature::default());
1593        self.public_keys.push(Vec::new());
1594        self.messages.push(intent_msg_bytes);
1595        self.messages.len() - 1
1596    }
1597
1598    // Attempts to add signature and public key to the obligation. If this fails, ensure to call `verify` manually.
1599    pub fn add_signature_and_public_key(
1600        &mut self,
1601        signature: &AuthoritySignature,
1602        public_key: &'a AuthorityPublicKey,
1603        idx: usize,
1604    ) -> SuiResult<()> {
1605        self.public_keys
1606            .get_mut(idx)
1607            .ok_or(SuiErrorKind::InvalidAuthenticator)?
1608            .push(public_key);
1609        self.signatures
1610            .get_mut(idx)
1611            .ok_or(SuiErrorKind::InvalidAuthenticator)?
1612            .add_signature(signature.clone())
1613            .map_err(|_| SuiErrorKind::InvalidSignature {
1614                error: "Failed to add signature to obligation".to_string(),
1615            })?;
1616        Ok(())
1617    }
1618
1619    pub fn verify_all(self) -> SuiResult<()> {
1620        let mut pks = Vec::with_capacity(self.public_keys.len());
1621        for pk in self.public_keys.clone() {
1622            pks.push(pk.into_iter());
1623        }
1624        AggregateAuthoritySignature::batch_verify(
1625            &self.signatures.iter().collect::<Vec<_>>()[..],
1626            pks,
1627            &self.messages.iter().map(|x| &x[..]).collect::<Vec<_>>()[..],
1628        )
1629        .map_err(|e| {
1630            let message = format!(
1631                "pks: {:?}, messages: {:?}, sigs: {:?}",
1632                &self.public_keys,
1633                self.messages
1634                    .iter()
1635                    .map(Base64::encode)
1636                    .collect::<Vec<String>>(),
1637                &self
1638                    .signatures
1639                    .iter()
1640                    .map(|s| Base64::encode(s.as_ref()))
1641                    .collect::<Vec<String>>()
1642            );
1643
1644            let chunk_size = 2048;
1645
1646            // This error message may be very long, so we print out the error in chunks of to avoid
1647            // hitting a max log line length on the system.
1648            for (i, chunk) in message
1649                .as_bytes()
1650                .chunks(chunk_size)
1651                .map(std::str::from_utf8)
1652                .enumerate()
1653            {
1654                warn!(
1655                    "Failed to batch verify aggregated auth sig: {} (chunk {}): {}",
1656                    e,
1657                    i,
1658                    chunk.unwrap()
1659                );
1660            }
1661
1662            SuiErrorKind::InvalidSignature {
1663                error: format!("Failed to batch verify aggregated auth sig: {}", e),
1664            }
1665        })?;
1666        Ok(())
1667    }
1668}
1669
1670pub mod bcs_signable_test {
1671    use serde::{Deserialize, Serialize};
1672
1673    #[derive(Clone, Serialize, Deserialize)]
1674    pub struct Foo(pub String);
1675
1676    #[cfg(test)]
1677    #[derive(Serialize, Deserialize)]
1678    pub struct Bar(pub String);
1679
1680    #[cfg(test)]
1681    use super::VerificationObligation;
1682
1683    #[cfg(test)]
1684    pub fn get_obligation_input<T>(value: &T) -> (VerificationObligation<'_>, usize)
1685    where
1686        T: super::bcs_signable::BcsSignable,
1687    {
1688        use shared_crypto::intent::{Intent, IntentScope};
1689
1690        let mut obligation = VerificationObligation::default();
1691        // Add the obligation of the authority signature verifications.
1692        let idx = obligation.add_message(
1693            value,
1694            0,
1695            Intent::sui_app(IntentScope::SenderSignedTransaction),
1696        );
1697        (obligation, idx)
1698    }
1699}
1700
1701#[derive(
1702    Clone,
1703    Copy,
1704    Deserialize,
1705    Serialize,
1706    JsonSchema,
1707    Debug,
1708    EnumString,
1709    strum_macros::Display,
1710    PartialEq,
1711    Eq,
1712)]
1713#[strum(serialize_all = "lowercase")]
1714pub enum SignatureScheme {
1715    ED25519,
1716    Secp256k1,
1717    Secp256r1,
1718    BLS12381, // This is currently not supported for user Sui Address.
1719    MultiSig,
1720    ZkLoginAuthenticator,
1721    PasskeyAuthenticator,
1722}
1723
1724impl SignatureScheme {
1725    pub fn flag(&self) -> u8 {
1726        match self {
1727            SignatureScheme::ED25519 => 0x00,
1728            SignatureScheme::Secp256k1 => 0x01,
1729            SignatureScheme::Secp256r1 => 0x02,
1730            SignatureScheme::MultiSig => 0x03,
1731            SignatureScheme::BLS12381 => 0x04, // This is currently not supported for user Sui Address.
1732            SignatureScheme::ZkLoginAuthenticator => 0x05,
1733            SignatureScheme::PasskeyAuthenticator => 0x06,
1734        }
1735    }
1736
1737    pub fn from_flag(flag: &str) -> Result<SignatureScheme, SuiError> {
1738        let byte_int = flag
1739            .parse::<u8>()
1740            .map_err(|_| SuiErrorKind::KeyConversionError("Invalid key scheme".to_string()))?;
1741        Self::from_flag_byte(&byte_int)
1742    }
1743
1744    pub fn from_flag_byte(byte_int: &u8) -> Result<SignatureScheme, SuiError> {
1745        match byte_int {
1746            0x00 => Ok(SignatureScheme::ED25519),
1747            0x01 => Ok(SignatureScheme::Secp256k1),
1748            0x02 => Ok(SignatureScheme::Secp256r1),
1749            0x03 => Ok(SignatureScheme::MultiSig),
1750            0x04 => Ok(SignatureScheme::BLS12381),
1751            0x05 => Ok(SignatureScheme::ZkLoginAuthenticator),
1752            0x06 => Ok(SignatureScheme::PasskeyAuthenticator),
1753            _ => Err(SuiErrorKind::KeyConversionError("Invalid key scheme".to_string()).into()),
1754        }
1755    }
1756}
1757/// Unlike [enum Signature], [enum CompressedSignature] does not contain public key.
1758#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
1759pub enum CompressedSignature {
1760    Ed25519(Ed25519SignatureAsBytes),
1761    Secp256k1(Secp256k1SignatureAsBytes),
1762    Secp256r1(Secp256r1SignatureAsBytes),
1763    ZkLogin(ZkLoginAuthenticatorAsBytes),
1764    Passkey(PasskeyAuthenticatorAsBytes),
1765}
1766
1767#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
1768pub struct ZkLoginAuthenticatorAsBytes(#[schemars(with = "Base64")] pub Vec<u8>);
1769
1770#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
1771pub struct PasskeyAuthenticatorAsBytes(#[schemars(with = "Base64")] pub Vec<u8>);
1772
1773impl AsRef<[u8]> for CompressedSignature {
1774    fn as_ref(&self) -> &[u8] {
1775        match self {
1776            CompressedSignature::Ed25519(sig) => &sig.0,
1777            CompressedSignature::Secp256k1(sig) => &sig.0,
1778            CompressedSignature::Secp256r1(sig) => &sig.0,
1779            CompressedSignature::ZkLogin(sig) => &sig.0,
1780            CompressedSignature::Passkey(sig) => &sig.0,
1781        }
1782    }
1783}
1784
1785impl FromStr for Signature {
1786    type Err = eyre::Report;
1787    fn from_str(s: &str) -> Result<Self, Self::Err> {
1788        Self::decode_base64(s).map_err(|e| eyre!("Fail to decode base64 {}", e.to_string()))
1789    }
1790}
1791
1792impl FromStr for PublicKey {
1793    type Err = eyre::Report;
1794    fn from_str(s: &str) -> Result<Self, Self::Err> {
1795        Self::decode_base64(s).map_err(|e| eyre!("Fail to decode base64 {}", e.to_string()))
1796    }
1797}
1798
1799impl FromStr for GenericSignature {
1800    type Err = eyre::Report;
1801    fn from_str(s: &str) -> Result<Self, Self::Err> {
1802        Self::decode_base64(s).map_err(|e| eyre!("Fail to decode base64 {}", e.to_string()))
1803    }
1804}
1805
1806//
1807// Types for randomness generation
1808//
1809pub type RandomnessSignature = fastcrypto_tbls::types::Signature;
1810pub type RandomnessPartialSignature = fastcrypto_tbls::tbls::PartialSignature<RandomnessSignature>;
1811pub type RandomnessPrivateKey =
1812    fastcrypto_tbls::ecies_v1::PrivateKey<fastcrypto::groups::bls12381::G2Element>;
1813
1814/// Round number of generated randomness.
1815#[derive(Clone, Copy, Hash, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord)]
1816pub struct RandomnessRound(pub u64);
1817
1818impl Display for RandomnessRound {
1819    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1820        write!(f, "{}", self.0)
1821    }
1822}
1823
1824impl std::ops::Add for RandomnessRound {
1825    type Output = Self;
1826    fn add(self, other: Self) -> Self {
1827        Self(self.0 + other.0)
1828    }
1829}
1830
1831impl std::ops::Add<u64> for RandomnessRound {
1832    type Output = Self;
1833    fn add(self, other: u64) -> Self {
1834        Self(self.0 + other)
1835    }
1836}
1837
1838impl std::ops::Sub for RandomnessRound {
1839    type Output = Self;
1840    fn sub(self, other: Self) -> Self {
1841        Self(self.0 - other.0)
1842    }
1843}
1844
1845impl std::ops::Sub<u64> for RandomnessRound {
1846    type Output = Self;
1847    fn sub(self, other: u64) -> Self {
1848        Self(self.0 - other)
1849    }
1850}
1851
1852impl RandomnessRound {
1853    pub fn new(round: u64) -> Self {
1854        Self(round)
1855    }
1856
1857    pub fn checked_add(self, rhs: u64) -> Option<Self> {
1858        self.0.checked_add(rhs).map(Self)
1859    }
1860
1861    pub fn signature_message(&self) -> Vec<u8> {
1862        "random_beacon round "
1863            .as_bytes()
1864            .iter()
1865            .cloned()
1866            .chain(bcs::to_bytes(&self.0).expect("serialization should not fail"))
1867            .collect()
1868    }
1869}