diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock index 2db192dcbf1a165ab19b2174647467cdaf7f4cef..b5506b12594362e4e3f299bd62faf7d18c433ba2 100644 --- a/substrate/Cargo.lock +++ b/substrate/Cargo.lock @@ -1788,6 +1788,20 @@ dependencies = [ "zeroize", ] +[[package]] +name = "ed25519-zebra" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "403ef3e961ab98f0ba902771d29f842058578bb1ce7e3c59dad5a6a93e784c69" +dependencies = [ + "curve25519-dalek 3.0.2", + "hex", + "rand_core 0.6.2", + "sha2 0.9.8", + "thiserror", + "zeroize", +] + [[package]] name = "either" version = "1.6.1" @@ -9624,7 +9638,7 @@ dependencies = [ "byteorder", "criterion", "dyn-clonable", - "ed25519-dalek", + "ed25519-zebra", "futures", "hash-db", "hash256-std-hasher", diff --git a/substrate/Cargo.toml b/substrate/Cargo.toml index 1f22343c002a86ff577e34dee3aec31fe6adb63f..e2907716ca9f2ac92e9a75e40aec1df09c310d95 100644 --- a/substrate/Cargo.toml +++ b/substrate/Cargo.toml @@ -258,7 +258,7 @@ crc32fast = { opt-level = 3 } crossbeam-deque = { opt-level = 3 } crypto-mac = { opt-level = 3 } curve25519-dalek = { opt-level = 3 } -ed25519-dalek = { opt-level = 3 } +ed25519-zebra = { opt-level = 3 } flate2 = { opt-level = 3 } futures-channel = { opt-level = 3 } hashbrown = { opt-level = 3 } diff --git a/substrate/primitives/core/Cargo.toml b/substrate/primitives/core/Cargo.toml index fced67829314088cb9dcafd4b6ae9b4ebc4e1bc7..2cdfd04e942d7e718718818da6d394408257e906 100644 --- a/substrate/primitives/core/Cargo.toml +++ b/substrate/primitives/core/Cargo.toml @@ -47,7 +47,7 @@ thiserror = { version = "1.0.30", optional = true } bitflags = "1.3" # full crypto -ed25519-dalek = { version = "1.0.1", default-features = false, features = ["u64_backend", "alloc"], optional = true } +ed25519-zebra = { version = "3.0.0", default-features = false, optional = true} blake2-rfc = { version = "0.2.18", default-features = false, optional = true } schnorrkel = { version = "0.9.1", features = [ "preaudit_deprecated", @@ -97,7 +97,7 @@ std = [ "sp-std/std", "serde", "blake2-rfc/std", - "ed25519-dalek/std", + "ed25519-zebra", "hex/std", "base58", "substrate-bip39", @@ -127,7 +127,7 @@ std = [ # or Intel SGX. # For the regular wasm runtime builds this should not be used. full_crypto = [ - "ed25519-dalek", + "ed25519-zebra", "blake2-rfc", "schnorrkel", "hex", diff --git a/substrate/primitives/core/src/ed25519.rs b/substrate/primitives/core/src/ed25519.rs index 177af0651c0efe678574e30b0eeabf5b9267998a..0553cf4843df5511968a85b71044db355d3750b5 100644 --- a/substrate/primitives/core/src/ed25519.rs +++ b/substrate/primitives/core/src/ed25519.rs @@ -39,7 +39,9 @@ use crate::crypto::{DeriveJunction, Pair as TraitPair, SecretStringError}; #[cfg(feature = "std")] use bip39::{Language, Mnemonic, MnemonicType}; #[cfg(feature = "full_crypto")] -use ed25519_dalek::{Signer as _, Verifier as _}; +use core::convert::TryFrom; +#[cfg(feature = "full_crypto")] +use ed25519_zebra::{SigningKey, VerificationKey}; #[cfg(feature = "std")] use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; use sp_runtime_interface::pass_by::PassByInner; @@ -75,17 +77,10 @@ pub struct Public(pub [u8; 32]); /// A key pair. #[cfg(feature = "full_crypto")] -pub struct Pair(ed25519_dalek::Keypair); - -#[cfg(feature = "full_crypto")] -impl Clone for Pair { - fn clone(&self) -> Self { - Pair(ed25519_dalek::Keypair { - public: self.0.public, - secret: ed25519_dalek::SecretKey::from_bytes(self.0.secret.as_bytes()) - .expect("key is always the correct size; qed"), - }) - } +#[derive(Copy, Clone)] +pub struct Pair { + public: VerificationKey, + secret: SigningKey, } impl AsRef<[u8; 32]> for Public { @@ -456,10 +451,10 @@ impl TraitPair for Pair { /// /// You should never need to use this; generate(), generate_with_phrase fn from_seed_slice(seed_slice: &[u8]) -> Result<Pair, SecretStringError> { - let secret = ed25519_dalek::SecretKey::from_bytes(seed_slice) - .map_err(|_| SecretStringError::InvalidSeedLength)?; - let public = ed25519_dalek::PublicKey::from(&secret); - Ok(Pair(ed25519_dalek::Keypair { secret, public })) + let secret = + SigningKey::try_from(seed_slice).map_err(|_| SecretStringError::InvalidSeedLength)?; + let public = VerificationKey::from(&secret); + Ok(Pair { secret, public }) } /// Derive a child key from a series of given junctions. @@ -468,7 +463,7 @@ impl TraitPair for Pair { path: Iter, _seed: Option<Seed>, ) -> Result<(Pair, Option<Seed>), DeriveError> { - let mut acc = self.0.secret.to_bytes(); + let mut acc = self.secret.into(); for j in path { match j { DeriveJunction::Soft(_cc) => return Err(DeriveError::SoftKeyInPath), @@ -480,16 +475,12 @@ impl TraitPair for Pair { /// Get the public key. fn public(&self) -> Public { - let mut r = [0u8; 32]; - let pk = self.0.public.as_bytes(); - r.copy_from_slice(pk); - Public(r) + Public(self.public.into()) } /// Sign a message. fn sign(&self, message: &[u8]) -> Signature { - let r = self.0.sign(message).to_bytes(); - Signature::from_raw(r) + Signature::from_raw(self.secret.sign(message).into()) } /// Verify a signature on a message. Returns true if the signature is good. @@ -502,17 +493,17 @@ impl TraitPair for Pair { /// This doesn't use the type system to ensure that `sig` and `pubkey` are the correct /// size. Use it only if you're coming from byte buffers and need the speed. fn verify_weak<P: AsRef<[u8]>, M: AsRef<[u8]>>(sig: &[u8], message: M, pubkey: P) -> bool { - let public_key = match ed25519_dalek::PublicKey::from_bytes(pubkey.as_ref()) { + let public_key = match VerificationKey::try_from(pubkey.as_ref()) { Ok(pk) => pk, Err(_) => return false, }; - let sig = match ed25519_dalek::Signature::try_from(sig) { + let sig = match ed25519_zebra::Signature::try_from(sig) { Ok(s) => s, Err(_) => return false, }; - public_key.verify(message.as_ref(), &sig).is_ok() + public_key.verify(&sig, message.as_ref()).is_ok() } /// Return a vec filled with raw data. @@ -524,8 +515,8 @@ impl TraitPair for Pair { #[cfg(feature = "full_crypto")] impl Pair { /// Get the seed for this key. - pub fn seed(&self) -> &Seed { - self.0.secret.as_bytes() + pub fn seed(&self) -> Seed { + self.secret.into() } /// Exactly as `from_string` except that if no matches are found then, the the first 32 @@ -577,12 +568,12 @@ mod test { fn seed_and_derive_should_work() { let seed = hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"); let pair = Pair::from_seed(&seed); - assert_eq!(pair.seed(), &seed); + assert_eq!(pair.seed(), seed); let path = vec![DeriveJunction::Hard([0u8; 32])]; let derived = pair.derive(path.into_iter(), None).ok().unwrap().0; assert_eq!( derived.seed(), - &hex!("ede3354e133f9c8e337ddd6ee5415ed4b4ffe5fc7d21e933f4930a3730e5b21c") + hex!("ede3354e133f9c8e337ddd6ee5415ed4b4ffe5fc7d21e933f4930a3730e5b21c") ); } diff --git a/substrate/primitives/io/src/lib.rs b/substrate/primitives/io/src/lib.rs index 9bf9345e594c312928356dc25e5d0305fb22987d..7942bafcc2a1bb860c36ea5bfb6c902659ba194c 100644 --- a/substrate/primitives/io/src/lib.rs +++ b/substrate/primitives/io/src/lib.rs @@ -1895,6 +1895,7 @@ mod tests { ext.register_extension(TaskExecutorExt::new(TaskExecutor::new())); ext.execute_with(|| { let pair = sr25519::Pair::generate_with_phrase(None).0; + let pair_unused = sr25519::Pair::generate_with_phrase(None).0; crypto::start_batch_verify(); for it in 0..70 { let msg = format!("Schnorrkel {}!", it); @@ -1902,8 +1903,10 @@ mod tests { crypto::sr25519_batch_verify(&signature, msg.as_bytes(), &pair.public()); } - // push invlaid - crypto::sr25519_batch_verify(&zero_sr_sig(), &Vec::new(), &zero_sr_pub()); + // push invalid + let msg = b"asdf!"; + let signature = pair.sign(msg); + crypto::sr25519_batch_verify(&signature, msg, &pair_unused.public()); assert!(!crypto::finish_batch_verify()); crypto::start_batch_verify(); @@ -1938,10 +1941,10 @@ mod tests { ext.register_extension(TaskExecutorExt::new(TaskExecutor::new())); ext.execute_with(|| { - // invalid ed25519 signature + // valid ed25519 signature crypto::start_batch_verify(); crypto::ed25519_batch_verify(&zero_ed_sig(), &Vec::new(), &zero_ed_pub()); - assert!(!crypto::finish_batch_verify()); + assert!(crypto::finish_batch_verify()); // 2 valid ed25519 signatures crypto::start_batch_verify(); @@ -1961,12 +1964,14 @@ mod tests { // 1 valid, 1 invalid ed25519 signature crypto::start_batch_verify(); - let pair = ed25519::Pair::generate_with_phrase(None).0; + let pair1 = ed25519::Pair::generate_with_phrase(None).0; + let pair2 = ed25519::Pair::generate_with_phrase(None).0; let msg = b"Important message"; - let signature = pair.sign(msg); - crypto::ed25519_batch_verify(&signature, msg, &pair.public()); + let signature = pair1.sign(msg); crypto::ed25519_batch_verify(&zero_ed_sig(), &Vec::new(), &zero_ed_pub()); + crypto::ed25519_batch_verify(&signature, msg, &pair1.public()); + crypto::ed25519_batch_verify(&signature, msg, &pair2.public()); assert!(!crypto::finish_batch_verify()); @@ -1993,11 +1998,13 @@ mod tests { // 1 valid sr25519, 1 invalid sr25519 crypto::start_batch_verify(); - let pair = sr25519::Pair::generate_with_phrase(None).0; + let pair1 = sr25519::Pair::generate_with_phrase(None).0; + let pair2 = sr25519::Pair::generate_with_phrase(None).0; let msg = b"Schnorrkcel!"; - let signature = pair.sign(msg); - crypto::sr25519_batch_verify(&signature, msg, &pair.public()); + let signature = pair1.sign(msg); + crypto::sr25519_batch_verify(&signature, msg, &pair1.public()); + crypto::sr25519_batch_verify(&signature, msg, &pair2.public()); crypto::sr25519_batch_verify(&zero_sr_sig(), &Vec::new(), &zero_sr_pub()); assert!(!crypto::finish_batch_verify());