diff --git a/Cargo.lock b/Cargo.lock index 94472582823..23e0d80b5e3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2875,6 +2875,7 @@ dependencies = [ "serde_json", "serde_with", "sha2", + "signature", "x25519-dalek", "zeroize", ] diff --git a/client/src/client.rs b/client/src/client.rs index d81c39aff56..dd907973c2c 100644 --- a/client/src/client.rs +++ b/client/src/client.rs @@ -1702,7 +1702,7 @@ mod tests { ), private_key: Some(iroha_crypto::PrivateKey::from_hex( iroha_crypto::Algorithm::Ed25519, - "9AC47ABF59B356E0BD7DCBBBB4DEC080E302156A48CA907E47CB6AEA1D32719E7233BFC89DCBD68C19FDE6CE6158225298EC1131B6A130D1AEB454C1AB5183C0".as_ref() + "9AC47ABF59B356E0BD7DCBBBB4DEC080E302156A48CA907E47CB6AEA1D32719E7233BFC89DCBD68C19FDE6CE6158225298EC1131B6A130D1AEB454C1AB5183C0" ).expect("Private key not hex encoded")), account_id: Some( "alice@wonderland" diff --git a/config/src/genesis.rs b/config/src/genesis.rs index 5831f73851b..fe51c5e33a3 100644 --- a/config/src/genesis.rs +++ b/config/src/genesis.rs @@ -42,7 +42,7 @@ pub mod tests { .expect("Public key not in multihash format"); let private_key = PrivateKey::from_hex( iroha_crypto::Algorithm::Ed25519, - "D748E18CE60CB30DEA3E73C9019B7AF45A8D465E3D71BCC9A5EF99A008205E534CFFD0EE429B1BDD36B3910EC570852B8BB63F18750341772FB46BC856C5CAAF".as_ref() + "D748E18CE60CB30DEA3E73C9019B7AF45A8D465E3D71BCC9A5EF99A008205E534CFFD0EE429B1BDD36B3910EC570852B8BB63F18750341772FB46BC856C5CAAF" ).expect("Private key not hex encoded"); KeyPair::new(public_key, private_key).expect("Key pair mismatch") diff --git a/config/src/iroha.rs b/config/src/iroha.rs index 4500dbe9d0e..cd11b80812e 100644 --- a/config/src/iroha.rs +++ b/config/src/iroha.rs @@ -183,7 +183,7 @@ mod tests { pub fn placeholder_keypair() -> KeyPair { let private_key = PrivateKey::from_hex( Algorithm::Ed25519, - "282ED9F3CF92811C3818DBC4AE594ED59DC1A2F78E4241E31924E101D6B1FB831C61FAF8FE94E253B93114240394F79A607B7FA55F9E5A41EBEC74B88055768B".as_ref() + "282ED9F3CF92811C3818DBC4AE594ED59DC1A2F78E4241E31924E101D6B1FB831C61FAF8FE94E253B93114240394F79A607B7FA55F9E5A41EBEC74B88055768B" ).expect("Private key not hex encoded"); KeyPair::new( diff --git a/core/test_network/src/lib.rs b/core/test_network/src/lib.rs index 28be214fd0f..25ba5941fa8 100644 --- a/core/test_network/src/lib.rs +++ b/core/test_network/src/lib.rs @@ -61,7 +61,7 @@ pub fn get_key_pair() -> KeyPair { .expect("Public key not in mulithash format"), PrivateKey::from_hex( Algorithm::Ed25519, - "9AC47ABF59B356E0BD7DCBBBB4DEC080E302156A48CA907E47CB6AEA1D32719E7233BFC89DCBD68C19FDE6CE6158225298EC1131B6A130D1AEB454C1AB5183C0".as_ref() + "9AC47ABF59B356E0BD7DCBBBB4DEC080E302156A48CA907E47CB6AEA1D32719E7233BFC89DCBD68C19FDE6CE6158225298EC1131B6A130D1AEB454C1AB5183C0" ).expect("Private key not hex encoded") ).expect("Key pair mismatch") } diff --git a/crypto/Cargo.toml b/crypto/Cargo.toml index 64693810f23..71779ff3d7c 100644 --- a/crypto/Cargo.toml +++ b/crypto/Cargo.toml @@ -21,6 +21,7 @@ std = [ "dep:hkdf", "dep:amcl", "dep:amcl_wrapper", + "dep:signature", "dep:ed25519-dalek", "dep:curve25519-dalek", "dep:x25519-dalek", @@ -64,6 +65,7 @@ hkdf = { version = "0.12.3", optional = true } amcl = { version = "0.2.0", optional = true, default-features = false, features = ["secp256k1"] } amcl_wrapper = { version = "0.4.0", optional = true } +signature = { version = "2.1.0", optional = true } ed25519-dalek = { version = "2.0.0", optional = true, features = ["rand_core"] } curve25519-dalek = { version = "4.1.1", optional = true } x25519-dalek = { version = "2.0.0", optional = true, features = ["static_secrets"] } diff --git a/crypto/src/encryption/chacha20poly1305.rs b/crypto/src/encryption/chacha20poly1305.rs index f58597032f2..3039aef616a 100644 --- a/crypto/src/encryption/chacha20poly1305.rs +++ b/crypto/src/encryption/chacha20poly1305.rs @@ -9,7 +9,7 @@ use chacha20poly1305::ChaCha20Poly1305 as SysChaCha20Poly1305; use super::Encryptor; -/// ChaCha20Poly1305 is a symmetric encryption algorithm that uses the ChaCha20 stream cipher +/// `ChaCha20Poly1305` is a symmetric encryption algorithm that uses the `ChaCha20` stream cipher #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub struct ChaCha20Poly1305 { key: GenericArray, @@ -67,20 +67,20 @@ mod tests { #[test] fn encrypt_easy_works() { - let aes = ChaCha20Poly1305::new(&ChaCha20Poly1305::key_gen().unwrap()); + let cipher = ChaCha20Poly1305::new(&ChaCha20Poly1305::key_gen().unwrap()); let aad = Vec::new(); let message = b"Hello and Goodbye!".to_vec(); - let res = aes.encrypt_easy(&aad, &message); + let res = cipher.encrypt_easy(&aad, &message); assert!(res.is_ok()); let ciphertext = res.unwrap(); - let res = aes.decrypt_easy(&aad, &ciphertext); + let res = cipher.decrypt_easy(&aad, &ciphertext); assert!(res.is_ok()); assert_eq!(message, res.unwrap()); } #[test] fn encrypt_works() { - let aes = ChaCha20Poly1305::new(&ChaCha20Poly1305::key_gen().unwrap()); + let cipher = ChaCha20Poly1305::new(&ChaCha20Poly1305::key_gen().unwrap()); let nonce = ChaCha20Poly1305::nonce_gen().unwrap(); let aad = b"encrypt test".to_vec(); let message = b"Hello and Goodbye!".to_vec(); @@ -88,47 +88,47 @@ mod tests { msg: message.as_slice(), aad: aad.as_slice(), }; - let res = aes.encrypt(&nonce, payload); + let res = cipher.encrypt(&nonce, payload); assert!(res.is_ok()); let ciphertext = res.unwrap(); let payload = Payload { msg: ciphertext.as_slice(), aad: aad.as_slice(), }; - let res = aes.decrypt(&nonce, payload); + let res = cipher.decrypt(&nonce, payload); assert!(res.is_ok()); assert_eq!(message, res.unwrap()); } #[test] fn decrypt_should_fail() { - let aes = ChaCha20Poly1305::new(&ChaCha20Poly1305::key_gen().unwrap()); + let cipher = ChaCha20Poly1305::new(&ChaCha20Poly1305::key_gen().unwrap()); let aad = b"decrypt should fail".to_vec(); let message = b"Hello and Goodbye!".to_vec(); - let res = aes.encrypt_easy(&aad, &message); + let res = cipher.encrypt_easy(&aad, &message); assert!(res.is_ok()); let mut ciphertext = res.unwrap(); let aad = b"decrypt should succeed".to_vec(); - let res = aes.decrypt_easy(&aad, &ciphertext); + let res = cipher.decrypt_easy(&aad, &ciphertext); assert!(res.is_err()); let aad = b"decrypt should fail".to_vec(); ciphertext[0] ^= ciphertext[1]; - let res = aes.decrypt_easy(&aad, &ciphertext); + let res = cipher.decrypt_easy(&aad, &ciphertext); assert!(res.is_err()); } #[test] fn buffer_works() { - let aes = ChaCha20Poly1305::new(&ChaCha20Poly1305::key_gen().unwrap()); + let cipher = ChaCha20Poly1305::new(&ChaCha20Poly1305::key_gen().unwrap()); let aad = b"buffer works".to_vec(); let dummytext = b"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."; let mut ciphertext = Vec::new(); - let res = aes.encrypt_buffer(&aad, &mut Cursor::new(dummytext), &mut ciphertext); + let res = cipher.encrypt_buffer(&aad, &mut Cursor::new(dummytext), &mut ciphertext); assert!(res.is_ok()); let mut plaintext = Vec::new(); - let res = aes.decrypt_buffer( + let res = cipher.decrypt_buffer( &aad, &mut Cursor::new(ciphertext.as_slice()), &mut plaintext, diff --git a/crypto/src/encryption/mod.rs b/crypto/src/encryption/mod.rs index ff4b082d38b..ee91515ab2d 100644 --- a/crypto/src/encryption/mod.rs +++ b/crypto/src/encryption/mod.rs @@ -31,7 +31,10 @@ use crate::SessionKey; // Helpful for generating bytes using the operating system random number generator fn random_vec(bytes: usize) -> Result, Error> { let mut value = vec![0u8; bytes]; - OsRng.fill_bytes(value.as_mut_slice()); + OsRng + .try_fill_bytes(value.as_mut_slice()) + // RustCrypto errors don't have any details, can't propagate the error + .map_err(|_| Error)?; Ok(value) } @@ -53,11 +56,11 @@ fn read_buffer(buffer: &mut I) -> Result, Error> { /// # Usage /// /// ``` -/// extern crate ursa; -/// use ursa::encryption::symm::prelude::*; +/// use iroha_crypto::encryption::{SymmetricEncryptor, ChaCha20Poly1305}; /// -/// let encryptor = SymmetricEncryptor::::default(); -/// let aad = b"Using Aes128Gcm to encrypt data"; +/// let key: Vec = (0..0x20).collect(); +/// let encryptor = SymmetricEncryptor::::new_with_key(&key); +/// let aad = b"Using ChaCha20Poly1305 to encrypt data"; /// let message = b"Hidden message"; /// let res = encryptor.encrypt_easy(aad.as_ref(), message.as_ref()); /// assert!(res.is_ok()); @@ -79,23 +82,31 @@ impl SymmetricEncryptor { } /// Create a new [`SymmetricEncryptor`] from a [`SessionKey`] - pub fn new_from_session_key(key: SessionKey) -> Self { + pub fn new_from_session_key(key: &SessionKey) -> Self { Self::new(::new(GenericArray::from_slice(&key.0))) } /// Create a new [`SymmetricEncryptor`] from key bytes - pub fn new_with_key>(key: A) -> Result { - Ok(Self { + pub fn new_with_key>(key: A) -> Self { + Self { encryptor: ::new(GenericArray::from_slice(key.as_ref())), - }) + } } /// Encrypt `plaintext` and integrity protect `aad`. The result is the ciphertext. /// This method handles safely generating a `nonce` and prepends it to the ciphertext + /// + /// # Errors + /// + /// This function will return an error if nonce generation or encryption fails pub fn encrypt_easy>(&self, aad: A, plaintext: A) -> Result, Error> { self.encryptor.encrypt_easy(aad, plaintext) } /// Encrypt `plaintext` and integrity protect `aad`. The result is the ciphertext. + /// + /// # Errors + /// + /// This function will return an error if encryption fails pub fn encrypt>( &self, nonce: A, @@ -115,6 +126,10 @@ impl SymmetricEncryptor { /// or incorrect key. /// `aad` must be the same value used in `encrypt_easy`. Expects the nonce to be prepended to /// the `ciphertext` + /// + /// # Errors + /// + /// This function will return an error if decryption fails pub fn decrypt_easy>(&self, aad: A, ciphertext: A) -> Result, Error> { self.encryptor.decrypt_easy(aad, ciphertext) } @@ -123,6 +138,10 @@ impl SymmetricEncryptor { /// or an error if the `ciphetext` cannot be decrypted due to tampering, an incorrect `aad` value, /// or incorrect key. /// `aad` must be the same value used in `encrypt_easy`. + /// + /// # Errors + /// + /// This function will return an error if decryption fails pub fn decrypt>( &self, nonce: A, @@ -138,6 +157,10 @@ impl SymmetricEncryptor { } /// Similar to `encrypt_easy` but reads from a stream instead of a slice + /// + /// # Errors + /// + /// This function will return an error if reading the buffer, nonce generation, encryption or writing the buffer fails pub fn encrypt_buffer, I: Read, O: Write>( &self, aad: A, @@ -148,6 +171,10 @@ impl SymmetricEncryptor { } /// Similar to `decrypt_easy` but reads from a stream instead of a slice + /// + /// # Errors + /// + /// This function will return an error if reading the buffer, decryption or writing the buffer fails pub fn decrypt_buffer, I: Read, O: Write>( &self, aad: A, @@ -174,6 +201,10 @@ pub trait Encryptor: Aead + KeyInit { /// A simple API to encrypt a message with authenticated associated data. /// /// This API handles nonce generation for you and prepends it in front of the ciphertext. Use [`Encryptor::decrypt_easy`] to decrypt the message encrypted this way. + /// + /// # Errors + /// + /// This function will return an error if nonce generation or encryption fails fn encrypt_easy>(&self, aad: M, plaintext: M) -> Result, Error> { let nonce = Self::nonce_gen()?; let payload = Payload { @@ -189,6 +220,10 @@ pub trait Encryptor: Aead + KeyInit { /// A simple API to decrypt a message with authenticated associated data. /// /// This API expects the nonce to be prepended to the ciphertext. Use [`Encryptor::encrypt_easy`] to encrypt the message this way. + /// + /// # Errors + /// + /// This function will return an error if decryption fails fn decrypt_easy>(&self, aad: M, ciphertext: M) -> Result, Error> { let ciphertext = ciphertext.as_ref(); if ciphertext.len() < Self::MinSize::to_usize() { @@ -200,11 +235,15 @@ pub trait Encryptor: Aead + KeyInit { msg: &ciphertext[Self::NonceSize::to_usize()..], aad: aad.as_ref(), }; - let plaintext = self.decrypt(&nonce, payload)?; + let plaintext = self.decrypt(nonce, payload)?; Ok(plaintext) } /// Same as [`Encryptor::encrypt_easy`] but works with [`std::io`] streams instead of slices + /// + /// # Errors + /// + /// This function will return an error if reading the buffer, nonce generation, encryption or writing the buffer fails fn encrypt_buffer, I: Read, O: Write>( &self, aad: M, @@ -218,6 +257,10 @@ pub trait Encryptor: Aead + KeyInit { } /// Same as [`Encryptor::decrypt_easy`] but works with [`std::io`] streams instead of slices + /// + /// # Errors + /// + /// This function will return an error if reading the buffer, decryption or writing the buffer fails fn decrypt_buffer, I: Read, O: Write>( &self, aad: M, @@ -231,11 +274,19 @@ pub trait Encryptor: Aead + KeyInit { } /// Generate a new key for this encryptor + /// + /// # Errors + /// + /// This function will return an error if the operating system random number generator fails fn key_gen() -> Result, Error> { random_bytes() } /// Generate a new nonce for this encryptor + /// + /// # Errors + /// + /// This function will return an error if the operating system random number generator fails fn nonce_gen() -> Result, Error> { random_bytes() } diff --git a/crypto/src/kex/mod.rs b/crypto/src/kex/mod.rs index 0096d167d09..f76bc4ac090 100644 --- a/crypto/src/kex/mod.rs +++ b/crypto/src/kex/mod.rs @@ -16,10 +16,14 @@ pub trait KeyExchangeScheme { fn new() -> Self; /// Create new keypairs. If /// `options` is None, the keys are generated ephemerally from the `OsRng` - /// `options` is UseSeed, the keys are generated ephemerally from the sha256 hash of the seed which is - /// then used to seed the ChaChaRng - /// `options` is FromPrivateKey, the corresponding public key is returned. This should be used for + /// `options` is `UseSeed`, the keys are generated ephemerally from the sha256 hash of the seed which is + /// then used to seed the `ChaChaRng` + /// `options` is `FromPrivateKey`, the corresponding public key is returned. This should be used for /// static Diffie-Hellman and loading a long-term key. + /// + /// # Errors + /// + /// Returns an error if the key generation fails. fn keypair(&self, options: Option) -> Result<(PublicKey, PrivateKey), Error>; /// Compute the diffie-hellman shared secret. /// `local_private_key` is the key generated from calling `keypair` while @@ -28,7 +32,7 @@ pub trait KeyExchangeScheme { &self, local_private_key: &PrivateKey, remote_public_key: &PublicKey, - ) -> Result; + ) -> SessionKey; /// Size of the shared secret in bytes. const SHARED_SECRET_SIZE: usize; diff --git a/crypto/src/kex/x25519.rs b/crypto/src/kex/x25519.rs index e269842fb52..ee6b9ca98cd 100644 --- a/crypto/src/kex/x25519.rs +++ b/crypto/src/kex/x25519.rs @@ -20,27 +20,25 @@ impl KeyExchangeScheme for X25519Sha256 { Self } - fn keypair(&self, option: Option) -> Result<(PublicKey, PrivateKey), Error> { + fn keypair(&self, mut option: Option) -> Result<(PublicKey, PrivateKey), Error> { let (pk, sk) = match option { - Some(mut o) => match o { - 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)); - let sk = StaticSecret::random_from_rng(&mut rng); - let pk = X25519PublicKey::from(&sk); - (pk, sk) - } - KeyGenOption::FromPrivateKey(ref s) => { - assert_eq!(s.digest_function, ALGORITHM); - let sk = StaticSecret::from(*array_ref!(&s.payload, 0, 32)); - let pk = X25519PublicKey::from(&sk); - (pk, sk) - } - }, + Some(KeyGenOption::UseSeed(ref mut s)) => { + let hash = sha2::Sha256::digest(s.as_slice()); + s.zeroize(); + let rng = ChaChaRng::from_seed(*array_ref!(hash.as_slice(), 0, 32)); + let sk = StaticSecret::random_from_rng(rng); + let pk = X25519PublicKey::from(&sk); + (pk, sk) + } + Some(KeyGenOption::FromPrivateKey(ref s)) => { + assert_eq!(s.digest_function, ALGORITHM); + let sk = StaticSecret::from(*array_ref!(&s.payload, 0, 32)); + let pk = X25519PublicKey::from(&sk); + (pk, sk) + } None => { - let mut rng = OsRng::default(); - let sk = StaticSecret::random_from_rng(&mut rng); + let rng = OsRng; + let sk = StaticSecret::random_from_rng(rng); let pk = X25519PublicKey::from(&sk); (pk, sk) } @@ -61,14 +59,14 @@ impl KeyExchangeScheme for X25519Sha256 { &self, local_private_key: &PrivateKey, remote_public_key: &PublicKey, - ) -> Result { + ) -> SessionKey { assert_eq!(local_private_key.digest_function, ALGORITHM); assert_eq!(remote_public_key.digest_function, ALGORITHM); let sk = StaticSecret::from(*array_ref!(&local_private_key.payload, 0, 32)); let pk = X25519PublicKey::from(*array_ref!(&remote_public_key.payload, 0, 32)); let shared_secret = sk.diffie_hellman(&pk); let hash = sha2::Sha256::digest(shared_secret.as_bytes()); - Ok(SessionKey(ConstVec::new(hash.as_slice().to_vec()))) + SessionKey(ConstVec::new(hash.as_slice().to_vec())) } const SHARED_SECRET_SIZE: usize = 32; @@ -85,21 +83,17 @@ mod tests { let scheme = X25519Sha256::new(); let res = scheme.keypair(None); assert!(res.is_ok()); - let (pk, sk) = res.unwrap(); - let res = scheme.compute_shared_secret(&sk, &pk); - assert!(res.is_ok()); + let (public_key1, secret_key1) = res.unwrap(); + let _res = scheme.compute_shared_secret(&secret_key1, &public_key1); let res = scheme.keypair(None); - assert!(res.is_ok()); - let (pk1, sk1) = res.unwrap(); - let res = scheme.compute_shared_secret(&sk1, &pk); - assert!(res.is_ok()); - let res = scheme.compute_shared_secret(&sk, &pk1); - assert!(res.is_ok()); + let (public_key2, secret_key2) = res.unwrap(); + let _res = scheme.compute_shared_secret(&secret_key2, &public_key1); + let _res = scheme.compute_shared_secret(&secret_key1, &public_key2); - let res = scheme.keypair(Some(KeyGenOption::FromPrivateKey(sk.clone()))); + let res = scheme.keypair(Some(KeyGenOption::FromPrivateKey(secret_key1))); assert!(res.is_ok()); - let (pk1, sk1) = res.unwrap(); - assert_eq!(pk1, pk); - assert_eq!(sk1, sk); + let (public_key2, secret_key1) = res.unwrap(); + assert_eq!(public_key2, public_key1); + assert_eq!(secret_key1, secret_key1); } } diff --git a/crypto/src/lib.rs b/crypto/src/lib.rs index 9b33032e095..eb11d4bf977 100755 --- a/crypto/src/lib.rs +++ b/crypto/src/lib.rs @@ -34,7 +34,6 @@ pub use blake2; use derive_more::{DebugCustom, Display}; use error::{Error, NoSuchAlgorithm}; use getset::{CopyGetters, Getters}; -// TODO: do not spill the hashes to the crate root pub use hash::*; use iroha_macro::ffi_impl_opaque; use iroha_primitives::const_vec::ConstVec; @@ -46,8 +45,8 @@ use parity_scale_codec::{Decode, Encode}; use serde::Deserialize; use serde::Serialize; use serde_with::{DeserializeFromStr, SerializeDisplay}; -// TODO: do not spill the signatures to the crate root -pub use signature::*; + +pub use self::signature::*; // Hiding constants is a bad idea. For one, you're forcing the user to // create temporaries, but also you're not actually hiding any @@ -233,12 +232,12 @@ impl KeyPair { }; let (public_key, private_key) = match configuration.algorithm { - Algorithm::Ed25519 => signature::ed25519::Ed25519Sha512.keypair(key_gen_option), + Algorithm::Ed25519 => signature::ed25519::Ed25519Sha512::keypair(key_gen_option), Algorithm::Secp256k1 => { - signature::secp256k1::EcdsaSecp256k1Sha256::new().keypair(key_gen_option) + signature::secp256k1::EcdsaSecp256k1Sha256::keypair(key_gen_option) } - Algorithm::BlsNormal => signature::bls::BlsNormal::new().keypair(key_gen_option), - Algorithm::BlsSmall => signature::bls::BlsSmall::new().keypair(key_gen_option), + Algorithm::BlsNormal => signature::bls::BlsNormal::keypair(key_gen_option), + Algorithm::BlsSmall => signature::bls::BlsSmall::keypair(key_gen_option), }?; Ok(Self { @@ -319,12 +318,12 @@ impl PublicKey { let key_gen_option = Some(KeyGenOption::FromPrivateKey(private_key)); let (public_key, _) = match digest_function { - Algorithm::Ed25519 => signature::ed25519::Ed25519Sha512.keypair(key_gen_option), + Algorithm::Ed25519 => signature::ed25519::Ed25519Sha512::keypair(key_gen_option), Algorithm::Secp256k1 => { - signature::secp256k1::EcdsaSecp256k1Sha256::new().keypair(key_gen_option) + signature::secp256k1::EcdsaSecp256k1Sha256::keypair(key_gen_option) } - Algorithm::BlsNormal => signature::bls::BlsNormal::new().keypair(key_gen_option), - Algorithm::BlsSmall => signature::bls::BlsSmall::new().keypair(key_gen_option), + Algorithm::BlsNormal => signature::bls::BlsNormal::keypair(key_gen_option), + Algorithm::BlsSmall => signature::bls::BlsSmall::keypair(key_gen_option), }?; Ok(public_key) @@ -687,7 +686,7 @@ mod tests { .expect("Public key not in mulithash format"), PrivateKey::from_hex( Algorithm::Ed25519, - "93CA389FC2979F3F7D2A7F8B76C70DE6D5EAF5FA58D4F93CB8B0FB298D398ACC59C8A4DA1EBB5380F74ABA51F502714652FDCCE9611FAFB9904E4A3C4D382774".as_ref() + "93CA389FC2979F3F7D2A7F8B76C70DE6D5EAF5FA58D4F93CB8B0FB298D398ACC59C8A4DA1EBB5380F74ABA51F502714652FDCCE9611FAFB9904E4A3C4D382774" ).expect("Private key not hex encoded")).is_ok()); assert!(KeyPair::new("ea0161040FCFADE2FC5D9104A9ACF9665EA545339DDF10AE50343249E01AF3B8F885CD5D52956542CCE8105DB3A2EC4006E637A7177FAAEA228C311F907DAAFC254F22667F1A1812BB710C6F4116A1415275D27BB9FB884F37E8EF525CC31F3945E945FA" @@ -695,7 +694,7 @@ mod tests { .expect("Public key not in mulithash format"), PrivateKey::from_hex( Algorithm::BlsNormal, - "0000000000000000000000000000000049BF70187154C57B97AF913163E8E875733B4EAF1F3F0689B31CE392129493E9".as_ref() + "0000000000000000000000000000000049BF70187154C57B97AF913163E8E875733B4EAF1F3F0689B31CE392129493E9" ).expect("Private key not hex encoded")).is_ok()); } @@ -731,13 +730,13 @@ mod tests { fn invalid_private_key() { assert!(PrivateKey::from_hex( Algorithm::Ed25519, - "0000000000000000000000000000000049BF70187154C57B97AF913163E8E875733B4EAF1F3F0689B31CE392129493E9".as_ref() + "0000000000000000000000000000000049BF70187154C57B97AF913163E8E875733B4EAF1F3F0689B31CE392129493E9" ).is_err()); assert!( PrivateKey::from_hex( Algorithm::BlsNormal, - "93CA389FC2979F3F7D2A7F8B76C70DE6D5EAF5FA58D4F93CB8B0FB298D398ACC59C8A4DA1EBB5380F74ABA51F502714652FDCCE9611FAFB9904E4A3C4D382774".as_ref() + "93CA389FC2979F3F7D2A7F8B76C70DE6D5EAF5FA58D4F93CB8B0FB298D398ACC59C8A4DA1EBB5380F74ABA51F502714652FDCCE9611FAFB9904E4A3C4D382774" ).is_err()); } @@ -749,7 +748,7 @@ mod tests { .expect("Public key not in mulithash format"), PrivateKey::from_hex( Algorithm::Ed25519, - "3A7991AF1ABB77F3FD27CC148404A6AE4439D095A63591B77C788D53F708A02A1509A611AD6D97B01D871E58ED00C8FD7C3917B6CA61A8C2833A19E000AAC2E4".as_ref() + "3A7991AF1ABB77F3FD27CC148404A6AE4439D095A63591B77C788D53F708A02A1509A611AD6D97B01D871E58ED00C8FD7C3917B6CA61A8C2833A19E000AAC2E4" ).expect("Private key not valid")).is_err()); assert!(KeyPair::new("ea0161040FCFADE2FC5D9104A9ACF9665EA545339DDF10AE50343249E01AF3B8F885CD5D52956542CCE8105DB3A2EC4006E637A7177FAAEA228C311F907DAAFC254F22667F1A1812BB710C6F4116A1415275D27BB9FB884F37E8EF525CC31F3945E945FA" @@ -757,7 +756,7 @@ mod tests { .expect("Public key not in mulithash format"), PrivateKey::from_hex( Algorithm::BlsNormal, - "000000000000000000000000000000002F57460183837EFBAC6AA6AB3B8DBB7CFFCFC59E9448B7860A206D37D470CBA3".as_ref() + "000000000000000000000000000000002F57460183837EFBAC6AA6AB3B8DBB7CFFCFC59E9448B7860A206D37D470CBA3" ).expect("Private key not valid")).is_err()); } diff --git a/crypto/src/signature/bls/implementation.rs b/crypto/src/signature/bls/implementation.rs index 4cef0d569b4..c3dff70bc9f 100644 --- a/crypto/src/signature/bls/implementation.rs +++ b/crypto/src/signature/bls/implementation.rs @@ -1,8 +1,8 @@ use std::{hash::Hash, marker::PhantomData}; /// Implements -/// https://eprint.iacr.org/2018/483 and -/// https://crypto.stanford.edu/~dabo/pubs/papers/BLSmultisig.html +/// and +/// use amcl_wrapper::{ field_elem::FieldElement, group_elem::GroupElement, group_elem_g1::G1, group_elem_g2::G2, }; @@ -20,7 +20,7 @@ use crate::{ PublicKey as IrohaPublicKey, }; -/// This is a simple alias so the consumer can just use PrivateKey::random() to generate a new one +/// This is a simple alias so the consumer can just use `PrivateKey::random`() to generate a new one /// instead of wrapping it as a private field pub type PrivateKey = FieldElement; @@ -120,7 +120,7 @@ impl Signature { g: &C::Generator, ) -> bool { let hash = C::hash_msg(message, context); - C::ate_2_pairing_is_one(&g, &self.0, &pk.0, &hash) + C::ate_2_pairing_is_one(g, &self.0, &pk.0, &hash) } pub fn to_bytes(&self) -> Vec { @@ -149,12 +149,9 @@ impl BlsImpl { .map_err(|e| Error::Parse(format!("Failed to parse private key: {}", e))) } - pub fn new() -> Self { - Self(PhantomData) - } - + // the names are from an RFC, not a good idea to change them + #[allow(clippy::similar_names)] pub fn keypair( - &self, options: Option, ) -> Result<(IrohaPublicKey, IrohaPrivateKey), Error> { let (public_key, private_key) = match options { @@ -162,7 +159,7 @@ impl BlsImpl { // Follows https://datatracker.ietf.org/doc/draft-irtf-cfrg-bls-signature/?include_text=1 KeyGenOption::UseSeed(ref seed) => { let salt = b"BLS-SIG-KEYGEN-SALT-"; - let info = [0u8, PRIVATE_KEY_SIZE as u8]; // key_info || I2OSP(L, 2) + let info = [0u8, PRIVATE_KEY_SIZE.try_into().unwrap()]; // key_info || I2OSP(L, 2) let mut ikm = vec![0u8; seed.len() + 1]; ikm[..seed.len()].copy_from_slice(seed); // IKM || I2OSP(0, 1) let mut okm = [0u8; PRIVATE_KEY_SIZE]; @@ -198,18 +195,13 @@ impl BlsImpl { )) } - pub fn sign(&self, message: &[u8], sk: &IrohaPrivateKey) -> Result, Error> { + pub fn sign(message: &[u8], sk: &IrohaPrivateKey) -> Result, Error> { let sk = Self::parse_private_key(sk)?; Ok(Signature::::new(message, None, &sk).to_bytes()) } - pub fn verify( - &self, - message: &[u8], - signature: &[u8], - pk: &IrohaPublicKey, - ) -> Result { + pub fn verify(message: &[u8], signature: &[u8], pk: &IrohaPublicKey) -> Result { let pk = Self::parse_public_key(pk)?; Ok(Signature::::from_bytes(signature) diff --git a/crypto/src/signature/bls/mod.rs b/crypto/src/signature/bls/mod.rs index 4a7c228a75e..c3dc918abfb 100644 --- a/crypto/src/signature/bls/mod.rs +++ b/crypto/src/signature/bls/mod.rs @@ -17,11 +17,11 @@ mod normal { use super::{implementation, implementation::BlsConfiguration}; use crate::Algorithm; - pub(crate) type NormalGenerator = G1; - pub(crate) type NormalSignatureGroup = G2; + pub type NormalGenerator = G1; + pub type NormalSignatureGroup = G2; #[cfg(test)] - pub(crate) fn normal_generate( + pub fn normal_generate( g: &NormalGenerator, ) -> (NormalPublicKey, super::implementation::PrivateKey) { NormalConfiguration::generate(g) @@ -52,9 +52,9 @@ mod normal { pub type NormalBls = implementation::BlsImpl; #[cfg(test)] - pub(crate) type NormalSignature = implementation::Signature; + pub type NormalSignature = implementation::Signature; #[cfg(test)] - pub(crate) type NormalPublicKey = implementation::PublicKey; + pub type NormalPublicKey = implementation::PublicKey; } /// This version is the small BLS signature scheme @@ -74,11 +74,11 @@ mod small { use super::implementation::{self, BlsConfiguration}; use crate::Algorithm; - pub(crate) type SmallGenerator = G2; - pub(crate) type SmallSignatureGroup = G1; + pub type SmallGenerator = G2; + pub type SmallSignatureGroup = G1; #[cfg(test)] - pub(crate) fn small_generate( + pub fn small_generate( g: &SmallGenerator, ) -> (SmallPublicKey, super::implementation::PrivateKey) { SmallConfiguration::generate(g) @@ -109,9 +109,9 @@ mod small { pub type SmallBls = implementation::BlsImpl; #[cfg(test)] - pub(crate) type SmallSignature = implementation::Signature; + pub type SmallSignature = implementation::Signature; #[cfg(test)] - pub(crate) type SmallPublicKey = implementation::PublicKey; + pub type SmallPublicKey = implementation::PublicKey; } pub use normal::NormalBls as BlsNormal; diff --git a/crypto/src/signature/bls/tests.rs b/crypto/src/signature/bls/tests.rs index 72c42f192ee..243f4d27bca 100644 --- a/crypto/src/signature/bls/tests.rs +++ b/crypto/src/signature/bls/tests.rs @@ -35,12 +35,8 @@ fn size_check() { } fn signature_generation_from_seed() { - let keypair_1 = BlsImpl::::new() - .keypair(Some(KeyGenOption::UseSeed(SEED.to_vec()))) - .unwrap(); - let keypair_2 = BlsImpl::::new() - .keypair(Some(KeyGenOption::UseSeed(SEED.to_vec()))) - .unwrap(); + let keypair_1 = BlsImpl::::keypair(Some(KeyGenOption::UseSeed(SEED.to_vec()))).unwrap(); + let keypair_2 = BlsImpl::::keypair(Some(KeyGenOption::UseSeed(SEED.to_vec()))).unwrap(); assert_eq!(keypair_1, keypair_2); } diff --git a/crypto/src/signature/ed25519.rs b/crypto/src/signature/ed25519.rs index b546d635f64..6f462ee9b75 100644 --- a/crypto/src/signature/ed25519.rs +++ b/crypto/src/signature/ed25519.rs @@ -1,7 +1,7 @@ use std::convert::TryFrom; use arrayref::array_ref; -use ed25519_dalek::{Signature, Signer, SigningKey, Verifier, VerifyingKey as PK}; +use ed25519_dalek::{Signature, SigningKey, VerifyingKey as PK}; pub use ed25519_dalek::{ EXPANDED_SECRET_KEY_LENGTH as PRIVATE_KEY_SIZE, PUBLIC_KEY_LENGTH as PUBLIC_KEY_SIZE, SIGNATURE_LENGTH as SIGNATURE_SIZE, @@ -10,6 +10,7 @@ use iroha_primitives::const_vec::ConstVec; use rand::{rngs::OsRng, SeedableRng}; use rand_chacha::ChaChaRng; use sha2::Digest; +use signature::{Signer as _, Verifier as _}; use zeroize::Zeroize; const ALGORITHM: Algorithm = Algorithm::Ed25519; @@ -33,22 +34,17 @@ fn parse_public_key(pk: &PublicKey) -> Result { pub struct Ed25519Sha512; impl Ed25519Sha512 { - pub fn new() -> Self { - Self - } - pub fn keypair(&self, option: Option) -> Result<(PublicKey, PrivateKey), Error> { + pub fn keypair(mut option: Option) -> Result<(PublicKey, PrivateKey), Error> { let kp = match option { - Some(mut o) => match o { - 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)); - SigningKey::generate(&mut rng) - } - KeyGenOption::FromPrivateKey(ref s) => parse_private_key(s)?, - }, + Some(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)); + SigningKey::generate(&mut rng) + } + Some(KeyGenOption::FromPrivateKey(ref s)) => parse_private_key(s)?, None => { - let mut rng = OsRng::default(); + let mut rng = OsRng; SigningKey::generate(&mut rng) } }; @@ -63,11 +59,11 @@ impl Ed25519Sha512 { }, )) } - pub fn sign(&self, message: &[u8], sk: &PrivateKey) -> Result, Error> { + pub fn sign(message: &[u8], sk: &PrivateKey) -> Result, Error> { let kp = parse_private_key(sk)?; Ok(kp.sign(message).to_bytes().to_vec()) } - pub fn verify(&self, message: &[u8], signature: &[u8], pk: &PublicKey) -> Result { + pub fn verify(message: &[u8], signature: &[u8], pk: &PublicKey) -> Result { let p = parse_public_key(pk)?; let s = Signature::try_from(signature).map_err(|e| Error::Parse(e.to_string()))?; p.verify(message, &s) @@ -94,18 +90,16 @@ mod test { #[test] #[ignore] fn create_new_keys() { - let scheme = Ed25519Sha512::new(); - let (p, s) = scheme.keypair(None).unwrap(); + let (p, s) = Ed25519Sha512::keypair(None).unwrap(); - println!("{:?}", s); - println!("{:?}", p); + println!("{s:?}"); + println!("{p:?}"); } #[test] fn ed25519_load_keys() { - let scheme = Ed25519Sha512::new(); let secret = PrivateKey::from_hex(Algorithm::Ed25519, PRIVATE_KEY).unwrap(); - let sres = scheme.keypair(Some(KeyGenOption::FromPrivateKey(secret))); + let sres = Ed25519Sha512::keypair(Some(KeyGenOption::FromPrivateKey(secret))); assert!(sres.is_ok()); let (p1, s1) = sres.unwrap(); @@ -121,13 +115,11 @@ mod test { #[test] fn ed25519_verify() { - let scheme = Ed25519Sha512::new(); let secret = PrivateKey::from_hex(Algorithm::Ed25519, PRIVATE_KEY).unwrap(); - let (p, _) = scheme - .keypair(Some(KeyGenOption::FromPrivateKey(secret))) - .unwrap(); + let (p, _) = Ed25519Sha512::keypair(Some(KeyGenOption::FromPrivateKey(secret))).unwrap(); - let result = scheme.verify(&MESSAGE_1, hex::decode(SIGNATURE_1).unwrap().as_slice(), &p); + let result = + Ed25519Sha512::verify(MESSAGE_1, hex::decode(SIGNATURE_1).unwrap().as_slice(), &p); assert!(result.is_ok()); assert!(result.unwrap()); @@ -146,38 +138,31 @@ mod test { #[test] fn ed25519_sign() { - let scheme = Ed25519Sha512::new(); let secret = PrivateKey::from_hex(Algorithm::Ed25519, PRIVATE_KEY).unwrap(); - let (p, s) = scheme - .keypair(Some(KeyGenOption::FromPrivateKey(secret))) - .unwrap(); - - match scheme.sign(&MESSAGE_1, &s) { - Ok(sig) => { - let result = scheme.verify(&MESSAGE_1, &sig, &p); - assert!(result.is_ok()); - assert!(result.unwrap()); - - assert_eq!(sig.len(), SIGNATURE_SIZE); - assert_eq!(hex::encode(sig.as_slice()), SIGNATURE_1); - - //Check if libsodium signs the message and this module still can verify it - //And that private keys can sign with other libraries - let mut signature = [0u8; ffi::crypto_sign_ed25519_BYTES as usize]; - unsafe { - ffi::crypto_sign_ed25519_detached( - signature.as_mut_ptr(), - std::ptr::null_mut(), - MESSAGE_1.as_ptr(), - MESSAGE_1.len() as u64, - s.payload().as_ptr(), - ) - }; - let result = scheme.verify(&MESSAGE_1, &signature, &p); - assert!(result.is_ok()); - assert!(result.unwrap()); - } - Err(e) => assert!(false, "{}", e), - } + let (p, s) = Ed25519Sha512::keypair(Some(KeyGenOption::FromPrivateKey(secret))).unwrap(); + + let sig = Ed25519Sha512::sign(MESSAGE_1, &s).unwrap(); + let result = Ed25519Sha512::verify(MESSAGE_1, &sig, &p); + assert!(result.is_ok()); + assert!(result.unwrap()); + + assert_eq!(sig.len(), SIGNATURE_SIZE); + assert_eq!(hex::encode(sig.as_slice()), SIGNATURE_1); + + //Check if libsodium signs the message and this module still can verify it + //And that private keys can sign with other libraries + let mut signature = [0u8; ffi::crypto_sign_ed25519_BYTES as usize]; + unsafe { + ffi::crypto_sign_ed25519_detached( + signature.as_mut_ptr(), + std::ptr::null_mut(), + MESSAGE_1.as_ptr(), + MESSAGE_1.len() as u64, + s.payload().as_ptr(), + ) + }; + let result = Ed25519Sha512::verify(MESSAGE_1, &signature, &p); + assert!(result.is_ok()); + assert!(result.unwrap()); } } diff --git a/crypto/src/signature/mod.rs b/crypto/src/signature/mod.rs index f8a2d1b9a8e..387a939be29 100644 --- a/crypto/src/signature/mod.rs +++ b/crypto/src/signature/mod.rs @@ -1,3 +1,6 @@ +// pub(crate) for inner modules it is not redundant, the contents of `signature` module get re-exported at root +#![allow(clippy::redundant_pub_crate)] + #[cfg(feature = "std")] #[cfg(not(feature = "ffi_import"))] pub(crate) mod bls; @@ -67,12 +70,12 @@ impl Signature { let algorithm: crate::Algorithm = private_key.digest_function(); let signature = match algorithm { - crate::Algorithm::Ed25519 => ed25519::Ed25519Sha512::new().sign(payload, &private_key), + crate::Algorithm::Ed25519 => ed25519::Ed25519Sha512::sign(payload, &private_key), crate::Algorithm::Secp256k1 => { - secp256k1::EcdsaSecp256k1Sha256::new().sign(payload, &private_key) + secp256k1::EcdsaSecp256k1Sha256::sign(payload, &private_key) } - crate::Algorithm::BlsSmall => bls::BlsSmall::new().sign(payload, &private_key), - crate::Algorithm::BlsNormal => bls::BlsNormal::new().sign(payload, &private_key), + crate::Algorithm::BlsSmall => bls::BlsSmall::sign(payload, &private_key), + crate::Algorithm::BlsNormal => bls::BlsNormal::sign(payload, &private_key), }?; Ok(Self { public_key, @@ -90,18 +93,16 @@ impl Signature { match algorithm { crate::Algorithm::Ed25519 => { - ed25519::Ed25519Sha512::new().verify(payload, self.payload(), &self.public_key) + ed25519::Ed25519Sha512::verify(payload, self.payload(), &self.public_key) + } + crate::Algorithm::Secp256k1 => { + secp256k1::EcdsaSecp256k1Sha256::verify(payload, self.payload(), &self.public_key) } - crate::Algorithm::Secp256k1 => secp256k1::EcdsaSecp256k1Sha256::new().verify( - payload, - self.payload(), - &self.public_key, - ), crate::Algorithm::BlsSmall => { - bls::BlsSmall::new().verify(payload, self.payload(), &self.public_key) + bls::BlsSmall::verify(payload, self.payload(), &self.public_key) } crate::Algorithm::BlsNormal => { - bls::BlsNormal::new().verify(payload, self.payload(), &self.public_key) + bls::BlsNormal::verify(payload, self.payload(), &self.public_key) } }?; diff --git a/crypto/src/signature/secp256k1.rs b/crypto/src/signature/secp256k1.rs index 77fb6cf6104..8cca69a1fd5 100644 --- a/crypto/src/signature/secp256k1.rs +++ b/crypto/src/signature/secp256k1.rs @@ -1,3 +1,4 @@ +use self::ecdsa_secp256k1::EcdsaSecp256k1Impl; use crate::{Algorithm, Error, KeyGenOption, PrivateKey, PublicKey}; pub const PRIVATE_KEY_SIZE: usize = 32; @@ -5,55 +6,45 @@ pub const PUBLIC_KEY_SIZE: usize = 33; const ALGORITHM: Algorithm = Algorithm::Secp256k1; -pub struct EcdsaSecp256k1Sha256(ecdsa_secp256k1::EcdsaSecp256k1Impl); +pub struct EcdsaSecp256k1Sha256; impl EcdsaSecp256k1Sha256 { - pub fn new() -> Self { - EcdsaSecp256k1Sha256(ecdsa_secp256k1::EcdsaSecp256k1Impl::new()) + pub fn keypair(option: Option) -> Result<(PublicKey, PrivateKey), Error> { + EcdsaSecp256k1Impl::keypair(option) } - pub fn keypair(&self, option: Option) -> Result<(PublicKey, PrivateKey), Error> { - self.0.keypair::(option) + pub fn sign(message: &[u8], sk: &PrivateKey) -> Result, Error> { + EcdsaSecp256k1Impl::sign(message, sk) } - pub fn sign(&self, message: &[u8], sk: &PrivateKey) -> Result, Error> { - self.0.sign::(message, sk) - } - pub fn verify(&self, message: &[u8], signature: &[u8], pk: &PublicKey) -> Result { - self.0.verify::(message, signature, pk) + pub fn verify(message: &[u8], signature: &[u8], pk: &PublicKey) -> Result { + EcdsaSecp256k1Impl::verify(message, signature, pk) } } mod ecdsa_secp256k1 { use amcl::secp256k1::ecp; use arrayref::array_ref; - use digest::{consts::U32, Digest}; - use ed25519_dalek::{Signer, Verifier}; + use digest::Digest as _; use iroha_primitives::const_vec::ConstVec; - use k256; use rand::{rngs::OsRng, RngCore, SeedableRng}; use rand_chacha::ChaChaRng; + use signature::{Signer as _, Verifier as _}; use zeroize::Zeroize; use super::{ALGORITHM, PRIVATE_KEY_SIZE, PUBLIC_KEY_SIZE}; use crate::{Error, KeyGenOption, PrivateKey, PublicKey}; pub struct EcdsaSecp256k1Impl; + type Digest = sha2::Sha256; impl EcdsaSecp256k1Impl { - pub fn public_key_compressed(&self, pk: &PublicKey) -> Vec { + pub fn public_key_compressed(pk: &PublicKey) -> Vec { assert_eq!(pk.digest_function, ALGORITHM); let mut compressed = [0u8; PUBLIC_KEY_SIZE]; ecp::ECP::frombytes(&pk.payload[..]).tobytes(&mut compressed, true); compressed.to_vec() } - pub fn new() -> Self { - Self {} - } - - pub fn keypair>( - &self, - option: Option, - ) -> Result<(PublicKey, PrivateKey), Error> { + pub fn keypair(option: Option) -> Result<(PublicKey, PrivateKey), Error> { let signing_key = match option { Some(mut o) => match o { KeyGenOption::UseSeed(ref mut seed) => { @@ -61,7 +52,7 @@ mod ecdsa_secp256k1 { let mut rng = ChaChaRng::from_seed(*array_ref!(seed.as_slice(), 0, 32)); seed.zeroize(); rng.fill_bytes(&mut s); - let k = D::digest(&s); + let k = Digest::digest(s); s.zeroize(); k256::SecretKey::from_slice(k.as_slice())? } @@ -87,10 +78,7 @@ mod ecdsa_secp256k1 { )) } - pub fn sign(&self, message: &[u8], sk: &PrivateKey) -> Result, Error> - where - D: Digest, - { + pub fn sign(message: &[u8], sk: &PrivateKey) -> Result, Error> { assert_eq!(sk.digest_function, ALGORITHM); let signing_key = k256::SecretKey::from_slice(&sk.payload[..]) .map_err(|e| Error::Signing(format!("{:?}", e)))?; @@ -100,16 +88,8 @@ mod ecdsa_secp256k1 { Ok(signature.to_bytes().to_vec()) } - pub fn verify( - &self, - message: &[u8], - signature: &[u8], - pk: &PublicKey, - ) -> Result - where - D: Digest, - { - let compressed_pk = self.public_key_compressed(pk); + pub fn verify(message: &[u8], signature: &[u8], pk: &PublicKey) -> Result { + let compressed_pk = Self::public_key_compressed(pk); let verifying_key = k256::PublicKey::from_sec1_bytes(&compressed_pk) .map_err(|e| Error::Signing(format!("{:?}", e)))?; let signature = k256::ecdsa::Signature::from_slice(signature) @@ -125,7 +105,7 @@ mod ecdsa_secp256k1 { impl From for Error { fn from(error: elliptic_curve::Error) -> Error { // RustCrypto doesn't expose any kind of error information =( - Error::Other(format!("{}", error)) + Error::Other(format!("{error}")) } } @@ -138,7 +118,6 @@ mod test { ecdsa::EcdsaSig, nid::Nid, }; - use secp256k1; use sha2::Digest; use super::*; @@ -160,28 +139,24 @@ mod test { #[test] #[ignore] fn create_new_keys() { - let scheme = EcdsaSecp256k1Sha256::new(); - let (s, p) = scheme.keypair(None).unwrap(); + let (s, p) = EcdsaSecp256k1Sha256::keypair(None).unwrap(); - println!("{:?}", s); - println!("{:?}", p); + println!("{s:?}"); + println!("{p:?}"); } #[test] fn secp256k1_load_keys() { - let scheme = EcdsaSecp256k1Sha256::new(); let secret = PrivateKey::from_hex(ALGORITHM, PRIVATE_KEY).unwrap(); - let sres = scheme.keypair(Some(KeyGenOption::FromPrivateKey(secret))); + let sres = EcdsaSecp256k1Sha256::keypair(Some(KeyGenOption::FromPrivateKey(secret))); assert!(sres.is_ok()); } #[test] fn secp256k1_compatibility() { - let scheme = EcdsaSecp256k1Sha256::new(); let secret = PrivateKey::from_hex(ALGORITHM, PRIVATE_KEY).unwrap(); - let (p, s) = scheme - .keypair(Some(KeyGenOption::FromPrivateKey(secret))) - .unwrap(); + let (p, s) = + EcdsaSecp256k1Sha256::keypair(Some(KeyGenOption::FromPrivateKey(secret))).unwrap(); let sk = secp256k1::SecretKey::from_slice(s.payload()); assert!(sk.is_ok()); @@ -197,10 +172,13 @@ mod test { #[test] fn secp256k1_verify() { - let scheme = EcdsaSecp256k1Sha256::new(); let p = PublicKey::from_hex(ALGORITHM, PUBLIC_KEY).unwrap(); - let result = scheme.verify(&MESSAGE_1, hex::decode(SIGNATURE_1).unwrap().as_slice(), &p); + let result = EcdsaSecp256k1Sha256::verify( + MESSAGE_1, + hex::decode(SIGNATURE_1).unwrap().as_slice(), + &p, + ); assert!(result.is_ok()); assert!(result.unwrap()); @@ -208,7 +186,7 @@ mod test { let pk = secp256k1::PublicKey::from_slice(hex::decode(PUBLIC_KEY).unwrap().as_slice()).unwrap(); - let h = sha2::Sha256::digest(&MESSAGE_1); + let h = sha2::Sha256::digest(MESSAGE_1); let msg = secp256k1::Message::from_digest_slice(h.as_slice()).unwrap(); //Check if signatures produced here can be verified by secp256k1 @@ -237,77 +215,65 @@ mod test { #[test] fn secp256k1_sign() { - let scheme = EcdsaSecp256k1Sha256::new(); let secret = PrivateKey::from_hex(ALGORITHM, PRIVATE_KEY).unwrap(); - let (p, s) = scheme - .keypair(Some(KeyGenOption::FromPrivateKey(secret))) - .unwrap(); - - match scheme.sign(MESSAGE_1, &s) { - Ok(sig) => { - let result = scheme.verify(&MESSAGE_1, &sig, &p); - assert!(result.is_ok()); - assert!(result.unwrap()); - - const SIGNATURE_SIZE: usize = 64; - assert_eq!(sig.len(), SIGNATURE_SIZE); - - // Check if secp256k1 signs the message and this module still can verify it - // And that private keys can sign with other libraries - let context = secp256k1::Secp256k1::new(); - let sk = - secp256k1::SecretKey::from_slice(hex::decode(PRIVATE_KEY).unwrap().as_slice()) - .unwrap(); - - let h = sha2::Sha256::digest(&MESSAGE_1); - - let msg = secp256k1::Message::from_digest_slice(h.as_slice()).unwrap(); - let sig_1 = context.sign_ecdsa(&msg, &sk).serialize_compact(); - - let result = scheme.verify(&MESSAGE_1, &sig_1, &p); - - assert!(result.is_ok()); - assert!(result.unwrap()); - - let openssl_group = EcGroup::from_curve_name(Nid::SECP256K1).unwrap(); - let mut ctx = BigNumContext::new().unwrap(); - let openssl_point = - EcPoint::from_bytes(&openssl_group, &public_key_uncompressed(&p)[..], &mut ctx) - .unwrap(); - let openssl_pkey = EcKey::from_public_key(&openssl_group, &openssl_point).unwrap(); - let openssl_skey = EcKey::from_private_components( - &openssl_group, - &BigNum::from_hex_str(PRIVATE_KEY).unwrap(), - &openssl_point, - ) + let (p, s) = + EcdsaSecp256k1Sha256::keypair(Some(KeyGenOption::FromPrivateKey(secret))).unwrap(); + + let sig = EcdsaSecp256k1Sha256::sign(MESSAGE_1, &s).unwrap(); + let result = EcdsaSecp256k1Sha256::verify(MESSAGE_1, &sig, &p); + assert!(result.is_ok()); + assert!(result.unwrap()); + + assert_eq!(sig.len(), 64); + + // Check if secp256k1 signs the message and this module still can verify it + // And that private keys can sign with other libraries + let context = secp256k1::Secp256k1::new(); + let sk = + secp256k1::SecretKey::from_slice(hex::decode(PRIVATE_KEY).unwrap().as_slice()).unwrap(); + + let h = sha2::Sha256::digest(MESSAGE_1); + + let msg = secp256k1::Message::from_digest_slice(h.as_slice()).unwrap(); + let sig_1 = context.sign_ecdsa(&msg, &sk).serialize_compact(); + + let result = EcdsaSecp256k1Sha256::verify(MESSAGE_1, &sig_1, &p); + + assert!(result.is_ok()); + assert!(result.unwrap()); + + let openssl_group = EcGroup::from_curve_name(Nid::SECP256K1).unwrap(); + let mut ctx = BigNumContext::new().unwrap(); + let openssl_point = + EcPoint::from_bytes(&openssl_group, &public_key_uncompressed(&p)[..], &mut ctx) .unwrap(); + let openssl_public_key = EcKey::from_public_key(&openssl_group, &openssl_point).unwrap(); + let openssl_secret_key = EcKey::from_private_components( + &openssl_group, + &BigNum::from_hex_str(PRIVATE_KEY).unwrap(), + &openssl_point, + ) + .unwrap(); + + let openssl_sig = EcdsaSig::sign(h.as_slice(), &openssl_secret_key).unwrap(); + let openssl_result = openssl_sig.verify(h.as_slice(), &openssl_public_key); + assert!(openssl_result.is_ok()); + assert!(openssl_result.unwrap()); + let mut temp_sig = Vec::new(); + temp_sig.extend(openssl_sig.r().to_vec()); + temp_sig.extend(openssl_sig.s().to_vec()); + + // secp256k1 expects normalized "s"'s. + // scheme.normalize_s(temp_sig.as_mut_slice()).unwrap(); + // k256 seems to be normalizing always now + let result = EcdsaSecp256k1Sha256::verify(MESSAGE_1, temp_sig.as_slice(), &p); + assert!(result.is_ok()); + assert!(result.unwrap()); - let openssl_sig = EcdsaSig::sign(h.as_slice(), &openssl_skey).unwrap(); - let openssl_result = openssl_sig.verify(h.as_slice(), &openssl_pkey); - assert!(openssl_result.is_ok()); - assert!(openssl_result.unwrap()); - let mut temp_sig = Vec::new(); - temp_sig.extend(openssl_sig.r().to_vec()); - temp_sig.extend(openssl_sig.s().to_vec()); - - // secp256k1 expects normalized "s"'s. - // scheme.normalize_s(temp_sig.as_mut_slice()).unwrap(); - // k256 seems to be normalizing always now - let result = scheme.verify(&MESSAGE_1, temp_sig.as_slice(), &p); - assert!(result.is_ok()); - assert!(result.unwrap()); - - let (p, s) = scheme.keypair(None).unwrap(); - match scheme.sign(&MESSAGE_1, &s) { - Ok(signed) => { - let result = scheme.verify(&MESSAGE_1, &signed, &p); - assert!(result.is_ok()); - assert!(result.unwrap()); - } - Err(er) => assert!(false, "{}", er), - } - } - Err(e) => assert!(false, "{}", e), - } + let (p, s) = EcdsaSecp256k1Sha256::keypair(None).unwrap(); + let signed = EcdsaSecp256k1Sha256::sign(MESSAGE_1, &s).unwrap(); + let result = EcdsaSecp256k1Sha256::verify(MESSAGE_1, &signed, &p); + assert!(result.is_ok()); + assert!(result.unwrap()); } } diff --git a/p2p/src/peer.rs b/p2p/src/peer.rs index 56162ab0ce2..898b2fc5dd6 100644 --- a/p2p/src/peer.rs +++ b/p2p/src/peer.rs @@ -431,8 +431,8 @@ mod state { PublicKey::from_raw(algorithm, ConstVec::new(key)) }; let shared_key = - key_exchange.compute_shared_secret(&local_private_key, &remote_public_key)?; - let cryptographer = Cryptographer::new(shared_key); + key_exchange.compute_shared_secret(&local_private_key, &remote_public_key); + let cryptographer = Cryptographer::new(&shared_key); Ok(SendKey { peer_id, connection, @@ -470,8 +470,8 @@ mod state { garbage::write(write_half).await?; write_half.write_all(&local_public_key_raw).await?; let shared_key = - key_exchange.compute_shared_secret(&local_private_key, &remote_public_key)?; - let cryptographer = Cryptographer::new(shared_key); + key_exchange.compute_shared_secret(&local_private_key, &remote_public_key); + let cryptographer = Cryptographer::new(&shared_key); Ok(SendKey { peer_id, connection, @@ -716,7 +716,7 @@ mod cryptographer { } /// Derives shared key from local private key and remote public key. - pub fn new(shared_key: SessionKey) -> Self { + pub fn new(shared_key: &SessionKey) -> Self { let disambiguator = blake2b_hash(shared_key.payload()); let encryptor = SymmetricEncryptor::::new_from_session_key(shared_key); diff --git a/p2p/tests/integration/p2p.rs b/p2p/tests/integration/p2p.rs index 4660d480660..33e7f6952d9 100644 --- a/p2p/tests/integration/p2p.rs +++ b/p2p/tests/integration/p2p.rs @@ -361,7 +361,7 @@ fn test_encryption() { 35, 231, 165, 122, 153, 14, 68, 13, 84, 5, 24, ]; - let encryptor = SymmetricEncryptor::::new_with_key(TEST_KEY).unwrap(); + let encryptor = SymmetricEncryptor::::new_with_key(TEST_KEY); let message = b"Some ciphertext"; let aad = b"Iroha2 AAD"; let res = encryptor.encrypt_easy(aad.as_ref(), message.as_ref()); diff --git a/primitives/src/const_vec.rs b/primitives/src/const_vec.rs index 27578187b53..f53d1b0d657 100644 --- a/primitives/src/const_vec.rs +++ b/primitives/src/const_vec.rs @@ -9,13 +9,20 @@ use iroha_schema::{IntoSchema, MetaMap, Metadata, TypeId, VecMeta}; use parity_scale_codec::{WrapperTypeDecode, WrapperTypeEncode}; use serde::{Deserialize, Serialize}; -/// Stores bytes that are not supposed to change during the runtime of the program in a compact way -/// -/// This is a more efficient than `Vec` because it does not have to store the capacity field -/// -/// It does not do reference-counting, so cloning is not cheap -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default, Serialize, Deserialize)] -pub struct ConstVec(Box<[T]>); +use crate::ffi; + +ffi::ffi_item! { + /// Stores bytes that are not supposed to change during the runtime of the program in a compact way + /// + /// This is a more efficient than `Vec` because it does not have to store the capacity field + /// + /// It does not do reference-counting, so cloning is not cheap + #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default, Serialize, Deserialize)] + #[repr(transparent)] + pub struct ConstVec(Box<[T]>); + + ffi_type(opaque) +} impl ConstVec { /// Create a new `ConstVec` from something convertible into a `Box<[T]>`. diff --git a/tools/kagami/src/config.rs b/tools/kagami/src/config.rs index de4937d7003..2d33d5b4a4b 100644 --- a/tools/kagami/src/config.rs +++ b/tools/kagami/src/config.rs @@ -52,7 +52,7 @@ mod client { )?), private_key: Some(PrivateKey::from_hex( Algorithm::Ed25519, - "9AC47ABF59B356E0BD7DCBBBB4DEC080E302156A48CA907E47CB6AEA1D32719E7233BFC89DCBD68C19FDE6CE6158225298EC1131B6A130D1AEB454C1AB5183C0".as_ref() + "9AC47ABF59B356E0BD7DCBBBB4DEC080E302156A48CA907E47CB6AEA1D32719E7233BFC89DCBD68C19FDE6CE6158225298EC1131B6A130D1AEB454C1AB5183C0" )?), ..ConfigurationProxy::default() }