iota_types/
crypto.rs

1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2024 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5use std::{
6    collections::BTreeMap,
7    fmt::{self, Debug, Display, Formatter},
8    hash::{Hash, Hasher},
9    str::FromStr,
10};
11
12use anyhow::{Error, anyhow};
13use derive_more::{AsMut, AsRef, From};
14pub use enum_dispatch::enum_dispatch;
15use eyre::eyre;
16pub use fastcrypto::traits::{
17    AggregateAuthenticator, Authenticator, EncodeDecodeBase64, KeyPair as KeypairTraits, Signer,
18    SigningKey, ToFromBytes, VerifyingKey,
19};
20use fastcrypto::{
21    bls12381::min_sig::{
22        BLS12381AggregateSignature, BLS12381AggregateSignatureAsBytes, BLS12381KeyPair,
23        BLS12381PrivateKey, BLS12381PublicKey, BLS12381Signature,
24    },
25    ed25519::{
26        Ed25519KeyPair, Ed25519PrivateKey, Ed25519PublicKey, Ed25519PublicKeyAsBytes,
27        Ed25519Signature, Ed25519SignatureAsBytes,
28    },
29    encoding::{Base64, Bech32, Encoding, Hex},
30    error::{FastCryptoError, FastCryptoResult},
31    hash::{Blake2b256, HashFunction},
32    secp256k1::{
33        Secp256k1KeyPair, Secp256k1PublicKey, Secp256k1PublicKeyAsBytes, Secp256k1Signature,
34        Secp256k1SignatureAsBytes,
35    },
36    secp256r1::{
37        Secp256r1KeyPair, Secp256r1PublicKey, Secp256r1PublicKeyAsBytes, Secp256r1Signature,
38        Secp256r1SignatureAsBytes,
39    },
40};
41use fastcrypto_zkp::{bn254::zk_login::ZkLoginInputs, zk_login_utils::Bn254FrElement};
42use iota_sdk_types::crypto::{Intent, IntentMessage, IntentScope};
43use rand::{
44    SeedableRng,
45    rngs::{OsRng, StdRng},
46};
47use roaring::RoaringBitmap;
48use schemars::JsonSchema;
49use serde::{Deserialize, Deserializer, Serialize, ser::Serializer};
50use serde_with::{Bytes, serde_as};
51use strum::EnumString;
52use tracing::{instrument, warn};
53
54use crate::{
55    base_types::{AuthorityName, ConciseableName, IotaAddress},
56    committee::{Committee, CommitteeTrait, EpochId, StakeUnit},
57    error::{IotaError, IotaResult},
58    iota_serde::{IotaBitmap, Readable},
59    signature::GenericSignature,
60};
61
62#[cfg(test)]
63#[path = "unit_tests/crypto_tests.rs"]
64mod crypto_tests;
65
66#[cfg(test)]
67#[path = "unit_tests/intent_tests.rs"]
68mod intent_tests;
69
70////////////////////////////////////////////////////////////////////////
71// Type aliases selecting the signature algorithm for the code base.
72////////////////////////////////////////////////////////////////////////
73// Here we select the types that are used by default in the code base.
74// The whole code base should only:
75// - refer to those aliases and not use the individual scheme implementations
76// - not use the schemes in a way that break genericity (e.g. using their Struct
77//   impl functions)
78// - swap one of those aliases to point to another type if necessary
79//
80// Beware: if you change those aliases to point to another scheme
81// implementation, you will have to change all related aliases to point to
82// concrete types that work with each other. Failure to do so will result in a
83// ton of compilation errors, and worse: it will not make sense!
84
85// Authority Objects
86pub type AuthorityKeyPair = BLS12381KeyPair;
87pub type AuthorityPublicKey = BLS12381PublicKey;
88pub type AuthorityPrivateKey = BLS12381PrivateKey;
89pub type AuthoritySignature = BLS12381Signature;
90pub type AggregateAuthoritySignature = BLS12381AggregateSignature;
91pub type AggregateAuthoritySignatureAsBytes = BLS12381AggregateSignatureAsBytes;
92
93// TODO(joyqvq): prefix these types with Default, DefaultAccountKeyPair etc
94pub type AccountKeyPair = Ed25519KeyPair;
95pub type AccountPublicKey = Ed25519PublicKey;
96pub type AccountPrivateKey = Ed25519PrivateKey;
97
98pub type NetworkKeyPair = Ed25519KeyPair;
99pub type NetworkPublicKey = Ed25519PublicKey;
100pub type NetworkPrivateKey = Ed25519PrivateKey;
101
102pub type DefaultHash = Blake2b256;
103
104pub const DEFAULT_EPOCH_ID: EpochId = 0;
105pub const IOTA_PRIV_KEY_PREFIX: &str = "iotaprivkey";
106
107/// Creates a proof of that the authority account address is owned by the
108/// holder of authority key, and also ensures that the authority
109/// public key exists. A proof of possession is an authority
110/// signature committed over the intent message `intent || message || epoch`
111/// (See more at [struct IntentMessage] and [struct Intent]) where the message
112/// is constructed as `authority_pubkey_bytes || authority_account_address`.
113pub fn generate_proof_of_possession(
114    keypair: &AuthorityKeyPair,
115    address: IotaAddress,
116) -> AuthoritySignature {
117    let mut msg: Vec<u8> = Vec::new();
118    msg.extend_from_slice(keypair.public().as_bytes());
119    msg.extend_from_slice(address.as_ref());
120    AuthoritySignature::new_secure(
121        &IntentMessage::new(Intent::iota_app(IntentScope::ProofOfPossession), msg),
122        &DEFAULT_EPOCH_ID,
123        keypair,
124    )
125}
126
127/// Verify proof of possession against the expected intent message,
128/// consisting of the authority pubkey and the authority account address.
129pub fn verify_proof_of_possession(
130    pop: &AuthoritySignature,
131    authority_pubkey: &AuthorityPublicKey,
132    iota_address: IotaAddress,
133) -> Result<(), IotaError> {
134    authority_pubkey
135        .validate()
136        .map_err(|_| IotaError::InvalidSignature {
137            error: "Fail to validate pubkey".to_string(),
138        })?;
139    let mut msg = authority_pubkey.as_bytes().to_vec();
140    msg.extend_from_slice(iota_address.as_ref());
141    pop.verify_secure(
142        &IntentMessage::new(Intent::iota_app(IntentScope::ProofOfPossession), msg),
143        DEFAULT_EPOCH_ID,
144        authority_pubkey.into(),
145    )
146}
147
148// Account Keys
149//
150// * The following section defines the keypairs that are used by
151// * accounts to interact with Iota.
152// * Currently we support eddsa and ecdsa on Iota.
153
154#[expect(clippy::large_enum_variant)]
155#[derive(Debug, From, PartialEq, Eq)]
156pub enum IotaKeyPair {
157    Ed25519(Ed25519KeyPair),
158    Secp256k1(Secp256k1KeyPair),
159    Secp256r1(Secp256r1KeyPair),
160}
161
162impl IotaKeyPair {
163    pub fn public(&self) -> PublicKey {
164        match self {
165            IotaKeyPair::Ed25519(kp) => PublicKey::Ed25519(kp.public().into()),
166            IotaKeyPair::Secp256k1(kp) => PublicKey::Secp256k1(kp.public().into()),
167            IotaKeyPair::Secp256r1(kp) => PublicKey::Secp256r1(kp.public().into()),
168        }
169    }
170}
171
172impl Clone for IotaKeyPair {
173    fn clone(&self) -> Self {
174        match self {
175            IotaKeyPair::Ed25519(kp) => kp.copy().into(),
176            IotaKeyPair::Secp256k1(kp) => kp.copy().into(),
177            IotaKeyPair::Secp256r1(kp) => kp.copy().into(),
178        }
179    }
180}
181
182impl Signer<Signature> for IotaKeyPair {
183    fn sign(&self, msg: &[u8]) -> Signature {
184        match self {
185            IotaKeyPair::Ed25519(kp) => kp.sign(msg),
186            IotaKeyPair::Secp256k1(kp) => kp.sign(msg),
187            IotaKeyPair::Secp256r1(kp) => kp.sign(msg),
188        }
189    }
190}
191
192impl EncodeDecodeBase64 for IotaKeyPair {
193    fn encode_base64(&self) -> String {
194        Base64::encode(self.to_bytes())
195    }
196
197    fn decode_base64(value: &str) -> FastCryptoResult<Self> {
198        let bytes = Base64::decode(value)?;
199        Self::from_bytes(&bytes).map_err(|_| FastCryptoError::InvalidInput)
200    }
201}
202
203impl IotaKeyPair {
204    pub fn to_bytes(&self) -> Vec<u8> {
205        let mut bytes: Vec<u8> = Vec::new();
206        bytes.push(self.public().flag());
207
208        match self {
209            IotaKeyPair::Ed25519(kp) => {
210                bytes.extend_from_slice(kp.as_bytes());
211            }
212            IotaKeyPair::Secp256k1(kp) => {
213                bytes.extend_from_slice(kp.as_bytes());
214            }
215            IotaKeyPair::Secp256r1(kp) => {
216                bytes.extend_from_slice(kp.as_bytes());
217            }
218        }
219        bytes
220    }
221
222    pub fn from_bytes(bytes: &[u8]) -> Result<Self, eyre::Report> {
223        match SignatureScheme::from_flag_byte(bytes.first().ok_or_else(|| eyre!("Invalid length"))?)
224        {
225            Ok(x) => match x {
226                SignatureScheme::ED25519 => Ok(IotaKeyPair::Ed25519(Ed25519KeyPair::from_bytes(
227                    bytes.get(1..).ok_or_else(|| eyre!("Invalid length"))?,
228                )?)),
229                SignatureScheme::Secp256k1 => {
230                    Ok(IotaKeyPair::Secp256k1(Secp256k1KeyPair::from_bytes(
231                        bytes.get(1..).ok_or_else(|| eyre!("Invalid length"))?,
232                    )?))
233                }
234                SignatureScheme::Secp256r1 => {
235                    Ok(IotaKeyPair::Secp256r1(Secp256r1KeyPair::from_bytes(
236                        bytes.get(1..).ok_or_else(|| eyre!("Invalid length"))?,
237                    )?))
238                }
239                _ => Err(eyre!("Invalid flag byte")),
240            },
241            _ => Err(eyre!("Invalid bytes")),
242        }
243    }
244
245    pub fn to_bytes_no_flag(&self) -> Vec<u8> {
246        match self {
247            IotaKeyPair::Ed25519(kp) => kp.as_bytes().to_vec(),
248            IotaKeyPair::Secp256k1(kp) => kp.as_bytes().to_vec(),
249            IotaKeyPair::Secp256r1(kp) => kp.as_bytes().to_vec(),
250        }
251    }
252
253    /// Encode a IotaKeyPair as `flag || privkey` in Bech32 starting with
254    /// "iotaprivkey" to a string. Note that the pubkey is not encoded.
255    pub fn encode(&self) -> Result<String, eyre::Report> {
256        Bech32::encode(self.to_bytes(), IOTA_PRIV_KEY_PREFIX).map_err(|e| eyre!(e))
257    }
258
259    /// Decode a IotaKeyPair from `flag || privkey` in Bech32 starting with
260    /// "iotaprivkey" to IotaKeyPair. The public key is computed directly from
261    /// the private key bytes.
262    pub fn decode(value: &str) -> Result<Self, eyre::Report> {
263        let bytes = Bech32::decode(value, IOTA_PRIV_KEY_PREFIX)?;
264        Self::from_bytes(&bytes)
265    }
266}
267
268impl Serialize for IotaKeyPair {
269    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
270    where
271        S: Serializer,
272    {
273        let s = self.encode_base64();
274        serializer.serialize_str(&s)
275    }
276}
277
278impl<'de> Deserialize<'de> for IotaKeyPair {
279    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
280    where
281        D: Deserializer<'de>,
282    {
283        use serde::de::Error;
284        let s = String::deserialize(deserializer)?;
285        IotaKeyPair::decode_base64(&s).map_err(|e| Error::custom(e.to_string()))
286    }
287}
288
289#[derive(Clone, Debug, PartialEq, Eq, JsonSchema, Serialize, Deserialize)]
290pub enum PublicKey {
291    Ed25519(Ed25519PublicKeyAsBytes),
292    Secp256k1(Secp256k1PublicKeyAsBytes),
293    Secp256r1(Secp256r1PublicKeyAsBytes),
294    ZkLogin(ZkLoginPublicIdentifier),
295    Passkey(Secp256r1PublicKeyAsBytes),
296}
297
298/// A wrapper struct to retrofit in [enum PublicKey] for zkLogin.
299/// Useful to construct [struct MultiSigPublicKey].
300#[derive(Clone, Debug, PartialEq, Eq, JsonSchema, Serialize, Deserialize)]
301pub struct ZkLoginPublicIdentifier(#[schemars(with = "Base64")] pub Vec<u8>);
302
303impl ZkLoginPublicIdentifier {
304    /// Consists of iss_bytes_len || iss_bytes || padded_32_byte_address_seed.
305    pub fn new(iss: &str, address_seed: &Bn254FrElement) -> IotaResult<Self> {
306        let mut bytes = Vec::new();
307        let iss_bytes = iss.as_bytes();
308        bytes.extend([iss_bytes.len() as u8]);
309        bytes.extend(iss_bytes);
310        bytes.extend(address_seed.padded());
311
312        Ok(Self(bytes))
313    }
314}
315impl AsRef<[u8]> for PublicKey {
316    fn as_ref(&self) -> &[u8] {
317        match self {
318            PublicKey::Ed25519(pk) => &pk.0,
319            PublicKey::Secp256k1(pk) => &pk.0,
320            PublicKey::Secp256r1(pk) => &pk.0,
321            PublicKey::ZkLogin(z) => &z.0,
322            PublicKey::Passkey(pk) => &pk.0,
323        }
324    }
325}
326
327impl EncodeDecodeBase64 for PublicKey {
328    fn encode_base64(&self) -> String {
329        let mut bytes: Vec<u8> = Vec::new();
330        bytes.extend_from_slice(&[self.flag()]);
331        bytes.extend_from_slice(self.as_ref());
332        Base64::encode(&bytes[..])
333    }
334
335    fn decode_base64(value: &str) -> FastCryptoResult<Self> {
336        let bytes = Base64::decode(value)?;
337        match bytes.first() {
338            Some(x) => {
339                if x == &SignatureScheme::ED25519.flag() {
340                    let pk: Ed25519PublicKey =
341                        Ed25519PublicKey::from_bytes(bytes.get(1..).ok_or(
342                            FastCryptoError::InputLengthWrong(Ed25519PublicKey::LENGTH + 1),
343                        )?)?;
344                    Ok(PublicKey::Ed25519((&pk).into()))
345                } else if x == &SignatureScheme::Secp256k1.flag() {
346                    let pk = Secp256k1PublicKey::from_bytes(bytes.get(1..).ok_or(
347                        FastCryptoError::InputLengthWrong(Secp256k1PublicKey::LENGTH + 1),
348                    )?)?;
349                    Ok(PublicKey::Secp256k1((&pk).into()))
350                } else if x == &SignatureScheme::Secp256r1.flag() {
351                    let pk = Secp256r1PublicKey::from_bytes(bytes.get(1..).ok_or(
352                        FastCryptoError::InputLengthWrong(Secp256r1PublicKey::LENGTH + 1),
353                    )?)?;
354                    Ok(PublicKey::Secp256r1((&pk).into()))
355                } else if x == &SignatureScheme::PasskeyAuthenticator.flag() {
356                    let pk = Secp256r1PublicKey::from_bytes(bytes.get(1..).ok_or(
357                        FastCryptoError::InputLengthWrong(Secp256r1PublicKey::LENGTH + 1),
358                    )?)?;
359                    Ok(PublicKey::Passkey((&pk).into()))
360                } else {
361                    Err(FastCryptoError::InvalidInput)
362                }
363            }
364            _ => Err(FastCryptoError::InvalidInput),
365        }
366    }
367}
368
369impl PublicKey {
370    pub fn flag(&self) -> u8 {
371        self.scheme().flag()
372    }
373
374    pub fn try_from_bytes(
375        curve: SignatureScheme,
376        key_bytes: &[u8],
377    ) -> Result<PublicKey, eyre::Report> {
378        match curve {
379            SignatureScheme::ED25519 => Ok(PublicKey::Ed25519(
380                (&Ed25519PublicKey::from_bytes(key_bytes)?).into(),
381            )),
382            SignatureScheme::Secp256k1 => Ok(PublicKey::Secp256k1(
383                (&Secp256k1PublicKey::from_bytes(key_bytes)?).into(),
384            )),
385            SignatureScheme::Secp256r1 => Ok(PublicKey::Secp256r1(
386                (&Secp256r1PublicKey::from_bytes(key_bytes)?).into(),
387            )),
388            SignatureScheme::PasskeyAuthenticator => Ok(PublicKey::Passkey(
389                (&Secp256r1PublicKey::from_bytes(key_bytes)?).into(),
390            )),
391            _ => Err(eyre!("Unsupported curve")),
392        }
393    }
394
395    pub fn scheme(&self) -> SignatureScheme {
396        match self {
397            PublicKey::Ed25519(_) => Ed25519IotaSignature::SCHEME,
398            PublicKey::Secp256k1(_) => Secp256k1IotaSignature::SCHEME,
399            PublicKey::Secp256r1(_) => Secp256r1IotaSignature::SCHEME,
400            PublicKey::ZkLogin(_) => SignatureScheme::ZkLoginAuthenticator,
401            PublicKey::Passkey(_) => SignatureScheme::PasskeyAuthenticator,
402        }
403    }
404
405    pub fn from_zklogin_inputs(inputs: &ZkLoginInputs) -> IotaResult<Self> {
406        Ok(PublicKey::ZkLogin(ZkLoginPublicIdentifier::new(
407            inputs.get_iss(),
408            inputs.get_address_seed(),
409        )?))
410    }
411}
412
413/// Defines the compressed version of the public key that we pass around
414/// in IOTA.
415#[serde_as]
416#[derive(
417    Copy,
418    Clone,
419    PartialEq,
420    Eq,
421    Hash,
422    PartialOrd,
423    Ord,
424    Serialize,
425    Deserialize,
426    schemars::JsonSchema,
427    AsRef,
428)]
429#[as_ref(forward)]
430pub struct AuthorityPublicKeyBytes(
431    #[schemars(with = "Base64")]
432    #[serde_as(as = "Readable<Base64, Bytes>")]
433    pub [u8; AuthorityPublicKey::LENGTH],
434);
435
436impl AuthorityPublicKeyBytes {
437    fn fmt_impl(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
438        let s = Hex::encode(self.0);
439        write!(f, "k#{s}")?;
440        Ok(())
441    }
442}
443
444impl<'a> ConciseableName<'a> for AuthorityPublicKeyBytes {
445    type ConciseTypeRef = ConciseAuthorityPublicKeyBytesRef<'a>;
446    type ConciseType = ConciseAuthorityPublicKeyBytes;
447
448    /// Get a ConciseAuthorityPublicKeyBytesRef. Usage:
449    ///
450    ///   debug!(name = ?authority.concise());
451    ///   format!("{:?}", authority.concise());
452    fn concise(&'a self) -> ConciseAuthorityPublicKeyBytesRef<'a> {
453        ConciseAuthorityPublicKeyBytesRef(self)
454    }
455
456    fn concise_owned(&self) -> ConciseAuthorityPublicKeyBytes {
457        ConciseAuthorityPublicKeyBytes(*self)
458    }
459}
460
461/// A wrapper around AuthorityPublicKeyBytes that provides a concise Debug impl.
462pub struct ConciseAuthorityPublicKeyBytesRef<'a>(&'a AuthorityPublicKeyBytes);
463
464impl Debug for ConciseAuthorityPublicKeyBytesRef<'_> {
465    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
466        let s = Hex::encode(self.0.0.get(0..4).ok_or(std::fmt::Error)?);
467        write!(f, "k#{s}..")
468    }
469}
470
471impl Display for ConciseAuthorityPublicKeyBytesRef<'_> {
472    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
473        Debug::fmt(self, f)
474    }
475}
476
477/// A wrapper around AuthorityPublicKeyBytes but owns it.
478#[derive(Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, schemars::JsonSchema)]
479pub struct ConciseAuthorityPublicKeyBytes(AuthorityPublicKeyBytes);
480
481impl Debug for ConciseAuthorityPublicKeyBytes {
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 ConciseAuthorityPublicKeyBytes {
489    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
490        Debug::fmt(self, f)
491    }
492}
493
494impl TryFrom<AuthorityPublicKeyBytes> for AuthorityPublicKey {
495    type Error = FastCryptoError;
496
497    fn try_from(bytes: AuthorityPublicKeyBytes) -> Result<AuthorityPublicKey, Self::Error> {
498        AuthorityPublicKey::from_bytes(bytes.as_ref())
499    }
500}
501
502impl From<&AuthorityPublicKey> for AuthorityPublicKeyBytes {
503    fn from(pk: &AuthorityPublicKey) -> AuthorityPublicKeyBytes {
504        AuthorityPublicKeyBytes::from_bytes(pk.as_ref()).unwrap()
505    }
506}
507
508impl Debug for AuthorityPublicKeyBytes {
509    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
510        self.fmt_impl(f)
511    }
512}
513
514impl Display for AuthorityPublicKeyBytes {
515    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
516        self.fmt_impl(f)
517    }
518}
519
520impl ToFromBytes for AuthorityPublicKeyBytes {
521    fn from_bytes(bytes: &[u8]) -> Result<Self, fastcrypto::error::FastCryptoError> {
522        let bytes: [u8; AuthorityPublicKey::LENGTH] = bytes
523            .try_into()
524            .map_err(|_| fastcrypto::error::FastCryptoError::InvalidInput)?;
525        Ok(AuthorityPublicKeyBytes(bytes))
526    }
527}
528
529impl AuthorityPublicKeyBytes {
530    pub const ZERO: Self = Self::new([0u8; AuthorityPublicKey::LENGTH]);
531
532    /// This ensures it's impossible to construct an instance with other than
533    /// registered lengths
534    pub const fn new(bytes: [u8; AuthorityPublicKey::LENGTH]) -> AuthorityPublicKeyBytes
535where {
536        AuthorityPublicKeyBytes(bytes)
537    }
538}
539
540impl FromStr for AuthorityPublicKeyBytes {
541    type Err = Error;
542
543    fn from_str(s: &str) -> Result<Self, Self::Err> {
544        let value = Hex::decode(s).map_err(|e| anyhow!(e))?;
545        Self::from_bytes(&value[..]).map_err(|e| anyhow!(e))
546    }
547}
548
549impl Default for AuthorityPublicKeyBytes {
550    fn default() -> Self {
551        Self::ZERO
552    }
553}
554
555// Add helper calls for Authority Signature
556//
557
558pub trait IotaAuthoritySignature {
559    fn verify_secure<T>(
560        &self,
561        value: &IntentMessage<T>,
562        epoch_id: EpochId,
563        author: AuthorityPublicKeyBytes,
564    ) -> Result<(), IotaError>
565    where
566        T: Serialize;
567
568    fn new_secure<T>(
569        value: &IntentMessage<T>,
570        epoch_id: &EpochId,
571        secret: &dyn Signer<Self>,
572    ) -> Self
573    where
574        T: Serialize;
575}
576
577impl IotaAuthoritySignature for AuthoritySignature {
578    #[instrument(level = "trace", skip_all)]
579    fn new_secure<T>(value: &IntentMessage<T>, epoch: &EpochId, secret: &dyn Signer<Self>) -> Self
580    where
581        T: Serialize,
582    {
583        let mut intent_msg_bytes =
584            bcs::to_bytes(&value).expect("Message serialization should not fail");
585        epoch.write(&mut intent_msg_bytes);
586        secret.sign(&intent_msg_bytes)
587    }
588
589    #[instrument(level = "trace", skip_all)]
590    fn verify_secure<T>(
591        &self,
592        value: &IntentMessage<T>,
593        epoch: EpochId,
594        author: AuthorityPublicKeyBytes,
595    ) -> Result<(), IotaError>
596    where
597        T: Serialize,
598    {
599        let mut message = bcs::to_bytes(&value).expect("Message serialization should not fail");
600        epoch.write(&mut message);
601
602        let public_key = AuthorityPublicKey::try_from(author).map_err(|_| {
603            IotaError::KeyConversion(
604                "Failed to serialize public key bytes to valid public key".to_string(),
605            )
606        })?;
607        public_key
608            .verify(&message[..], self)
609            .map_err(|e| IotaError::InvalidSignature {
610                error: format!(
611                    "Fail to verify auth sig {} epoch: {} author: {}",
612                    e,
613                    epoch,
614                    author.concise()
615                ),
616            })
617    }
618}
619
620// TODO: get_key_pair() and get_key_pair_from_bytes() should return KeyPair
621// only. TODO: rename to random_key_pair
622pub fn get_key_pair<KP: KeypairTraits>() -> (IotaAddress, KP)
623where
624    <KP as KeypairTraits>::PubKey: IotaPublicKey,
625{
626    get_key_pair_from_rng(&mut OsRng)
627}
628
629/// Generate a random committee key pairs with a given committee size
630pub fn random_committee_key_pairs_of_size(size: usize) -> Vec<AuthorityKeyPair> {
631    let mut rng = StdRng::from_seed([0; 32]);
632    (0..size)
633        .map(|_| {
634            // TODO: We are generating the keys 4 times to match exactly as how we generate
635            // keys in ConfigBuilder::build (iota-config/src/network_config_builder). This
636            // is because we are using these key generation functions as
637            // fixtures and we call them independently in different paths and
638            // exact the results to be the same. We should eliminate them.
639            let key_pair = get_key_pair_from_rng::<AuthorityKeyPair, _>(&mut rng);
640            get_key_pair_from_rng::<AuthorityKeyPair, _>(&mut rng);
641            get_key_pair_from_rng::<AccountKeyPair, _>(&mut rng);
642            get_key_pair_from_rng::<AccountKeyPair, _>(&mut rng);
643            key_pair.1
644        })
645        .collect()
646}
647
648pub fn deterministic_random_account_key() -> (IotaAddress, AccountKeyPair) {
649    let mut rng = StdRng::from_seed([0; 32]);
650    get_key_pair_from_rng(&mut rng)
651}
652
653pub fn get_account_key_pair() -> (IotaAddress, AccountKeyPair) {
654    get_key_pair()
655}
656
657pub fn get_authority_key_pair() -> (IotaAddress, AuthorityKeyPair) {
658    get_key_pair()
659}
660
661/// Generate a keypair from the specified RNG (useful for testing with seedable
662/// rngs).
663pub fn get_key_pair_from_rng<KP: KeypairTraits, R>(csprng: &mut R) -> (IotaAddress, KP)
664where
665    R: rand::CryptoRng + rand::RngCore,
666    <KP as KeypairTraits>::PubKey: IotaPublicKey,
667{
668    let kp = KP::generate(&mut StdRng::from_rng(csprng).unwrap());
669    (kp.public().into(), kp)
670}
671
672// TODO: C-GETTER
673pub fn get_key_pair_from_bytes<KP: KeypairTraits>(bytes: &[u8]) -> IotaResult<(IotaAddress, KP)>
674where
675    <KP as KeypairTraits>::PubKey: IotaPublicKey,
676{
677    let priv_length = <KP as KeypairTraits>::PrivKey::LENGTH;
678    let pub_key_length = <KP as KeypairTraits>::PubKey::LENGTH;
679    if bytes.len() != priv_length + pub_key_length {
680        return Err(IotaError::KeyConversion(format!(
681            "Invalid input byte length, expected {}: {}",
682            priv_length + pub_key_length,
683            bytes.len()
684        )));
685    }
686    let sk = <KP as KeypairTraits>::PrivKey::from_bytes(
687        bytes
688            .get(..priv_length)
689            .ok_or(IotaError::InvalidPrivateKey)?,
690    )
691    .map_err(|_| IotaError::InvalidPrivateKey)?;
692    let kp: KP = sk.into();
693    Ok((kp.public().into(), kp))
694}
695
696// Account Signatures
697//
698
699// Enums for signature scheme signatures
700#[enum_dispatch]
701#[derive(Clone, JsonSchema, Debug, PartialEq, Eq, Hash)]
702pub enum Signature {
703    Ed25519IotaSignature,
704    Secp256k1IotaSignature,
705    Secp256r1IotaSignature,
706}
707
708impl Serialize for Signature {
709    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
710    where
711        S: Serializer,
712    {
713        let bytes = self.as_ref();
714
715        if serializer.is_human_readable() {
716            let s = Base64::encode(bytes);
717            serializer.serialize_str(&s)
718        } else {
719            serializer.serialize_bytes(bytes)
720        }
721    }
722}
723
724impl<'de> Deserialize<'de> for Signature {
725    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
726    where
727        D: Deserializer<'de>,
728    {
729        use serde::de::Error;
730
731        let bytes = if deserializer.is_human_readable() {
732            let s = String::deserialize(deserializer)?;
733            Base64::decode(&s).map_err(|e| Error::custom(e.to_string()))?
734        } else {
735            let data: Vec<u8> = Vec::deserialize(deserializer)?;
736            data
737        };
738
739        Self::from_bytes(&bytes).map_err(|e| Error::custom(e.to_string()))
740    }
741}
742
743impl Signature {
744    /// The messaged passed in is already hashed form.
745    pub fn new_hashed(hashed_msg: &[u8], secret: &dyn Signer<Signature>) -> Self {
746        Signer::sign(secret, hashed_msg)
747    }
748
749    #[instrument(level = "trace", skip_all)]
750    pub fn new_secure<T>(value: &IntentMessage<T>, secret: &dyn Signer<Signature>) -> Self
751    where
752        T: Serialize,
753    {
754        // Compute the BCS hash of the value in intent message. In the case of
755        // transaction data, this is the BCS hash of `struct TransactionData`,
756        // different from the transaction digest itself that computes the BCS
757        // hash of the Rust type prefix and `struct TransactionData`.
758        // (See `fn digest` in `impl Message for SenderSignedData`).
759        let mut hasher = DefaultHash::default();
760        hasher.update(bcs::to_bytes(&value).expect("Message serialization should not fail"));
761
762        Signer::sign(secret, &hasher.finalize().digest)
763    }
764}
765
766impl AsRef<[u8]> for Signature {
767    fn as_ref(&self) -> &[u8] {
768        match self {
769            Signature::Ed25519IotaSignature(sig) => sig.as_ref(),
770            Signature::Secp256k1IotaSignature(sig) => sig.as_ref(),
771            Signature::Secp256r1IotaSignature(sig) => sig.as_ref(),
772        }
773    }
774}
775impl AsMut<[u8]> for Signature {
776    fn as_mut(&mut self) -> &mut [u8] {
777        match self {
778            Signature::Ed25519IotaSignature(sig) => sig.as_mut(),
779            Signature::Secp256k1IotaSignature(sig) => sig.as_mut(),
780            Signature::Secp256r1IotaSignature(sig) => sig.as_mut(),
781        }
782    }
783}
784
785impl ToFromBytes for Signature {
786    fn from_bytes(bytes: &[u8]) -> Result<Self, FastCryptoError> {
787        match bytes.first() {
788            Some(x) => {
789                if x == &Ed25519IotaSignature::SCHEME.flag() {
790                    Ok(<Ed25519IotaSignature as ToFromBytes>::from_bytes(bytes)?.into())
791                } else if x == &Secp256k1IotaSignature::SCHEME.flag() {
792                    Ok(<Secp256k1IotaSignature as ToFromBytes>::from_bytes(bytes)?.into())
793                } else if x == &Secp256r1IotaSignature::SCHEME.flag() {
794                    Ok(<Secp256r1IotaSignature as ToFromBytes>::from_bytes(bytes)?.into())
795                } else {
796                    Err(FastCryptoError::InvalidInput)
797                }
798            }
799            _ => Err(FastCryptoError::InvalidInput),
800        }
801    }
802}
803
804// BLS Port
805//
806
807impl IotaPublicKey for BLS12381PublicKey {
808    const SIGNATURE_SCHEME: SignatureScheme = SignatureScheme::BLS12381;
809}
810
811// Ed25519 Iota Signature port
812//
813
814#[serde_as]
815#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, AsRef, AsMut)]
816#[as_ref(forward)]
817#[as_mut(forward)]
818pub struct Ed25519IotaSignature(
819    #[schemars(with = "Base64")]
820    #[serde_as(as = "Readable<Base64, Bytes>")]
821    [u8; Ed25519PublicKey::LENGTH + Ed25519Signature::LENGTH + 1],
822);
823
824// Implementation useful for simplify testing when mock signature is needed
825impl Default for Ed25519IotaSignature {
826    fn default() -> Self {
827        Self([0; Ed25519PublicKey::LENGTH + Ed25519Signature::LENGTH + 1])
828    }
829}
830
831impl IotaSignatureInner for Ed25519IotaSignature {
832    type Sig = Ed25519Signature;
833    type PubKey = Ed25519PublicKey;
834    type KeyPair = Ed25519KeyPair;
835    const LENGTH: usize = Ed25519PublicKey::LENGTH + Ed25519Signature::LENGTH + 1;
836}
837
838impl IotaPublicKey for Ed25519PublicKey {
839    const SIGNATURE_SCHEME: SignatureScheme = SignatureScheme::ED25519;
840}
841
842impl ToFromBytes for Ed25519IotaSignature {
843    fn from_bytes(bytes: &[u8]) -> Result<Self, FastCryptoError> {
844        if bytes.len() != Self::LENGTH {
845            return Err(FastCryptoError::InputLengthWrong(Self::LENGTH));
846        }
847        let mut sig_bytes = [0; Self::LENGTH];
848        sig_bytes.copy_from_slice(bytes);
849        Ok(Self(sig_bytes))
850    }
851}
852
853impl Signer<Signature> for Ed25519KeyPair {
854    fn sign(&self, msg: &[u8]) -> Signature {
855        Ed25519IotaSignature::new(self, msg).into()
856    }
857}
858
859// Secp256k1 Iota Signature port
860//
861#[serde_as]
862#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, AsRef, AsMut)]
863#[as_ref(forward)]
864#[as_mut(forward)]
865pub struct Secp256k1IotaSignature(
866    #[schemars(with = "Base64")]
867    #[serde_as(as = "Readable<Base64, Bytes>")]
868    [u8; Secp256k1PublicKey::LENGTH + Secp256k1Signature::LENGTH + 1],
869);
870
871impl IotaSignatureInner for Secp256k1IotaSignature {
872    type Sig = Secp256k1Signature;
873    type PubKey = Secp256k1PublicKey;
874    type KeyPair = Secp256k1KeyPair;
875    const LENGTH: usize = Secp256k1PublicKey::LENGTH + Secp256k1Signature::LENGTH + 1;
876}
877
878impl IotaPublicKey for Secp256k1PublicKey {
879    const SIGNATURE_SCHEME: SignatureScheme = SignatureScheme::Secp256k1;
880}
881
882impl ToFromBytes for Secp256k1IotaSignature {
883    fn from_bytes(bytes: &[u8]) -> Result<Self, FastCryptoError> {
884        if bytes.len() != Self::LENGTH {
885            return Err(FastCryptoError::InputLengthWrong(Self::LENGTH));
886        }
887        let mut sig_bytes = [0; Self::LENGTH];
888        sig_bytes.copy_from_slice(bytes);
889        Ok(Self(sig_bytes))
890    }
891}
892
893impl Signer<Signature> for Secp256k1KeyPair {
894    fn sign(&self, msg: &[u8]) -> Signature {
895        Secp256k1IotaSignature::new(self, msg).into()
896    }
897}
898
899// Secp256r1 Iota Signature port
900//
901#[serde_as]
902#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, AsRef, AsMut)]
903#[as_ref(forward)]
904#[as_mut(forward)]
905pub struct Secp256r1IotaSignature(
906    #[schemars(with = "Base64")]
907    #[serde_as(as = "Readable<Base64, Bytes>")]
908    [u8; Secp256r1PublicKey::LENGTH + Secp256r1Signature::LENGTH + 1],
909);
910
911impl IotaSignatureInner for Secp256r1IotaSignature {
912    type Sig = Secp256r1Signature;
913    type PubKey = Secp256r1PublicKey;
914    type KeyPair = Secp256r1KeyPair;
915    const LENGTH: usize = Secp256r1PublicKey::LENGTH + Secp256r1Signature::LENGTH + 1;
916}
917
918impl IotaPublicKey for Secp256r1PublicKey {
919    const SIGNATURE_SCHEME: SignatureScheme = SignatureScheme::Secp256r1;
920}
921
922impl ToFromBytes for Secp256r1IotaSignature {
923    fn from_bytes(bytes: &[u8]) -> Result<Self, FastCryptoError> {
924        if bytes.len() != Self::LENGTH {
925            return Err(FastCryptoError::InputLengthWrong(Self::LENGTH));
926        }
927        let mut sig_bytes = [0; Self::LENGTH];
928        sig_bytes.copy_from_slice(bytes);
929        Ok(Self(sig_bytes))
930    }
931}
932
933impl Signer<Signature> for Secp256r1KeyPair {
934    fn sign(&self, msg: &[u8]) -> Signature {
935        Secp256r1IotaSignature::new(self, msg).into()
936    }
937}
938
939// This struct exists due to the limitations of the `enum_dispatch` library.
940//
941pub trait IotaSignatureInner: Sized + ToFromBytes + PartialEq + Eq + Hash {
942    type Sig: Authenticator<PubKey = Self::PubKey>;
943    type PubKey: VerifyingKey<Sig = Self::Sig> + IotaPublicKey;
944    type KeyPair: KeypairTraits<PubKey = Self::PubKey, Sig = Self::Sig>;
945
946    const LENGTH: usize = Self::Sig::LENGTH + Self::PubKey::LENGTH + 1;
947    const SCHEME: SignatureScheme = Self::PubKey::SIGNATURE_SCHEME;
948
949    /// Returns the deserialized signature and deserialized pubkey.
950    fn get_verification_inputs(&self) -> IotaResult<(Self::Sig, Self::PubKey)> {
951        let pk = Self::PubKey::from_bytes(self.public_key_bytes())
952            .map_err(|_| IotaError::KeyConversion("Invalid public key".to_string()))?;
953
954        // deserialize the signature
955        let signature = Self::Sig::from_bytes(self.signature_bytes()).map_err(|_| {
956            IotaError::InvalidSignature {
957                error: "Fail to get pubkey and sig".to_string(),
958            }
959        })?;
960
961        Ok((signature, pk))
962    }
963
964    fn new(kp: &Self::KeyPair, message: &[u8]) -> Self {
965        let sig = Signer::sign(kp, message);
966
967        let mut signature_bytes: Vec<u8> = Vec::new();
968        signature_bytes
969            .extend_from_slice(&[<Self::PubKey as IotaPublicKey>::SIGNATURE_SCHEME.flag()]);
970        signature_bytes.extend_from_slice(sig.as_ref());
971        signature_bytes.extend_from_slice(kp.public().as_ref());
972        Self::from_bytes(&signature_bytes[..])
973            .expect("Serialized signature did not have expected size")
974    }
975}
976
977pub trait IotaPublicKey: VerifyingKey {
978    const SIGNATURE_SCHEME: SignatureScheme;
979}
980
981#[enum_dispatch(Signature)]
982pub trait IotaSignature: Sized + ToFromBytes {
983    fn signature_bytes(&self) -> &[u8];
984    fn public_key_bytes(&self) -> &[u8];
985    fn scheme(&self) -> SignatureScheme;
986
987    fn verify_secure<T>(
988        &self,
989        value: &IntentMessage<T>,
990        author: IotaAddress,
991        scheme: SignatureScheme,
992    ) -> IotaResult<()>
993    where
994        T: Serialize;
995}
996
997impl<S: IotaSignatureInner + Sized> IotaSignature for S {
998    fn signature_bytes(&self) -> &[u8] {
999        // Access array slice is safe because the array bytes is initialized as
1000        // flag || signature || pubkey with its defined length.
1001        &self.as_ref()[1..1 + S::Sig::LENGTH]
1002    }
1003
1004    fn public_key_bytes(&self) -> &[u8] {
1005        // Access array slice is safe because the array bytes is initialized as
1006        // flag || signature || pubkey with its defined length.
1007        &self.as_ref()[S::Sig::LENGTH + 1..]
1008    }
1009
1010    fn scheme(&self) -> SignatureScheme {
1011        S::PubKey::SIGNATURE_SCHEME
1012    }
1013
1014    #[instrument(level = "trace", skip_all)]
1015    fn verify_secure<T>(
1016        &self,
1017        value: &IntentMessage<T>,
1018        author: IotaAddress,
1019        scheme: SignatureScheme,
1020    ) -> Result<(), IotaError>
1021    where
1022        T: Serialize,
1023    {
1024        let mut hasher = DefaultHash::default();
1025        hasher.update(bcs::to_bytes(&value).expect("Message serialization should not fail"));
1026        let digest = hasher.finalize().digest;
1027
1028        let (sig, pk) = &self.get_verification_inputs()?;
1029        match scheme {
1030            SignatureScheme::ZkLoginAuthenticator => {} // Pass this check because zk login does
1031            // not derive address from pubkey.
1032            _ => {
1033                let address = IotaAddress::from(pk);
1034                if author != address {
1035                    return Err(IotaError::IncorrectSigner {
1036                        error: format!("Incorrect signer, expected {author:?}, got {address:?}"),
1037                    });
1038                }
1039            }
1040        }
1041
1042        pk.verify(&digest, sig)
1043            .map_err(|e| IotaError::InvalidSignature {
1044                error: format!("Fail to verify user sig {e}"),
1045            })
1046    }
1047}
1048
1049/// AuthoritySignInfoTrait is a trait used specifically for a few structs in
1050/// messages.rs to template on whether the struct is signed by an authority. We
1051/// want to limit how those structs can be instantiated on, hence the sealed
1052/// trait. TODO: We could also add the aggregated signature as another impl of
1053/// the trait.       This will make CertifiedTransaction also an instance of the
1054/// same struct.
1055pub trait AuthoritySignInfoTrait: private::SealedAuthoritySignInfoTrait {
1056    fn verify_secure<T: Serialize>(
1057        &self,
1058        data: &T,
1059        intent: Intent,
1060        committee: &Committee,
1061    ) -> IotaResult;
1062
1063    fn add_to_verification_obligation<'a>(
1064        &self,
1065        committee: &'a Committee,
1066        obligation: &mut VerificationObligation<'a>,
1067        message_index: usize,
1068    ) -> IotaResult<()>;
1069}
1070
1071#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
1072pub struct EmptySignInfo {}
1073impl AuthoritySignInfoTrait for EmptySignInfo {
1074    fn verify_secure<T: Serialize>(
1075        &self,
1076        _data: &T,
1077        _intent: Intent,
1078        _committee: &Committee,
1079    ) -> IotaResult {
1080        Ok(())
1081    }
1082
1083    fn add_to_verification_obligation<'a>(
1084        &self,
1085        _committee: &'a Committee,
1086        _obligation: &mut VerificationObligation<'a>,
1087        _message_index: usize,
1088    ) -> IotaResult<()> {
1089        Ok(())
1090    }
1091}
1092
1093#[derive(Clone, Debug, Eq, Serialize, Deserialize)]
1094pub struct AuthoritySignInfo {
1095    pub epoch: EpochId,
1096    pub authority: AuthorityName,
1097    pub signature: AuthoritySignature,
1098}
1099
1100impl AuthoritySignInfoTrait for AuthoritySignInfo {
1101    #[instrument(level = "trace", skip_all)]
1102    fn verify_secure<T: Serialize>(
1103        &self,
1104        data: &T,
1105        intent: Intent,
1106        committee: &Committee,
1107    ) -> IotaResult<()> {
1108        let mut obligation = VerificationObligation::default();
1109        let idx = obligation.add_message(data, self.epoch, intent);
1110        self.add_to_verification_obligation(committee, &mut obligation, idx)?;
1111        obligation.verify_all()?;
1112        Ok(())
1113    }
1114
1115    fn add_to_verification_obligation<'a>(
1116        &self,
1117        committee: &'a Committee,
1118        obligation: &mut VerificationObligation<'a>,
1119        message_index: usize,
1120    ) -> IotaResult<()> {
1121        fp_ensure!(
1122            self.epoch == committee.epoch(),
1123            IotaError::WrongEpoch {
1124                expected_epoch: committee.epoch(),
1125                actual_epoch: self.epoch,
1126            }
1127        );
1128        let weight = committee.weight(&self.authority);
1129        fp_ensure!(
1130            weight > 0,
1131            IotaError::UnknownSigner {
1132                signer: Some(self.authority.concise().to_string()),
1133                index: None,
1134                committee: Box::new(committee.clone())
1135            }
1136        );
1137
1138        obligation
1139            .public_keys
1140            .get_mut(message_index)
1141            .ok_or(IotaError::InvalidAddress)?
1142            .push(committee.public_key(&self.authority)?);
1143        obligation
1144            .signatures
1145            .get_mut(message_index)
1146            .ok_or(IotaError::InvalidAddress)?
1147            .add_signature(self.signature.clone())
1148            .map_err(|_| IotaError::InvalidSignature {
1149                error: "Fail to aggregator auth sig".to_string(),
1150            })?;
1151        Ok(())
1152    }
1153}
1154
1155impl AuthoritySignInfo {
1156    pub fn new<T>(
1157        epoch: EpochId,
1158        value: &T,
1159        intent: Intent,
1160        name: AuthorityName,
1161        secret: &dyn Signer<AuthoritySignature>,
1162    ) -> Self
1163    where
1164        T: Serialize,
1165    {
1166        Self {
1167            epoch,
1168            authority: name,
1169            signature: AuthoritySignature::new_secure(
1170                &IntentMessage::new(intent, value),
1171                &epoch,
1172                secret,
1173            ),
1174        }
1175    }
1176}
1177
1178impl Hash for AuthoritySignInfo {
1179    fn hash<H: Hasher>(&self, state: &mut H) {
1180        self.epoch.hash(state);
1181        self.authority.hash(state);
1182    }
1183}
1184
1185impl Display for AuthoritySignInfo {
1186    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1187        write!(
1188            f,
1189            "AuthoritySignInfo {{ epoch: {:?}, authority: {} }}",
1190            self.epoch, self.authority,
1191        )
1192    }
1193}
1194
1195impl PartialEq for AuthoritySignInfo {
1196    fn eq(&self, other: &Self) -> bool {
1197        // We do not compare the signature, because there can be multiple
1198        // valid signatures for the same epoch and authority.
1199        self.epoch == other.epoch && self.authority == other.authority
1200    }
1201}
1202
1203/// Represents at least a quorum (could be more) of authority signatures.
1204/// STRONG_THRESHOLD indicates whether to use the quorum threshold for quorum
1205/// check. When STRONG_THRESHOLD is true, the quorum is valid when the total
1206/// stake is at least the quorum threshold (2f+1) of the committee; when
1207/// STRONG_THRESHOLD is false, the quorum is valid when the total stake is at
1208/// least the validity threshold (f+1) of the committee.
1209#[serde_as]
1210#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
1211pub struct AuthorityQuorumSignInfo<const STRONG_THRESHOLD: bool> {
1212    pub epoch: EpochId,
1213    #[schemars(with = "Base64")]
1214    pub signature: AggregateAuthoritySignature,
1215    #[schemars(with = "Base64")]
1216    #[serde_as(as = "IotaBitmap")]
1217    pub signers_map: RoaringBitmap,
1218}
1219
1220pub type AuthorityStrongQuorumSignInfo = AuthorityQuorumSignInfo<true>;
1221
1222// Variant of [AuthorityStrongQuorumSignInfo] but with a serialized signature,
1223// to be used in external APIs.
1224#[serde_as]
1225#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
1226pub struct IotaAuthorityStrongQuorumSignInfo {
1227    pub epoch: EpochId,
1228    pub signature: AggregateAuthoritySignatureAsBytes,
1229    #[schemars(with = "Base64")]
1230    #[serde_as(as = "IotaBitmap")]
1231    pub signers_map: RoaringBitmap,
1232}
1233
1234impl From<&AuthorityStrongQuorumSignInfo> for IotaAuthorityStrongQuorumSignInfo {
1235    fn from(info: &AuthorityStrongQuorumSignInfo) -> Self {
1236        Self {
1237            epoch: info.epoch,
1238            signature: (&info.signature).into(),
1239            signers_map: info.signers_map.clone(),
1240        }
1241    }
1242}
1243
1244impl TryFrom<&IotaAuthorityStrongQuorumSignInfo> for AuthorityStrongQuorumSignInfo {
1245    type Error = FastCryptoError;
1246
1247    fn try_from(info: &IotaAuthorityStrongQuorumSignInfo) -> Result<Self, Self::Error> {
1248        Ok(Self {
1249            epoch: info.epoch,
1250            signature: (&info.signature).try_into()?,
1251            signers_map: info.signers_map.clone(),
1252        })
1253    }
1254}
1255
1256// Note: if you meet an error due to this line it may be because you need an Eq
1257// implementation for `CertifiedTransaction`, or one of the structs that include
1258// it, i.e. `ConfirmationTransaction`, `TransactionInfoResponse` or
1259// `ObjectInfoResponse`.
1260//
1261// Please note that any such implementation must be agnostic to the exact set of
1262// signatures in the certificate, as clients are allowed to equivocate on the
1263// exact nature of valid certificates they send to the system. This assertion is
1264// a simple tool to make sure certificates are accounted for correctly - should
1265// you remove it, you're on your own to maintain the invariant that valid
1266// certificates with distinct signatures are equivalent, but yet-unchecked
1267// certificates that differ on signers aren't.
1268//
1269// see also https://github.com/iotaledger/iota/issues/266
1270static_assertions::assert_not_impl_any!(AuthorityStrongQuorumSignInfo: Hash, Eq, PartialEq);
1271
1272impl<const STRONG_THRESHOLD: bool> AuthoritySignInfoTrait
1273    for AuthorityQuorumSignInfo<STRONG_THRESHOLD>
1274{
1275    #[instrument(level = "trace", skip_all)]
1276    fn verify_secure<T: Serialize>(
1277        &self,
1278        data: &T,
1279        intent: Intent,
1280        committee: &Committee,
1281    ) -> IotaResult {
1282        let mut obligation = VerificationObligation::default();
1283        let idx = obligation.add_message(data, self.epoch, intent);
1284        self.add_to_verification_obligation(committee, &mut obligation, idx)?;
1285        obligation.verify_all()?;
1286        Ok(())
1287    }
1288
1289    fn add_to_verification_obligation<'a>(
1290        &self,
1291        committee: &'a Committee,
1292        obligation: &mut VerificationObligation<'a>,
1293        message_index: usize,
1294    ) -> IotaResult<()> {
1295        // Check epoch
1296        fp_ensure!(
1297            self.epoch == committee.epoch(),
1298            IotaError::WrongEpoch {
1299                expected_epoch: committee.epoch(),
1300                actual_epoch: self.epoch,
1301            }
1302        );
1303
1304        let mut weight = 0;
1305
1306        // Create obligations for the committee signatures
1307        obligation
1308            .signatures
1309            .get_mut(message_index)
1310            .ok_or(IotaError::InvalidAuthenticator)?
1311            .add_aggregate(self.signature.clone())
1312            .map_err(|_| IotaError::InvalidSignature {
1313                error: "Signature Aggregation failed".to_string(),
1314            })?;
1315
1316        let selected_public_keys = obligation
1317            .public_keys
1318            .get_mut(message_index)
1319            .ok_or(IotaError::InvalidAuthenticator)?;
1320
1321        for authority_index in self.signers_map.iter() {
1322            let authority = committee
1323                .authority_by_index(authority_index)
1324                .ok_or_else(|| IotaError::UnknownSigner {
1325                    signer: None,
1326                    index: Some(authority_index),
1327                    committee: Box::new(committee.clone()),
1328                })?;
1329
1330            // Update weight.
1331            let voting_rights = committee.weight(authority);
1332            fp_ensure!(
1333                voting_rights > 0,
1334                IotaError::UnknownSigner {
1335                    signer: Some(authority.concise().to_string()),
1336                    index: Some(authority_index),
1337                    committee: Box::new(committee.clone()),
1338                }
1339            );
1340            weight += voting_rights;
1341
1342            selected_public_keys.push(committee.public_key(authority)?);
1343        }
1344
1345        fp_ensure!(
1346            weight >= Self::quorum_threshold(committee),
1347            IotaError::CertificateRequiresQuorum
1348        );
1349
1350        Ok(())
1351    }
1352}
1353
1354impl<const STRONG_THRESHOLD: bool> AuthorityQuorumSignInfo<STRONG_THRESHOLD> {
1355    pub fn new_from_auth_sign_infos(
1356        auth_sign_infos: Vec<AuthoritySignInfo>,
1357        committee: &Committee,
1358    ) -> IotaResult<Self> {
1359        fp_ensure!(
1360            auth_sign_infos.iter().all(|a| a.epoch == committee.epoch),
1361            IotaError::InvalidSignature {
1362                error: "All signatures must be from the same epoch as the committee".to_string()
1363            }
1364        );
1365        let total_stake: StakeUnit = auth_sign_infos
1366            .iter()
1367            .map(|a| committee.weight(&a.authority))
1368            .sum();
1369        fp_ensure!(
1370            total_stake >= Self::quorum_threshold(committee),
1371            IotaError::InvalidSignature {
1372                error: "Signatures don't have enough stake to form a quorum".to_string()
1373            }
1374        );
1375
1376        let signatures: BTreeMap<_, _> = auth_sign_infos
1377            .into_iter()
1378            .map(|a| (a.authority, a.signature))
1379            .collect();
1380        let mut map = RoaringBitmap::new();
1381        for pk in signatures.keys() {
1382            map.insert(
1383                committee
1384                    .authority_index(pk)
1385                    .ok_or_else(|| IotaError::UnknownSigner {
1386                        signer: Some(pk.concise().to_string()),
1387                        index: None,
1388                        committee: Box::new(committee.clone()),
1389                    })?,
1390            );
1391        }
1392        let sigs: Vec<AuthoritySignature> = signatures.into_values().collect();
1393
1394        Ok(AuthorityQuorumSignInfo {
1395            epoch: committee.epoch,
1396            signature: AggregateAuthoritySignature::aggregate(&sigs).map_err(|e| {
1397                IotaError::InvalidSignature {
1398                    error: e.to_string(),
1399                }
1400            })?,
1401            signers_map: map,
1402        })
1403    }
1404
1405    pub fn authorities<'a>(
1406        &'a self,
1407        committee: &'a Committee,
1408    ) -> impl Iterator<Item = IotaResult<&'a AuthorityName>> {
1409        self.signers_map.iter().map(|i| {
1410            committee
1411                .authority_by_index(i)
1412                .ok_or(IotaError::InvalidAuthenticator)
1413        })
1414    }
1415
1416    pub fn quorum_threshold(committee: &Committee) -> StakeUnit {
1417        committee.threshold::<STRONG_THRESHOLD>()
1418    }
1419
1420    pub fn len(&self) -> u64 {
1421        self.signers_map.len()
1422    }
1423
1424    pub fn is_empty(&self) -> bool {
1425        self.signers_map.is_empty()
1426    }
1427}
1428
1429impl<const S: bool> Display for AuthorityQuorumSignInfo<S> {
1430    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1431        writeln!(
1432            f,
1433            "{} {{ epoch: {:?}, signers_map: {:?} }}",
1434            if S {
1435                "AuthorityStrongQuorumSignInfo"
1436            } else {
1437                "AuthorityWeakQuorumSignInfo"
1438            },
1439            self.epoch,
1440            self.signers_map,
1441        )?;
1442        Ok(())
1443    }
1444}
1445
1446mod private {
1447    pub trait SealedAuthoritySignInfoTrait {}
1448    impl SealedAuthoritySignInfoTrait for super::EmptySignInfo {}
1449    impl SealedAuthoritySignInfoTrait for super::AuthoritySignInfo {}
1450    impl<const S: bool> SealedAuthoritySignInfoTrait for super::AuthorityQuorumSignInfo<S> {}
1451}
1452
1453/// Something that we know how to hash and sign.
1454pub trait Signable<W> {
1455    fn write(&self, writer: &mut W);
1456}
1457
1458pub trait SignableBytes
1459where
1460    Self: Sized,
1461{
1462    fn from_signable_bytes(bytes: &[u8]) -> Result<Self, Error>;
1463}
1464
1465/// Activate the blanket implementation of `Signable` based on serde and BCS.
1466/// * We use `serde_name` to extract a seed from the name of structs and enums.
1467/// * We use `BCS` to generate canonical bytes suitable for hashing and signing.
1468///
1469/// # Safety
1470/// We protect the access to this marker trait through a "sealed trait" pattern:
1471/// impls must be add added here (nowehre else) which lets us note those impls
1472/// MUST be on types that comply with the `serde_name` machinery
1473/// for the below implementations not to panic. One way to check they work is to
1474/// write a unit test for serialization to / deserialization from signable
1475/// bytes.
1476mod bcs_signable {
1477
1478    pub trait BcsSignable: serde::Serialize + serde::de::DeserializeOwned {}
1479    impl BcsSignable for crate::committee::Committee {}
1480    impl BcsSignable for crate::messages_checkpoint::CheckpointSummary {}
1481    impl BcsSignable for crate::messages_checkpoint::CheckpointContents {}
1482    impl BcsSignable for crate::messages_consensus::VersionedMisbehaviorReport {}
1483
1484    impl BcsSignable for crate::effects::TransactionEffects {}
1485    impl BcsSignable for crate::effects::TransactionEvents {}
1486    impl BcsSignable for crate::transaction::TransactionData {}
1487    impl BcsSignable for crate::transaction::SenderSignedData {}
1488    impl BcsSignable for crate::object::ObjectInner {}
1489
1490    impl BcsSignable for crate::accumulator::Accumulator {}
1491
1492    impl BcsSignable for super::bcs_signable_test::Foo {}
1493    #[cfg(test)]
1494    impl BcsSignable for super::bcs_signable_test::Bar {}
1495}
1496
1497impl<T, W> Signable<W> for T
1498where
1499    T: bcs_signable::BcsSignable,
1500    W: std::io::Write,
1501{
1502    fn write(&self, writer: &mut W) {
1503        let name = serde_name::trace_name::<Self>().expect("Self must be a struct or an enum");
1504        // Note: This assumes that names never contain the separator `::`.
1505        write!(writer, "{name}::").expect("Hasher should not fail");
1506        bcs::serialize_into(writer, &self).expect("Message serialization should not fail");
1507    }
1508}
1509
1510/// Manual [`Signable`] impl for MoveAuthenticator.
1511///
1512/// `serde_name::trace_name` returns `None` for types that carry
1513/// `#[serde(flatten)]`, so the blanket impl via `BcsSignable` panics.
1514/// We hardcode the tag and serialise via `self.inner` — the same
1515/// representation that `AsRef<[u8]>` already uses.
1516impl<W> Signable<W> for crate::move_authenticator::MoveAuthenticator
1517where
1518    W: std::io::Write,
1519{
1520    fn write(&self, writer: &mut W) {
1521        let name = "MoveAuthenticator";
1522        write!(writer, "{name}::").expect("Hasher should not fail");
1523        bcs::serialize_into(writer, &self.inner).expect("Message serialization should not fail");
1524    }
1525}
1526
1527impl SignableBytes for crate::move_authenticator::MoveAuthenticator {
1528    fn from_signable_bytes(bytes: &[u8]) -> Result<Self, Error> {
1529        let name = "MoveAuthenticator";
1530        let name_byte_len = format!("{name}::").bytes().len();
1531        let inner = bcs::from_bytes(
1532            bytes
1533                .get(name_byte_len..)
1534                .ok_or_else(|| anyhow!("Failed to deserialize to {name}."))?,
1535        )?;
1536        Ok(Self::from_inner(inner))
1537    }
1538}
1539
1540impl<W> Signable<W> for EpochId
1541where
1542    W: std::io::Write,
1543{
1544    fn write(&self, writer: &mut W) {
1545        bcs::serialize_into(writer, &self).expect("Message serialization should not fail");
1546    }
1547}
1548
1549impl<T> SignableBytes for T
1550where
1551    T: bcs_signable::BcsSignable,
1552{
1553    fn from_signable_bytes(bytes: &[u8]) -> Result<Self, Error> {
1554        // Remove name tag before deserialization using BCS
1555        let name = serde_name::trace_name::<Self>().expect("Self should be a struct or an enum");
1556        let name_byte_len = format!("{name}::").bytes().len();
1557        Ok(bcs::from_bytes(bytes.get(name_byte_len..).ok_or_else(
1558            || anyhow!("Failed to deserialize to {name}."),
1559        )?)?)
1560    }
1561}
1562
1563fn hash<S: Signable<H>, H: HashFunction<DIGEST_SIZE>, const DIGEST_SIZE: usize>(
1564    signable: &S,
1565) -> [u8; DIGEST_SIZE] {
1566    let mut digest = H::default();
1567    signable.write(&mut digest);
1568    let hash = digest.finalize();
1569    hash.into()
1570}
1571
1572pub fn default_hash<S: Signable<DefaultHash>>(signable: &S) -> [u8; 32] {
1573    hash::<S, DefaultHash, 32>(signable)
1574}
1575
1576#[derive(Default)]
1577pub struct VerificationObligation<'a> {
1578    pub messages: Vec<Vec<u8>>,
1579    pub signatures: Vec<AggregateAuthoritySignature>,
1580    pub public_keys: Vec<Vec<&'a AuthorityPublicKey>>,
1581}
1582
1583impl<'a> VerificationObligation<'a> {
1584    pub fn new() -> VerificationObligation<'a> {
1585        VerificationObligation::default()
1586    }
1587
1588    /// Add a new message to the list of messages to be verified.
1589    /// Returns the index of the message.
1590    pub fn add_message<T>(&mut self, message_value: &T, epoch: EpochId, intent: Intent) -> usize
1591    where
1592        T: Serialize,
1593    {
1594        let intent_msg = IntentMessage::new(intent, message_value);
1595        let mut intent_msg_bytes =
1596            bcs::to_bytes(&intent_msg).expect("Message serialization should not fail");
1597        epoch.write(&mut intent_msg_bytes);
1598        self.signatures.push(AggregateAuthoritySignature::default());
1599        self.public_keys.push(Vec::new());
1600        self.messages.push(intent_msg_bytes);
1601        self.messages.len() - 1
1602    }
1603
1604    // Attempts to add signature and public key to the obligation. If this fails,
1605    // ensure to call `verify` manually.
1606    pub fn add_signature_and_public_key(
1607        &mut self,
1608        signature: &AuthoritySignature,
1609        public_key: &'a AuthorityPublicKey,
1610        idx: usize,
1611    ) -> IotaResult<()> {
1612        self.public_keys
1613            .get_mut(idx)
1614            .ok_or(IotaError::InvalidAuthenticator)?
1615            .push(public_key);
1616        self.signatures
1617            .get_mut(idx)
1618            .ok_or(IotaError::InvalidAuthenticator)?
1619            .add_signature(signature.clone())
1620            .map_err(|_| IotaError::InvalidSignature {
1621                error: "Failed to add signature to obligation".to_string(),
1622            })?;
1623        Ok(())
1624    }
1625
1626    #[instrument(level = "trace", skip_all)]
1627    pub fn verify_all(self) -> IotaResult<()> {
1628        let mut pks = Vec::with_capacity(self.public_keys.len());
1629        for pk in self.public_keys.clone() {
1630            pks.push(pk.into_iter());
1631        }
1632        AggregateAuthoritySignature::batch_verify(
1633            &self.signatures.iter().collect::<Vec<_>>()[..],
1634            pks,
1635            &self.messages.iter().map(|x| &x[..]).collect::<Vec<_>>()[..],
1636        )
1637        .map_err(|e| {
1638            let message = format!(
1639                "pks: {:?}, messages: {:?}, sigs: {:?}",
1640                &self.public_keys,
1641                self.messages
1642                    .iter()
1643                    .map(Base64::encode)
1644                    .collect::<Vec<String>>(),
1645                &self
1646                    .signatures
1647                    .iter()
1648                    .map(|s| Base64::encode(s.as_ref()))
1649                    .collect::<Vec<String>>()
1650            );
1651
1652            let chunk_size = 2048;
1653
1654            // This error message may be very long, so we print out the error in chunks of
1655            // to avoid hitting a max log line length on the system.
1656            for (i, chunk) in message
1657                .as_bytes()
1658                .chunks(chunk_size)
1659                .map(std::str::from_utf8)
1660                .enumerate()
1661            {
1662                warn!(
1663                    "Failed to batch verify aggregated auth sig: {} (chunk {}): {}",
1664                    e,
1665                    i,
1666                    chunk.unwrap()
1667                );
1668            }
1669
1670            IotaError::InvalidSignature {
1671                error: format!("Failed to batch verify aggregated auth sig: {e}"),
1672            }
1673        })?;
1674        Ok(())
1675    }
1676}
1677
1678pub mod bcs_signable_test {
1679    use serde::{Deserialize, Serialize};
1680
1681    #[derive(Clone, Serialize, Deserialize)]
1682    pub struct Foo(pub String);
1683
1684    #[cfg(test)]
1685    #[derive(Serialize, Deserialize)]
1686    pub struct Bar(pub String);
1687
1688    #[cfg(test)]
1689    use super::VerificationObligation;
1690
1691    #[cfg(test)]
1692    pub fn get_obligation_input<T>(value: &T) -> (VerificationObligation<'_>, usize)
1693    where
1694        T: super::bcs_signable::BcsSignable,
1695    {
1696        use iota_sdk_types::crypto::{Intent, IntentScope};
1697
1698        let mut obligation = VerificationObligation::default();
1699        // Add the obligation of the authority signature verifications.
1700        let idx = obligation.add_message(
1701            value,
1702            0,
1703            Intent::iota_app(IntentScope::SenderSignedTransaction),
1704        );
1705        (obligation, idx)
1706    }
1707}
1708
1709#[derive(
1710    Clone,
1711    Copy,
1712    Deserialize,
1713    Serialize,
1714    JsonSchema,
1715    Debug,
1716    EnumString,
1717    strum_macros::Display,
1718    PartialEq,
1719    Eq,
1720)]
1721#[strum(serialize_all = "lowercase")]
1722pub enum SignatureScheme {
1723    ED25519,
1724    Secp256k1,
1725    Secp256r1,
1726    BLS12381, // This is currently not supported for user Iota Address.
1727    MultiSig,
1728    ZkLoginAuthenticator,
1729    PasskeyAuthenticator,
1730    MoveAuthenticator,
1731}
1732
1733impl SignatureScheme {
1734    pub fn flag(&self) -> u8 {
1735        match self {
1736            SignatureScheme::ED25519 => 0x00,
1737            SignatureScheme::Secp256k1 => 0x01,
1738            SignatureScheme::Secp256r1 => 0x02,
1739            SignatureScheme::MultiSig => 0x03,
1740            SignatureScheme::BLS12381 => 0x04, // This is currently not supported for user Iota
1741            // Address.
1742            SignatureScheme::ZkLoginAuthenticator => 0x05,
1743            SignatureScheme::PasskeyAuthenticator => 0x06,
1744            SignatureScheme::MoveAuthenticator => 0x07,
1745        }
1746    }
1747
1748    /// Takes as input an hasher and updates it with a flag byte if the input
1749    /// scheme is not ED25519; it does nothing otherwise.
1750    pub fn update_hasher_with_flag(&self, hasher: &mut DefaultHash) {
1751        match self {
1752            SignatureScheme::ED25519 => (),
1753            _ => hasher.update([self.flag()]),
1754        };
1755    }
1756
1757    pub fn from_flag(flag: &str) -> Result<SignatureScheme, IotaError> {
1758        let byte_int = flag
1759            .parse::<u8>()
1760            .map_err(|_| IotaError::KeyConversion("Invalid key scheme".to_string()))?;
1761        Self::from_flag_byte(&byte_int)
1762    }
1763
1764    pub fn from_flag_byte(byte_int: &u8) -> Result<SignatureScheme, IotaError> {
1765        match byte_int {
1766            0x00 => Ok(SignatureScheme::ED25519),
1767            0x01 => Ok(SignatureScheme::Secp256k1),
1768            0x02 => Ok(SignatureScheme::Secp256r1),
1769            0x03 => Ok(SignatureScheme::MultiSig),
1770            0x04 => Ok(SignatureScheme::BLS12381),
1771            0x05 => Ok(SignatureScheme::ZkLoginAuthenticator),
1772            0x06 => Ok(SignatureScheme::PasskeyAuthenticator),
1773            0x07 => Ok(SignatureScheme::MoveAuthenticator),
1774            _ => Err(IotaError::KeyConversion("Invalid key scheme".to_string())),
1775        }
1776    }
1777}
1778/// Unlike [enum Signature], [enum CompressedSignature] does not contain public
1779/// key.
1780#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
1781pub enum CompressedSignature {
1782    Ed25519(Ed25519SignatureAsBytes),
1783    Secp256k1(Secp256k1SignatureAsBytes),
1784    Secp256r1(Secp256r1SignatureAsBytes),
1785    ZkLogin(ZkLoginAuthenticatorAsBytes),
1786    Passkey(PasskeyAuthenticatorAsBytes),
1787    Move(MoveAuthenticatorAsBytes),
1788}
1789
1790#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
1791pub struct ZkLoginAuthenticatorAsBytes(#[schemars(with = "Base64")] pub Vec<u8>);
1792
1793#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
1794pub struct PasskeyAuthenticatorAsBytes(#[schemars(with = "Base64")] pub Vec<u8>);
1795
1796#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
1797pub struct MoveAuthenticatorAsBytes(#[schemars(with = "Base64")] pub Vec<u8>);
1798
1799impl AsRef<[u8]> for CompressedSignature {
1800    fn as_ref(&self) -> &[u8] {
1801        match self {
1802            CompressedSignature::Ed25519(sig) => &sig.0,
1803            CompressedSignature::Secp256k1(sig) => &sig.0,
1804            CompressedSignature::Secp256r1(sig) => &sig.0,
1805            CompressedSignature::ZkLogin(sig) => &sig.0,
1806            CompressedSignature::Passkey(sig) => &sig.0,
1807            CompressedSignature::Move(sig) => &sig.0,
1808        }
1809    }
1810}
1811
1812impl FromStr for Signature {
1813    type Err = eyre::Report;
1814    fn from_str(s: &str) -> Result<Self, Self::Err> {
1815        Self::decode_base64(s).map_err(|e| eyre!("Fail to decode base64 {}", e.to_string()))
1816    }
1817}
1818
1819impl FromStr for PublicKey {
1820    type Err = eyre::Report;
1821    fn from_str(s: &str) -> Result<Self, Self::Err> {
1822        Self::decode_base64(s).map_err(|e| eyre!("Fail to decode base64 {}", e.to_string()))
1823    }
1824}
1825
1826impl FromStr for GenericSignature {
1827    type Err = eyre::Report;
1828    fn from_str(s: &str) -> Result<Self, Self::Err> {
1829        Self::decode_base64(s).map_err(|e| eyre!("Fail to decode base64 {}", e.to_string()))
1830    }
1831}
1832
1833// Types for randomness generation
1834//
1835pub type RandomnessSignature = fastcrypto_tbls::types::Signature;
1836pub type RandomnessPartialSignature = fastcrypto_tbls::tbls::PartialSignature<RandomnessSignature>;
1837pub type RandomnessPrivateKey =
1838    fastcrypto_tbls::ecies_v1::PrivateKey<fastcrypto::groups::bls12381::G2Element>;
1839
1840/// Round number of generated randomness.
1841#[derive(Clone, Copy, Hash, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord)]
1842pub struct RandomnessRound(pub u64);
1843
1844impl Display for RandomnessRound {
1845    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1846        write!(f, "{}", self.0)
1847    }
1848}
1849
1850impl std::ops::Add for RandomnessRound {
1851    type Output = Self;
1852    fn add(self, other: Self) -> Self {
1853        Self(self.0 + other.0)
1854    }
1855}
1856
1857impl std::ops::Add<u64> for RandomnessRound {
1858    type Output = Self;
1859    fn add(self, other: u64) -> Self {
1860        Self(self.0 + other)
1861    }
1862}
1863
1864impl std::ops::Sub for RandomnessRound {
1865    type Output = Self;
1866    fn sub(self, other: Self) -> Self {
1867        Self(self.0 - other.0)
1868    }
1869}
1870
1871impl std::ops::Sub<u64> for RandomnessRound {
1872    type Output = Self;
1873    fn sub(self, other: u64) -> Self {
1874        Self(self.0 - other)
1875    }
1876}
1877
1878impl RandomnessRound {
1879    pub fn new(round: u64) -> Self {
1880        Self(round)
1881    }
1882
1883    pub fn checked_add(self, rhs: u64) -> Option<Self> {
1884        self.0.checked_add(rhs).map(Self)
1885    }
1886
1887    pub fn signature_message(&self) -> Vec<u8> {
1888        "random_beacon round "
1889            .as_bytes()
1890            .iter()
1891            .cloned()
1892            .chain(bcs::to_bytes(&self.0).expect("serialization should not fail"))
1893            .collect()
1894    }
1895}