diff --git a/Cargo.lock b/Cargo.lock index b0f5d59e5ec..436bf704458 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -137,7 +137,7 @@ dependencies = [ "hashbrown 0.16.0", "indexmap 2.11.4", "itoa", - "k256 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)", + "k256", "paste", "rand 0.9.2", "ruint", @@ -1740,7 +1740,7 @@ dependencies = [ "coins-core", "digest 0.10.7", "hmac", - "k256 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)", + "k256", "serde", "sha2", "thiserror 1.0.69", @@ -2867,25 +2867,12 @@ dependencies = [ "der", "digest 0.10.7", "elliptic-curve", - "rfc6979 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rfc6979", "serdect", "signature", "spki", ] -[[package]] -name = "ecdsa" -version = "0.16.9" -source = "git+https://github.com/sp1-patches/signatures?tag=patch-16.9-sp1-4.1.0#1880299a48fe7ef249edaa616fd411239fb5daf1" -dependencies = [ - "der", - "digest 0.10.7", - "elliptic-curve", - "rfc6979 0.4.0 (git+https://github.com/sp1-patches/signatures?tag=patch-16.9-sp1-4.1.0)", - "signature", - "spki", -] - [[package]] name = "educe" version = "0.6.0" @@ -2967,7 +2954,6 @@ dependencies = [ "ff 0.13.1", "generic-array 0.14.7", "group 0.13.0", - "hkdf", "pem-rfc7468", "pkcs8", "rand_core 0.6.4", @@ -3031,7 +3017,7 @@ dependencies = [ "base64 0.21.7", "bytes", "hex", - "k256 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)", + "k256", "log", "rand 0.8.5", "rlp 0.5.2", @@ -3357,7 +3343,7 @@ dependencies = [ "elliptic-curve", "ethabi", "generic-array 0.14.7", - "k256 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)", + "k256", "num_enum 0.7.4", "once_cell", "open-fastrlp", @@ -3807,7 +3793,7 @@ dependencies = [ "ethrex-crypto", "ethrex-rlp 3.0.0", "hex", - "k256 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)", + "k256", "lambdaworks-math 0.11.0", "lazy_static", "malachite 0.6.1", @@ -5054,15 +5040,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "hkdf" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" -dependencies = [ - "hmac", -] - [[package]] name = "hmac" version = "0.12.1" @@ -5891,7 +5868,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" dependencies = [ "cfg-if 1.0.3", - "ecdsa 0.16.9 (registry+https://github.com/rust-lang/crates.io-index)", + "ecdsa", "elliptic-curve", "once_cell", "serdect", @@ -5899,21 +5876,6 @@ dependencies = [ "signature", ] -[[package]] -name = "k256" -version = "0.13.4" -source = "git+https://github.com/sp1-patches/elliptic-curves?tag=patch-k256-13.4-sp1-5.0.0#f7d8998e05d8cbcbd8e543eba1030a7385011fa8" -dependencies = [ - "cfg-if 1.0.3", - "ecdsa 0.16.9 (git+https://github.com/sp1-patches/signatures?tag=patch-16.9-sp1-4.1.0)", - "elliptic-curve", - "hex", - "once_cell", - "sha2", - "signature", - "sp1-lib", -] - [[package]] name = "keccak" version = "0.1.5" @@ -7229,7 +7191,7 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" dependencies = [ - "ecdsa 0.16.9 (registry+https://github.com/rust-lang/crates.io-index)", + "ecdsa", "elliptic-curve", "primeorder", "sha2", @@ -8788,15 +8750,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "rfc6979" -version = "0.4.0" -source = "git+https://github.com/sp1-patches/signatures?tag=patch-16.9-sp1-4.1.0#1880299a48fe7ef249edaa616fd411239fb5daf1" -dependencies = [ - "hmac", - "subtle", -] - [[package]] name = "rgb" version = "0.8.52" @@ -9834,19 +9787,19 @@ dependencies = [ [[package]] name = "secp256k1" version = "0.30.0" -source = "git+https://github.com/sp1-patches/rust-secp256k1?tag=patch-0.30.0-sp1-5.0.0#04d87db04bcc2dc5dd8e1ab3f046cc655440d07a" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b50c5943d326858130af85e049f2661ba3c78b26589b8ab98e65e80ae44a1252" dependencies = [ "bitcoin_hashes", - "cfg-if 1.0.3", - "k256 0.13.4 (git+https://github.com/sp1-patches/elliptic-curves?tag=patch-k256-13.4-sp1-5.0.0)", "rand 0.8.5", "secp256k1-sys", ] [[package]] name = "secp256k1-sys" -version = "0.10.0" -source = "git+https://github.com/sp1-patches/rust-secp256k1?tag=patch-0.30.0-sp1-5.0.0#04d87db04bcc2dc5dd8e1ab3f046cc655440d07a" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4387882333d3aa8cb20530a17c69a3752e97837832f34f6dccc760e715001d9" dependencies = [ "cc", ] @@ -10363,7 +10316,7 @@ dependencies = [ "hashbrown 0.14.5", "hex", "itertools 0.13.0", - "k256 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)", + "k256", "num", "num_cpus", "p256", @@ -10431,7 +10384,7 @@ dependencies = [ "elliptic-curve", "generic-array 1.1.0", "itertools 0.13.0", - "k256 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)", + "k256", "num", "p256", "p3-field", @@ -10459,7 +10412,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fce8ad0f153443d09d398eccb650a0b2dcbf829470e394e4bf60ec4379c7af93" dependencies = [ "bincode", - "elliptic-curve", "serde", "sp1-primitives", ] @@ -10684,7 +10636,7 @@ dependencies = [ "hex", "indicatif", "itertools 0.13.0", - "k256 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)", + "k256", "p3-baby-bear", "p3-field", "p3-fri", diff --git a/Cargo.toml b/Cargo.toml index 65c7600b9af..dfbb5cd23b1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -127,6 +127,3 @@ tower-http = { version = "0.6.2", features = ["cors"] } indexmap = { version = "2.11.4" } rocksdb = "0.24.0" - -[patch.crates-io] -secp256k1 = { git = "https://github.com/sp1-patches/rust-secp256k1", tag = "patch-0.30.0-sp1-5.0.0" } diff --git a/crates/l2/prover/src/guest_program/src/risc0/Cargo.toml b/crates/l2/prover/src/guest_program/src/risc0/Cargo.toml index f4b0cea8cee..559e04cf3e9 100644 --- a/crates/l2/prover/src/guest_program/src/risc0/Cargo.toml +++ b/crates/l2/prover/src/guest_program/src/risc0/Cargo.toml @@ -24,7 +24,7 @@ ethrex-common = { path = "../../../../../../common", default-features = false } ethrex-storage = { path = "../../../../../../storage", default-features = false } ethrex-rlp = { path = "../../../../../../common/rlp" } ethrex-vm = { path = "../../../../../../vm", default-features = false, features = [ - "c-kzg", + "risc0", ] } ethrex-blockchain = { path = "../../../../../../blockchain", default-features = false } ethrex-l2-common = { path = "../../../../../common", default-features = false } diff --git a/crates/l2/prover/src/guest_program/src/sp1/Cargo.toml b/crates/l2/prover/src/guest_program/src/sp1/Cargo.toml index 097c9b5ada0..1ab4ee1649f 100644 --- a/crates/l2/prover/src/guest_program/src/sp1/Cargo.toml +++ b/crates/l2/prover/src/guest_program/src/sp1/Cargo.toml @@ -14,7 +14,9 @@ guest_program = { path = "../../" } ethrex-common = { path = "../../../../../../common", default-features = false } ethrex-storage = { path = "../../../../../../storage", default-features = false } ethrex-rlp = { path = "../../../../../../common/rlp" } -ethrex-vm = { path = "../../../../../../vm", default-features = false } +ethrex-vm = { path = "../../../../../../vm", default-features = false, features = [ + "sp1", +] } ethrex-blockchain = { path = "../../../../../../blockchain", default-features = false } ethrex-l2-common = { path = "../../../../../common", default-features = false } diff --git a/crates/vm/Cargo.toml b/crates/vm/Cargo.toml index 6a429945038..201f6d51cda 100644 --- a/crates/vm/Cargo.toml +++ b/crates/vm/Cargo.toml @@ -31,7 +31,12 @@ path = "./lib.rs" [features] default = [] + c-kzg = ["ethrex-levm/c-kzg", "ethrex-common/c-kzg"] + +sp1 = ["ethrex-levm/sp1"] +risc0 = ["ethrex-levm/risc0", "c-kzg"] + debug = ["ethrex-levm/debug"] [lints.clippy] diff --git a/crates/vm/levm/Cargo.toml b/crates/vm/levm/Cargo.toml index ec81c64064c..4a224b5c1fe 100644 --- a/crates/vm/levm/Cargo.toml +++ b/crates/vm/levm/Cargo.toml @@ -21,7 +21,11 @@ sha3 = "0.10.8" datatest-stable = "0.2.9" walkdir = "2.5.0" secp256k1.workspace = true -p256 = { version = "0.13.2", features = ["ecdsa", "arithmetic", "expose-field"] } +p256 = { version = "0.13.2", features = [ + "ecdsa", + "arithmetic", + "expose-field", +] } sha2 = "0.10.8" ripemd = "0.1.3" malachite = "0.6.1" @@ -47,8 +51,14 @@ spinoff = "0.8.0" [features] default = [] + c-kzg = ["ethrex-common/c-kzg"] + +sp1 = [] +risc0 = ["c-kzg"] + ethereum_foundation_tests = [] + debug = [] [lints.rust] diff --git a/crates/vm/levm/src/precompiles.rs b/crates/vm/levm/src/precompiles.rs index e4ad1c0f80b..5e29b33731f 100644 --- a/crates/vm/levm/src/precompiles.rs +++ b/crates/vm/levm/src/precompiles.rs @@ -7,13 +7,12 @@ use bls12_381::{ }; use bytes::{Buf, Bytes}; use ethrex_common::H160; -use ethrex_common::utils::{keccak, u256_from_big_endian_const}; +use ethrex_common::utils::u256_from_big_endian_const; use ethrex_common::{ Address, H256, U256, serde_utils::bool, types::Fork, types::Fork::*, utils::u256_from_big_endian, }; use ethrex_crypto::{blake2f::blake2b_f, kzg::verify_kzg_proof}; -use k256::ecdsa::{RecoveryId, Signature, VerifyingKey}; use k256::elliptic_curve::Field; use lambdaworks_math::{ elliptic_curve::{ @@ -61,8 +60,8 @@ use crate::{ gas_cost::{ self, BLAKE2F_ROUND_COST, BLS12_381_G1_K_DISCOUNT, BLS12_381_G1ADD_COST, BLS12_381_G2_K_DISCOUNT, BLS12_381_G2ADD_COST, BLS12_381_MAP_FP_TO_G1_COST, - BLS12_381_MAP_FP2_TO_G2_COST, ECADD_COST, ECMUL_COST, ECRECOVER_COST, G1_MUL_COST, - G2_MUL_COST, POINT_EVALUATION_COST, + BLS12_381_MAP_FP2_TO_G2_COST, ECADD_COST, ECMUL_COST, G1_MUL_COST, G2_MUL_COST, + POINT_EVALUATION_COST, }, }; use lambdaworks_math::elliptic_curve::short_weierstrass::curves::bls12_381::curve::{ @@ -383,6 +382,65 @@ pub(crate) fn fill_with_zeros(calldata: &Bytes, target_len: usize) -> Bytes { padded_calldata.into() } +#[cfg(all(not(feature = "sp1"), not(feature = "risc0")))] +pub fn ecrecover(calldata: &Bytes, gas_remaining: &mut u64, _fork: Fork) -> Result { + use sha3::Keccak256; + + use crate::gas_cost::ECRECOVER_COST; + + increase_precompile_consumed_gas(ECRECOVER_COST, gas_remaining)?; + + const INPUT_LEN: usize = 128; + const WORD: usize = 32; + + let input = fill_with_zeros(calldata, INPUT_LEN); + + // len(raw_hash) == 32, len(raw_v) == 32, len(raw_sig) == 64 + let (raw_hash, tail) = input.split_at(WORD); + let (raw_v, raw_sig) = tail.split_at(WORD); + + // EVM expects v ∈ {27, 28}. Anything else is invalid → empty return. + let recovery_id_byte = match u8::try_from(u256_from_big_endian(raw_v)) { + Ok(27) => 0_i32, + Ok(28) => 1_i32, + _ => return Ok(Bytes::new()), + }; + + // Recovery id from the adjusted byte. + let Ok(recovery_id) = secp256k1::ecdsa::RecoveryId::try_from(recovery_id_byte) else { + return Ok(Bytes::new()); + }; + + let Ok(recoverable_signature) = + secp256k1::ecdsa::RecoverableSignature::from_compact(raw_sig, recovery_id) + else { + return Ok(Bytes::new()); + }; + + let message = secp256k1::Message::from_digest( + raw_hash + .try_into() + .map_err(|_err| InternalError::msg("Invalid message length for ecrecover"))?, + ); + + let Ok(public_key) = recoverable_signature.recover(&message) else { + return Ok(Bytes::new()); + }; + + // We need to take the 64 bytes from the public key (discarding the first pos of the slice) + let public_key_hash = Keccak256::digest(&public_key.serialize_uncompressed()[1..]); + + // Address is the last 20 bytes of the hash. + #[expect(clippy::indexing_slicing)] + let recovered_address_bytes = &public_key_hash[12..]; + + let mut out = [0u8; 32]; + + out[12..32].copy_from_slice(recovered_address_bytes); + + Ok(Bytes::copy_from_slice(&out)) +} + /// ## ECRECOVER precompile. /// Elliptic curve digital signature algorithm (ECDSA) public key recovery function. /// @@ -392,7 +450,13 @@ pub(crate) fn fill_with_zeros(calldata: &Bytes, target_len: usize) -> Bytes { /// [64..128): r||s (64 bytes) /// /// Returns the recovered address. +#[cfg(any(feature = "sp1", feature = "risc0"))] pub fn ecrecover(calldata: &Bytes, gas_remaining: &mut u64, _fork: Fork) -> Result { + use ethrex_common::utils::keccak; + use k256::ecdsa::{RecoveryId, Signature, VerifyingKey}; + + use crate::gas_cost::ECRECOVER_COST; + increase_precompile_consumed_gas(ECRECOVER_COST, gas_remaining)?; const INPUT_LEN: usize = 128;