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 }
84 }
85
86 pub fn homestead() -> &'static Self {
88 static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
89 INSTANCE.get_or_init(|| {
90 let mut precompiles = Precompiles::default();
91 precompiles.extend([
92 secp256k1::ECRECOVER,
93 hash::SHA256,
94 hash::RIPEMD160,
95 identity::FUN,
96 ]);
97 Box::new(precompiles)
98 })
99 }
100
101 pub fn inner(&self) -> &HashMap<Address, PrecompileFn> {
103 &self.inner
104 }
105
106 pub fn byzantium() -> &'static Self {
108 static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
109 INSTANCE.get_or_init(|| {
110 let mut precompiles = Self::homestead().clone();
111 precompiles.extend([
112 modexp::BYZANTIUM,
114 bn128::add::BYZANTIUM,
117 bn128::mul::BYZANTIUM,
118 bn128::pair::BYZANTIUM,
119 ]);
120 Box::new(precompiles)
121 })
122 }
123
124 pub fn istanbul() -> &'static Self {
126 static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
127 INSTANCE.get_or_init(|| {
128 let mut precompiles = Self::byzantium().clone();
129 precompiles.extend([
130 bn128::add::ISTANBUL,
132 bn128::mul::ISTANBUL,
133 bn128::pair::ISTANBUL,
134 blake2::FUN,
136 ]);
137 Box::new(precompiles)
138 })
139 }
140
141 pub fn berlin() -> &'static Self {
143 static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
144 INSTANCE.get_or_init(|| {
145 let mut precompiles = Self::istanbul().clone();
146 precompiles.extend([
147 modexp::BERLIN,
149 ]);
150 Box::new(precompiles)
151 })
152 }
153
154 pub fn cancun() -> &'static Self {
159 static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
160 INSTANCE.get_or_init(|| {
161 let mut precompiles = Self::berlin().clone();
162
163 cfg_if! {
165 if #[cfg(any(feature = "c-kzg", feature = "kzg-rs"))] {
166 let precompile = kzg_point_evaluation::POINT_EVALUATION.clone();
167 } else {
168 let precompile = PrecompileWithAddress(u64_to_address(0x0A), |_,_| Err(PrecompileError::Fatal("c-kzg feature is not enabled".into())));
169 }
170 }
171
172
173 precompiles.extend([
174 precompile,
175 ]);
176
177 Box::new(precompiles)
178 })
179 }
180
181 pub fn prague() -> &'static Self {
183 static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
184 INSTANCE.get_or_init(|| {
185 let mut precompiles = Self::cancun().clone();
186 precompiles.extend(bls12_381::precompiles());
187 Box::new(precompiles)
188 })
189 }
190
191 pub fn latest() -> &'static Self {
193 Self::prague()
194 }
195
196 #[inline]
198 pub fn addresses(&self) -> impl ExactSizeIterator<Item = &Address> {
199 self.inner.keys()
200 }
201
202 #[inline]
204 pub fn into_addresses(self) -> impl ExactSizeIterator<Item = Address> {
205 self.inner.into_keys()
206 }
207
208 #[inline]
210 pub fn contains(&self, address: &Address) -> bool {
211 self.inner.contains_key(address)
212 }
213
214 #[inline]
216 pub fn get(&self, address: &Address) -> Option<&PrecompileFn> {
217 self.inner.get(address)
218 }
219
220 #[inline]
222 pub fn get_mut(&mut self, address: &Address) -> Option<&mut PrecompileFn> {
223 self.inner.get_mut(address)
224 }
225
226 pub fn is_empty(&self) -> bool {
228 self.inner.len() == 0
229 }
230
231 pub fn len(&self) -> usize {
233 self.inner.len()
234 }
235
236 pub fn addresses_set(&self) -> &HashSet<Address> {
238 &self.addresses
239 }
240
241 #[inline]
245 pub fn extend(&mut self, other: impl IntoIterator<Item = PrecompileWithAddress>) {
246 let items: Vec<PrecompileWithAddress> = other.into_iter().collect::<Vec<_>>();
247 self.addresses.extend(items.iter().map(|p| *p.address()));
248 self.inner.extend(items.into_iter().map(|p| (p.0, p.1)));
249 }
250
251 pub fn difference(&self, other: &Self) -> Self {
255 let Self { inner, .. } = self;
256
257 let inner = inner
258 .iter()
259 .filter(|(a, _)| !other.inner.contains_key(*a))
260 .map(|(a, p)| (*a, *p))
261 .collect::<HashMap<_, _>>();
262
263 let addresses = inner.keys().cloned().collect::<HashSet<_>>();
264
265 Self { inner, addresses }
266 }
267
268 pub fn intersection(&self, other: &Self) -> Self {
272 let Self { inner, .. } = self;
273
274 let inner = inner
275 .iter()
276 .filter(|(a, _)| other.inner.contains_key(*a))
277 .map(|(a, p)| (*a, *p))
278 .collect::<HashMap<_, _>>();
279
280 let addresses = inner.keys().cloned().collect::<HashSet<_>>();
281
282 Self { inner, addresses }
283 }
284}
285
286#[derive(Clone, Debug)]
288pub struct PrecompileWithAddress(pub Address, pub PrecompileFn);
289
290impl From<(Address, PrecompileFn)> for PrecompileWithAddress {
291 fn from(value: (Address, PrecompileFn)) -> Self {
292 PrecompileWithAddress(value.0, value.1)
293 }
294}
295
296impl From<PrecompileWithAddress> for (Address, PrecompileFn) {
297 fn from(value: PrecompileWithAddress) -> Self {
298 (value.0, value.1)
299 }
300}
301
302impl PrecompileWithAddress {
303 #[inline]
305 pub fn address(&self) -> &Address {
306 &self.0
307 }
308
309 #[inline]
311 pub fn precompile(&self) -> &PrecompileFn {
312 &self.1
313 }
314}
315
316#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
318pub enum PrecompileSpecId {
319 HOMESTEAD,
321 BYZANTIUM,
326 ISTANBUL,
331 BERLIN,
334 CANCUN,
337 PRAGUE,
346}
347
348impl From<SpecId> for PrecompileSpecId {
349 fn from(spec_id: SpecId) -> Self {
350 Self::from_spec_id(spec_id)
351 }
352}
353
354impl PrecompileSpecId {
355 pub const fn from_spec_id(spec_id: primitives::hardfork::SpecId) -> Self {
357 use primitives::hardfork::SpecId::*;
358 match spec_id {
359 FRONTIER | FRONTIER_THAWING | HOMESTEAD | DAO_FORK | TANGERINE | SPURIOUS_DRAGON => {
360 Self::HOMESTEAD
361 }
362 BYZANTIUM | CONSTANTINOPLE | PETERSBURG => Self::BYZANTIUM,
363 ISTANBUL | MUIR_GLACIER => Self::ISTANBUL,
364 BERLIN | LONDON | ARROW_GLACIER | GRAY_GLACIER | MERGE | SHANGHAI => Self::BERLIN,
365 CANCUN => Self::CANCUN,
366 PRAGUE | OSAKA => Self::PRAGUE,
367 }
368 }
369}
370
371#[inline]
377pub const fn u64_to_address(x: u64) -> Address {
378 let x = x.to_be_bytes();
379 Address::new([
380 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],
381 ])
382}
383
384#[cfg(test)]
385mod test {
386 use crate::Precompiles;
387
388 #[test]
389 fn test_difference_precompile_sets() {
390 let difference = Precompiles::istanbul().difference(Precompiles::berlin());
391 assert!(difference.is_empty());
392 }
393
394 #[test]
395 fn test_intersection_precompile_sets() {
396 let intersection = Precompiles::homestead().intersection(Precompiles::byzantium());
397
398 assert_eq!(intersection.len(), 4)
399 }
400}