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