revm_precompile/
secp256k1.rs1#[cfg(feature = "secp256k1")]
16pub mod bitcoin_secp256k1;
17pub mod k256;
18
19use crate::{
20 crypto, eth_precompile_fn, utilities::right_pad, EthPrecompileOutput, EthPrecompileResult,
21 Precompile, PrecompileHalt, PrecompileId,
22};
23use primitives::{alloy_primitives::B512, Bytes, B256};
24
25eth_precompile_fn!(ecrecover_precompile, ec_recover_run);
26
27pub const ECRECOVER: Precompile = Precompile::new(
29 PrecompileId::EcRec,
30 crate::u64_to_address(1),
31 ecrecover_precompile,
32);
33
34pub fn ec_recover_run(input: &[u8], gas_limit: u64) -> EthPrecompileResult {
36 const ECRECOVER_BASE: u64 = 3_000;
37
38 if ECRECOVER_BASE > gas_limit {
39 return Err(PrecompileHalt::OutOfGas);
40 }
41
42 let input = right_pad::<128>(input);
43
44 if !(input[32..63].iter().all(|&b| b == 0) && matches!(input[63], 27 | 28)) {
46 return Ok(EthPrecompileOutput::new(ECRECOVER_BASE, Bytes::new()));
47 }
48
49 let msg = <&B256>::try_from(&input[0..32]).unwrap();
50 let recid = input[63] - 27;
51 let sig = <&B512>::try_from(&input[64..128]).unwrap();
52
53 let res = crypto().secp256k1_ecrecover(&sig.0, recid, &msg.0).ok();
54 let out = res.map(|o| o.to_vec().into()).unwrap_or_default();
55 Ok(EthPrecompileOutput::new(ECRECOVER_BASE, out))
56}
57
58pub(crate) fn ecrecover_bytes(sig: &[u8; 64], recid: u8, msg: &[u8; 32]) -> Option<[u8; 32]> {
59 match ecrecover(sig.into(), recid, msg.into()) {
60 Ok(address) => Some(address.0),
61 Err(_) => None,
62 }
63}
64
65cfg_if::cfg_if! {
67 if #[cfg(feature = "secp256k1")] {
68 pub use bitcoin_secp256k1::ecrecover;
69 } else {
70 pub use k256::ecrecover;
71 }
72}