From 4db37e7a3eecd5f5e0ba741cfd109a0a388f0f6d Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Thu, 17 Feb 2022 10:47:32 +0100 Subject: [PATCH 1/8] Replace libsecp256k1 with k256 in beefy-mmr --- Cargo.lock | 144 ++++++++++++++++++++++++++++++++++++- frame/beefy-mmr/Cargo.toml | 4 +- frame/beefy-mmr/src/lib.rs | 27 ++++--- 3 files changed, 156 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 992a49306f18f..19f978b7fcbe5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -437,6 +437,12 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4521f3e3d031370679b3b140beb36dfe4801b09ac77e30c61941f97df3ef28b" +[[package]] +name = "base16ct" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" + [[package]] name = "base58" version = "0.2.0" @@ -474,6 +480,12 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +[[package]] +name = "base64ct" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "874f8444adcb4952a8bc51305c8be95c8ec8237bb0d2e78d2e039f771f8828a0" + [[package]] name = "beef" version = "0.5.1" @@ -1066,6 +1078,12 @@ dependencies = [ "cache-padded", ] +[[package]] +name = "const-oid" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3" + [[package]] name = "constant_time_eq" version = "0.1.5" @@ -1390,6 +1408,18 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +[[package]] +name = "crypto-bigint" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c6a1d5fa1de37e071642dfa44ec552ca5b299adb128fab16138e24b548fd21" +dependencies = [ + "generic-array 0.14.4", + "rand_core 0.6.2", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.2" @@ -1567,6 +1597,15 @@ dependencies = [ "syn", ] +[[package]] +name = "der" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6919815d73839e7ad218de758883aae3a257ba6759ce7a9992501efbb53d705c" +dependencies = [ + "const-oid", +] + [[package]] name = "derive_more" version = "0.99.16" @@ -1749,6 +1788,17 @@ dependencies = [ "memmap2 0.2.1", ] +[[package]] +name = "ecdsa" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0d69ae62e0ce582d56380743515fefaf1a8c70cec685d9677636d7e30ae9dc9" +dependencies = [ + "der", + "elliptic-curve", + "signature", +] + [[package]] name = "ed25519" version = "1.0.3" @@ -1778,6 +1828,24 @@ version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +[[package]] +name = "elliptic-curve" +version = "0.11.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25b477563c2bfed38a3b7a60964c49e058b2510ad3f12ba3483fd8f62c2306d6" +dependencies = [ + "base16ct", + "crypto-bigint", + "der", + "ff", + "generic-array 0.14.4", + "group", + "rand_core 0.6.2", + "sec1", + "subtle", + "zeroize", +] + [[package]] name = "enum-as-inner" version = "0.3.3" @@ -1939,6 +2007,16 @@ dependencies = [ "libc", ] +[[package]] +name = "ff" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2958d04124b9f27f175eaeb9a9f383d026098aa837eadd8ba22c11f13a05b9e" +dependencies = [ + "rand_core 0.6.2", + "subtle", +] + [[package]] name = "file-per-thread-logger" version = "0.1.4" @@ -2619,6 +2697,17 @@ dependencies = [ "web-sys", ] +[[package]] +name = "group" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5ac374b108929de78460075f3dc439fa66df9d8fc77e8f12caa5165fcf0c89" +dependencies = [ + "ff", + "rand_core 0.6.2", + "subtle", +] + [[package]] name = "h2" version = "0.3.9" @@ -3403,6 +3492,18 @@ dependencies = [ "jsonrpsee-types 0.8.0", ] +[[package]] +name = "k256" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cc5937366afd3b38071f400d1ce5bd8b1d40b5083cc14e6f8dbcc4032a7f5bb" +dependencies = [ + "cfg-if 1.0.0", + "ecdsa", + "elliptic-curve", + "sec1", +] + [[package]] name = "keccak" version = "0.1.0" @@ -5523,7 +5624,7 @@ dependencies = [ "frame-system", "hex", "hex-literal", - "libsecp256k1", + "k256", "log 0.4.14", "pallet-beefy", "pallet-mmr", @@ -6865,6 +6966,17 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkcs8" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cabda3fb821068a9a4fab19a683eac3af12edf0f34b94a8be53c4972b8149d0" +dependencies = [ + "der", + "spki", + "zeroize", +] + [[package]] name = "pkg-config" version = "0.3.19" @@ -9027,6 +9139,19 @@ dependencies = [ "untrusted", ] +[[package]] +name = "sec1" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08da66b8b0965a5555b6bd6639e68ccba85e1e2506f5fbb089e93f8a04e1a2d1" +dependencies = [ + "der", + "generic-array 0.14.4", + "pkcs8", + "subtle", + "zeroize", +] + [[package]] name = "secrecy" version = "0.8.0" @@ -9285,9 +9410,12 @@ dependencies = [ [[package]] name = "signature" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f0242b8e50dd9accdd56170e94ca1ebd223b098eb9c83539a6e367d0f36ae68" +checksum = "02658e48d89f2bec991f9a78e69cfa4c316f8d6a6c4ec12fae1aeb263d486788" +dependencies = [ + "rand_core 0.6.2", +] [[package]] name = "simba" @@ -10224,6 +10352,16 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "spki" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d01ac02a6ccf3e07db148d2be087da624fea0221a16152ed01f0496a6b0a27" +dependencies = [ + "base64ct", + "der", +] + [[package]] name = "ss58-registry" version = "1.11.0" diff --git a/frame/beefy-mmr/Cargo.toml b/frame/beefy-mmr/Cargo.toml index f381d4c975776..bb30c540ca1c8 100644 --- a/frame/beefy-mmr/Cargo.toml +++ b/frame/beefy-mmr/Cargo.toml @@ -10,7 +10,7 @@ repository = "https://github.com/paritytech/substrate" [dependencies] hex = { version = "0.4", optional = true } codec = { version = "2.2.0", package = "parity-scale-codec", default-features = false, features = ["derive"] } -libsecp256k1 = { version = "0.7.0", default-features = false } +k256 = { version = "0.10.2", default-features = false, features = ["arithmetic"] } log = { version = "0.4.13", default-features = false } scale-info = { version = "1.0", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true } @@ -43,7 +43,7 @@ std = [ "frame-support/std", "frame-system/std", "hex", - "libsecp256k1/std", + "k256/std", "log/std", "pallet-beefy/std", "pallet-mmr-primitives/std", diff --git a/frame/beefy-mmr/src/lib.rs b/frame/beefy-mmr/src/lib.rs index 38d0a6ac9a7f8..476589717e06c 100644 --- a/frame/beefy-mmr/src/lib.rs +++ b/frame/beefy-mmr/src/lib.rs @@ -72,21 +72,20 @@ where pub struct BeefyEcdsaToEthereum; impl Convert> for BeefyEcdsaToEthereum { fn convert(a: beefy_primitives::crypto::AuthorityId) -> Vec { + use k256::{elliptic_curve::sec1::ToEncodedPoint, PublicKey}; use sp_core::crypto::ByteArray; - let compressed_key = a.as_slice(); - - libsecp256k1::PublicKey::parse_slice( - compressed_key, - Some(libsecp256k1::PublicKeyFormat::Compressed), - ) - // uncompress the key - .map(|pub_key| pub_key.serialize().to_vec()) - // now convert to ETH address - .map(|uncompressed| sp_io::hashing::keccak_256(&uncompressed[1..])[12..].to_vec()) - .map_err(|_| { - log::error!(target: "runtime::beefy", "Invalid BEEFY PublicKey format!"); - }) - .unwrap_or_default() + + PublicKey::from_sec1_bytes(a.as_slice()) + .map(|pub_key| { + // uncompress the key + let uncompressed = pub_key.to_encoded_point(false); + // convert to ETH address + sp_io::hashing::keccak_256(&uncompressed.as_bytes()[1..])[12..].to_vec() + }) + .map_err(|_| { + log::error!(target: "runtime::beefy", "Invalid BEEFY PublicKey format!"); + }) + .unwrap_or_default() } } From f6ded34eeb3b161e11086da804217bb76fea8d56 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Thu, 17 Feb 2022 12:14:55 +0100 Subject: [PATCH 2/8] Port of FRAME `contracts` benchmarking from `libsecp256k1` to `k256` --- Cargo.lock | 17 +++++++- Cargo.toml | 1 + frame/contracts/Cargo.toml | 7 ++-- frame/contracts/src/benchmarking/mod.rs | 54 +++++++++++++++++++------ 4 files changed, 63 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 19f978b7fcbe5..2caa3b520488b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1796,6 +1796,7 @@ checksum = "d0d69ae62e0ce582d56380743515fefaf1a8c70cec685d9677636d7e30ae9dc9" dependencies = [ "der", "elliptic-curve", + "rfc6979", "signature", ] @@ -3502,6 +3503,7 @@ dependencies = [ "ecdsa", "elliptic-curve", "sec1", + "sha2 0.9.8", ] [[package]] @@ -5699,12 +5701,13 @@ version = "4.0.0-dev" dependencies = [ "assert_matches", "bitflags", + "ecdsa", "env_logger 0.9.0", "frame-benchmarking", "frame-support", "frame-system", "hex-literal", - "libsecp256k1", + "k256", "log 0.4.14", "pallet-balances", "pallet-contracts-primitives", @@ -7706,6 +7709,17 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "448296241d034b96c11173591deaa1302f2c17b56092106c1f92c1bc0183a8c9" +[[package]] +name = "rfc6979" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96ef608575f6392792f9ecf7890c00086591d29a83910939d430753f7c050525" +dependencies = [ + "crypto-bigint", + "hmac 0.11.0", + "zeroize", +] + [[package]] name = "ring" version = "0.16.20" @@ -9414,6 +9428,7 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02658e48d89f2bec991f9a78e69cfa4c316f8d6a6c4ec12fae1aeb263d486788" dependencies = [ + "digest 0.9.0", "rand_core 0.6.2", ] diff --git a/Cargo.toml b/Cargo.toml index a31d8011a9f44..d919fc4805631 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -250,6 +250,7 @@ hash-db = { opt-level = 3 } hmac = { opt-level = 3 } httparse = { opt-level = 3 } integer-sqrt = { opt-level = 3 } +k256 = { opt-level = 3 } keccak = { opt-level = 3 } libm = { opt-level = 3 } librocksdb-sys = { opt-level = 3 } diff --git a/frame/contracts/Cargo.toml b/frame/contracts/Cargo.toml index f24e393daa2ee..f74ba395b0b3d 100644 --- a/frame/contracts/Cargo.toml +++ b/frame/contracts/Cargo.toml @@ -28,7 +28,8 @@ smallvec = { version = "1", default-features = false, features = [ wasmi-validation = { version = "0.4", default-features = false } # Only used in benchmarking to generate random contract code -libsecp256k1 = { version = "0.7", optional = true, default-features = false, features = ["hmac", "static-context"] } +k256 = { version = "0.10.2", optional = true } +ecdsa = { version = "0.13.4", optional = true } rand = { version = "0.8", optional = true, default-features = false } rand_pcg = { version = "0.3", optional = true } @@ -77,11 +78,11 @@ std = [ "pallet-contracts-proc-macro/full", "log/std", "rand/std", - "libsecp256k1/std", ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", - "libsecp256k1", + "k256", + "ecdsa", "rand", "rand_pcg", "unstable-interface", diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index 827c729e16150..ec4f6e23af0bc 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -195,6 +195,47 @@ macro_rules! load_benchmark { }}; } +// For security reasons `k256` authors decided to not directly expose the low-level +// api for pre-hashed messages signature. +// This is a convenience function to wrap the verbose procedure. +// Refer to [this](https://github.com/RustCrypto/elliptic-curves/issues/525) issue +// for some details. +fn sign_prehashed(hash: [u8; 32]) -> [u8; 65] { + use ecdsa::{ + elliptic_curve::{ + generic_array::{typenum::U32, GenericArray}, + ops::Reduce, + }, + hazmat::{rfc6979_generate_k, SignPrimitive}, + signature::PrehashSignature, + }; + use k256::{ + ecdsa::{Signature, SigningKey}, + NonZeroScalar, Scalar, U256, + }; + + let signing_key = SigningKey::random(&mut rand::rngs::OsRng); + + let hash_array: GenericArray = GenericArray::from_slice(&hash).clone(); + let hash_scalar = >::from_be_bytes_reduced(hash_array); + + let priv_bytes = signing_key.to_bytes(); + let priv_scalar = >::from_be_bytes_reduced(priv_bytes); + + let k = rfc6979_generate_k::<_, ::Digest>( + &priv_scalar, + &hash_scalar, + &[], + ); + + let (sig, recid) = priv_scalar.try_sign_prehashed(**k, hash_scalar).unwrap(); + + let mut full_signature = [0; 65]; + full_signature[..64].copy_from_slice(sig.as_ref()); + full_signature[64] = recid.unwrap().to_byte(); + full_signature +} + benchmarks! { where_clause { where T::AccountId: UncheckedFrom, @@ -1866,21 +1907,10 @@ benchmarks! { // It generates different private keys and signatures for the message "Hello world". seal_ecdsa_recover { let r in 0 .. API_BENCHMARK_BATCHES; - use rand::SeedableRng; - let mut rng = rand_pcg::Pcg32::seed_from_u64(123456); let message_hash = sp_io::hashing::blake2_256("Hello world".as_bytes()); let signatures = (0..r * API_BENCHMARK_BATCH_SIZE) - .map(|i| { - use libsecp256k1::{SecretKey, Message, sign}; - - let private_key = SecretKey::random(&mut rng); - let (signature, recovery_id) = sign(&Message::parse(&message_hash), &private_key); - let mut full_signature = [0; 65]; - full_signature[..64].copy_from_slice(&signature.serialize()); - full_signature[64] = recovery_id.serialize(); - full_signature - }) + .map(|i| sign_prehashed(message_hash)) .collect::>(); let signatures = signatures.iter().flatten().cloned().collect::>(); let signatures_bytes_len = signatures.len() as i32; From c64ebbd021e69292cba1adfab63162732b9106ef Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Fri, 18 Feb 2022 20:04:46 +0100 Subject: [PATCH 3/8] Newtype to allow `Pcg32` rng usage with `k256` in contracts benchmarks --- frame/contracts/src/benchmarking/mod.rs | 26 ++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index ec4f6e23af0bc..beceb5b2ca2a2 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -213,8 +213,32 @@ fn sign_prehashed(hash: [u8; 32]) -> [u8; 65] { ecdsa::{Signature, SigningKey}, NonZeroScalar, Scalar, U256, }; + use rand::{CryptoRng, RngCore, SeedableRng}; + + // The PCG algorithms are not suitable for cryptographic uses, but + // perform well in statistical tests, use little memory and are fairly fast. + // For this reason they doesn't implement the `CryptoRng` trait required + // by `k256` to generate a new random signing key. + // This newtype implements `CryptoRng` only for the scope of the tests. + struct Pcg32Wrap(rand_pcg::Pcg32); + impl CryptoRng for Pcg32Wrap {} + impl RngCore for Pcg32Wrap { + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0.fill_bytes(dest) + } + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand::Error> { + self.0.try_fill_bytes(dest) + } + } - let signing_key = SigningKey::random(&mut rand::rngs::OsRng); + let mut rng = Pcg32Wrap(rand_pcg::Pcg32::seed_from_u64(123456)); + let signing_key = SigningKey::random(&mut rng); let hash_array: GenericArray = GenericArray::from_slice(&hash).clone(); let hash_scalar = >::from_be_bytes_reduced(hash_array); From 22996728684b7a3aee1b7f075521650c390066e2 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Mon, 21 Feb 2022 15:30:03 +0100 Subject: [PATCH 4/8] Use `sp-io::crypto` to generate dummy keys in `contracts` bechmarks --- Cargo.lock | 17 +----- frame/contracts/Cargo.toml | 6 +- frame/contracts/src/benchmarking/mod.rs | 73 +++---------------------- frame/contracts/src/tests.rs | 4 +- 4 files changed, 13 insertions(+), 87 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2caa3b520488b..e4325e974f4e6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1796,7 +1796,6 @@ checksum = "d0d69ae62e0ce582d56380743515fefaf1a8c70cec685d9677636d7e30ae9dc9" dependencies = [ "der", "elliptic-curve", - "rfc6979", "signature", ] @@ -3503,7 +3502,6 @@ dependencies = [ "ecdsa", "elliptic-curve", "sec1", - "sha2 0.9.8", ] [[package]] @@ -5701,13 +5699,11 @@ version = "4.0.0-dev" dependencies = [ "assert_matches", "bitflags", - "ecdsa", "env_logger 0.9.0", "frame-benchmarking", "frame-support", "frame-system", "hex-literal", - "k256", "log 0.4.14", "pallet-balances", "pallet-contracts-primitives", @@ -5724,6 +5720,7 @@ dependencies = [ "smallvec 1.7.0", "sp-core", "sp-io", + "sp-keystore", "sp-runtime", "sp-sandbox", "sp-std", @@ -7709,17 +7706,6 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "448296241d034b96c11173591deaa1302f2c17b56092106c1f92c1bc0183a8c9" -[[package]] -name = "rfc6979" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96ef608575f6392792f9ecf7890c00086591d29a83910939d430753f7c050525" -dependencies = [ - "crypto-bigint", - "hmac 0.11.0", - "zeroize", -] - [[package]] name = "ring" version = "0.16.20" @@ -9428,7 +9414,6 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02658e48d89f2bec991f9a78e69cfa4c316f8d6a6c4ec12fae1aeb263d486788" dependencies = [ - "digest 0.9.0", "rand_core 0.6.2", ] diff --git a/frame/contracts/Cargo.toml b/frame/contracts/Cargo.toml index f74ba395b0b3d..b3c328d2748e1 100644 --- a/frame/contracts/Cargo.toml +++ b/frame/contracts/Cargo.toml @@ -28,8 +28,6 @@ smallvec = { version = "1", default-features = false, features = [ wasmi-validation = { version = "0.4", default-features = false } # Only used in benchmarking to generate random contract code -k256 = { version = "0.10.2", optional = true } -ecdsa = { version = "0.13.4", optional = true } rand = { version = "0.8", optional = true, default-features = false } rand_pcg = { version = "0.3", optional = true } @@ -41,6 +39,7 @@ pallet-contracts-primitives = { version = "5.0.0", default-features = false, pat pallet-contracts-proc-macro = { version = "4.0.0-dev", path = "proc-macro" } sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } +sp-keystore = { version = "0.11.0", default-features = false, path = "../../primitives/keystore" } sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } sp-sandbox = { version = "0.10.0-dev", default-features = false, path = "../../primitives/sandbox" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } @@ -67,6 +66,7 @@ std = [ "sp-core/std", "sp-runtime/std", "sp-io/std", + "sp-keystore/std", "sp-std/std", "sp-sandbox/std", "frame-benchmarking/std", @@ -81,8 +81,6 @@ std = [ ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", - "k256", - "ecdsa", "rand", "rand_pcg", "unstable-interface", diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index beceb5b2ca2a2..6455ddfff6202 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -195,71 +195,6 @@ macro_rules! load_benchmark { }}; } -// For security reasons `k256` authors decided to not directly expose the low-level -// api for pre-hashed messages signature. -// This is a convenience function to wrap the verbose procedure. -// Refer to [this](https://github.com/RustCrypto/elliptic-curves/issues/525) issue -// for some details. -fn sign_prehashed(hash: [u8; 32]) -> [u8; 65] { - use ecdsa::{ - elliptic_curve::{ - generic_array::{typenum::U32, GenericArray}, - ops::Reduce, - }, - hazmat::{rfc6979_generate_k, SignPrimitive}, - signature::PrehashSignature, - }; - use k256::{ - ecdsa::{Signature, SigningKey}, - NonZeroScalar, Scalar, U256, - }; - use rand::{CryptoRng, RngCore, SeedableRng}; - - // The PCG algorithms are not suitable for cryptographic uses, but - // perform well in statistical tests, use little memory and are fairly fast. - // For this reason they doesn't implement the `CryptoRng` trait required - // by `k256` to generate a new random signing key. - // This newtype implements `CryptoRng` only for the scope of the tests. - struct Pcg32Wrap(rand_pcg::Pcg32); - impl CryptoRng for Pcg32Wrap {} - impl RngCore for Pcg32Wrap { - fn next_u32(&mut self) -> u32 { - self.0.next_u32() - } - fn next_u64(&mut self) -> u64 { - self.0.next_u64() - } - fn fill_bytes(&mut self, dest: &mut [u8]) { - self.0.fill_bytes(dest) - } - fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand::Error> { - self.0.try_fill_bytes(dest) - } - } - - let mut rng = Pcg32Wrap(rand_pcg::Pcg32::seed_from_u64(123456)); - let signing_key = SigningKey::random(&mut rng); - - let hash_array: GenericArray = GenericArray::from_slice(&hash).clone(); - let hash_scalar = >::from_be_bytes_reduced(hash_array); - - let priv_bytes = signing_key.to_bytes(); - let priv_scalar = >::from_be_bytes_reduced(priv_bytes); - - let k = rfc6979_generate_k::<_, ::Digest>( - &priv_scalar, - &hash_scalar, - &[], - ); - - let (sig, recid) = priv_scalar.try_sign_prehashed(**k, hash_scalar).unwrap(); - - let mut full_signature = [0; 65]; - full_signature[..64].copy_from_slice(sig.as_ref()); - full_signature[64] = recid.unwrap().to_byte(); - full_signature -} - benchmarks! { where_clause { where T::AccountId: UncheckedFrom, @@ -1933,8 +1868,14 @@ benchmarks! { let r in 0 .. API_BENCHMARK_BATCHES; let message_hash = sp_io::hashing::blake2_256("Hello world".as_bytes()); + let key_type = sp_core::crypto::KeyTypeId(*b"code"); + let pub_key = sp_io::crypto::ecdsa_generate(key_type, None); let signatures = (0..r * API_BENCHMARK_BATCH_SIZE) - .map(|i| sign_prehashed(message_hash)) + .map(|i| { + let sig = sp_io::crypto::ecdsa_sign_prehashed(key_type, &pub_key, &message_hash).expect("Generates signature"); + let bytes: &[u8; 65] = sig.as_ref(); + bytes.to_vec() + }) .collect::>(); let signatures = signatures.iter().flatten().cloned().collect::>(); let signatures_bytes_len = signatures.len() as i32; diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index 9ea23e974b21d..01482433d976c 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -43,12 +43,13 @@ use frame_system::{self as system, EventRecord, Phase}; use pretty_assertions::assert_eq; use sp_core::Bytes; use sp_io::hashing::blake2_256; +use sp_keystore::{KeystoreExt, testing::KeyStore}; use sp_runtime::{ testing::{Header, H256}, traits::{BlakeTwo256, Convert, Hash, IdentityLookup}, AccountId32, }; -use std::cell::RefCell; +use std::{cell::RefCell, sync::Arc}; use crate as pallet_contracts; @@ -322,6 +323,7 @@ impl ExtBuilder { .assimilate_storage(&mut t) .unwrap(); let mut ext = sp_io::TestExternalities::new(t); + ext.register_extension(KeystoreExt(Arc::new(KeyStore::new()))); ext.execute_with(|| System::set_block_number(1)); ext } From 1a4feec4026b289f11fc7983636d53fd80144fd0 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Mon, 21 Feb 2022 16:23:37 +0100 Subject: [PATCH 5/8] More compact code --- frame/contracts/src/benchmarking/mod.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index 6455ddfff6202..067e68345e212 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -1873,8 +1873,7 @@ benchmarks! { let signatures = (0..r * API_BENCHMARK_BATCH_SIZE) .map(|i| { let sig = sp_io::crypto::ecdsa_sign_prehashed(key_type, &pub_key, &message_hash).expect("Generates signature"); - let bytes: &[u8; 65] = sig.as_ref(); - bytes.to_vec() + AsRef::<[u8; 65]>::as_ref(&sig).to_vec() }) .collect::>(); let signatures = signatures.iter().flatten().cloned().collect::>(); From 0dad860eafacb252eacb19a5673482ebce7bdcfb Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Mon, 21 Feb 2022 16:30:00 +0100 Subject: [PATCH 6/8] Cargo fmt --- frame/contracts/src/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index 01482433d976c..428dfb9a97db5 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -43,7 +43,7 @@ use frame_system::{self as system, EventRecord, Phase}; use pretty_assertions::assert_eq; use sp_core::Bytes; use sp_io::hashing::blake2_256; -use sp_keystore::{KeystoreExt, testing::KeyStore}; +use sp_keystore::{testing::KeyStore, KeystoreExt}; use sp_runtime::{ testing::{Header, H256}, traits::{BlakeTwo256, Convert, Hash, IdentityLookup}, From 65f3027bfe8b01a035d23e62229b900669611457 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Mon, 21 Feb 2022 21:25:06 +0100 Subject: [PATCH 7/8] Build `sp-keystore` only for dev profile --- frame/contracts/Cargo.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frame/contracts/Cargo.toml b/frame/contracts/Cargo.toml index b3c328d2748e1..5ab1389f65c1a 100644 --- a/frame/contracts/Cargo.toml +++ b/frame/contracts/Cargo.toml @@ -39,7 +39,6 @@ pallet-contracts-primitives = { version = "5.0.0", default-features = false, pat pallet-contracts-proc-macro = { version = "4.0.0-dev", path = "proc-macro" } sp-core = { version = "5.0.0", default-features = false, path = "../../primitives/core" } sp-io = { version = "5.0.0", default-features = false, path = "../../primitives/io" } -sp-keystore = { version = "0.11.0", default-features = false, path = "../../primitives/keystore" } sp-runtime = { version = "5.0.0", default-features = false, path = "../../primitives/runtime" } sp-sandbox = { version = "0.10.0-dev", default-features = false, path = "../../primitives/sandbox" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } @@ -56,6 +55,7 @@ pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-timestamp = { version = "4.0.0-dev", path = "../timestamp" } pallet-randomness-collective-flip = { version = "4.0.0-dev", path = "../randomness-collective-flip" } pallet-utility = { version = "4.0.0-dev", path = "../utility" } +sp-keystore = { version = "0.11.0", path = "../../primitives/keystore" } [features] default = ["std"] @@ -66,7 +66,6 @@ std = [ "sp-core/std", "sp-runtime/std", "sp-io/std", - "sp-keystore/std", "sp-std/std", "sp-sandbox/std", "frame-benchmarking/std", From c45381a84cc5e0b631be511f2e88ed874302c09b Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Tue, 22 Feb 2022 10:01:11 +0100 Subject: [PATCH 8/8] Move public key generation back to the `map` --- frame/contracts/src/benchmarking/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index 067e68345e212..687553e2ced22 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -1869,9 +1869,9 @@ benchmarks! { let message_hash = sp_io::hashing::blake2_256("Hello world".as_bytes()); let key_type = sp_core::crypto::KeyTypeId(*b"code"); - let pub_key = sp_io::crypto::ecdsa_generate(key_type, None); let signatures = (0..r * API_BENCHMARK_BATCH_SIZE) .map(|i| { + let pub_key = sp_io::crypto::ecdsa_generate(key_type, None); let sig = sp_io::crypto::ecdsa_sign_prehashed(key_type, &pub_key, &message_hash).expect("Generates signature"); AsRef::<[u8; 65]>::as_ref(&sig).to_vec() })