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 {
60 (len as u64).div_ceil(32) * word + base
61}
62
63#[derive(Clone, Default, Debug)]
64pub struct Precompiles {
65 inner: HashMap<Address, PrecompileFn>,
67 addresses: HashSet<Address>,
69}
70
71impl Precompiles {
72 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 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 pub fn inner(&self) -> &HashMap<Address, PrecompileFn> {
102 &self.inner
103 }
104
105 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 bn128::add::BYZANTIUM,
114 bn128::mul::BYZANTIUM,
115 bn128::pair::BYZANTIUM,
116 modexp::BYZANTIUM,
118 ]);
119 Box::new(precompiles)
120 })
121 }
122
123 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 bn128::add::ISTANBUL,
131 bn128::mul::ISTANBUL,
132 bn128::pair::ISTANBUL,
133 blake2::FUN,
135 ]);
136 Box::new(precompiles)
137 })
138 }
139
140 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 modexp::BERLIN,
148 ]);
149 Box::new(precompiles)
150 })
151 }
152
153 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 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 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 pub fn latest() -> &'static Self {
192 Self::prague()
193 }
194
195 #[inline]
197 pub fn addresses(&self) -> impl ExactSizeIterator<Item = &Address> {
198 self.inner.keys()
199 }
200
201 #[inline]
203 pub fn into_addresses(self) -> impl ExactSizeIterator<Item = Address> {
204 self.inner.into_keys()
205 }
206
207 #[inline]
209 pub fn contains(&self, address: &Address) -> bool {
210 self.inner.contains_key(address)
211 }
212
213 #[inline]
215 pub fn get(&self, address: &Address) -> Option<&PrecompileFn> {
216 self.inner.get(address)
217 }
218
219 #[inline]
221 pub fn get_mut(&mut self, address: &Address) -> Option<&mut PrecompileFn> {
222 self.inner.get_mut(address)
223 }
224
225 pub fn is_empty(&self) -> bool {
227 self.inner.len() == 0
228 }
229
230 pub fn len(&self) -> usize {
232 self.inner.len()
233 }
234
235 pub fn addresses_set(&self) -> &HashSet<Address> {
237 &self.addresses
238 }
239
240 #[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 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 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 #[inline]
303 pub fn address(&self) -> &Address {
304 &self.0
305 }
306
307 #[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 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#[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}