revm_precompile/
lib.rs

1//! # revm-precompile
2//!
3//! Implementations of EVM precompiled contracts.
4#![cfg_attr(not(test), warn(unused_crate_dependencies))]
5#![cfg_attr(not(feature = "std"), no_std)]
6
7#[macro_use]
8#[cfg(not(feature = "std"))]
9extern crate alloc as std;
10
11pub mod blake2;
12#[cfg(feature = "blst")]
13pub mod bls12_381;
14pub mod bn128;
15pub mod fatal_precompile;
16pub mod hash;
17pub mod identity;
18#[cfg(any(feature = "c-kzg", feature = "kzg-rs"))]
19pub mod kzg_point_evaluation;
20pub mod modexp;
21pub mod secp256k1;
22#[cfg(feature = "secp256r1")]
23pub mod secp256r1;
24pub mod utilities;
25
26pub use fatal_precompile::fatal_precompile;
27
28#[cfg(all(feature = "c-kzg", feature = "kzg-rs"))]
29// silence kzg-rs lint as c-kzg will be used as default if both are enabled.
30use kzg_rs as _;
31pub use primitives::{
32    precompile::{PrecompileError as Error, *},
33    Address, Bytes, HashMap, HashSet, Log, B256,
34};
35#[doc(hidden)]
36pub use revm_primitives as primitives;
37
38use cfg_if::cfg_if;
39use core::hash::Hash;
40use once_cell::race::OnceBox;
41use std::{boxed::Box, vec::Vec};
42
43pub fn calc_linear_cost_u32(len: usize, base: u64, word: u64) -> u64 {
44    (len as u64).div_ceil(32) * word + base
45}
46
47#[derive(Clone, Default, Debug)]
48pub struct Precompiles {
49    /// Precompiles.
50    inner: HashMap<Address, Precompile>,
51    /// Addresses of precompile.
52    addresses: HashSet<Address>,
53}
54
55impl Precompiles {
56    /// Returns the precompiles for the given spec.
57    pub fn new(spec: PrecompileSpecId) -> &'static Self {
58        match spec {
59            PrecompileSpecId::HOMESTEAD => Self::homestead(),
60            PrecompileSpecId::BYZANTIUM => Self::byzantium(),
61            PrecompileSpecId::ISTANBUL => Self::istanbul(),
62            PrecompileSpecId::BERLIN => Self::berlin(),
63            PrecompileSpecId::CANCUN => Self::cancun(),
64            PrecompileSpecId::PRAGUE => Self::prague(),
65            PrecompileSpecId::LATEST => Self::latest(),
66        }
67    }
68
69    /// Returns precompiles for Homestead spec.
70    pub fn homestead() -> &'static Self {
71        static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
72        INSTANCE.get_or_init(|| {
73            let mut precompiles = Precompiles::default();
74            precompiles.extend([
75                secp256k1::ECRECOVER,
76                hash::SHA256,
77                hash::RIPEMD160,
78                identity::FUN,
79            ]);
80            Box::new(precompiles)
81        })
82    }
83
84    /// Returns inner HashMap of precompiles.
85    pub fn inner(&self) -> &HashMap<Address, Precompile> {
86        &self.inner
87    }
88
89    /// Returns precompiles for Byzantium spec.
90    pub fn byzantium() -> &'static Self {
91        static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
92        INSTANCE.get_or_init(|| {
93            let mut precompiles = Self::homestead().clone();
94            precompiles.extend([
95                // EIP-196: Precompiled contracts for addition and scalar multiplication on the elliptic curve alt_bn128.
96                // EIP-197: Precompiled contracts for optimal ate pairing check on the elliptic curve alt_bn128.
97                bn128::add::BYZANTIUM,
98                bn128::mul::BYZANTIUM,
99                bn128::pair::BYZANTIUM,
100                // EIP-198: Big integer modular exponentiation.
101                modexp::BYZANTIUM,
102            ]);
103            Box::new(precompiles)
104        })
105    }
106
107    /// Returns precompiles for Istanbul spec.
108    pub fn istanbul() -> &'static Self {
109        static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
110        INSTANCE.get_or_init(|| {
111            let mut precompiles = Self::byzantium().clone();
112            precompiles.extend([
113                // EIP-1108: Reduce alt_bn128 precompile gas costs.
114                bn128::add::ISTANBUL,
115                bn128::mul::ISTANBUL,
116                bn128::pair::ISTANBUL,
117                // EIP-152: Add BLAKE2 compression function `F` precompile.
118                blake2::FUN,
119            ]);
120            Box::new(precompiles)
121        })
122    }
123
124    /// Returns precompiles for Berlin spec.
125    pub fn berlin() -> &'static Self {
126        static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
127        INSTANCE.get_or_init(|| {
128            let mut precompiles = Self::istanbul().clone();
129            precompiles.extend([
130                // EIP-2565: ModExp Gas Cost.
131                modexp::BERLIN,
132            ]);
133            Box::new(precompiles)
134        })
135    }
136
137    /// Returns precompiles for Cancun spec.
138    ///
139    /// If the `c-kzg` feature is not enabled KZG Point Evaluation precompile will not be included,
140    /// effectively making this the same as Berlin.
141    pub fn cancun() -> &'static Self {
142        static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
143        INSTANCE.get_or_init(|| {
144            let mut precompiles = Self::berlin().clone();
145
146            // EIP-4844: Shard Blob Transactions
147            cfg_if! {
148                if #[cfg(any(feature = "c-kzg", feature = "kzg-rs"))] {
149                    let precompile = kzg_point_evaluation::POINT_EVALUATION.clone();
150                } else {
151                    // TODO move constants to separate file.
152                    let precompile = fatal_precompile(u64_to_address(0x0A), "c-kzg feature is not enabled".into());
153                }
154            }
155
156            precompiles.extend([
157                precompile,
158            ]);
159
160            Box::new(precompiles)
161        })
162    }
163
164    /// Returns precompiles for Prague spec.
165    pub fn prague() -> &'static Self {
166        static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
167        INSTANCE.get_or_init(|| {
168            let precompiles = Self::cancun().clone();
169
170            // Don't include BLS12-381 precompiles in no_std builds.
171            #[cfg(feature = "blst")]
172            let precompiles = {
173                let mut precompiles = precompiles;
174                precompiles.extend(bls12_381::precompiles());
175                precompiles
176            };
177
178            Box::new(precompiles)
179        })
180    }
181
182    /// Returns the precompiles for the latest spec.
183    pub fn latest() -> &'static Self {
184        Self::prague()
185    }
186
187    /// Returns an iterator over the precompiles addresses.
188    #[inline]
189    pub fn addresses(&self) -> impl ExactSizeIterator<Item = &Address> {
190        self.inner.keys()
191    }
192
193    /// Consumes the type and returns all precompile addresses.
194    #[inline]
195    pub fn into_addresses(self) -> impl ExactSizeIterator<Item = Address> {
196        self.inner.into_keys()
197    }
198
199    /// Is the given address a precompile.
200    #[inline]
201    pub fn contains(&self, address: &Address) -> bool {
202        self.inner.contains_key(address)
203    }
204
205    /// Returns the precompile for the given address.
206    #[inline]
207    pub fn get(&self, address: &Address) -> Option<&Precompile> {
208        self.inner.get(address)
209    }
210
211    /// Returns the precompile for the given address.
212    #[inline]
213    pub fn get_mut(&mut self, address: &Address) -> Option<&mut Precompile> {
214        self.inner.get_mut(address)
215    }
216
217    /// Is the precompiles list empty.
218    pub fn is_empty(&self) -> bool {
219        self.inner.len() == 0
220    }
221
222    /// Returns the number of precompiles.
223    pub fn len(&self) -> usize {
224        self.inner.len()
225    }
226
227    /// Returns the precompiles addresses as a set.
228    pub fn addresses_set(&self) -> &HashSet<Address> {
229        &self.addresses
230    }
231
232    /// Extends the precompiles with the given precompiles.
233    ///
234    /// Other precompiles with overwrite existing precompiles.
235    #[inline]
236    pub fn extend(&mut self, other: impl IntoIterator<Item = PrecompileWithAddress>) {
237        let items = other.into_iter().collect::<Vec<_>>();
238        self.addresses.extend(items.iter().map(|p| *p.address()));
239        self.inner.extend(items.into_iter().map(Into::into));
240    }
241}
242
243#[derive(Clone, Debug)]
244pub struct PrecompileWithAddress(pub Address, pub Precompile);
245
246impl From<(Address, Precompile)> for PrecompileWithAddress {
247    fn from(value: (Address, Precompile)) -> Self {
248        PrecompileWithAddress(value.0, value.1)
249    }
250}
251
252impl From<PrecompileWithAddress> for (Address, Precompile) {
253    fn from(value: PrecompileWithAddress) -> Self {
254        (value.0, value.1)
255    }
256}
257
258impl PrecompileWithAddress {
259    /// Returns reference of address.
260    #[inline]
261    pub fn address(&self) -> &Address {
262        &self.0
263    }
264
265    /// Returns reference of precompile.
266    #[inline]
267    pub fn precompile(&self) -> &Precompile {
268        &self.1
269    }
270}
271
272#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
273pub enum PrecompileSpecId {
274    HOMESTEAD,
275    BYZANTIUM,
276    ISTANBUL,
277    BERLIN,
278    CANCUN,
279    PRAGUE,
280    LATEST,
281}
282
283impl PrecompileSpecId {
284    /// Returns the appropriate precompile Spec for the primitive [SpecId](revm_primitives::SpecId)
285    pub const fn from_spec_id(spec_id: revm_primitives::SpecId) -> Self {
286        use revm_primitives::SpecId::*;
287        match spec_id {
288            FRONTIER | FRONTIER_THAWING | HOMESTEAD | DAO_FORK | TANGERINE | SPURIOUS_DRAGON => {
289                Self::HOMESTEAD
290            }
291            BYZANTIUM | CONSTANTINOPLE | PETERSBURG => Self::BYZANTIUM,
292            ISTANBUL | MUIR_GLACIER => Self::ISTANBUL,
293            BERLIN | LONDON | ARROW_GLACIER | GRAY_GLACIER | MERGE | SHANGHAI => Self::BERLIN,
294            CANCUN => Self::CANCUN,
295            PRAGUE | OSAKA => Self::PRAGUE,
296            LATEST => Self::LATEST,
297            #[cfg(feature = "optimism")]
298            BEDROCK | REGOLITH | CANYON => Self::BERLIN,
299            #[cfg(feature = "optimism")]
300            ECOTONE | FJORD | GRANITE | HOLOCENE => Self::CANCUN,
301        }
302    }
303}
304
305/// Const function for making an address by concatenating the bytes from two given numbers.
306///
307/// Note that 32 + 128 = 160 = 20 bytes (the length of an address). This function is used
308/// as a convenience for specifying the addresses of the various precompiles.
309#[inline]
310pub const fn u64_to_address(x: u64) -> Address {
311    let x = x.to_be_bytes();
312    Address::new([
313        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7],
314    ])
315}