1#![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
29cfg_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"))]
40use kzg_rs as _;
42
43cfg_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 {
61 (len as u64).div_ceil(32) * word + base
62}
63
64#[derive(Clone, Default, Debug)]
66pub struct Precompiles {
67 inner: HashMap<Address, PrecompileFn>,
69 addresses: HashSet<Address>,
71}
72
73impl Precompiles {
74 pub fn new(spec: PrecompileSpecId) -> &'static Self {
76 match spec {
77 PrecompileSpecId::HOMESTEAD => Self::homestead(),
78 PrecompileSpecId::BYZANTIUM => Self::byzantium(),
79 PrecompileSpecId::ISTANBUL => Self::istanbul(),
80 PrecompileSpecId::BERLIN => Self::berlin(),
81 PrecompileSpecId::CANCUN => Self::cancun(),
82 PrecompileSpecId::PRAGUE => Self::prague(),
83 PrecompileSpecId::OSAKA => Self::osaka(),
84 }
85 }
86
87 pub fn homestead() -> &'static Self {
89 static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
90 INSTANCE.get_or_init(|| {
91 let mut precompiles = Precompiles::default();
92 precompiles.extend([
93 secp256k1::ECRECOVER,
94 hash::SHA256,
95 hash::RIPEMD160,
96 identity::FUN,
97 ]);
98 Box::new(precompiles)
99 })
100 }
101
102 pub fn inner(&self) -> &HashMap<Address, PrecompileFn> {
104 &self.inner
105 }
106
107 pub fn byzantium() -> &'static Self {
109 static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
110 INSTANCE.get_or_init(|| {
111 let mut precompiles = Self::homestead().clone();
112 precompiles.extend([
113 modexp::BYZANTIUM,
115 bn128::add::BYZANTIUM,
118 bn128::mul::BYZANTIUM,
119 bn128::pair::BYZANTIUM,
120 ]);
121 Box::new(precompiles)
122 })
123 }
124
125 pub fn istanbul() -> &'static Self {
127 static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
128 INSTANCE.get_or_init(|| {
129 let mut precompiles = Self::byzantium().clone();
130 precompiles.extend([
131 bn128::add::ISTANBUL,
133 bn128::mul::ISTANBUL,
134 bn128::pair::ISTANBUL,
135 blake2::FUN,
137 ]);
138 Box::new(precompiles)
139 })
140 }
141
142 pub fn berlin() -> &'static Self {
144 static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
145 INSTANCE.get_or_init(|| {
146 let mut precompiles = Self::istanbul().clone();
147 precompiles.extend([
148 modexp::BERLIN,
150 ]);
151 Box::new(precompiles)
152 })
153 }
154
155 pub fn cancun() -> &'static Self {
160 static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
161 INSTANCE.get_or_init(|| {
162 let mut precompiles = Self::berlin().clone();
163
164 cfg_if! {
166 if #[cfg(any(feature = "c-kzg", feature = "kzg-rs"))] {
167 let precompile = kzg_point_evaluation::POINT_EVALUATION.clone();
168 } else {
169 let precompile = PrecompileWithAddress(u64_to_address(0x0A), |_,_| Err(PrecompileError::Fatal("c-kzg feature is not enabled".into())));
170 }
171 }
172
173
174 precompiles.extend([
175 precompile,
176 ]);
177
178 Box::new(precompiles)
179 })
180 }
181
182 pub fn prague() -> &'static Self {
184 static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
185 INSTANCE.get_or_init(|| {
186 let mut precompiles = Self::cancun().clone();
187 precompiles.extend(bls12_381::precompiles());
188 Box::new(precompiles)
189 })
190 }
191
192 pub fn osaka() -> &'static Self {
194 static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
195 INSTANCE.get_or_init(|| {
196 let mut precompiles = Self::prague().clone();
197 precompiles.extend([modexp::OSAKA]);
198 Box::new(precompiles)
199 })
200 }
201
202 pub fn latest() -> &'static Self {
204 Self::osaka()
205 }
206
207 #[inline]
209 pub fn addresses(&self) -> impl ExactSizeIterator<Item = &Address> {
210 self.inner.keys()
211 }
212
213 #[inline]
215 pub fn into_addresses(self) -> impl ExactSizeIterator<Item = Address> {
216 self.inner.into_keys()
217 }
218
219 #[inline]
221 pub fn contains(&self, address: &Address) -> bool {
222 self.inner.contains_key(address)
223 }
224
225 #[inline]
227 pub fn get(&self, address: &Address) -> Option<&PrecompileFn> {
228 self.inner.get(address)
229 }
230
231 #[inline]
233 pub fn get_mut(&mut self, address: &Address) -> Option<&mut PrecompileFn> {
234 self.inner.get_mut(address)
235 }
236
237 pub fn is_empty(&self) -> bool {
239 self.inner.len() == 0
240 }
241
242 pub fn len(&self) -> usize {
244 self.inner.len()
245 }
246
247 pub fn addresses_set(&self) -> &HashSet<Address> {
249 &self.addresses
250 }
251
252 #[inline]
256 pub fn extend(&mut self, other: impl IntoIterator<Item = PrecompileWithAddress>) {
257 let items: Vec<PrecompileWithAddress> = other.into_iter().collect::<Vec<_>>();
258 self.addresses.extend(items.iter().map(|p| *p.address()));
259 self.inner.extend(items.into_iter().map(|p| (p.0, p.1)));
260 }
261
262 pub fn difference(&self, other: &Self) -> Self {
266 let Self { inner, .. } = self;
267
268 let inner = inner
269 .iter()
270 .filter(|(a, _)| !other.inner.contains_key(*a))
271 .map(|(a, p)| (*a, *p))
272 .collect::<HashMap<_, _>>();
273
274 let addresses = inner.keys().cloned().collect::<HashSet<_>>();
275
276 Self { inner, addresses }
277 }
278
279 pub fn intersection(&self, other: &Self) -> Self {
283 let Self { inner, .. } = self;
284
285 let inner = inner
286 .iter()
287 .filter(|(a, _)| other.inner.contains_key(*a))
288 .map(|(a, p)| (*a, *p))
289 .collect::<HashMap<_, _>>();
290
291 let addresses = inner.keys().cloned().collect::<HashSet<_>>();
292
293 Self { inner, addresses }
294 }
295}
296
297#[derive(Clone, Debug)]
299pub struct PrecompileWithAddress(pub Address, pub PrecompileFn);
300
301impl From<(Address, PrecompileFn)> for PrecompileWithAddress {
302 fn from(value: (Address, PrecompileFn)) -> Self {
303 PrecompileWithAddress(value.0, value.1)
304 }
305}
306
307impl From<PrecompileWithAddress> for (Address, PrecompileFn) {
308 fn from(value: PrecompileWithAddress) -> Self {
309 (value.0, value.1)
310 }
311}
312
313impl PrecompileWithAddress {
314 #[inline]
316 pub fn address(&self) -> &Address {
317 &self.0
318 }
319
320 #[inline]
322 pub fn precompile(&self) -> &PrecompileFn {
323 &self.1
324 }
325}
326
327#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
329pub enum PrecompileSpecId {
330 HOMESTEAD,
332 BYZANTIUM,
337 ISTANBUL,
342 BERLIN,
345 CANCUN,
348 PRAGUE,
357 OSAKA,
361}
362
363impl From<SpecId> for PrecompileSpecId {
364 fn from(spec_id: SpecId) -> Self {
365 Self::from_spec_id(spec_id)
366 }
367}
368
369impl PrecompileSpecId {
370 pub const fn from_spec_id(spec_id: primitives::hardfork::SpecId) -> Self {
372 use primitives::hardfork::SpecId::*;
373 match spec_id {
374 FRONTIER | FRONTIER_THAWING | HOMESTEAD | DAO_FORK | TANGERINE | SPURIOUS_DRAGON => {
375 Self::HOMESTEAD
376 }
377 BYZANTIUM | CONSTANTINOPLE | PETERSBURG => Self::BYZANTIUM,
378 ISTANBUL | MUIR_GLACIER => Self::ISTANBUL,
379 BERLIN | LONDON | ARROW_GLACIER | GRAY_GLACIER | MERGE | SHANGHAI => Self::BERLIN,
380 CANCUN => Self::CANCUN,
381 PRAGUE => Self::PRAGUE,
382 OSAKA => Self::OSAKA,
383 }
384 }
385}
386
387#[inline]
393pub const fn u64_to_address(x: u64) -> Address {
394 let x = x.to_be_bytes();
395 Address::new([
396 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],
397 ])
398}
399
400#[cfg(test)]
401mod test {
402 use crate::Precompiles;
403
404 #[test]
405 fn test_difference_precompile_sets() {
406 let difference = Precompiles::istanbul().difference(Precompiles::berlin());
407 assert!(difference.is_empty());
408 }
409
410 #[test]
411 fn test_intersection_precompile_sets() {
412 let intersection = Precompiles::homestead().intersection(Precompiles::byzantium());
413
414 assert_eq!(intersection.len(), 4)
415 }
416}