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