revm_precompile/
secp256k1.rs

1//! `ecrecover` precompile.
2//!
3//! Depending on enabled features, it will use different implementations of `ecrecover`.
4//! * [`k256`](https://crates.io/crates/k256) - uses maintained pure rust lib `k256`, it is perfect use for no_std environments.
5//! * [`secp256k1`](https://crates.io/crates/secp256k1) - uses `bitcoin_secp256k1` lib, it is a C implementation of secp256k1 used in bitcoin core.
6//!   It is faster than k256 and enabled by default and in std environment.
7//! * [`libsecp256k1`](https://crates.io/crates/libsecp256k1) - is made from parity in pure rust, it is alternative for k256.
8//!
9//! Order of preference is `secp256k1` -> `k256` -> `libsecp256k1`. Where if no features are enabled, it will use `k256`.
10//!
11//! Input format:
12//! [32 bytes for message][64 bytes for signature][1 byte for recovery id]
13//!
14//! Output format:
15//! [32 bytes for recovered address]
16#[cfg(feature = "secp256k1")]
17pub mod bitcoin_secp256k1;
18pub mod k256;
19#[cfg(feature = "libsecp256k1")]
20pub mod parity_libsecp256k1;
21
22use crate::{
23    utilities::right_pad, PrecompileError, PrecompileOutput, PrecompileResult,
24    PrecompileWithAddress,
25};
26use primitives::{alloy_primitives::B512, Bytes, B256};
27
28/// `ecrecover` precompile, containing address and function to run.
29pub const ECRECOVER: PrecompileWithAddress =
30    PrecompileWithAddress(crate::u64_to_address(1), ec_recover_run);
31
32/// `ecrecover` precompile function. Read more about input and output format in [this module docs](self).
33pub fn ec_recover_run(input: &[u8], gas_limit: u64) -> PrecompileResult {
34    const ECRECOVER_BASE: u64 = 3_000;
35
36    if ECRECOVER_BASE > gas_limit {
37        return Err(PrecompileError::OutOfGas);
38    }
39
40    let input = right_pad::<128>(input);
41
42    // `v` must be a 32-byte big-endian integer equal to 27 or 28.
43    if !(input[32..63].iter().all(|&b| b == 0) && matches!(input[63], 27 | 28)) {
44        return Ok(PrecompileOutput::new(ECRECOVER_BASE, Bytes::new()));
45    }
46
47    let msg = <&B256>::try_from(&input[0..32]).unwrap();
48    let recid = input[63] - 27;
49    let sig = <&B512>::try_from(&input[64..128]).unwrap();
50
51    let res = ecrecover(sig, recid, msg);
52
53    let out = res.map(|o| o.to_vec().into()).unwrap_or_default();
54    Ok(PrecompileOutput::new(ECRECOVER_BASE, out))
55}
56
57// Select the correct implementation based on the enabled features.
58cfg_if::cfg_if! {
59    if #[cfg(feature = "secp256k1")] {
60        pub use bitcoin_secp256k1::ecrecover;
61    } else if #[cfg(feature = "libsecp256k1")] {
62        pub use parity_libsecp256k1::ecrecover;
63    } else {
64        pub use k256::ecrecover;
65    }
66}