Repository: bluealloy/revm (language: rust)

Issue:
Integrate rust-secp256k1
We should integrate it inside Precompiles under the feature flag.  https://github.com/tarcieri/rust-secp256k1-ecdsa-bench




Discussion / hints:

Fix patch:
diff --git a/Cargo.lock b/Cargo.lock
index 79dff5bc1d..3d28071ff1 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -132,7 +132,7 @@ dependencies = [
  "derive_more 1.0.0",
  "once_cell",
  "serde",
- "sha2",
+ "sha2 0.10.8",
 ]
 
 [[package]]
@@ -432,7 +432,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f99acddb34000d104961897dbb0240298e8b775a7efffb9fda2a1a3efedd65b3"
 dependencies = [
  "alloy-json-rpc",
- "base64",
+ "base64 0.22.1",
  "futures-util",
  "futures-utils-wasm",
  "serde",
@@ -651,6 +651,12 @@ dependencies = [
  "rand",
 ]
 
+[[package]]
+name = "arrayref"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb"
+
 [[package]]
 name = "arrayvec"
 version = "0.7.4"
@@ -744,6 +750,12 @@ version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf"
 
+[[package]]
+name = "base64"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
+
 [[package]]
 name = "base64"
 version = "0.22.1"
@@ -802,6 +814,15 @@ dependencies = [
  "wyz",
 ]
 
+[[package]]
+name = "block-buffer"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
+dependencies = [
+ "generic-array",
+]
+
 [[package]]
 name = "block-buffer"
 version = "0.10.4"
@@ -1247,7 +1268,7 @@ version = "0.10.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
 dependencies = [
- "block-buffer",
+ "block-buffer 0.10.4",
  "const-oid",
  "crypto-common",
  "subtle",
@@ -2125,7 +2146,7 @@ dependencies = [
  "ecdsa",
  "elliptic-curve",
  "once_cell",
- "sha2",
+ "sha2 0.10.8",
  "signature",
 ]
 
@@ -2156,7 +2177,7 @@ checksum = "0850eb19206463a61bede4f7b7e6b21731807137619044b1f3c287ebcfe2b3b0"
 dependencies = [
  "ff",
  "hex",
- "sha2",
+ "sha2 0.10.8",
  "sp1_bls12_381",
  "spin",
 ]
@@ -2182,6 +2203,52 @@ version = "0.2.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058"
 
+[[package]]
+name = "libsecp256k1"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1"
+dependencies = [
+ "arrayref",
+ "base64 0.13.1",
+ "digest 0.9.0",
+ "libsecp256k1-core",
+ "libsecp256k1-gen-ecmult",
+ "libsecp256k1-gen-genmult",
+ "rand",
+ "serde",
+ "sha2 0.9.9",
+]
+
+[[package]]
+name = "libsecp256k1-core"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451"
+dependencies = [
+ "crunchy",
+ "digest 0.9.0",
+ "subtle",
+]
+
+[[package]]
+name = "libsecp256k1-gen-ecmult"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809"
+dependencies = [
+ "libsecp256k1-core",
+]
+
+[[package]]
+name = "libsecp256k1-gen-genmult"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c"
+dependencies = [
+ "libsecp256k1-core",
+]
+
 [[package]]
 name = "linux-raw-sys"
 version = "0.4.14"
@@ -2412,6 +2479,12 @@ version = "11.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9"
 
+[[package]]
+name = "opaque-debug"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
+
 [[package]]
 name = "open-fastrlp"
 version = "0.1.4"
@@ -2490,7 +2563,7 @@ dependencies = [
  "ecdsa",
  "elliptic-curve",
  "primeorder",
- "sha2",
+ "sha2 0.10.8",
 ]
 
 [[package]]
@@ -2938,7 +3011,7 @@ version = "0.12.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f8f4955649ef5c38cc7f9e8aa41761d48fb9677197daea9984dc54f56aad5e63"
 dependencies = [
- "base64",
+ "base64 0.22.1",
  "bytes",
  "encoding_rs",
  "futures-core",
@@ -3159,6 +3232,7 @@ dependencies = [
  "eyre",
  "k256",
  "kzg-rs",
+ "libsecp256k1",
  "once_cell",
  "p256",
  "rand",
@@ -3171,7 +3245,7 @@ dependencies = [
  "serde",
  "serde_derive",
  "serde_json",
- "sha2",
+ "sha2 0.10.8",
  "substrate-bn",
 ]
 
@@ -3459,7 +3533,7 @@ version = "2.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d"
 dependencies = [
- "base64",
+ "base64 0.22.1",
  "rustls-pki-types",
 ]
 
@@ -3688,6 +3762,19 @@ dependencies = [
  "serde",
 ]
 
+[[package]]
+name = "sha2"
+version = "0.9.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800"
+dependencies = [
+ "block-buffer 0.9.0",
+ "cfg-if",
+ "cpufeatures",
+ "digest 0.9.0",
+ "opaque-debug",
+]
+
 [[package]]
 name = "sha2"
 version = "0.10.8"
diff --git a/crates/precompile/Cargo.toml b/crates/precompile/Cargo.toml
index 968cfd13a4..2168bd1939 100644
--- a/crates/precompile/Cargo.toml
+++ b/crates/precompile/Cargo.toml
@@ -38,6 +38,9 @@ secp256k1 = { version = ">=0.28, <=0.29", default-features = false, features = [
     "rand",
     "global-context",
 ], optional = true }
+libsecp256k1 = { version = "0.7", default-features = false, package = "libsecp256k1", features = [
+    "static-context",
+], optional = true }
 
 # SHA2-256 and RIPEMD-160
 sha2 = { version = "0.10", default-features = false }
@@ -87,6 +90,7 @@ std = [
     "sha2/std",
     "c-kzg?/std",
     "secp256k1?/std",
+    "libsecp256k1?/std",
 ]
 hashbrown = ["primitives/hashbrown"]
 asm-keccak = ["primitives/asm-keccak"]
@@ -107,6 +111,7 @@ portable = ["c-kzg"]
 # The problem that `secp256k1` has is it fails to build for `wasm` target on Windows and Mac as it is c lib.
 # In Linux it passes. If you don't require to build wasm on win/mac, it is safe to use it and it is enabled by default.
 secp256k1 = ["dep:secp256k1"]
+libsecp256k1 = ["dep:libsecp256k1"]
 
 # Enables the BLS12-381 precompiles.
 blst = ["dep:blst"]
diff --git a/crates/precompile/src/secp256k1.rs b/crates/precompile/src/secp256k1.rs
index 0cd459723e..6911027cf6 100644
--- a/crates/precompile/src/secp256k1.rs
+++ b/crates/precompile/src/secp256k1.rs
@@ -1,3 +1,9 @@
+#[cfg(feature = "secp256k1")]
+pub mod bitcoin_secp256k1;
+pub mod k256;
+#[cfg(feature = "libsecp256k1")]
+pub mod parity_libsecp256k1;
+
 use crate::{
     utilities::right_pad, PrecompileError, PrecompileOutput, PrecompileResult,
     PrecompileWithAddress,
@@ -7,65 +13,6 @@ use primitives::{alloy_primitives::B512, Bytes, B256};
 pub const ECRECOVER: PrecompileWithAddress =
     PrecompileWithAddress(crate::u64_to_address(1), ec_recover_run);
 
-pub use self::secp256k1::ecrecover;
-
-#[cfg(not(feature = "secp256k1"))]
-#[allow(clippy::module_inception)]
-mod secp256k1 {
-    use k256::ecdsa::{Error, RecoveryId, Signature, VerifyingKey};
-    use primitives::{alloy_primitives::B512, keccak256, B256};
-
-    pub fn ecrecover(sig: &B512, mut recid: u8, msg: &B256) -> Result<B256, Error> {
-        // Parse signature
-        let mut sig = Signature::from_slice(sig.as_slice())?;
-
-        // Normalize signature and flip recovery id if needed.
-        if let Some(sig_normalized) = sig.normalize_s() {
-            sig = sig_normalized;
-            recid ^= 1;
-        }
-        let recid = RecoveryId::from_byte(recid).expect("recovery ID is valid");
-
-        // Recover key
-        let recovered_key = VerifyingKey::recover_from_prehash(&msg[..], &sig, recid)?;
-        // Hash it
-        let mut hash = keccak256(
-            &recovered_key
-                .to_encoded_point(/* compress = */ false)
-                .as_bytes()[1..],
-        );
-
-        // Truncate to 20 bytes
-        hash[..12].fill(0);
-        Ok(hash)
-    }
-}
-
-#[cfg(feature = "secp256k1")]
-#[allow(clippy::module_inception)]
-mod secp256k1 {
-    use primitives::{alloy_primitives::B512, keccak256, B256};
-    use secp256k1::{
-        ecdsa::{RecoverableSignature, RecoveryId},
-        Message, SECP256K1,
-    };
-
-    // Silence the unused crate dependency warning.
-    use k256 as _;
-
-    pub fn ecrecover(sig: &B512, recid: u8, msg: &B256) -> Result<B256, secp256k1::Error> {
-        let recid = RecoveryId::from_i32(recid as i32).expect("recovery ID is valid");
-        let sig = RecoverableSignature::from_compact(sig.as_slice(), recid)?;
-
-        let msg = Message::from_digest(msg.0);
-        let public = SECP256K1.recover_ecdsa(&msg, &sig)?;
-
-        let mut hash = keccak256(&public.serialize_uncompressed()[1..]);
-        hash[..12].fill(0);
-        Ok(hash)
-    }
-}
-
 pub fn ec_recover_run(input: &Bytes, gas_limit: u64) -> PrecompileResult {
     const ECRECOVER_BASE: u64 = 3_000;
 
@@ -84,8 +31,16 @@ pub fn ec_recover_run(input: &Bytes, gas_limit: u64) -> PrecompileResult {
     let recid = input[63] - 27;
     let sig = <&B512>::try_from(&input[64..128]).unwrap();
 
-    let out = secp256k1::ecrecover(sig, recid, msg)
-        .map(|o| o.to_vec().into())
-        .unwrap_or_default();
+    cfg_if::cfg_if! {
+        if #[cfg(feature = "secp256k1")] {
+            let res = bitcoin_secp256k1::ecrecover(sig, recid, msg);
+        } else if #[cfg(feature = "libsecp256k1")] {
+            let res = parity_libsecp256k1::ecrecover(sig, recid, msg);
+        } else {
+            let res = k256::ecrecover(sig, recid, msg);
+        }
+    };
+
+    let out = res.map(|o| o.to_vec().into()).unwrap_or_default();
     Ok(PrecompileOutput::new(ECRECOVER_BASE, out))
 }
diff --git a/crates/precompile/src/secp256k1/bitcoin_secp256k1.rs b/crates/precompile/src/secp256k1/bitcoin_secp256k1.rs
new file mode 100644
index 0000000000..7444dd61f1
--- /dev/null
+++ b/crates/precompile/src/secp256k1/bitcoin_secp256k1.rs
@@ -0,0 +1,20 @@
+use primitives::{alloy_primitives::B512, keccak256, B256};
+use secp256k1::{
+    ecdsa::{RecoverableSignature, RecoveryId},
+    Message, SECP256K1,
+};
+
+// Silence the unused crate dependency warning.
+use k256 as _;
+
+pub fn ecrecover(sig: &B512, recid: u8, msg: &B256) -> Result<B256, secp256k1::Error> {
+    let recid = RecoveryId::from_i32(recid as i32).expect("recovery ID is valid");
+    let sig = RecoverableSignature::from_compact(sig.as_slice(), recid)?;
+
+    let msg = Message::from_digest(msg.0);
+    let public = SECP256K1.recover_ecdsa(&msg, &sig)?;
+
+    let mut hash = keccak256(&public.serialize_uncompressed()[1..]);
+    hash[..12].fill(0);
+    Ok(hash)
+}
diff --git a/crates/precompile/src/secp256k1/k256.rs b/crates/precompile/src/secp256k1/k256.rs
new file mode 100644
index 0000000000..6e16952c06
--- /dev/null
+++ b/crates/precompile/src/secp256k1/k256.rs
@@ -0,0 +1,27 @@
+use k256::ecdsa::{Error, RecoveryId, Signature, VerifyingKey};
+use primitives::{alloy_primitives::B512, keccak256, B256};
+
+pub fn ecrecover(sig: &B512, mut recid: u8, msg: &B256) -> Result<B256, Error> {
+    // parse signature
+    let mut sig = Signature::from_slice(sig.as_slice())?;
+
+    // normalize signature and flip recovery id if needed.
+    if let Some(sig_normalized) = sig.normalize_s() {
+        sig = sig_normalized;
+        recid ^= 1;
+    }
+    let recid = RecoveryId::from_byte(recid).expect("recovery ID is valid");
+
+    // recover key
+    let recovered_key = VerifyingKey::recover_from_prehash(&msg[..], &sig, recid)?;
+    // hash it
+    let mut hash = keccak256(
+        &recovered_key
+            .to_encoded_point(/* compress = */ false)
+            .as_bytes()[1..],
+    );
+
+    // truncate to 20 bytes
+    hash[..12].fill(0);
+    Ok(hash)
+}
diff --git a/crates/precompile/src/secp256k1/parity_libsecp256k1.rs b/crates/precompile/src/secp256k1/parity_libsecp256k1.rs
new file mode 100644
index 0000000000..b9ea28de0f
--- /dev/null
+++ b/crates/precompile/src/secp256k1/parity_libsecp256k1.rs
@@ -0,0 +1,15 @@
+use libsecp256k1::{recover, Error, Message, RecoveryId, Signature};
+use primitives::{alloy_primitives::B512, keccak256, B256};
+
+pub fn ecrecover(sig: &B512, recid: u8, msg: &B256) -> Result<B256, Error> {
+    let recid = RecoveryId::parse(recid)?;
+    let sig = Signature::parse_standard(sig)?;
+    let msg = Message::parse(msg.as_ref());
+
+    // uses static context.
+    let public = recover(&msg, &sig, &recid)?;
+
+    let mut hash = keccak256(&public.serialize()[1..]);
+    hash[..12].fill(0);
+    Ok(hash)
+}


Test patch: