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