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