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::{Ed25519KeyPair, Ed25519PublicKey, Ed25519PublicKeyAsBytes, Ed25519Signature},
28    encoding::{Base64, Encoding, Hex},
29    error::{FastCryptoError, FastCryptoResult},
30    hash::{Blake2b256, HashFunction},
31    secp256k1::{Secp256k1PublicKey, Secp256k1PublicKeyAsBytes},
32    secp256r1::{Secp256r1PublicKey, Secp256r1PublicKeyAsBytes},
33    serde_helpers::BytesRepresentation,
34};
35use iota_sdk_crypto::{
36    ed25519::Ed25519PrivateKey, secp256k1::Secp256k1PrivateKey, secp256r1::Secp256r1PrivateKey,
37    simple::SimpleKeypair,
38};
39use iota_sdk_types::{
40    Address, SignatureScheme,
41    crypto::{Intent, IntentMessage, IntentScope, SimpleSignature},
42};
43use rand::{
44    SeedableRng,
45    rand_core::UnwrapErr,
46    rngs::{StdRng, SysRng},
47};
48use rand08::SeedableRng as _;
49use roaring::RoaringBitmap;
50use serde::{Deserialize, Serialize};
51use serde_with::{Bytes, serde_as};
52use tracing::{instrument, warn};
53
54use crate::{
55    base_types::{AuthorityName, ConciseableName},
56    committee::{Committee, CommitteeTrait, EpochId, StakeUnit},
57    error::{IotaError, IotaResult},
58    iota_serde::{IotaBitmap, Readable},
59};
60
61#[cfg(test)]
62#[path = "unit_tests/crypto_tests.rs"]
63mod crypto_tests;
64
65#[cfg(test)]
66#[path = "unit_tests/intent_tests.rs"]
67mod intent_tests;
68
69////////////////////////////////////////////////////////////////////////
70// Type aliases selecting the signature algorithm for the code base.
71////////////////////////////////////////////////////////////////////////
72// Here we select the types that are used by default in the code base.
73// The whole code base should only:
74// - refer to those aliases and not use the individual scheme implementations
75// - not use the schemes in a way that break genericity (e.g. using their Struct impl functions)
76// - swap one of those aliases to point to another type if necessary
77//
78// Beware: if you change those aliases to point to another scheme
79// implementation, you will have to change all related aliases to point to
80// concrete types that work with each other. Failure to do so will result in a
81// ton of compilation errors, and worse: it will not make sense!
82
83// Authority Objects
84pub type AuthorityKeyPair = BLS12381KeyPair;
85pub type AuthorityPublicKey = BLS12381PublicKey;
86pub type AuthorityPrivateKey = BLS12381PrivateKey;
87pub type AuthoritySignature = BLS12381Signature;
88pub type AggregateAuthorityPublicKey = BLS12381PublicKey;
89pub type AggregateAuthoritySignature = BLS12381AggregateSignature;
90pub type AggregateAuthoritySignatureAsBytes = BLS12381AggregateSignatureAsBytes;
91
92pub type AccountPrivateKey = Ed25519PrivateKey;
93
94pub type NetworkKeyPair = Ed25519KeyPair;
95pub type NetworkPublicKey = Ed25519PublicKey;
96pub type NetworkPrivateKey = Ed25519PrivateKey;
97
98pub type DefaultHash = Blake2b256;
99
100pub const DEFAULT_EPOCH_ID: EpochId = 0;
101pub const IOTA_PRIV_KEY_PREFIX: &str = "iotaprivkey";
102
103/// Creates a proof of that the authority account address is owned by the
104/// holder of authority key, and also ensures that the authority
105/// public key exists. A proof of possession is an authority
106/// signature committed over the intent message `intent || message || epoch`
107/// (See more at [struct IntentMessage] and [struct Intent]) where the message
108/// is constructed as `authority_pubkey_bytes || authority_account_address`.
109pub fn generate_proof_of_possession(
110    keypair: &AuthorityKeyPair,
111    address: Address,
112) -> AuthoritySignature {
113    let mut msg: Vec<u8> = Vec::new();
114    msg.extend_from_slice(keypair.public().as_bytes());
115    msg.extend_from_slice(address.as_ref());
116    AuthoritySignature::new_secure(
117        &IntentMessage::new(Intent::iota_app(IntentScope::ProofOfPossession), msg),
118        &DEFAULT_EPOCH_ID,
119        keypair,
120    )
121}
122
123/// Verify proof of possession against the expected intent message,
124/// consisting of the authority pubkey and the authority account address.
125pub fn verify_proof_of_possession(
126    pop: &AuthoritySignature,
127    authority_pubkey: &AuthorityPublicKey,
128    iota_address: Address,
129) -> Result<(), IotaError> {
130    authority_pubkey
131        .validate()
132        .map_err(|_| IotaError::InvalidSignature {
133            error: "Fail to validate pubkey".to_string(),
134        })?;
135    let mut msg = authority_pubkey.as_bytes().to_vec();
136    msg.extend_from_slice(iota_address.as_ref());
137    pop.verify_secure(
138        &IntentMessage::new(Intent::iota_app(IntentScope::ProofOfPossession), msg),
139        DEFAULT_EPOCH_ID,
140        authority_pubkey.into(),
141    )
142}
143
144/// The validator network stacks keep using the fastcrypto ed25519 keypair
145/// type; this conversion lets those keys be stored in configs as
146/// [`SimpleKeypair`].
147pub fn network_to_simple_keypair(kp: &NetworkKeyPair) -> SimpleKeypair {
148    use iota_sdk_crypto::ToFromBytes as _;
149
150    SimpleKeypair::from(
151        Ed25519PrivateKey::from_bytes(kp.as_bytes()).expect("valid ed25519 private key bytes"),
152    )
153}
154
155/// Convert a stored [`SimpleKeypair`] back into the fastcrypto ed25519 keypair
156/// consumed by the validator network stacks. Fails if the key is not ed25519.
157pub fn simple_to_network_keypair(kp: &SimpleKeypair) -> Result<NetworkKeyPair, Error> {
158    if kp.scheme() != SignatureScheme::Ed25519 {
159        return Err(anyhow!(
160            "invalid scheme for network keypair: {}",
161            kp.scheme()
162        ));
163    }
164    NetworkKeyPair::from_bytes(&kp.to_bytes()[1..]).map_err(|e| anyhow!(e))
165}
166
167impl From<&SimpleKeypair> for PublicKey {
168    fn from(kp: &SimpleKeypair) -> Self {
169        match kp.public_key() {
170            iota_sdk_types::PublicKey::Ed25519(pk) => {
171                PublicKey::Ed25519(BytesRepresentation(pk.into_bytes()))
172            }
173            iota_sdk_types::PublicKey::Secp256k1(pk) => {
174                PublicKey::Secp256k1(BytesRepresentation(pk.into_bytes()))
175            }
176            iota_sdk_types::PublicKey::Secp256r1(pk) => {
177                PublicKey::Secp256r1(BytesRepresentation(pk.into_bytes()))
178            }
179            _ => unreachable!("SimpleKeypair keys use the three simple signature schemes"),
180        }
181    }
182}
183
184#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
185pub enum PublicKey {
186    Ed25519(Ed25519PublicKeyAsBytes),
187    Secp256k1(Secp256k1PublicKeyAsBytes),
188    Secp256r1(Secp256r1PublicKeyAsBytes),
189    Passkey(Secp256r1PublicKeyAsBytes),
190}
191
192impl AsRef<[u8]> for PublicKey {
193    fn as_ref(&self) -> &[u8] {
194        match self {
195            PublicKey::Ed25519(pk) => &pk.0,
196            PublicKey::Secp256k1(pk) => &pk.0,
197            PublicKey::Secp256r1(pk) => &pk.0,
198            PublicKey::Passkey(pk) => &pk.0,
199        }
200    }
201}
202
203impl EncodeDecodeBase64 for PublicKey {
204    fn encode_base64(&self) -> String {
205        let mut bytes: Vec<u8> = Vec::new();
206        bytes.extend_from_slice(&[self.flag()]);
207        bytes.extend_from_slice(self.as_ref());
208        Base64::encode(&bytes[..])
209    }
210
211    fn decode_base64(value: &str) -> FastCryptoResult<Self> {
212        let bytes = Base64::decode(value)?;
213        match bytes.first() {
214            Some(x) => {
215                if x == &SignatureScheme::Ed25519.to_u8() {
216                    let pk: Ed25519PublicKey =
217                        Ed25519PublicKey::from_bytes(bytes.get(1..).ok_or(
218                            FastCryptoError::InputLengthWrong(Ed25519PublicKey::LENGTH + 1),
219                        )?)?;
220                    Ok(PublicKey::Ed25519((&pk).into()))
221                } else if x == &SignatureScheme::Secp256k1.to_u8() {
222                    let pk = Secp256k1PublicKey::from_bytes(bytes.get(1..).ok_or(
223                        FastCryptoError::InputLengthWrong(Secp256k1PublicKey::LENGTH + 1),
224                    )?)?;
225                    Ok(PublicKey::Secp256k1((&pk).into()))
226                } else if x == &SignatureScheme::Secp256r1.to_u8() {
227                    let pk = Secp256r1PublicKey::from_bytes(bytes.get(1..).ok_or(
228                        FastCryptoError::InputLengthWrong(Secp256r1PublicKey::LENGTH + 1),
229                    )?)?;
230                    Ok(PublicKey::Secp256r1((&pk).into()))
231                } else if x == &SignatureScheme::PasskeyAuthenticator.to_u8() {
232                    let pk = Secp256r1PublicKey::from_bytes(bytes.get(1..).ok_or(
233                        FastCryptoError::InputLengthWrong(Secp256r1PublicKey::LENGTH + 1),
234                    )?)?;
235                    Ok(PublicKey::Passkey((&pk).into()))
236                } else {
237                    Err(FastCryptoError::InvalidInput)
238                }
239            }
240            _ => Err(FastCryptoError::InvalidInput),
241        }
242    }
243}
244
245impl PublicKey {
246    pub fn flag(&self) -> u8 {
247        self.scheme().to_u8()
248    }
249
250    pub fn try_from_bytes(
251        curve: SignatureScheme,
252        key_bytes: &[u8],
253    ) -> Result<PublicKey, eyre::Report> {
254        match curve {
255            SignatureScheme::Ed25519 => Ok(PublicKey::Ed25519(
256                (&Ed25519PublicKey::from_bytes(key_bytes)?).into(),
257            )),
258            SignatureScheme::Secp256k1 => Ok(PublicKey::Secp256k1(
259                (&Secp256k1PublicKey::from_bytes(key_bytes)?).into(),
260            )),
261            SignatureScheme::Secp256r1 => Ok(PublicKey::Secp256r1(
262                (&Secp256r1PublicKey::from_bytes(key_bytes)?).into(),
263            )),
264            SignatureScheme::PasskeyAuthenticator => Ok(PublicKey::Passkey(
265                (&Secp256r1PublicKey::from_bytes(key_bytes)?).into(),
266            )),
267            _ => Err(eyre!("Unsupported curve")),
268        }
269    }
270
271    pub fn scheme(&self) -> SignatureScheme {
272        match self {
273            PublicKey::Ed25519(_) => SignatureScheme::Ed25519,
274            PublicKey::Secp256k1(_) => SignatureScheme::Secp256k1,
275            PublicKey::Secp256r1(_) => SignatureScheme::Secp256r1,
276            PublicKey::Passkey(_) => SignatureScheme::PasskeyAuthenticator,
277        }
278    }
279}
280
281/// Defines the compressed version of the public key that we pass around
282/// in IOTA.
283#[serde_as]
284#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize, AsRef)]
285#[as_ref(forward)]
286pub struct AuthorityPublicKeyBytes(
287    #[serde_as(as = "Readable<Base64, Bytes>")] pub [u8; AuthorityPublicKey::LENGTH],
288);
289
290impl AuthorityPublicKeyBytes {
291    fn fmt_impl(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
292        let s = Hex::encode(self.0);
293        write!(f, "k#{s}")?;
294        Ok(())
295    }
296}
297
298impl<'a> ConciseableName<'a> for AuthorityPublicKeyBytes {
299    type ConciseTypeRef = ConciseAuthorityPublicKeyBytesRef<'a>;
300    type ConciseType = ConciseAuthorityPublicKeyBytes;
301
302    /// Get a ConciseAuthorityPublicKeyBytesRef. Usage:
303    ///
304    ///   debug!(name = ?authority.concise());
305    ///   format!("{:?}", authority.concise());
306    fn concise(&'a self) -> ConciseAuthorityPublicKeyBytesRef<'a> {
307        ConciseAuthorityPublicKeyBytesRef(self)
308    }
309
310    fn concise_owned(&self) -> ConciseAuthorityPublicKeyBytes {
311        ConciseAuthorityPublicKeyBytes(*self)
312    }
313}
314
315/// A wrapper around AuthorityPublicKeyBytes that provides a concise Debug impl.
316pub struct ConciseAuthorityPublicKeyBytesRef<'a>(&'a AuthorityPublicKeyBytes);
317
318impl Debug for ConciseAuthorityPublicKeyBytesRef<'_> {
319    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
320        let s = Hex::encode(self.0.0.get(0..4).ok_or(std::fmt::Error)?);
321        write!(f, "k#{s}..")
322    }
323}
324
325impl Display for ConciseAuthorityPublicKeyBytesRef<'_> {
326    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
327        Debug::fmt(self, f)
328    }
329}
330
331/// A wrapper around AuthorityPublicKeyBytes but owns it.
332#[derive(Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
333pub struct ConciseAuthorityPublicKeyBytes(AuthorityPublicKeyBytes);
334
335impl Debug for ConciseAuthorityPublicKeyBytes {
336    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
337        let s = Hex::encode(self.0.0.get(0..4).ok_or(std::fmt::Error)?);
338        write!(f, "k#{s}..")
339    }
340}
341
342impl Display for ConciseAuthorityPublicKeyBytes {
343    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
344        Debug::fmt(self, f)
345    }
346}
347
348impl TryFrom<AuthorityPublicKeyBytes> for AggregateAuthorityPublicKey {
349    type Error = FastCryptoError;
350
351    fn try_from(
352        bytes: AuthorityPublicKeyBytes,
353    ) -> Result<AggregateAuthorityPublicKey, Self::Error> {
354        AggregateAuthorityPublicKey::from_bytes(bytes.as_ref())
355    }
356}
357
358impl From<&AggregateAuthorityPublicKey> for AuthorityPublicKeyBytes {
359    fn from(pk: &AggregateAuthorityPublicKey) -> AuthorityPublicKeyBytes {
360        AuthorityPublicKeyBytes::from_bytes(pk.as_ref()).unwrap()
361    }
362}
363
364impl Debug for AuthorityPublicKeyBytes {
365    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
366        self.fmt_impl(f)
367    }
368}
369
370impl Display for AuthorityPublicKeyBytes {
371    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
372        self.fmt_impl(f)
373    }
374}
375
376impl ToFromBytes for AuthorityPublicKeyBytes {
377    fn from_bytes(bytes: &[u8]) -> Result<Self, fastcrypto::error::FastCryptoError> {
378        let bytes: [u8; AuthorityPublicKey::LENGTH] = bytes
379            .try_into()
380            .map_err(|_| fastcrypto::error::FastCryptoError::InvalidInput)?;
381        Ok(AuthorityPublicKeyBytes(bytes))
382    }
383}
384
385impl AuthorityPublicKeyBytes {
386    pub const ZERO: Self = Self::new([0u8; AuthorityPublicKey::LENGTH]);
387
388    /// This ensures it's impossible to construct an instance with other than
389    /// registered lengths
390    pub const fn new(bytes: [u8; AuthorityPublicKey::LENGTH]) -> AuthorityPublicKeyBytes
391where {
392        AuthorityPublicKeyBytes(bytes)
393    }
394}
395
396impl FromStr for AuthorityPublicKeyBytes {
397    type Err = Error;
398
399    fn from_str(s: &str) -> Result<Self, Self::Err> {
400        let value = Hex::decode(s).map_err(|e| anyhow!(e))?;
401        Self::from_bytes(&value[..]).map_err(|e| anyhow!(e))
402    }
403}
404
405impl Default for AuthorityPublicKeyBytes {
406    fn default() -> Self {
407        Self::ZERO
408    }
409}
410
411// Add helper calls for Authority Signature
412//
413
414pub trait IotaAuthoritySignature {
415    fn verify_secure<T>(
416        &self,
417        value: &IntentMessage<T>,
418        epoch_id: EpochId,
419        author: AuthorityPublicKeyBytes,
420    ) -> Result<(), IotaError>
421    where
422        T: Serialize;
423
424    fn new_secure<T>(
425        value: &IntentMessage<T>,
426        epoch_id: &EpochId,
427        secret: &dyn Signer<Self>,
428    ) -> Self
429    where
430        T: Serialize;
431}
432
433impl IotaAuthoritySignature for AuthoritySignature {
434    #[instrument(level = "trace", skip_all)]
435    fn new_secure<T>(value: &IntentMessage<T>, epoch: &EpochId, secret: &dyn Signer<Self>) -> Self
436    where
437        T: Serialize,
438    {
439        let mut intent_msg_bytes =
440            bcs::to_bytes(&value).expect("Message serialization should not fail");
441        epoch.write(&mut intent_msg_bytes);
442        secret.sign(&intent_msg_bytes)
443    }
444
445    #[instrument(level = "trace", skip_all)]
446    fn verify_secure<T>(
447        &self,
448        value: &IntentMessage<T>,
449        epoch: EpochId,
450        author: AuthorityPublicKeyBytes,
451    ) -> Result<(), IotaError>
452    where
453        T: Serialize,
454    {
455        let mut message = bcs::to_bytes(&value).expect("Message serialization should not fail");
456        epoch.write(&mut message);
457
458        let public_key = AuthorityPublicKey::try_from(author).map_err(|_| {
459            IotaError::KeyConversion(
460                "Failed to serialize public key bytes to valid public key".to_string(),
461            )
462        })?;
463        public_key
464            .verify(&message[..], self)
465            .map_err(|e| IotaError::InvalidSignature {
466                error: format!(
467                    "Fail to verify auth sig {} epoch: {} author: {}",
468                    e,
469                    epoch,
470                    author.concise()
471                ),
472            })
473    }
474}
475
476/// Random key-pair generation for the `get_key_pair` helpers, implemented for
477/// the fastcrypto authority/network keypairs and the SDK account keys.
478pub trait RandomKeyPair: Sized {
479    fn generate_with_address(seed: [u8; 32]) -> (Address, Self);
480}
481
482impl RandomKeyPair for BLS12381KeyPair {
483    fn generate_with_address(seed: [u8; 32]) -> (Address, Self) {
484        let kp = <BLS12381KeyPair as KeypairTraits>::generate(
485            &mut rand08::rngs::StdRng::from_seed(seed),
486        );
487        // Authority keys have no on-chain account; this address only labels
488        // key files and `keytool` output.
489        let mut hasher = DefaultHash::default();
490        hasher.update([SignatureScheme::Bls12381.to_u8()]);
491        hasher.update(kp.public().as_ref());
492        (Address::new(hasher.finalize().digest), kp)
493    }
494}
495
496impl RandomKeyPair for Ed25519KeyPair {
497    fn generate_with_address(seed: [u8; 32]) -> (Address, Self) {
498        let kp =
499            <Ed25519KeyPair as KeypairTraits>::generate(&mut rand08::rngs::StdRng::from_seed(seed));
500        let public = PublicKey::Ed25519(BytesRepresentation(
501            kp.public()
502                .as_ref()
503                .try_into()
504                .expect("ed25519 public keys are 32 bytes"),
505        ));
506        (Address::from(&public), kp)
507    }
508}
509
510macro_rules! random_key_pair_from_sdk {
511    ($private_key:ty, $variant:ident) => {
512        impl RandomKeyPair for $private_key {
513            fn generate_with_address(seed: [u8; 32]) -> (Address, Self) {
514                let key = <$private_key>::random_with(StdRng::from_seed(seed));
515                let public =
516                    PublicKey::$variant(BytesRepresentation(key.public_key().into_bytes()));
517                (Address::from(&public), key)
518            }
519        }
520    };
521}
522
523random_key_pair_from_sdk!(Ed25519PrivateKey, Ed25519);
524random_key_pair_from_sdk!(Secp256k1PrivateKey, Secp256k1);
525random_key_pair_from_sdk!(Secp256r1PrivateKey, Secp256r1);
526
527// TODO: get_key_pair() should return KeyPair only.
528// TODO: rename to random_key_pair
529pub fn get_key_pair<KP: RandomKeyPair>() -> (Address, KP) {
530    get_key_pair_from_rng(&mut UnwrapErr(SysRng))
531}
532
533/// Generate a random committee key pairs with a given committee size
534pub fn random_committee_key_pairs_of_size(size: usize) -> Vec<AuthorityKeyPair> {
535    let mut rng = StdRng::from_seed([0; 32]);
536    (0..size)
537        .map(|_| {
538            // TODO: We are generating the keys 4 times to match exactly as how we generate
539            // keys in ConfigBuilder::build (iota-config/src/network_config_builder). This
540            // is because we are using these key generation functions as
541            // fixtures and we call them independently in different paths and
542            // exact the results to be the same. We should eliminate them.
543            let key_pair = get_key_pair_from_rng::<AuthorityKeyPair, _>(&mut rng);
544            get_key_pair_from_rng::<AuthorityKeyPair, _>(&mut rng);
545            get_key_pair_from_rng::<AccountPrivateKey, _>(&mut rng);
546            get_key_pair_from_rng::<AccountPrivateKey, _>(&mut rng);
547            key_pair.1
548        })
549        .collect()
550}
551
552pub fn deterministic_random_account_private_key() -> (Address, AccountPrivateKey) {
553    let mut rng = StdRng::from_seed([0; 32]);
554    get_key_pair_from_rng(&mut rng)
555}
556
557pub fn get_account_private_key() -> (Address, AccountPrivateKey) {
558    get_key_pair()
559}
560
561pub fn get_authority_key_pair() -> (Address, AuthorityKeyPair) {
562    get_key_pair()
563}
564
565/// Generate a keypair from the specified RNG (useful for testing with seedable
566/// rngs).
567pub fn get_key_pair_from_rng<KP: RandomKeyPair, R>(csprng: &mut R) -> (Address, KP)
568where
569    R: rand::CryptoRng,
570{
571    let mut seed = [0u8; 32];
572    csprng.fill_bytes(&mut seed);
573    KP::generate_with_address(seed)
574}
575
576// TODO: C-GETTER
577pub fn get_key_pair_from_bytes<KP: KeypairTraits>(bytes: &[u8]) -> IotaResult<KP> {
578    let priv_length = <KP as KeypairTraits>::PrivKey::LENGTH;
579    let pub_key_length = <KP as KeypairTraits>::PubKey::LENGTH;
580    if bytes.len() != priv_length + pub_key_length {
581        return Err(IotaError::KeyConversion(format!(
582            "Invalid input byte length, expected {}: {}",
583            priv_length + pub_key_length,
584            bytes.len()
585        )));
586    }
587    let sk = <KP as KeypairTraits>::PrivKey::from_bytes(
588        bytes
589            .get(..priv_length)
590            .ok_or(IotaError::InvalidPrivateKey)?,
591    )
592    .map_err(|_| IotaError::InvalidPrivateKey)?;
593    Ok(sk.into())
594}
595
596/// An all-zero ed25519 [`SimpleSignature`] placeholder, used for system
597/// transactions (which are not signed) and in tests where the signature
598/// content is irrelevant.
599pub fn zero_ed25519_signature() -> SimpleSignature {
600    // `flag || signature || public key`, all zero; the leading zero byte selects
601    // the ed25519 scheme.
602    SimpleSignature::from_bytes([0u8; 1 + Ed25519Signature::LENGTH + Ed25519PublicKey::LENGTH])
603        .expect("zero-filled ed25519 signature has the expected length")
604}
605
606// BLS Port
607//
608
609impl IotaPublicKey for BLS12381PublicKey {
610    const SIGNATURE_SCHEME: SignatureScheme = SignatureScheme::Bls12381;
611}
612
613impl IotaPublicKey for Ed25519PublicKey {
614    const SIGNATURE_SCHEME: SignatureScheme = SignatureScheme::Ed25519;
615}
616
617impl IotaPublicKey for Secp256k1PublicKey {
618    const SIGNATURE_SCHEME: SignatureScheme = SignatureScheme::Secp256k1;
619}
620
621impl IotaPublicKey for Secp256r1PublicKey {
622    const SIGNATURE_SCHEME: SignatureScheme = SignatureScheme::Secp256r1;
623}
624
625pub trait IotaPublicKey: VerifyingKey {
626    const SIGNATURE_SCHEME: SignatureScheme;
627}
628
629/// AuthoritySignInfoTrait is a trait used specifically for a few structs in
630/// messages.rs to template on whether the struct is signed by an authority. We
631/// want to limit how those structs can be instantiated on, hence the sealed
632/// trait. TODO: We could also add the aggregated signature as another impl of
633/// the trait.       This will make CertifiedTransaction also an instance of the
634/// same struct.
635pub trait AuthoritySignInfoTrait: private::SealedAuthoritySignInfoTrait {
636    fn verify_secure<T: Serialize>(
637        &self,
638        data: &T,
639        intent: Intent,
640        committee: &Committee,
641    ) -> IotaResult;
642
643    fn add_to_verification_obligation<'a>(
644        &self,
645        committee: &'a Committee,
646        obligation: &mut VerificationObligation<'a>,
647        message_index: usize,
648    ) -> IotaResult<()>;
649}
650
651#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
652pub struct EmptySignInfo {}
653impl AuthoritySignInfoTrait for EmptySignInfo {
654    fn verify_secure<T: Serialize>(
655        &self,
656        _data: &T,
657        _intent: Intent,
658        _committee: &Committee,
659    ) -> IotaResult {
660        Ok(())
661    }
662
663    fn add_to_verification_obligation<'a>(
664        &self,
665        _committee: &'a Committee,
666        _obligation: &mut VerificationObligation<'a>,
667        _message_index: usize,
668    ) -> IotaResult<()> {
669        Ok(())
670    }
671}
672
673#[derive(Clone, Debug, Eq, Serialize, Deserialize)]
674pub struct AuthoritySignInfo {
675    pub epoch: EpochId,
676    pub authority: AuthorityName,
677    pub signature: AuthoritySignature,
678}
679
680impl AuthoritySignInfoTrait for AuthoritySignInfo {
681    #[instrument(level = "trace", skip_all)]
682    fn verify_secure<T: Serialize>(
683        &self,
684        data: &T,
685        intent: Intent,
686        committee: &Committee,
687    ) -> IotaResult<()> {
688        let mut obligation = VerificationObligation::default();
689        let idx = obligation.add_message(data, self.epoch, intent);
690        self.add_to_verification_obligation(committee, &mut obligation, idx)?;
691        obligation.verify_all()?;
692        Ok(())
693    }
694
695    fn add_to_verification_obligation<'a>(
696        &self,
697        committee: &'a Committee,
698        obligation: &mut VerificationObligation<'a>,
699        message_index: usize,
700    ) -> IotaResult<()> {
701        fp_ensure!(
702            self.epoch == committee.epoch(),
703            IotaError::WrongEpoch {
704                expected_epoch: committee.epoch(),
705                actual_epoch: self.epoch,
706            }
707        );
708        let weight = committee.weight(&self.authority);
709        fp_ensure!(
710            weight > 0,
711            IotaError::UnknownSigner {
712                signer: Some(self.authority.concise().to_string()),
713                index: None,
714                committee: Box::new(committee.clone())
715            }
716        );
717
718        obligation
719            .public_keys
720            .get_mut(message_index)
721            .ok_or(IotaError::InvalidAddress)?
722            .push(committee.public_key(&self.authority)?);
723        obligation
724            .signatures
725            .get_mut(message_index)
726            .ok_or(IotaError::InvalidAddress)?
727            .add_signature(self.signature.clone())
728            .map_err(|_| IotaError::InvalidSignature {
729                error: "Fail to aggregator auth sig".to_string(),
730            })?;
731        Ok(())
732    }
733}
734
735impl AuthoritySignInfo {
736    pub fn new<T>(
737        epoch: EpochId,
738        value: &T,
739        intent: Intent,
740        name: AuthorityName,
741        secret: &dyn Signer<AuthoritySignature>,
742    ) -> Self
743    where
744        T: Serialize,
745    {
746        Self {
747            epoch,
748            authority: name,
749            signature: AuthoritySignature::new_secure(
750                &IntentMessage::new(intent, value),
751                &epoch,
752                secret,
753            ),
754        }
755    }
756}
757
758impl Hash for AuthoritySignInfo {
759    fn hash<H: Hasher>(&self, state: &mut H) {
760        self.epoch.hash(state);
761        self.authority.hash(state);
762    }
763}
764
765impl Display for AuthoritySignInfo {
766    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
767        write!(
768            f,
769            "AuthoritySignInfo {{ epoch: {:?}, authority: {} }}",
770            self.epoch, self.authority,
771        )
772    }
773}
774
775impl PartialEq for AuthoritySignInfo {
776    fn eq(&self, other: &Self) -> bool {
777        // We do not compare the signature, because there can be multiple
778        // valid signatures for the same epoch and authority.
779        self.epoch == other.epoch && self.authority == other.authority
780    }
781}
782
783/// Represents at least a quorum (could be more) of authority signatures.
784/// STRONG_THRESHOLD indicates whether to use the quorum threshold for quorum
785/// check. When STRONG_THRESHOLD is true, the quorum is valid when the total
786/// stake is at least the quorum threshold (2f+1) of the committee; when
787/// STRONG_THRESHOLD is false, the quorum is valid when the total stake is at
788/// least the validity threshold (f+1) of the committee.
789#[serde_as]
790#[derive(Clone, Debug, Serialize, Deserialize)]
791pub struct AuthorityQuorumSignInfo<const STRONG_THRESHOLD: bool> {
792    pub epoch: EpochId,
793    pub signature: AggregateAuthoritySignature,
794    #[serde_as(as = "IotaBitmap")]
795    pub signers_map: RoaringBitmap,
796}
797
798pub type AuthorityStrongQuorumSignInfo = AuthorityQuorumSignInfo<true>;
799
800// Variant of [AuthorityStrongQuorumSignInfo] but with a serialized signature,
801// to be used in external APIs.
802#[serde_as]
803#[derive(Clone, Debug, Serialize, Deserialize)]
804pub struct IotaAuthorityStrongQuorumSignInfo {
805    pub epoch: EpochId,
806    pub signature: AggregateAuthoritySignatureAsBytes,
807    #[serde_as(as = "IotaBitmap")]
808    pub signers_map: RoaringBitmap,
809}
810
811impl From<&AuthorityStrongQuorumSignInfo> for IotaAuthorityStrongQuorumSignInfo {
812    fn from(info: &AuthorityStrongQuorumSignInfo) -> Self {
813        Self {
814            epoch: info.epoch,
815            signature: (&info.signature).into(),
816            signers_map: info.signers_map.clone(),
817        }
818    }
819}
820
821impl TryFrom<&IotaAuthorityStrongQuorumSignInfo> for AuthorityStrongQuorumSignInfo {
822    type Error = FastCryptoError;
823
824    fn try_from(info: &IotaAuthorityStrongQuorumSignInfo) -> Result<Self, Self::Error> {
825        Ok(Self {
826            epoch: info.epoch,
827            signature: (&info.signature).try_into()?,
828            signers_map: info.signers_map.clone(),
829        })
830    }
831}
832
833// Note: if you meet an error due to this line it may be because you need an Eq
834// implementation for `CertifiedTransaction`, or one of the structs that include
835// it, i.e. `ConfirmationTransaction`, `TransactionInfoResponse` or
836// `ObjectInfoResponse`.
837//
838// Please note that any such implementation must be agnostic to the exact set of
839// signatures in the certificate, as clients are allowed to equivocate on the
840// exact nature of valid certificates they send to the system. This assertion is
841// a simple tool to make sure certificates are accounted for correctly - should
842// you remove it, you're on your own to maintain the invariant that valid
843// certificates with distinct signatures are equivalent, but yet-unchecked
844// certificates that differ on signers aren't.
845//
846// see also https://github.com/iotaledger/iota/issues/266
847static_assertions::assert_not_impl_any!(AuthorityStrongQuorumSignInfo: Hash, Eq, PartialEq);
848
849impl<const STRONG_THRESHOLD: bool> AuthoritySignInfoTrait
850    for AuthorityQuorumSignInfo<STRONG_THRESHOLD>
851{
852    #[instrument(level = "trace", skip_all)]
853    fn verify_secure<T: Serialize>(
854        &self,
855        data: &T,
856        intent: Intent,
857        committee: &Committee,
858    ) -> IotaResult {
859        let mut obligation = VerificationObligation::default();
860        let idx = obligation.add_message(data, self.epoch, intent);
861        self.add_to_verification_obligation(committee, &mut obligation, idx)?;
862        obligation.verify_all()?;
863        Ok(())
864    }
865
866    fn add_to_verification_obligation<'a>(
867        &self,
868        committee: &'a Committee,
869        obligation: &mut VerificationObligation<'a>,
870        message_index: usize,
871    ) -> IotaResult<()> {
872        // Check epoch
873        fp_ensure!(
874            self.epoch == committee.epoch(),
875            IotaError::WrongEpoch {
876                expected_epoch: committee.epoch(),
877                actual_epoch: self.epoch,
878            }
879        );
880
881        let mut weight = 0;
882
883        // Create obligations for the committee signatures
884        obligation
885            .signatures
886            .get_mut(message_index)
887            .ok_or(IotaError::InvalidAuthenticator)?
888            .add_aggregate(self.signature.clone())
889            .map_err(|_| IotaError::InvalidSignature {
890                error: "Signature Aggregation failed".to_string(),
891            })?;
892
893        let selected_public_keys = obligation
894            .public_keys
895            .get_mut(message_index)
896            .ok_or(IotaError::InvalidAuthenticator)?;
897
898        for authority_index in self.signers_map.iter() {
899            let authority = committee
900                .authority_by_index(authority_index)
901                .ok_or_else(|| IotaError::UnknownSigner {
902                    signer: None,
903                    index: Some(authority_index),
904                    committee: Box::new(committee.clone()),
905                })?;
906            let voting_rights = committee.weight(authority);
907            fp_ensure!(
908                voting_rights > 0,
909                IotaError::UnknownSigner {
910                    signer: Some(authority.concise().to_string()),
911                    index: Some(authority_index),
912                    committee: Box::new(committee.clone()),
913                }
914            );
915            weight += voting_rights;
916
917            selected_public_keys.push(committee.public_key(authority)?);
918        }
919
920        fp_ensure!(
921            weight >= Self::quorum_threshold(committee),
922            IotaError::CertificateRequiresQuorum
923        );
924
925        Ok(())
926    }
927}
928
929impl<const STRONG_THRESHOLD: bool> AuthorityQuorumSignInfo<STRONG_THRESHOLD> {
930    pub fn new_from_auth_sign_infos(
931        auth_sign_infos: Vec<AuthoritySignInfo>,
932        committee: &Committee,
933    ) -> IotaResult<Self> {
934        fp_ensure!(
935            auth_sign_infos.iter().all(|a| a.epoch == committee.epoch),
936            IotaError::InvalidSignature {
937                error: "All signatures must be from the same epoch as the committee".to_string()
938            }
939        );
940        let total_stake: StakeUnit = auth_sign_infos
941            .iter()
942            .map(|a| committee.weight(&a.authority))
943            .sum();
944        fp_ensure!(
945            total_stake >= Self::quorum_threshold(committee),
946            IotaError::InvalidSignature {
947                error: "Signatures don't have enough stake to form a quorum".to_string()
948            }
949        );
950
951        let signatures: BTreeMap<_, _> = auth_sign_infos
952            .into_iter()
953            .map(|a| (a.authority, a.signature))
954            .collect();
955        let mut map = RoaringBitmap::new();
956        for pk in signatures.keys() {
957            map.insert(
958                committee
959                    .authority_index(pk)
960                    .ok_or_else(|| IotaError::UnknownSigner {
961                        signer: Some(pk.concise().to_string()),
962                        index: None,
963                        committee: Box::new(committee.clone()),
964                    })?,
965            );
966        }
967        let sigs: Vec<AuthoritySignature> = signatures.into_values().collect();
968
969        Ok(AuthorityQuorumSignInfo {
970            epoch: committee.epoch,
971            signature: AggregateAuthoritySignature::aggregate(&sigs).map_err(|e| {
972                IotaError::InvalidSignature {
973                    error: e.to_string(),
974                }
975            })?,
976            signers_map: map,
977        })
978    }
979
980    pub fn authorities<'a>(
981        &'a self,
982        committee: &'a Committee,
983    ) -> impl Iterator<Item = IotaResult<&'a AuthorityName>> {
984        self.signers_map.iter().map(|i| {
985            committee
986                .authority_by_index(i)
987                .ok_or(IotaError::InvalidAuthenticator)
988        })
989    }
990
991    pub fn quorum_threshold(committee: &Committee) -> StakeUnit {
992        committee.threshold::<STRONG_THRESHOLD>()
993    }
994
995    pub fn len(&self) -> u64 {
996        self.signers_map.len()
997    }
998
999    pub fn is_empty(&self) -> bool {
1000        self.signers_map.is_empty()
1001    }
1002}
1003
1004impl<const S: bool> Display for AuthorityQuorumSignInfo<S> {
1005    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1006        writeln!(
1007            f,
1008            "{} {{ epoch: {:?}, signers_map: {:?} }}",
1009            if S {
1010                "AuthorityStrongQuorumSignInfo"
1011            } else {
1012                "AuthorityWeakQuorumSignInfo"
1013            },
1014            self.epoch,
1015            self.signers_map,
1016        )?;
1017        Ok(())
1018    }
1019}
1020
1021mod private {
1022    pub trait SealedAuthoritySignInfoTrait {}
1023    impl SealedAuthoritySignInfoTrait for super::EmptySignInfo {}
1024    impl SealedAuthoritySignInfoTrait for super::AuthoritySignInfo {}
1025    impl<const S: bool> SealedAuthoritySignInfoTrait for super::AuthorityQuorumSignInfo<S> {}
1026}
1027
1028/// Something that we know how to hash and sign.
1029pub trait Signable<W> {
1030    fn write(&self, writer: &mut W);
1031}
1032
1033/// Activate the blanket implementation of `Signable` based on serde and BCS.
1034/// * We use `serde_name` to extract a seed from the name of structs and enums.
1035/// * We use `BCS` to generate canonical bytes suitable for hashing and signing.
1036///
1037/// # Safety
1038/// We protect the access to this marker trait through a "sealed trait" pattern:
1039/// impls must be add added here (nowehre else) which lets us note those impls
1040/// MUST be on types that comply with the `serde_name` machinery
1041/// for the below implementations not to panic. One way to check they work is to
1042/// write a unit test for serialization to / deserialization from signable
1043/// bytes.
1044mod bcs_signable {
1045
1046    pub trait BcsSignable: serde::Serialize + serde::de::DeserializeOwned {}
1047    impl BcsSignable for crate::committee::Committee {}
1048    impl BcsSignable for iota_sdk_types::CheckpointSummary {}
1049    impl BcsSignable for iota_sdk_types::CheckpointContents {}
1050    #[cfg(not(target_arch = "wasm32"))]
1051    impl BcsSignable for crate::messages_consensus::VersionedMisbehaviorReport {}
1052
1053    impl BcsSignable for iota_sdk_types::TransactionEffects {}
1054    impl BcsSignable for iota_sdk_types::TransactionEvents {}
1055    impl BcsSignable for iota_sdk_types::Transaction {}
1056    impl BcsSignable for iota_sdk_types::SenderSignedTransaction {}
1057    impl BcsSignable for crate::object::ObjectInner {}
1058
1059    impl BcsSignable for crate::global_state_hash::GlobalStateHash {}
1060
1061    impl BcsSignable for super::bcs_signable_test::Foo {}
1062    #[cfg(test)]
1063    impl BcsSignable for super::bcs_signable_test::Bar {}
1064}
1065
1066impl<T, W> Signable<W> for T
1067where
1068    T: bcs_signable::BcsSignable,
1069    W: std::io::Write,
1070{
1071    fn write(&self, writer: &mut W) {
1072        let name = serde_name::trace_name::<Self>().expect("Self must be a struct or an enum");
1073        // Note: This assumes that names never contain the separator `::`.
1074        write!(writer, "{name}::").expect("Hasher should not fail");
1075        bcs::serialize_into(writer, &self).expect("Message serialization should not fail");
1076    }
1077}
1078
1079impl<W> Signable<W> for EpochId
1080where
1081    W: std::io::Write,
1082{
1083    fn write(&self, writer: &mut W) {
1084        bcs::serialize_into(writer, &self).expect("Message serialization should not fail");
1085    }
1086}
1087
1088fn hash<S: Signable<H>, H: HashFunction<DIGEST_SIZE>, const DIGEST_SIZE: usize>(
1089    signable: &S,
1090) -> [u8; DIGEST_SIZE] {
1091    let mut digest = H::default();
1092    signable.write(&mut digest);
1093    let hash = digest.finalize();
1094    hash.into()
1095}
1096
1097pub fn default_hash<S: Signable<DefaultHash>>(signable: &S) -> [u8; 32] {
1098    hash::<S, DefaultHash, 32>(signable)
1099}
1100
1101#[derive(Default)]
1102pub struct VerificationObligation<'a> {
1103    pub messages: Vec<Vec<u8>>,
1104    pub signatures: Vec<AggregateAuthoritySignature>,
1105    pub public_keys: Vec<Vec<&'a AggregateAuthorityPublicKey>>,
1106}
1107
1108impl<'a> VerificationObligation<'a> {
1109    pub fn new() -> VerificationObligation<'a> {
1110        VerificationObligation::default()
1111    }
1112
1113    /// Add a new message to the list of messages to be verified.
1114    /// Returns the index of the message.
1115    pub fn add_message<T>(&mut self, message_value: &T, epoch: EpochId, intent: Intent) -> usize
1116    where
1117        T: Serialize,
1118    {
1119        let intent_msg = IntentMessage::new(intent, message_value);
1120        let mut intent_msg_bytes =
1121            bcs::to_bytes(&intent_msg).expect("Message serialization should not fail");
1122        epoch.write(&mut intent_msg_bytes);
1123        self.signatures.push(AggregateAuthoritySignature::default());
1124        self.public_keys.push(Vec::new());
1125        self.messages.push(intent_msg_bytes);
1126        self.messages.len() - 1
1127    }
1128
1129    // Attempts to add signature and public key to the obligation. If this fails,
1130    // ensure to call `verify` manually.
1131    pub fn add_signature_and_public_key(
1132        &mut self,
1133        signature: &AuthoritySignature,
1134        public_key: &'a AggregateAuthorityPublicKey,
1135        idx: usize,
1136    ) -> IotaResult<()> {
1137        self.public_keys
1138            .get_mut(idx)
1139            .ok_or(IotaError::InvalidAuthenticator)?
1140            .push(public_key);
1141        self.signatures
1142            .get_mut(idx)
1143            .ok_or(IotaError::InvalidAuthenticator)?
1144            .add_signature(signature.clone())
1145            .map_err(|_| IotaError::InvalidSignature {
1146                error: "Failed to add signature to obligation".to_string(),
1147            })?;
1148        Ok(())
1149    }
1150
1151    #[instrument(level = "trace", skip_all)]
1152    pub fn verify_all(self) -> IotaResult<()> {
1153        let mut pks = Vec::with_capacity(self.public_keys.len());
1154        for pk in self.public_keys.clone() {
1155            pks.push(pk.into_iter());
1156        }
1157        AggregateAuthoritySignature::batch_verify(
1158            &self.signatures.iter().collect::<Vec<_>>()[..],
1159            pks,
1160            &self.messages.iter().map(|x| &x[..]).collect::<Vec<_>>()[..],
1161        )
1162        .map_err(|e| {
1163            let message = format!(
1164                "pks: {:?}, messages: {:?}, sigs: {:?}",
1165                self.public_keys,
1166                self.messages
1167                    .iter()
1168                    .map(Base64::encode)
1169                    .collect::<Vec<String>>(),
1170                self.signatures
1171                    .iter()
1172                    .map(|s| Base64::encode(s.as_ref()))
1173                    .collect::<Vec<String>>()
1174            );
1175
1176            let chunk_size = 2048;
1177
1178            // This error message may be very long, so we print out the error in chunks of
1179            // to avoid hitting a max log line length on the system.
1180            for (i, chunk) in message
1181                .as_bytes()
1182                .chunks(chunk_size)
1183                .map(std::str::from_utf8)
1184                .enumerate()
1185            {
1186                warn!(
1187                    "Failed to batch verify aggregated auth sig: {} (chunk {}): {}",
1188                    e,
1189                    i,
1190                    chunk.unwrap()
1191                );
1192            }
1193
1194            IotaError::InvalidSignature {
1195                error: format!("Failed to batch verify aggregated auth sig: {e}"),
1196            }
1197        })?;
1198        Ok(())
1199    }
1200}
1201
1202pub mod bcs_signable_test {
1203    use serde::{Deserialize, Serialize};
1204
1205    #[derive(Clone, Serialize, Deserialize)]
1206    pub struct Foo(pub String);
1207
1208    #[cfg(test)]
1209    #[derive(Serialize, Deserialize)]
1210    pub struct Bar(pub String);
1211
1212    #[cfg(test)]
1213    use super::VerificationObligation;
1214
1215    #[cfg(test)]
1216    pub fn get_obligation_input<T>(value: &T) -> (VerificationObligation<'_>, usize)
1217    where
1218        T: super::bcs_signable::BcsSignable,
1219    {
1220        use iota_sdk_types::crypto::{Intent, IntentScope};
1221
1222        let mut obligation = VerificationObligation::default();
1223        // Add the obligation of the authority signature verifications.
1224        let idx = obligation.add_message(
1225            value,
1226            0,
1227            Intent::iota_app(IntentScope::SenderSignedTransaction),
1228        );
1229        (obligation, idx)
1230    }
1231}
1232
1233impl FromStr for PublicKey {
1234    type Err = eyre::Report;
1235    fn from_str(s: &str) -> Result<Self, Self::Err> {
1236        Self::decode_base64(s).map_err(|e| eyre!("Fail to decode base64 {}", e.to_string()))
1237    }
1238}
1239
1240// Types for randomness generation
1241//
1242#[cfg(not(target_arch = "wasm32"))]
1243pub type RandomnessSignature = fastcrypto_tbls::types::Signature;
1244#[cfg(not(target_arch = "wasm32"))]
1245pub type RandomnessPartialSignature = fastcrypto_tbls::tbls::PartialSignature<RandomnessSignature>;
1246#[cfg(not(target_arch = "wasm32"))]
1247pub type RandomnessPrivateKey =
1248    fastcrypto_tbls::ecies_v1::PrivateKey<fastcrypto::groups::bls12381::G2Element>;