Skip to main content

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
5// This module broadly handles cryptographic types and operations.
6
7use std::{
8    collections::BTreeMap,
9    fmt::{Debug, Display, Formatter},
10    hash::{Hash, Hasher},
11    str::FromStr,
12};
13
14use anyhow::{Error, anyhow};
15use derive_more::{AsRef, From};
16pub use enum_dispatch::enum_dispatch;
17use eyre::eyre;
18pub use fastcrypto::traits::{
19    AggregateAuthenticator, Authenticator, EncodeDecodeBase64, KeyPair as KeypairTraits, Signer,
20    SigningKey, ToFromBytes, VerifyingKey,
21};
22use fastcrypto::{
23    bls12381::min_sig::{
24        BLS12381AggregateSignature, BLS12381AggregateSignatureAsBytes, BLS12381KeyPair,
25        BLS12381PrivateKey, BLS12381PublicKey, BLS12381Signature,
26    },
27    ed25519::{
28        Ed25519KeyPair, Ed25519PrivateKey, Ed25519PublicKey, Ed25519PublicKeyAsBytes,
29        Ed25519Signature,
30    },
31    encoding::{Base64, Bech32, Encoding, Hex},
32    error::{FastCryptoError, FastCryptoResult},
33    hash::{Blake2b256, HashFunction},
34    secp256k1::{
35        Secp256k1KeyPair, Secp256k1PublicKey, Secp256k1PublicKeyAsBytes, Secp256k1Signature,
36    },
37    secp256r1::{
38        Secp256r1KeyPair, Secp256r1PublicKey, Secp256r1PublicKeyAsBytes, Secp256r1Signature,
39    },
40};
41use iota_sdk_crypto::{Verifier, simple::SimpleVerifier};
42use iota_sdk_types::{
43    Address, SignatureScheme,
44    crypto::{Intent, IntentMessage, IntentScope},
45};
46use rand::{
47    SeedableRng,
48    rngs::{OsRng, StdRng},
49};
50use roaring::RoaringBitmap;
51use serde::{Deserialize, Deserializer, Serialize, ser::Serializer};
52use serde_with::{Bytes, serde_as};
53use tracing::{instrument, warn};
54
55use crate::{
56    base_types::{AuthorityName, ConciseableName, address_from_iota_pub_key},
57    committee::{Committee, CommitteeTrait, EpochId, StakeUnit},
58    error::{IotaError, IotaResult},
59    iota_serde::{IotaBitmap, Readable},
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: Address,
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: Address,
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        // Assemble `flag || signature || public_key` and parse it back into the
185        // SDK signature type, which uses the same byte layout.
186        let mut bytes = vec![self.public().flag()];
187        match self {
188            IotaKeyPair::Ed25519(kp) => {
189                let sig: Ed25519Signature = kp.sign(msg);
190                bytes.extend_from_slice(sig.as_ref());
191            }
192            IotaKeyPair::Secp256k1(kp) => {
193                let sig: Secp256k1Signature = kp.sign(msg);
194                bytes.extend_from_slice(sig.as_ref());
195            }
196            IotaKeyPair::Secp256r1(kp) => {
197                let sig: Secp256r1Signature = kp.sign(msg);
198                bytes.extend_from_slice(sig.as_ref());
199            }
200        }
201        bytes.extend_from_slice(self.public().as_ref());
202        Signature::from_bytes(&bytes).expect("Serialized signature did not have expected size")
203    }
204}
205
206// By-reference conversions into [`IotaKeyPair`], so the per-scheme keypairs
207// (and `IotaKeyPair` itself) can be passed to the signing helpers, which are
208// generic over `impl Into<IotaKeyPair>`.
209impl From<&Ed25519KeyPair> for IotaKeyPair {
210    fn from(kp: &Ed25519KeyPair) -> Self {
211        IotaKeyPair::Ed25519(kp.copy())
212    }
213}
214
215impl From<&Secp256k1KeyPair> for IotaKeyPair {
216    fn from(kp: &Secp256k1KeyPair) -> Self {
217        IotaKeyPair::Secp256k1(kp.copy())
218    }
219}
220
221impl From<&Secp256r1KeyPair> for IotaKeyPair {
222    fn from(kp: &Secp256r1KeyPair) -> Self {
223        IotaKeyPair::Secp256r1(kp.copy())
224    }
225}
226
227impl From<&IotaKeyPair> for IotaKeyPair {
228    fn from(kp: &IotaKeyPair) -> Self {
229        kp.clone()
230    }
231}
232
233impl EncodeDecodeBase64 for IotaKeyPair {
234    fn encode_base64(&self) -> String {
235        Base64::encode(self.to_bytes())
236    }
237
238    fn decode_base64(value: &str) -> FastCryptoResult<Self> {
239        let bytes = Base64::decode(value)?;
240        Self::from_bytes(&bytes).map_err(|_| FastCryptoError::InvalidInput)
241    }
242}
243
244impl IotaKeyPair {
245    pub fn to_bytes(&self) -> Vec<u8> {
246        let mut bytes: Vec<u8> = Vec::new();
247        bytes.push(self.public().flag());
248
249        match self {
250            IotaKeyPair::Ed25519(kp) => {
251                bytes.extend_from_slice(kp.as_bytes());
252            }
253            IotaKeyPair::Secp256k1(kp) => {
254                bytes.extend_from_slice(kp.as_bytes());
255            }
256            IotaKeyPair::Secp256r1(kp) => {
257                bytes.extend_from_slice(kp.as_bytes());
258            }
259        }
260        bytes
261    }
262
263    pub fn from_bytes(bytes: &[u8]) -> Result<Self, eyre::Report> {
264        let (flag, key_bytes) = bytes.split_first().ok_or_else(|| eyre!("Invalid length"))?;
265        match SignatureScheme::from_byte(*flag) {
266            Ok(SignatureScheme::Ed25519) => {
267                Ok(IotaKeyPair::Ed25519(Ed25519KeyPair::from_bytes(key_bytes)?))
268            }
269            Ok(SignatureScheme::Secp256k1) => Ok(IotaKeyPair::Secp256k1(
270                Secp256k1KeyPair::from_bytes(key_bytes)?,
271            )),
272            Ok(SignatureScheme::Secp256r1) => Ok(IotaKeyPair::Secp256r1(
273                Secp256r1KeyPair::from_bytes(key_bytes)?,
274            )),
275            Ok(_) => Err(eyre!("Invalid flag byte")),
276            Err(_) => Err(eyre!("Invalid bytes")),
277        }
278    }
279
280    pub fn to_bytes_no_flag(&self) -> Vec<u8> {
281        match self {
282            IotaKeyPair::Ed25519(kp) => kp.as_bytes().to_vec(),
283            IotaKeyPair::Secp256k1(kp) => kp.as_bytes().to_vec(),
284            IotaKeyPair::Secp256r1(kp) => kp.as_bytes().to_vec(),
285        }
286    }
287
288    /// Encode a IotaKeyPair as `flag || privkey` in Bech32 starting with
289    /// "iotaprivkey" to a string. Note that the pubkey is not encoded.
290    pub fn encode(&self) -> Result<String, eyre::Report> {
291        Bech32::encode(self.to_bytes(), IOTA_PRIV_KEY_PREFIX).map_err(|e| eyre!(e))
292    }
293
294    /// Decode a IotaKeyPair from `flag || privkey` in Bech32 starting with
295    /// "iotaprivkey" to IotaKeyPair. The public key is computed directly from
296    /// the private key bytes.
297    pub fn decode(value: &str) -> Result<Self, eyre::Report> {
298        let bytes = Bech32::decode(value, IOTA_PRIV_KEY_PREFIX)?;
299        Self::from_bytes(&bytes)
300    }
301}
302
303impl Serialize for IotaKeyPair {
304    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
305    where
306        S: Serializer,
307    {
308        let s = self.encode_base64();
309        serializer.serialize_str(&s)
310    }
311}
312
313impl<'de> Deserialize<'de> for IotaKeyPair {
314    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
315    where
316        D: Deserializer<'de>,
317    {
318        use serde::de::Error;
319        let s = String::deserialize(deserializer)?;
320        IotaKeyPair::decode_base64(&s).map_err(|e| Error::custom(e.to_string()))
321    }
322}
323
324#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
325pub enum PublicKey {
326    Ed25519(Ed25519PublicKeyAsBytes),
327    Secp256k1(Secp256k1PublicKeyAsBytes),
328    Secp256r1(Secp256r1PublicKeyAsBytes),
329    Passkey(Secp256r1PublicKeyAsBytes),
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::Passkey(pk) => &pk.0,
339        }
340    }
341}
342
343impl EncodeDecodeBase64 for PublicKey {
344    fn encode_base64(&self) -> String {
345        let mut bytes: Vec<u8> = Vec::new();
346        bytes.extend_from_slice(&[self.flag()]);
347        bytes.extend_from_slice(self.as_ref());
348        Base64::encode(&bytes[..])
349    }
350
351    fn decode_base64(value: &str) -> FastCryptoResult<Self> {
352        let bytes = Base64::decode(value)?;
353        match bytes.first() {
354            Some(x) => {
355                if x == &SignatureScheme::Ed25519.to_u8() {
356                    let pk: Ed25519PublicKey =
357                        Ed25519PublicKey::from_bytes(bytes.get(1..).ok_or(
358                            FastCryptoError::InputLengthWrong(Ed25519PublicKey::LENGTH + 1),
359                        )?)?;
360                    Ok(PublicKey::Ed25519((&pk).into()))
361                } else if x == &SignatureScheme::Secp256k1.to_u8() {
362                    let pk = Secp256k1PublicKey::from_bytes(bytes.get(1..).ok_or(
363                        FastCryptoError::InputLengthWrong(Secp256k1PublicKey::LENGTH + 1),
364                    )?)?;
365                    Ok(PublicKey::Secp256k1((&pk).into()))
366                } else if x == &SignatureScheme::Secp256r1.to_u8() {
367                    let pk = Secp256r1PublicKey::from_bytes(bytes.get(1..).ok_or(
368                        FastCryptoError::InputLengthWrong(Secp256r1PublicKey::LENGTH + 1),
369                    )?)?;
370                    Ok(PublicKey::Secp256r1((&pk).into()))
371                } else if x == &SignatureScheme::PasskeyAuthenticator.to_u8() {
372                    let pk = Secp256r1PublicKey::from_bytes(bytes.get(1..).ok_or(
373                        FastCryptoError::InputLengthWrong(Secp256r1PublicKey::LENGTH + 1),
374                    )?)?;
375                    Ok(PublicKey::Passkey((&pk).into()))
376                } else {
377                    Err(FastCryptoError::InvalidInput)
378                }
379            }
380            _ => Err(FastCryptoError::InvalidInput),
381        }
382    }
383}
384
385impl PublicKey {
386    pub fn flag(&self) -> u8 {
387        self.scheme().to_u8()
388    }
389
390    pub fn try_from_bytes(
391        curve: SignatureScheme,
392        key_bytes: &[u8],
393    ) -> Result<PublicKey, eyre::Report> {
394        match curve {
395            SignatureScheme::Ed25519 => Ok(PublicKey::Ed25519(
396                (&Ed25519PublicKey::from_bytes(key_bytes)?).into(),
397            )),
398            SignatureScheme::Secp256k1 => Ok(PublicKey::Secp256k1(
399                (&Secp256k1PublicKey::from_bytes(key_bytes)?).into(),
400            )),
401            SignatureScheme::Secp256r1 => Ok(PublicKey::Secp256r1(
402                (&Secp256r1PublicKey::from_bytes(key_bytes)?).into(),
403            )),
404            SignatureScheme::PasskeyAuthenticator => Ok(PublicKey::Passkey(
405                (&Secp256r1PublicKey::from_bytes(key_bytes)?).into(),
406            )),
407            _ => Err(eyre!("Unsupported curve")),
408        }
409    }
410
411    pub fn scheme(&self) -> SignatureScheme {
412        match self {
413            PublicKey::Ed25519(_) => SignatureScheme::Ed25519,
414            PublicKey::Secp256k1(_) => SignatureScheme::Secp256k1,
415            PublicKey::Secp256r1(_) => SignatureScheme::Secp256r1,
416            PublicKey::Passkey(_) => SignatureScheme::PasskeyAuthenticator,
417        }
418    }
419}
420
421/// Defines the compressed version of the public key that we pass around
422/// in IOTA.
423#[serde_as]
424#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize, AsRef)]
425#[as_ref(forward)]
426pub struct AuthorityPublicKeyBytes(
427    #[serde_as(as = "Readable<Base64, Bytes>")] pub [u8; AuthorityPublicKey::LENGTH],
428);
429
430impl AuthorityPublicKeyBytes {
431    fn fmt_impl(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
432        let s = Hex::encode(self.0);
433        write!(f, "k#{s}")?;
434        Ok(())
435    }
436}
437
438impl<'a> ConciseableName<'a> for AuthorityPublicKeyBytes {
439    type ConciseTypeRef = ConciseAuthorityPublicKeyBytesRef<'a>;
440    type ConciseType = ConciseAuthorityPublicKeyBytes;
441
442    /// Get a ConciseAuthorityPublicKeyBytesRef. Usage:
443    ///
444    ///   debug!(name = ?authority.concise());
445    ///   format!("{:?}", authority.concise());
446    fn concise(&'a self) -> ConciseAuthorityPublicKeyBytesRef<'a> {
447        ConciseAuthorityPublicKeyBytesRef(self)
448    }
449
450    fn concise_owned(&self) -> ConciseAuthorityPublicKeyBytes {
451        ConciseAuthorityPublicKeyBytes(*self)
452    }
453}
454
455/// A wrapper around AuthorityPublicKeyBytes that provides a concise Debug impl.
456pub struct ConciseAuthorityPublicKeyBytesRef<'a>(&'a AuthorityPublicKeyBytes);
457
458impl Debug for ConciseAuthorityPublicKeyBytesRef<'_> {
459    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
460        let s = Hex::encode(self.0.0.get(0..4).ok_or(std::fmt::Error)?);
461        write!(f, "k#{s}..")
462    }
463}
464
465impl Display for ConciseAuthorityPublicKeyBytesRef<'_> {
466    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
467        Debug::fmt(self, f)
468    }
469}
470
471/// A wrapper around AuthorityPublicKeyBytes but owns it.
472#[derive(Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
473pub struct ConciseAuthorityPublicKeyBytes(AuthorityPublicKeyBytes);
474
475impl Debug for ConciseAuthorityPublicKeyBytes {
476    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
477        let s = Hex::encode(self.0.0.get(0..4).ok_or(std::fmt::Error)?);
478        write!(f, "k#{s}..")
479    }
480}
481
482impl Display for ConciseAuthorityPublicKeyBytes {
483    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
484        Debug::fmt(self, f)
485    }
486}
487
488impl TryFrom<AuthorityPublicKeyBytes> for AuthorityPublicKey {
489    type Error = FastCryptoError;
490
491    fn try_from(bytes: AuthorityPublicKeyBytes) -> Result<AuthorityPublicKey, Self::Error> {
492        AuthorityPublicKey::from_bytes(bytes.as_ref())
493    }
494}
495
496impl From<&AuthorityPublicKey> for AuthorityPublicKeyBytes {
497    fn from(pk: &AuthorityPublicKey) -> AuthorityPublicKeyBytes {
498        AuthorityPublicKeyBytes::from_bytes(pk.as_ref()).unwrap()
499    }
500}
501
502impl Debug for AuthorityPublicKeyBytes {
503    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
504        self.fmt_impl(f)
505    }
506}
507
508impl Display for AuthorityPublicKeyBytes {
509    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
510        self.fmt_impl(f)
511    }
512}
513
514impl ToFromBytes for AuthorityPublicKeyBytes {
515    fn from_bytes(bytes: &[u8]) -> Result<Self, fastcrypto::error::FastCryptoError> {
516        let bytes: [u8; AuthorityPublicKey::LENGTH] = bytes
517            .try_into()
518            .map_err(|_| fastcrypto::error::FastCryptoError::InvalidInput)?;
519        Ok(AuthorityPublicKeyBytes(bytes))
520    }
521}
522
523impl AuthorityPublicKeyBytes {
524    pub const ZERO: Self = Self::new([0u8; AuthorityPublicKey::LENGTH]);
525
526    /// This ensures it's impossible to construct an instance with other than
527    /// registered lengths
528    pub const fn new(bytes: [u8; AuthorityPublicKey::LENGTH]) -> AuthorityPublicKeyBytes
529where {
530        AuthorityPublicKeyBytes(bytes)
531    }
532}
533
534impl FromStr for AuthorityPublicKeyBytes {
535    type Err = Error;
536
537    fn from_str(s: &str) -> Result<Self, Self::Err> {
538        let value = Hex::decode(s).map_err(|e| anyhow!(e))?;
539        Self::from_bytes(&value[..]).map_err(|e| anyhow!(e))
540    }
541}
542
543impl Default for AuthorityPublicKeyBytes {
544    fn default() -> Self {
545        Self::ZERO
546    }
547}
548
549// Add helper calls for Authority Signature
550//
551
552pub trait IotaAuthoritySignature {
553    fn verify_secure<T>(
554        &self,
555        value: &IntentMessage<T>,
556        epoch_id: EpochId,
557        author: AuthorityPublicKeyBytes,
558    ) -> Result<(), IotaError>
559    where
560        T: Serialize;
561
562    fn new_secure<T>(
563        value: &IntentMessage<T>,
564        epoch_id: &EpochId,
565        secret: &dyn Signer<Self>,
566    ) -> Self
567    where
568        T: Serialize;
569}
570
571impl IotaAuthoritySignature for AuthoritySignature {
572    #[instrument(level = "trace", skip_all)]
573    fn new_secure<T>(value: &IntentMessage<T>, epoch: &EpochId, secret: &dyn Signer<Self>) -> Self
574    where
575        T: Serialize,
576    {
577        let mut intent_msg_bytes =
578            bcs::to_bytes(&value).expect("Message serialization should not fail");
579        epoch.write(&mut intent_msg_bytes);
580        secret.sign(&intent_msg_bytes)
581    }
582
583    #[instrument(level = "trace", skip_all)]
584    fn verify_secure<T>(
585        &self,
586        value: &IntentMessage<T>,
587        epoch: EpochId,
588        author: AuthorityPublicKeyBytes,
589    ) -> Result<(), IotaError>
590    where
591        T: Serialize,
592    {
593        let mut message = bcs::to_bytes(&value).expect("Message serialization should not fail");
594        epoch.write(&mut message);
595
596        let public_key = AuthorityPublicKey::try_from(author).map_err(|_| {
597            IotaError::KeyConversion(
598                "Failed to serialize public key bytes to valid public key".to_string(),
599            )
600        })?;
601        public_key
602            .verify(&message[..], self)
603            .map_err(|e| IotaError::InvalidSignature {
604                error: format!(
605                    "Fail to verify auth sig {} epoch: {} author: {}",
606                    e,
607                    epoch,
608                    author.concise()
609                ),
610            })
611    }
612}
613
614// TODO: get_key_pair() and get_key_pair_from_bytes() should return KeyPair
615// only. TODO: rename to random_key_pair
616pub fn get_key_pair<KP: KeypairTraits>() -> (Address, KP)
617where
618    <KP as KeypairTraits>::PubKey: IotaPublicKey,
619{
620    get_key_pair_from_rng(&mut OsRng)
621}
622
623/// Generate a random committee key pairs with a given committee size
624pub fn random_committee_key_pairs_of_size(size: usize) -> Vec<AuthorityKeyPair> {
625    let mut rng = StdRng::from_seed([0; 32]);
626    (0..size)
627        .map(|_| {
628            // TODO: We are generating the keys 4 times to match exactly as how we generate
629            // keys in ConfigBuilder::build (iota-config/src/network_config_builder). This
630            // is because we are using these key generation functions as
631            // fixtures and we call them independently in different paths and
632            // exact the results to be the same. We should eliminate them.
633            let key_pair = get_key_pair_from_rng::<AuthorityKeyPair, _>(&mut rng);
634            get_key_pair_from_rng::<AuthorityKeyPair, _>(&mut rng);
635            get_key_pair_from_rng::<AccountKeyPair, _>(&mut rng);
636            get_key_pair_from_rng::<AccountKeyPair, _>(&mut rng);
637            key_pair.1
638        })
639        .collect()
640}
641
642pub fn deterministic_random_account_key() -> (Address, AccountKeyPair) {
643    let mut rng = StdRng::from_seed([0; 32]);
644    get_key_pair_from_rng(&mut rng)
645}
646
647pub fn get_account_key_pair() -> (Address, AccountKeyPair) {
648    get_key_pair()
649}
650
651pub fn get_authority_key_pair() -> (Address, AuthorityKeyPair) {
652    get_key_pair()
653}
654
655/// Generate a keypair from the specified RNG (useful for testing with seedable
656/// rngs).
657pub fn get_key_pair_from_rng<KP: KeypairTraits, R>(csprng: &mut R) -> (Address, KP)
658where
659    R: rand::CryptoRng + rand::RngCore,
660    <KP as KeypairTraits>::PubKey: IotaPublicKey,
661{
662    let kp = KP::generate(&mut StdRng::from_rng(csprng).unwrap());
663    (address_from_iota_pub_key(kp.public()), kp)
664}
665
666// TODO: C-GETTER
667pub fn get_key_pair_from_bytes<KP: KeypairTraits>(bytes: &[u8]) -> IotaResult<(Address, KP)>
668where
669    <KP as KeypairTraits>::PubKey: IotaPublicKey,
670{
671    let priv_length = <KP as KeypairTraits>::PrivKey::LENGTH;
672    let pub_key_length = <KP as KeypairTraits>::PubKey::LENGTH;
673    if bytes.len() != priv_length + pub_key_length {
674        return Err(IotaError::KeyConversion(format!(
675            "Invalid input byte length, expected {}: {}",
676            priv_length + pub_key_length,
677            bytes.len()
678        )));
679    }
680    let sk = <KP as KeypairTraits>::PrivKey::from_bytes(
681        bytes
682            .get(..priv_length)
683            .ok_or(IotaError::InvalidPrivateKey)?,
684    )
685    .map_err(|_| IotaError::InvalidPrivateKey)?;
686    let kp: KP = sk.into();
687    Ok((address_from_iota_pub_key(kp.public()), kp))
688}
689
690// Account Signatures
691//
692
693// User signatures over transactions. Sourced from the SDK so the node shares a
694// single definition with clients; node-only behaviour (signing and
695// intent-message verification) lives in the [`IotaSignature`] extension trait
696// below.
697pub use iota_sdk_types::SimpleSignature as Signature;
698
699/// An all-zero ed25519 [`Signature`] placeholder, used for system transactions
700/// (which are not signed) and in tests where the signature content is
701/// irrelevant.
702pub fn zero_ed25519_signature() -> Signature {
703    // `flag || signature || public key`, all zero; the leading zero byte selects
704    // the ed25519 scheme.
705    Signature::from_bytes([0u8; 1 + Ed25519Signature::LENGTH + Ed25519PublicKey::LENGTH])
706        .expect("zero-filled ed25519 signature has the expected length")
707}
708
709// BLS Port
710//
711
712impl IotaPublicKey for BLS12381PublicKey {
713    const SIGNATURE_SCHEME: SignatureScheme = SignatureScheme::Bls12381;
714}
715
716impl IotaPublicKey for Ed25519PublicKey {
717    const SIGNATURE_SCHEME: SignatureScheme = SignatureScheme::Ed25519;
718}
719
720impl IotaPublicKey for Secp256k1PublicKey {
721    const SIGNATURE_SCHEME: SignatureScheme = SignatureScheme::Secp256k1;
722}
723
724impl IotaPublicKey for Secp256r1PublicKey {
725    const SIGNATURE_SCHEME: SignatureScheme = SignatureScheme::Secp256r1;
726}
727
728pub trait IotaPublicKey: VerifyingKey {
729    const SIGNATURE_SCHEME: SignatureScheme;
730}
731
732/// Node-only behaviour layered on top of the SDK [`Signature`]
733/// (`iota_sdk_types::SimpleSignature`): construction from a signer and
734/// intent-message verification.
735pub trait IotaSignature: Sized {
736    /// Signs a message that is already in hashed form.
737    fn new_hashed(hashed_msg: &[u8], secret: impl Into<IotaKeyPair>) -> Signature {
738        Signer::sign(&secret.into(), hashed_msg)
739    }
740
741    /// Signs the BCS hash of the value wrapped in the intent message.
742    #[instrument(level = "trace", skip_all)]
743    fn new_secure<T>(value: &IntentMessage<T>, secret: impl Into<IotaKeyPair>) -> Signature
744    where
745        T: Serialize,
746    {
747        // Compute the BCS hash of the value in intent message. In the case of
748        // transaction data, this is the BCS hash of `struct TransactionData`,
749        // different from the transaction digest itself that computes the BCS
750        // hash of the Rust type prefix and `struct TransactionData`.
751        // (See `fn digest` in `impl Message for SenderSignedData`).
752        let mut hasher = DefaultHash::default();
753        hasher.update(bcs::to_bytes(&value).expect("Message serialization should not fail"));
754
755        Signer::sign(&secret.into(), &hasher.finalize().digest)
756    }
757
758    fn verify_secure<T>(&self, value: &IntentMessage<T>, author: Address) -> IotaResult<()>
759    where
760        T: Serialize;
761}
762
763impl IotaSignature for Signature {
764    #[instrument(level = "trace", skip_all)]
765    fn verify_secure<T>(&self, value: &IntentMessage<T>, author: Address) -> Result<(), IotaError>
766    where
767        T: Serialize,
768    {
769        let mut hasher = DefaultHash::default();
770        hasher.update(bcs::to_bytes(&value).expect("Message serialization should not fail"));
771        let digest = hasher.finalize().digest;
772
773        // `SimpleVerifier` only checks the signature against its embedded public
774        // key, so the signer/author binding is enforced here.
775        let address: Address = self.to_public_key().into();
776        if author != address {
777            return Err(IotaError::IncorrectSigner {
778                error: format!("Incorrect signer, expected {author}, got {address}"),
779            });
780        }
781
782        SimpleVerifier
783            .verify(&digest, self)
784            .map_err(|e| IotaError::InvalidSignature {
785                error: format!("Fail to verify user sig {e}"),
786            })
787    }
788}
789
790/// AuthoritySignInfoTrait is a trait used specifically for a few structs in
791/// messages.rs to template on whether the struct is signed by an authority. We
792/// want to limit how those structs can be instantiated on, hence the sealed
793/// trait. TODO: We could also add the aggregated signature as another impl of
794/// the trait.       This will make CertifiedTransaction also an instance of the
795/// same struct.
796pub trait AuthoritySignInfoTrait: private::SealedAuthoritySignInfoTrait {
797    fn verify_secure<T: Serialize>(
798        &self,
799        data: &T,
800        intent: Intent,
801        committee: &Committee,
802    ) -> IotaResult;
803
804    fn add_to_verification_obligation<'a>(
805        &self,
806        committee: &'a Committee,
807        obligation: &mut VerificationObligation<'a>,
808        message_index: usize,
809    ) -> IotaResult<()>;
810}
811
812#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
813pub struct EmptySignInfo {}
814impl AuthoritySignInfoTrait for EmptySignInfo {
815    fn verify_secure<T: Serialize>(
816        &self,
817        _data: &T,
818        _intent: Intent,
819        _committee: &Committee,
820    ) -> IotaResult {
821        Ok(())
822    }
823
824    fn add_to_verification_obligation<'a>(
825        &self,
826        _committee: &'a Committee,
827        _obligation: &mut VerificationObligation<'a>,
828        _message_index: usize,
829    ) -> IotaResult<()> {
830        Ok(())
831    }
832}
833
834#[derive(Clone, Debug, Eq, Serialize, Deserialize)]
835pub struct AuthoritySignInfo {
836    pub epoch: EpochId,
837    pub authority: AuthorityName,
838    pub signature: AuthoritySignature,
839}
840
841impl AuthoritySignInfoTrait for AuthoritySignInfo {
842    #[instrument(level = "trace", skip_all)]
843    fn verify_secure<T: Serialize>(
844        &self,
845        data: &T,
846        intent: Intent,
847        committee: &Committee,
848    ) -> IotaResult<()> {
849        let mut obligation = VerificationObligation::default();
850        let idx = obligation.add_message(data, self.epoch, intent);
851        self.add_to_verification_obligation(committee, &mut obligation, idx)?;
852        obligation.verify_all()?;
853        Ok(())
854    }
855
856    fn add_to_verification_obligation<'a>(
857        &self,
858        committee: &'a Committee,
859        obligation: &mut VerificationObligation<'a>,
860        message_index: usize,
861    ) -> IotaResult<()> {
862        fp_ensure!(
863            self.epoch == committee.epoch(),
864            IotaError::WrongEpoch {
865                expected_epoch: committee.epoch(),
866                actual_epoch: self.epoch,
867            }
868        );
869        let weight = committee.weight(&self.authority);
870        fp_ensure!(
871            weight > 0,
872            IotaError::UnknownSigner {
873                signer: Some(self.authority.concise().to_string()),
874                index: None,
875                committee: Box::new(committee.clone())
876            }
877        );
878
879        obligation
880            .public_keys
881            .get_mut(message_index)
882            .ok_or(IotaError::InvalidAddress)?
883            .push(committee.public_key(&self.authority)?);
884        obligation
885            .signatures
886            .get_mut(message_index)
887            .ok_or(IotaError::InvalidAddress)?
888            .add_signature(self.signature.clone())
889            .map_err(|_| IotaError::InvalidSignature {
890                error: "Fail to aggregator auth sig".to_string(),
891            })?;
892        Ok(())
893    }
894}
895
896impl AuthoritySignInfo {
897    pub fn new<T>(
898        epoch: EpochId,
899        value: &T,
900        intent: Intent,
901        name: AuthorityName,
902        secret: &dyn Signer<AuthoritySignature>,
903    ) -> Self
904    where
905        T: Serialize,
906    {
907        Self {
908            epoch,
909            authority: name,
910            signature: AuthoritySignature::new_secure(
911                &IntentMessage::new(intent, value),
912                &epoch,
913                secret,
914            ),
915        }
916    }
917}
918
919impl Hash for AuthoritySignInfo {
920    fn hash<H: Hasher>(&self, state: &mut H) {
921        self.epoch.hash(state);
922        self.authority.hash(state);
923    }
924}
925
926impl Display for AuthoritySignInfo {
927    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
928        write!(
929            f,
930            "AuthoritySignInfo {{ epoch: {:?}, authority: {} }}",
931            self.epoch, self.authority,
932        )
933    }
934}
935
936impl PartialEq for AuthoritySignInfo {
937    fn eq(&self, other: &Self) -> bool {
938        // We do not compare the signature, because there can be multiple
939        // valid signatures for the same epoch and authority.
940        self.epoch == other.epoch && self.authority == other.authority
941    }
942}
943
944/// Represents at least a quorum (could be more) of authority signatures.
945/// STRONG_THRESHOLD indicates whether to use the quorum threshold for quorum
946/// check. When STRONG_THRESHOLD is true, the quorum is valid when the total
947/// stake is at least the quorum threshold (2f+1) of the committee; when
948/// STRONG_THRESHOLD is false, the quorum is valid when the total stake is at
949/// least the validity threshold (f+1) of the committee.
950#[serde_as]
951#[derive(Clone, Debug, Serialize, Deserialize)]
952pub struct AuthorityQuorumSignInfo<const STRONG_THRESHOLD: bool> {
953    pub epoch: EpochId,
954    pub signature: AggregateAuthoritySignature,
955    #[serde_as(as = "IotaBitmap")]
956    pub signers_map: RoaringBitmap,
957}
958
959pub type AuthorityStrongQuorumSignInfo = AuthorityQuorumSignInfo<true>;
960
961// Variant of [AuthorityStrongQuorumSignInfo] but with a serialized signature,
962// to be used in external APIs.
963#[serde_as]
964#[derive(Clone, Debug, Serialize, Deserialize)]
965pub struct IotaAuthorityStrongQuorumSignInfo {
966    pub epoch: EpochId,
967    pub signature: AggregateAuthoritySignatureAsBytes,
968    #[serde_as(as = "IotaBitmap")]
969    pub signers_map: RoaringBitmap,
970}
971
972impl From<&AuthorityStrongQuorumSignInfo> for IotaAuthorityStrongQuorumSignInfo {
973    fn from(info: &AuthorityStrongQuorumSignInfo) -> Self {
974        Self {
975            epoch: info.epoch,
976            signature: (&info.signature).into(),
977            signers_map: info.signers_map.clone(),
978        }
979    }
980}
981
982impl TryFrom<&IotaAuthorityStrongQuorumSignInfo> for AuthorityStrongQuorumSignInfo {
983    type Error = FastCryptoError;
984
985    fn try_from(info: &IotaAuthorityStrongQuorumSignInfo) -> Result<Self, Self::Error> {
986        Ok(Self {
987            epoch: info.epoch,
988            signature: (&info.signature).try_into()?,
989            signers_map: info.signers_map.clone(),
990        })
991    }
992}
993
994// Note: if you meet an error due to this line it may be because you need an Eq
995// implementation for `CertifiedTransaction`, or one of the structs that include
996// it, i.e. `ConfirmationTransaction`, `TransactionInfoResponse` or
997// `ObjectInfoResponse`.
998//
999// Please note that any such implementation must be agnostic to the exact set of
1000// signatures in the certificate, as clients are allowed to equivocate on the
1001// exact nature of valid certificates they send to the system. This assertion is
1002// a simple tool to make sure certificates are accounted for correctly - should
1003// you remove it, you're on your own to maintain the invariant that valid
1004// certificates with distinct signatures are equivalent, but yet-unchecked
1005// certificates that differ on signers aren't.
1006//
1007// see also https://github.com/iotaledger/iota/issues/266
1008static_assertions::assert_not_impl_any!(AuthorityStrongQuorumSignInfo: Hash, Eq, PartialEq);
1009
1010impl<const STRONG_THRESHOLD: bool> AuthoritySignInfoTrait
1011    for AuthorityQuorumSignInfo<STRONG_THRESHOLD>
1012{
1013    #[instrument(level = "trace", skip_all)]
1014    fn verify_secure<T: Serialize>(
1015        &self,
1016        data: &T,
1017        intent: Intent,
1018        committee: &Committee,
1019    ) -> IotaResult {
1020        let mut obligation = VerificationObligation::default();
1021        let idx = obligation.add_message(data, self.epoch, intent);
1022        self.add_to_verification_obligation(committee, &mut obligation, idx)?;
1023        obligation.verify_all()?;
1024        Ok(())
1025    }
1026
1027    fn add_to_verification_obligation<'a>(
1028        &self,
1029        committee: &'a Committee,
1030        obligation: &mut VerificationObligation<'a>,
1031        message_index: usize,
1032    ) -> IotaResult<()> {
1033        // Check epoch
1034        fp_ensure!(
1035            self.epoch == committee.epoch(),
1036            IotaError::WrongEpoch {
1037                expected_epoch: committee.epoch(),
1038                actual_epoch: self.epoch,
1039            }
1040        );
1041
1042        let mut weight = 0;
1043
1044        // Create obligations for the committee signatures
1045        obligation
1046            .signatures
1047            .get_mut(message_index)
1048            .ok_or(IotaError::InvalidAuthenticator)?
1049            .add_aggregate(self.signature.clone())
1050            .map_err(|_| IotaError::InvalidSignature {
1051                error: "Signature Aggregation failed".to_string(),
1052            })?;
1053
1054        let selected_public_keys = obligation
1055            .public_keys
1056            .get_mut(message_index)
1057            .ok_or(IotaError::InvalidAuthenticator)?;
1058
1059        for authority_index in self.signers_map.iter() {
1060            let authority = committee
1061                .authority_by_index(authority_index)
1062                .ok_or_else(|| IotaError::UnknownSigner {
1063                    signer: None,
1064                    index: Some(authority_index),
1065                    committee: Box::new(committee.clone()),
1066                })?;
1067            let voting_rights = committee.weight(authority);
1068            fp_ensure!(
1069                voting_rights > 0,
1070                IotaError::UnknownSigner {
1071                    signer: Some(authority.concise().to_string()),
1072                    index: Some(authority_index),
1073                    committee: Box::new(committee.clone()),
1074                }
1075            );
1076            weight += voting_rights;
1077
1078            selected_public_keys.push(committee.public_key(authority)?);
1079        }
1080
1081        fp_ensure!(
1082            weight >= Self::quorum_threshold(committee),
1083            IotaError::CertificateRequiresQuorum
1084        );
1085
1086        Ok(())
1087    }
1088}
1089
1090impl<const STRONG_THRESHOLD: bool> AuthorityQuorumSignInfo<STRONG_THRESHOLD> {
1091    pub fn new_from_auth_sign_infos(
1092        auth_sign_infos: Vec<AuthoritySignInfo>,
1093        committee: &Committee,
1094    ) -> IotaResult<Self> {
1095        fp_ensure!(
1096            auth_sign_infos.iter().all(|a| a.epoch == committee.epoch),
1097            IotaError::InvalidSignature {
1098                error: "All signatures must be from the same epoch as the committee".to_string()
1099            }
1100        );
1101        let total_stake: StakeUnit = auth_sign_infos
1102            .iter()
1103            .map(|a| committee.weight(&a.authority))
1104            .sum();
1105        fp_ensure!(
1106            total_stake >= Self::quorum_threshold(committee),
1107            IotaError::InvalidSignature {
1108                error: "Signatures don't have enough stake to form a quorum".to_string()
1109            }
1110        );
1111
1112        let signatures: BTreeMap<_, _> = auth_sign_infos
1113            .into_iter()
1114            .map(|a| (a.authority, a.signature))
1115            .collect();
1116        let mut map = RoaringBitmap::new();
1117        for pk in signatures.keys() {
1118            map.insert(
1119                committee
1120                    .authority_index(pk)
1121                    .ok_or_else(|| IotaError::UnknownSigner {
1122                        signer: Some(pk.concise().to_string()),
1123                        index: None,
1124                        committee: Box::new(committee.clone()),
1125                    })?,
1126            );
1127        }
1128        let sigs: Vec<AuthoritySignature> = signatures.into_values().collect();
1129
1130        Ok(AuthorityQuorumSignInfo {
1131            epoch: committee.epoch,
1132            signature: AggregateAuthoritySignature::aggregate(&sigs).map_err(|e| {
1133                IotaError::InvalidSignature {
1134                    error: e.to_string(),
1135                }
1136            })?,
1137            signers_map: map,
1138        })
1139    }
1140
1141    pub fn authorities<'a>(
1142        &'a self,
1143        committee: &'a Committee,
1144    ) -> impl Iterator<Item = IotaResult<&'a AuthorityName>> {
1145        self.signers_map.iter().map(|i| {
1146            committee
1147                .authority_by_index(i)
1148                .ok_or(IotaError::InvalidAuthenticator)
1149        })
1150    }
1151
1152    pub fn quorum_threshold(committee: &Committee) -> StakeUnit {
1153        committee.threshold::<STRONG_THRESHOLD>()
1154    }
1155
1156    pub fn len(&self) -> u64 {
1157        self.signers_map.len()
1158    }
1159
1160    pub fn is_empty(&self) -> bool {
1161        self.signers_map.is_empty()
1162    }
1163}
1164
1165impl<const S: bool> Display for AuthorityQuorumSignInfo<S> {
1166    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1167        writeln!(
1168            f,
1169            "{} {{ epoch: {:?}, signers_map: {:?} }}",
1170            if S {
1171                "AuthorityStrongQuorumSignInfo"
1172            } else {
1173                "AuthorityWeakQuorumSignInfo"
1174            },
1175            self.epoch,
1176            self.signers_map,
1177        )?;
1178        Ok(())
1179    }
1180}
1181
1182mod private {
1183    pub trait SealedAuthoritySignInfoTrait {}
1184    impl SealedAuthoritySignInfoTrait for super::EmptySignInfo {}
1185    impl SealedAuthoritySignInfoTrait for super::AuthoritySignInfo {}
1186    impl<const S: bool> SealedAuthoritySignInfoTrait for super::AuthorityQuorumSignInfo<S> {}
1187}
1188
1189/// Something that we know how to hash and sign.
1190pub trait Signable<W> {
1191    fn write(&self, writer: &mut W);
1192}
1193
1194/// Activate the blanket implementation of `Signable` based on serde and BCS.
1195/// * We use `serde_name` to extract a seed from the name of structs and enums.
1196/// * We use `BCS` to generate canonical bytes suitable for hashing and signing.
1197///
1198/// # Safety
1199/// We protect the access to this marker trait through a "sealed trait" pattern:
1200/// impls must be add added here (nowehre else) which lets us note those impls
1201/// MUST be on types that comply with the `serde_name` machinery
1202/// for the below implementations not to panic. One way to check they work is to
1203/// write a unit test for serialization to / deserialization from signable
1204/// bytes.
1205mod bcs_signable {
1206
1207    pub trait BcsSignable: serde::Serialize + serde::de::DeserializeOwned {}
1208    impl BcsSignable for crate::committee::Committee {}
1209    impl BcsSignable for iota_sdk_types::checkpoint::CheckpointSummary {}
1210    impl BcsSignable for iota_sdk_types::checkpoint::CheckpointContents {}
1211    #[cfg(not(target_arch = "wasm32"))]
1212    impl BcsSignable for crate::messages_consensus::VersionedMisbehaviorReport {}
1213
1214    impl BcsSignable for crate::effects::TransactionEffects {}
1215    impl BcsSignable for crate::effects::TransactionEvents {}
1216    impl BcsSignable for crate::transaction::TransactionData {}
1217    impl BcsSignable for crate::transaction::SenderSignedData {}
1218    impl BcsSignable for crate::object::ObjectInner {}
1219
1220    impl BcsSignable for crate::global_state_hash::GlobalStateHash {}
1221
1222    impl BcsSignable for super::bcs_signable_test::Foo {}
1223    #[cfg(test)]
1224    impl BcsSignable for super::bcs_signable_test::Bar {}
1225}
1226
1227impl<T, W> Signable<W> for T
1228where
1229    T: bcs_signable::BcsSignable,
1230    W: std::io::Write,
1231{
1232    fn write(&self, writer: &mut W) {
1233        let name = serde_name::trace_name::<Self>().expect("Self must be a struct or an enum");
1234        // Note: This assumes that names never contain the separator `::`.
1235        write!(writer, "{name}::").expect("Hasher should not fail");
1236        bcs::serialize_into(writer, &self).expect("Message serialization should not fail");
1237    }
1238}
1239
1240impl<W> Signable<W> for EpochId
1241where
1242    W: std::io::Write,
1243{
1244    fn write(&self, writer: &mut W) {
1245        bcs::serialize_into(writer, &self).expect("Message serialization should not fail");
1246    }
1247}
1248
1249fn hash<S: Signable<H>, H: HashFunction<DIGEST_SIZE>, const DIGEST_SIZE: usize>(
1250    signable: &S,
1251) -> [u8; DIGEST_SIZE] {
1252    let mut digest = H::default();
1253    signable.write(&mut digest);
1254    let hash = digest.finalize();
1255    hash.into()
1256}
1257
1258pub fn default_hash<S: Signable<DefaultHash>>(signable: &S) -> [u8; 32] {
1259    hash::<S, DefaultHash, 32>(signable)
1260}
1261
1262#[derive(Default)]
1263pub struct VerificationObligation<'a> {
1264    pub messages: Vec<Vec<u8>>,
1265    pub signatures: Vec<AggregateAuthoritySignature>,
1266    pub public_keys: Vec<Vec<&'a AuthorityPublicKey>>,
1267}
1268
1269impl<'a> VerificationObligation<'a> {
1270    pub fn new() -> VerificationObligation<'a> {
1271        VerificationObligation::default()
1272    }
1273
1274    /// Add a new message to the list of messages to be verified.
1275    /// Returns the index of the message.
1276    pub fn add_message<T>(&mut self, message_value: &T, epoch: EpochId, intent: Intent) -> usize
1277    where
1278        T: Serialize,
1279    {
1280        let intent_msg = IntentMessage::new(intent, message_value);
1281        let mut intent_msg_bytes =
1282            bcs::to_bytes(&intent_msg).expect("Message serialization should not fail");
1283        epoch.write(&mut intent_msg_bytes);
1284        self.signatures.push(AggregateAuthoritySignature::default());
1285        self.public_keys.push(Vec::new());
1286        self.messages.push(intent_msg_bytes);
1287        self.messages.len() - 1
1288    }
1289
1290    // Attempts to add signature and public key to the obligation. If this fails,
1291    // ensure to call `verify` manually.
1292    pub fn add_signature_and_public_key(
1293        &mut self,
1294        signature: &AuthoritySignature,
1295        public_key: &'a AuthorityPublicKey,
1296        idx: usize,
1297    ) -> IotaResult<()> {
1298        self.public_keys
1299            .get_mut(idx)
1300            .ok_or(IotaError::InvalidAuthenticator)?
1301            .push(public_key);
1302        self.signatures
1303            .get_mut(idx)
1304            .ok_or(IotaError::InvalidAuthenticator)?
1305            .add_signature(signature.clone())
1306            .map_err(|_| IotaError::InvalidSignature {
1307                error: "Failed to add signature to obligation".to_string(),
1308            })?;
1309        Ok(())
1310    }
1311
1312    #[instrument(level = "trace", skip_all)]
1313    pub fn verify_all(self) -> IotaResult<()> {
1314        let mut pks = Vec::with_capacity(self.public_keys.len());
1315        for pk in self.public_keys.clone() {
1316            pks.push(pk.into_iter());
1317        }
1318        AggregateAuthoritySignature::batch_verify(
1319            &self.signatures.iter().collect::<Vec<_>>()[..],
1320            pks,
1321            &self.messages.iter().map(|x| &x[..]).collect::<Vec<_>>()[..],
1322        )
1323        .map_err(|e| {
1324            let message = format!(
1325                "pks: {:?}, messages: {:?}, sigs: {:?}",
1326                self.public_keys,
1327                self.messages
1328                    .iter()
1329                    .map(Base64::encode)
1330                    .collect::<Vec<String>>(),
1331                self.signatures
1332                    .iter()
1333                    .map(|s| Base64::encode(s.as_ref()))
1334                    .collect::<Vec<String>>()
1335            );
1336
1337            let chunk_size = 2048;
1338
1339            // This error message may be very long, so we print out the error in chunks of
1340            // to avoid hitting a max log line length on the system.
1341            for (i, chunk) in message
1342                .as_bytes()
1343                .chunks(chunk_size)
1344                .map(std::str::from_utf8)
1345                .enumerate()
1346            {
1347                warn!(
1348                    "Failed to batch verify aggregated auth sig: {} (chunk {}): {}",
1349                    e,
1350                    i,
1351                    chunk.unwrap()
1352                );
1353            }
1354
1355            IotaError::InvalidSignature {
1356                error: format!("Failed to batch verify aggregated auth sig: {e}"),
1357            }
1358        })?;
1359        Ok(())
1360    }
1361}
1362
1363pub mod bcs_signable_test {
1364    use serde::{Deserialize, Serialize};
1365
1366    #[derive(Clone, Serialize, Deserialize)]
1367    pub struct Foo(pub String);
1368
1369    #[cfg(test)]
1370    #[derive(Serialize, Deserialize)]
1371    pub struct Bar(pub String);
1372
1373    #[cfg(test)]
1374    use super::VerificationObligation;
1375
1376    #[cfg(test)]
1377    pub fn get_obligation_input<T>(value: &T) -> (VerificationObligation<'_>, usize)
1378    where
1379        T: super::bcs_signable::BcsSignable,
1380    {
1381        use iota_sdk_types::crypto::{Intent, IntentScope};
1382
1383        let mut obligation = VerificationObligation::default();
1384        // Add the obligation of the authority signature verifications.
1385        let idx = obligation.add_message(
1386            value,
1387            0,
1388            Intent::iota_app(IntentScope::SenderSignedTransaction),
1389        );
1390        (obligation, idx)
1391    }
1392}
1393
1394impl FromStr for PublicKey {
1395    type Err = eyre::Report;
1396    fn from_str(s: &str) -> Result<Self, Self::Err> {
1397        Self::decode_base64(s).map_err(|e| eyre!("Fail to decode base64 {}", e.to_string()))
1398    }
1399}
1400
1401// Types for randomness generation
1402//
1403#[cfg(not(target_arch = "wasm32"))]
1404pub type RandomnessSignature = fastcrypto_tbls::types::Signature;
1405#[cfg(not(target_arch = "wasm32"))]
1406pub type RandomnessPartialSignature = fastcrypto_tbls::tbls::PartialSignature<RandomnessSignature>;
1407#[cfg(not(target_arch = "wasm32"))]
1408pub type RandomnessPrivateKey =
1409    fastcrypto_tbls::ecies_v1::PrivateKey<fastcrypto::groups::bls12381::G2Element>;