diff --git a/.rustfmt.toml b/.rustfmt.toml index 0e0e77b53ca..422da2beabf 100644 --- a/.rustfmt.toml +++ b/.rustfmt.toml @@ -43,7 +43,7 @@ trailing_comma = "Vertical" match_block_trailing_comma = false blank_lines_upper_bound = 1 blank_lines_lower_bound = 0 -edition = "2018" # changed +edition = "2021" # changed version = "One" merge_derives = true use_try_shorthand = true # changed diff --git a/Cargo.toml b/Cargo.toml index 554092d4a5e..48f592ff034 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,4 +1,5 @@ [workspace] +resolver = "2" members = [ "crates/metadata", "crates/allocator", diff --git a/crates/engine/Cargo.toml b/crates/engine/Cargo.toml index 83b9e400e3d..a7506aaa319 100644 --- a/crates/engine/Cargo.toml +++ b/crates/engine/Cargo.toml @@ -23,7 +23,7 @@ sha3 = { version = "0.9" } blake2 = { version = "0.9" } # ECDSA for the off-chain environment. -libsecp256k1 = { version = "0.3.5", default-features = false } +libsecp256k1 = { version = "0.7.0" } [features] default = ["std"] diff --git a/crates/engine/src/ext.rs b/crates/engine/src/ext.rs index a302df6390a..a28957954cc 100644 --- a/crates/engine/src/ext.rs +++ b/crates/engine/src/ext.rs @@ -428,7 +428,7 @@ impl Engine { message_hash: &[u8; 32], output: &mut [u8; 33], ) -> Result { - use secp256k1::{ + use libsecp256k1::{ recover, Message, RecoveryId, @@ -443,7 +443,7 @@ impl Engine { signature[64] }; let message = Message::parse(message_hash); - let signature = Signature::parse_slice(&signature[0..64]) + let signature = Signature::parse_standard_slice(&signature[0..64]) .unwrap_or_else(|error| panic!("Unable to parse the signature: {}", error)); let recovery_id = RecoveryId::parse(recovery_byte) diff --git a/crates/engine/src/tests.rs b/crates/engine/src/tests.rs index 798f5287de7..b8fd7179d50 100644 --- a/crates/engine/src/tests.rs +++ b/crates/engine/src/tests.rs @@ -16,6 +16,11 @@ use crate::ext::{ Engine, Error, }; +use libsecp256k1::{ + Message, + PublicKey, + SecretKey, +}; /// The public methods of the `contracts` pallet write their result into an /// `output` buffer instead of returning them. Since we aim to emulate this @@ -192,3 +197,74 @@ fn must_panic_when_buffer_too_small() { // then unreachable!("`get_storage` must already have panicked"); } + +#[test] +fn ecdsa_recovery_test_from_contracts_pallet() { + // given + let mut engine = Engine::new(); + #[rustfmt::skip] + let signature: [u8; 65] = [ + 161, 234, 203, 74, 147, 96, 51, 212, 5, 174, 231, 9, 142, 48, 137, 201, + 162, 118, 192, 67, 239, 16, 71, 216, 125, 86, 167, 139, 70, 7, 86, 241, + 33, 87, 154, 251, 81, 29, 160, 4, 176, 239, 88, 211, 244, 232, 232, 52, + 211, 234, 100, 115, 230, 47, 80, 44, 152, 166, 62, 50, 8, 13, 86, 175, + 28, + ]; + #[rustfmt::skip] + let message_hash: [u8; 32] = [ + 162, 28, 244, 179, 96, 76, 244, 178, 188, 83, 230, 248, 143, 106, 77, 117, + 239, 95, 244, 171, 65, 95, 62, 153, 174, 166, 182, 28, 130, 73, 196, 208 + ]; + + // when + let mut output = [0; 33]; + engine + .ecdsa_recover(&signature, &message_hash, &mut output) + .expect("must work"); + + // then + #[rustfmt::skip] + const EXPECTED_COMPRESSED_PUBLIC_KEY: [u8; 33] = [ + 2, 121, 190, 102, 126, 249, 220, 187, 172, 85, 160, 98, 149, 206, 135, 11, + 7, 2, 155, 252, 219, 45, 206, 40, 217, 89, 242, 129, 91, 22, 248, 23, + 152, + ]; + assert_eq!(output, EXPECTED_COMPRESSED_PUBLIC_KEY); +} + +#[test] +fn ecdsa_recovery_with_secp256k1_crate() { + // given + let mut engine = Engine::new(); + let seckey = [ + 59, 148, 11, 85, 134, 130, 61, 253, 2, 174, 59, 70, 27, 180, 51, 107, 94, 203, + 174, 253, 102, 39, 170, 146, 46, 252, 4, 143, 236, 12, 136, 28, + ]; + let pubkey = PublicKey::parse_compressed(&[ + 2, 29, 21, 35, 7, 198, 183, 43, 14, 208, 65, 139, 14, 112, 205, 128, 231, 245, + 41, 91, 141, 134, 245, 114, 45, 63, 82, 19, 251, 210, 57, 79, 54, + ]) + .expect("pubkey creation failed"); + + let mut msg_hash = [0; 32]; + crate::hashing::sha2_256(b"Some message", &mut msg_hash); + + let msg = Message::parse(&msg_hash); + let seckey = SecretKey::parse(&seckey).expect("secret key creation failed"); + let (signature, recovery_id) = libsecp256k1::sign(&msg, &seckey); + + let mut signature = signature.serialize().to_vec(); + signature.push(recovery_id.serialize()); + let signature_with_recovery_id: [u8; 65] = signature + .try_into() + .expect("unable to create signature with recovery id"); + + // when + let mut output = [0; 33]; + engine + .ecdsa_recover(&signature_with_recovery_id, &msg.serialize(), &mut output) + .expect("ecdsa recovery failed"); + + // then + assert_eq!(output, pubkey.serialize_compressed()); +} diff --git a/crates/env/Cargo.toml b/crates/env/Cargo.toml index f8194bdabbf..3c0edd0db83 100644 --- a/crates/env/Cargo.toml +++ b/crates/env/Cargo.toml @@ -15,7 +15,6 @@ categories = ["no-std", "embedded"] include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE"] [dependencies] -ink_engine = { version = "3.0.0-rc6", path = "../engine/", default-features = false, optional = true } ink_metadata = { version = "3.0.0-rc6", path = "../metadata/", default-features = false, features = ["derive"], optional = true } ink_allocator = { version = "3.0.0-rc6", path = "../allocator/", default-features = false } ink_primitives = { version = "3.0.0-rc6", path = "../primitives/", default-features = false } @@ -30,13 +29,19 @@ arrayref = "0.3" static_assertions = "1.1" sp-arithmetic = { version = "3.0", default-features = false } +[target.'cfg(target_arch = "wasm32")'.dependencies] +libsecp256k1 = { version = "0.7.0", default-features = false } + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +ink_engine = { version = "3.0.0-rc6", path = "../engine/", default-features = false, optional = true } + # Hashes for the off-chain environment. sha2 = { version = "0.9", optional = true } sha3 = { version = "0.9", optional = true } blake2 = { version = "0.9", optional = true } # ECDSA for the off-chain environment. -libsecp256k1 = { version = "0.3.5", default-features = false } +libsecp256k1 = { version = "0.7.0" } # Only used in the off-chain environment. # diff --git a/crates/env/src/engine/experimental_off_chain/impls.rs b/crates/env/src/engine/experimental_off_chain/impls.rs index 23fdf4e00aa..f2f7ceff243 100644 --- a/crates/env/src/engine/experimental_off_chain/impls.rs +++ b/crates/env/src/engine/experimental_off_chain/impls.rs @@ -34,6 +34,7 @@ use crate::{ Clear, EnvBackend, Environment, + Error, RentParams, RentStatus, Result, @@ -252,7 +253,7 @@ impl EnvBackend for EnvInstance { message_hash: &[u8; 32], output: &mut [u8; 33], ) -> Result<()> { - use secp256k1::{ + use libsecp256k1::{ recover, Message, RecoveryId, @@ -267,7 +268,7 @@ impl EnvBackend for EnvInstance { signature[64] }; let message = Message::parse(message_hash); - let signature = Signature::parse_slice(&signature[0..64]) + let signature = Signature::parse_standard_slice(&signature[0..64]) .unwrap_or_else(|error| panic!("Unable to parse the signature: {}", error)); let recovery_id = RecoveryId::parse(recovery_byte) @@ -279,7 +280,7 @@ impl EnvBackend for EnvInstance { *output = pub_key.serialize_compressed(); Ok(()) } - Err(_) => Err(crate::Error::EcdsaRecoverFailed), + Err(_) => Err(Error::EcdsaRecoverFailed), } } diff --git a/crates/env/src/engine/off_chain/impls.rs b/crates/env/src/engine/off_chain/impls.rs index 22591308252..45d18fcf044 100644 --- a/crates/env/src/engine/off_chain/impls.rs +++ b/crates/env/src/engine/off_chain/impls.rs @@ -201,7 +201,7 @@ impl EnvBackend for EnvInstance { message_hash: &[u8; 32], output: &mut [u8; 33], ) -> Result<()> { - use secp256k1::{ + use libsecp256k1::{ recover, Message, RecoveryId, @@ -216,7 +216,7 @@ impl EnvBackend for EnvInstance { signature[64] }; let message = Message::parse(message_hash); - let signature = Signature::parse_slice(&signature[0..64]) + let signature = Signature::parse_standard_slice(&signature[0..64]) .unwrap_or_else(|error| panic!("Unable to parse the signature: {}", error)); let recovery_id = RecoveryId::parse(recovery_byte) diff --git a/crates/eth_compatibility/Cargo.toml b/crates/eth_compatibility/Cargo.toml index d3698864667..b6681d68763 100644 --- a/crates/eth_compatibility/Cargo.toml +++ b/crates/eth_compatibility/Cargo.toml @@ -16,7 +16,7 @@ include = ["Cargo.toml", "src/**/*.rs", "/README.md", "/LICENSE"] [dependencies] ink_env = { version = "3.0.0-rc6", path = "../env", default-features = false } -libsecp256k1 = { version = "0.3.5", default-features = false } +libsecp256k1 = { version = "0.7.0", default-features = false } [features] default = ["std"] diff --git a/crates/eth_compatibility/src/lib.rs b/crates/eth_compatibility/src/lib.rs index 4c27cad1ef3..827384ed3b2 100644 --- a/crates/eth_compatibility/src/lib.rs +++ b/crates/eth_compatibility/src/lib.rs @@ -13,6 +13,7 @@ // limitations under the License. #![no_std] + use ink_env::{ DefaultEnvironment, Environment, @@ -92,7 +93,7 @@ impl ECDSAPublicKey { /// ``` pub fn to_eth_address(&self) -> EthereumAddress { use ink_env::hash; - use secp256k1::PublicKey; + use libsecp256k1::PublicKey; // Transform compressed public key into uncompressed. let pub_key = PublicKey::parse_compressed(&self.0) diff --git a/crates/storage/Cargo.toml b/crates/storage/Cargo.toml index 798cb632a9f..291537ee37c 100644 --- a/crates/storage/Cargo.toml +++ b/crates/storage/Cargo.toml @@ -27,6 +27,7 @@ scale-info = { version = "1.0", default-features = false, features = ["derive"], cfg-if = "1.0" array-init = { version = "2.0", default-features = false } +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] # Workaround: we actually just need criterion as a dev-dependency, but # there is an issue with a doubly included std lib when executing # `cargo check --no-default-features --target wasm32-unknown-unknown`.