diff --git a/Cargo.lock b/Cargo.lock index d2bad0789f4..19d94018060 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2878,6 +2878,7 @@ dependencies = [ "parity-scale-codec", "rand", "rand_chacha", + "rand_core", "secp256k1", "serde", "serde_json", diff --git a/configs/swarm/executor.wasm b/configs/swarm/executor.wasm index 1086fcb7a9a..135f1021cc0 100644 Binary files a/configs/swarm/executor.wasm and b/configs/swarm/executor.wasm differ diff --git a/crypto/Cargo.toml b/crypto/Cargo.toml index 4cff389c997..199ad0aca6c 100644 --- a/crypto/Cargo.toml +++ b/crypto/Cargo.toml @@ -24,6 +24,7 @@ std = [ "signature/std", "ed25519-dalek/std", "rand/std", + "rand_core/std", "rand_chacha/std", "zeroize/std", "aead/std", @@ -70,6 +71,7 @@ curve25519-dalek = { version = "4.1.1", default-features = false } x25519-dalek = { version = "2.0.0", default-features = false, features = ["static_secrets"] } rand = { workspace = true, default-features = false, features = ["std_rng", "alloc"]} +rand_core = { version = "0.6.4", default-features = false, features = ["alloc"]} rand_chacha = { version = "0.3.1", default-features = false } diff --git a/crypto/src/lib.rs b/crypto/src/lib.rs index 715a9603cf8..913bc1ae6aa 100755 --- a/crypto/src/lib.rs +++ b/crypto/src/lib.rs @@ -193,7 +193,6 @@ impl KeyPair { Self::generate_with_configuration( KeyGenConfiguration::from_random().with_algorithm(Algorithm::Ed25519), ) - .expect("Ed25519 key generation from random bytes should never fail") } } @@ -225,28 +224,20 @@ impl KeyPair { } /// Generates a pair of Public and Private key with the corresponding [`KeyGenConfiguration`]. - /// - /// # Errors - /// - /// Fails if used [`Secp256k1`](Algorithm::Secp256k1) algorithm with seed less than `32` bytes. - pub fn generate_with_configuration(configuration: KeyGenConfiguration) -> Result { - let key_gen_option = match (configuration.algorithm, configuration.key_gen_option) { - (Algorithm::Secp256k1, KeyGenOption::UseSeed(seed)) if seed.len() < 32 => { - return Err(Error::KeyGen( - "secp256k1 seed for must be at least 32 bytes long".to_owned(), - )) - } - (_, key_gen_option) => key_gen_option, - }; - - Ok(match configuration.algorithm { + pub fn generate_with_configuration( + KeyGenConfiguration { + key_gen_option, + algorithm, + }: KeyGenConfiguration, + ) -> Self { + match algorithm { Algorithm::Ed25519 => signature::ed25519::Ed25519Sha512::keypair(key_gen_option).into(), Algorithm::Secp256k1 => { signature::secp256k1::EcdsaSecp256k1Sha256::keypair(key_gen_option).into() } Algorithm::BlsNormal => signature::bls::BlsNormal::keypair(key_gen_option).into(), Algorithm::BlsSmall => signature::bls::BlsSmall::keypair(key_gen_option).into(), - }) + } } } @@ -894,8 +885,7 @@ mod tests { ] { let key_pair = KeyPair::generate_with_configuration( KeyGenConfiguration::from_random().with_algorithm(algorithm), - ) - .expect("Failed to generate key pair"); + ); assert_eq!( key_pair, @@ -956,8 +946,7 @@ mod tests { ] { let key_pair = KeyPair::generate_with_configuration( KeyGenConfiguration::from_random().with_algorithm(algorithm), - ) - .expect("Failed to generate key pair"); + ); let (public_key, _) = key_pair.into(); let encoded_public_key = public_key.encode(); @@ -1148,21 +1137,4 @@ mod tests { } ); } - - #[test] - #[cfg(feature = "rand")] - fn secp256k1_key_gen_fails_with_seed_smaller_than_32() { - let seed: Vec<_> = (0..12u8).collect(); - - let result = KeyPair::generate_with_configuration( - KeyGenConfiguration::from_seed(seed).with_algorithm(Algorithm::Secp256k1), - ); - - assert_eq!( - result, - Err(Error::KeyGen( - "secp256k1 seed for must be at least 32 bytes long".to_owned() - )) - ); - } } diff --git a/crypto/src/signature/ed25519.rs b/crypto/src/signature/ed25519.rs index 959eaf3bf48..46ed5291fe7 100644 --- a/crypto/src/signature/ed25519.rs +++ b/crypto/src/signature/ed25519.rs @@ -1,14 +1,9 @@ use core::{borrow::Borrow as _, convert::TryFrom}; -use arrayref::array_ref; use ed25519_dalek::Signature; #[cfg(feature = "rand")] use rand::rngs::OsRng; -use rand::SeedableRng; -use rand_chacha::ChaChaRng; -use sha2::Digest; use signature::{Signer as _, Verifier as _}; -use zeroize::Zeroize; use crate::{Error, KeyGenOption, ParseError}; @@ -22,16 +17,11 @@ use alloc::{string::ToString as _, vec::Vec}; pub struct Ed25519Sha512; impl Ed25519Sha512 { - pub fn keypair(mut option: KeyGenOption) -> (PublicKey, PrivateKey) { + pub fn keypair(option: KeyGenOption) -> (PublicKey, PrivateKey) { let signing_key = match option { #[cfg(feature = "rand")] KeyGenOption::Random => PrivateKey::generate(&mut OsRng), - KeyGenOption::UseSeed(ref mut s) => { - let hash = sha2::Sha256::digest(s.as_slice()); - s.zeroize(); - let mut rng = ChaChaRng::from_seed(*array_ref!(hash.as_slice(), 0, 32)); - PrivateKey::generate(&mut rng) - } + KeyGenOption::UseSeed(seed) => PrivateKey::generate(&mut super::rng_from_seed(seed)), KeyGenOption::FromPrivateKey(ref s) => { let crate::PrivateKeyInner::Ed25519(s) = s.0.borrow() else { panic!("Wrong private key type, expected `Ed25519`, got {s:?}") diff --git a/crypto/src/signature/mod.rs b/crypto/src/signature/mod.rs index 4131f673e50..e99b90239be 100644 --- a/crypto/src/signature/mod.rs +++ b/crypto/src/signature/mod.rs @@ -19,15 +19,26 @@ use core::{borrow::Borrow as _, marker::PhantomData}; #[cfg(feature = "std")] use std::collections::btree_set; +use arrayref::array_ref; use derive_more::{Deref, DerefMut}; use iroha_primitives::const_vec::ConstVec; use iroha_schema::{IntoSchema, TypeId}; use parity_scale_codec::{Decode, Encode}; +use rand_core::{CryptoRngCore, SeedableRng as _}; #[cfg(not(feature = "ffi_import"))] use serde::{Deserialize, Serialize}; +use sha2::Digest as _; +use zeroize::Zeroize as _; use crate::{ffi, Error, HashOf, KeyPair, PublicKey}; +/// Construct cryptographic RNG from seed. +fn rng_from_seed(mut seed: Vec) -> impl CryptoRngCore { + let hash = sha2::Sha256::digest(&seed); + seed.zeroize(); + rand_chacha::ChaChaRng::from_seed(*array_ref!(hash.as_slice(), 0, 32)) +} + ffi::ffi_item! { /// Represents signature of the data (`Block` or `Transaction` for example). #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, getset::Getters)] @@ -534,8 +545,7 @@ mod tests { fn create_signature_ed25519() { let key_pair = KeyPair::generate_with_configuration( KeyGenConfiguration::from_random().with_algorithm(crate::Algorithm::Ed25519), - ) - .expect("Failed to generate key pair."); + ); let message = b"Test message to sign."; let signature = Signature::new(&key_pair, message); assert!(*signature.public_key() == *key_pair.public_key()); @@ -547,8 +557,7 @@ mod tests { fn create_signature_secp256k1() { let key_pair = KeyPair::generate_with_configuration( KeyGenConfiguration::from_random().with_algorithm(crate::Algorithm::Secp256k1), - ) - .expect("Failed to generate key pair."); + ); let message = b"Test message to sign."; let signature = Signature::new(&key_pair, message); assert!(*signature.public_key() == *key_pair.public_key()); @@ -560,8 +569,7 @@ mod tests { fn create_signature_bls_normal() { let key_pair = KeyPair::generate_with_configuration( KeyGenConfiguration::from_random().with_algorithm(crate::Algorithm::BlsNormal), - ) - .expect("Failed to generate key pair."); + ); let message = b"Test message to sign."; let signature = Signature::new(&key_pair, message); assert!(*signature.public_key() == *key_pair.public_key()); @@ -573,8 +581,7 @@ mod tests { fn create_signature_bls_small() { let key_pair = KeyPair::generate_with_configuration( KeyGenConfiguration::from_random().with_algorithm(crate::Algorithm::BlsSmall), - ) - .expect("Failed to generate key pair."); + ); let message = b"Test message to sign."; let signature = Signature::new(&key_pair, message); assert!(*signature.public_key() == *key_pair.public_key()); diff --git a/crypto/src/signature/secp256k1.rs b/crypto/src/signature/secp256k1.rs index bdfae36a66f..fc84c4adac2 100644 --- a/crypto/src/signature/secp256k1.rs +++ b/crypto/src/signature/secp256k1.rs @@ -4,8 +4,6 @@ use alloc::{format, vec::Vec}; use self::ecdsa_secp256k1::EcdsaSecp256k1Impl; use crate::{Error, KeyGenOption, ParseError}; -pub const PRIVATE_KEY_SIZE: usize = 32; - pub struct EcdsaSecp256k1Sha256; pub type PublicKey = k256::PublicKey; @@ -38,35 +36,22 @@ mod ecdsa_secp256k1 { use alloc::{format, string::ToString as _, vec::Vec}; use core::borrow::Borrow; - use arrayref::array_ref; - use digest::Digest as _; #[cfg(feature = "rand")] use rand::rngs::OsRng; - use rand::{RngCore, SeedableRng}; - use rand_chacha::ChaChaRng; use signature::{Signer as _, Verifier as _}; - use zeroize::Zeroize; - use super::{PrivateKey, PublicKey, PRIVATE_KEY_SIZE}; + use super::{PrivateKey, PublicKey}; use crate::{Error, KeyGenOption, ParseError}; pub struct EcdsaSecp256k1Impl; - type Digest = sha2::Sha256; impl EcdsaSecp256k1Impl { - pub fn keypair(mut option: KeyGenOption) -> (PublicKey, PrivateKey) { + pub fn keypair(option: KeyGenOption) -> (PublicKey, PrivateKey) { let signing_key = match option { #[cfg(feature = "rand")] KeyGenOption::Random => PrivateKey::random(&mut OsRng), - KeyGenOption::UseSeed(ref mut seed) => { - let mut s = [0u8; PRIVATE_KEY_SIZE]; - let mut rng = ChaChaRng::from_seed(*array_ref!(seed.as_slice(), 0, 32)); - seed.zeroize(); - rng.fill_bytes(&mut s); - let k = Digest::digest(s); - s.zeroize(); - PrivateKey::from_slice(k.as_slice()) - .expect("Creating private key from seed should always succeed") + KeyGenOption::UseSeed(seed) => { + PrivateKey::random(&mut super::super::rng_from_seed(seed)) } KeyGenOption::FromPrivateKey(ref s) => { let crate::PrivateKeyInner::Secp256k1(s) = s.0.borrow() else { diff --git a/tools/kagami/src/crypto.rs b/tools/kagami/src/crypto.rs index 7d5b2038ab4..2f4e519bfe6 100644 --- a/tools/kagami/src/crypto.rs +++ b/tools/kagami/src/crypto.rs @@ -93,8 +93,9 @@ impl Args { _ => unreachable!("Clap group invariant"), }; - KeyPair::generate_with_configuration(configuration.with_algorithm(algorithm)) - .wrap_err("Failed to generate key pair") + Ok(KeyPair::generate_with_configuration( + configuration.with_algorithm(algorithm), + )) } } diff --git a/tools/swarm/src/compose.rs b/tools/swarm/src/compose.rs index 5a4f449a2cd..316015e6613 100644 --- a/tools/swarm/src/compose.rs +++ b/tools/swarm/src/compose.rs @@ -8,10 +8,7 @@ use std::{ }; use color_eyre::eyre::{eyre, Context, ContextCompat}; -use iroha_crypto::{ - error::Error as IrohaCryptoError, Algorithm, KeyGenConfiguration, KeyPair, PrivateKey, - PublicKey, -}; +use iroha_crypto::{Algorithm, KeyGenConfiguration, KeyPair, PrivateKey, PublicKey}; use iroha_data_model::{prelude::PeerId, ChainId}; use iroha_primitives::addr::{socket_addr, SocketAddr}; use peer_generator::Peer; @@ -389,8 +386,7 @@ impl DockerComposeBuilder<'_> { let chain_id = ChainId::from("00000000-0000-0000-0000-000000000000"); let peers = peer_generator::generate_peers(self.peers, self.seed) .wrap_err("Failed to generate peers")?; - let genesis_key_pair = generate_key_pair(self.seed, GENESIS_KEYPAIR_SEED) - .wrap_err("Failed to generate genesis key pair")?; + let genesis_key_pair = generate_key_pair(self.seed, GENESIS_KEYPAIR_SEED); let service_source = match &self.image_source { ResolvedImageSource::Build { path } => { ServiceSource::Build(path.relative_to(target_file_dir)?) @@ -468,10 +464,7 @@ impl DockerComposeBuilder<'_> { } } -fn generate_key_pair( - base_seed: Option<&[u8]>, - additional_seed: &[u8], -) -> color_eyre::Result { +fn generate_key_pair(base_seed: Option<&[u8]>, additional_seed: &[u8]) -> KeyPair { let cfg = base_seed.map_or_else(KeyGenConfiguration::from_random, |base| { let seed: Vec<_> = base.iter().chain(additional_seed).copied().collect(); KeyGenConfiguration::from_seed(seed) @@ -483,7 +476,7 @@ fn generate_key_pair( mod peer_generator { use std::{collections::BTreeMap, num::NonZeroU16}; - use color_eyre::{eyre::Context, Report}; + use color_eyre::Report; use iroha_crypto::KeyPair; use iroha_data_model::prelude::PeerId; use iroha_primitives::addr::{SocketAddr, SocketAddrHost}; @@ -521,8 +514,7 @@ mod peer_generator { .map(|i| { let service_name = format!("{BASE_SERVICE_NAME}{i}"); - let key_pair = super::generate_key_pair(base_seed, service_name.as_bytes()) - .wrap_err("Failed to generate key pair")?; + let key_pair = super::generate_key_pair(base_seed, service_name.as_bytes()); let peer = Peer { name: service_name.clone(), @@ -648,8 +640,7 @@ mod tests { let key_pair = KeyPair::generate_with_configuration(KeyGenConfiguration::from_seed(vec![ 1, 5, 1, 2, 2, 3, 4, 1, 2, 3, - ])) - .unwrap(); + ])); map.insert( "iroha0".to_owned(), @@ -721,8 +712,7 @@ mod tests { let chain_id = ChainId::from("00000000-0000-0000-0000-000000000000"); let key_pair = - KeyPair::generate_with_configuration(KeyGenConfiguration::from_seed(vec![0, 1, 2])) - .unwrap(); + KeyPair::generate_with_configuration(KeyGenConfiguration::from_seed(vec![0, 1, 2])); let env: FullPeerEnv = CompactPeerEnv { chain_id,