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;
23pub mod secp256r1;
24pub mod utilities;
25
26pub use interface::*;
27
28cfg_if::cfg_if! {
30 if #[cfg(feature = "bn")]{
31 use ark_bn254 as _;
32 use ark_ff as _;
33 use ark_ec as _;
34 use ark_serialize as _;
35 }
36}
37
38#[cfg(not(target_feature = "avx2"))]
39use arrayref as _;
40
41#[cfg(all(feature = "c-kzg", feature = "kzg-rs"))]
42use kzg_rs as _;
44
45cfg_if::cfg_if! {
47 if #[cfg(feature = "blst")]{
48 use ark_bls12_381 as _;
49 use ark_ff as _;
50 use ark_ec as _;
51 use ark_serialize as _;
52 }
53}
54
55#[cfg(feature = "gmp")]
57use aurora_engine_modexp as _;
58
59use cfg_if::cfg_if;
60use core::hash::Hash;
61use once_cell::race::OnceBox;
62use primitives::{hardfork::SpecId, Address, HashMap, HashSet};
63use std::{boxed::Box, vec::Vec};
64
65pub fn calc_linear_cost_u32(len: usize, base: u64, word: u64) -> u64 {
67 (len as u64).div_ceil(32) * word + base
68}
69
70#[derive(Clone, Default, Debug)]
72pub struct Precompiles {
73 inner: HashMap<Address, PrecompileFn>,
75 addresses: HashSet<Address>,
77}
78
79impl Precompiles {
80 pub fn new(spec: PrecompileSpecId) -> &'static Self {
82 match spec {
83 PrecompileSpecId::HOMESTEAD => Self::homestead(),
84 PrecompileSpecId::BYZANTIUM => Self::byzantium(),
85 PrecompileSpecId::ISTANBUL => Self::istanbul(),
86 PrecompileSpecId::BERLIN => Self::berlin(),
87 PrecompileSpecId::CANCUN => Self::cancun(),
88 PrecompileSpecId::PRAGUE => Self::prague(),
89 PrecompileSpecId::OSAKA => Self::osaka(),
90 }
91 }
92
93 pub fn homestead() -> &'static Self {
95 static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
96 INSTANCE.get_or_init(|| {
97 let mut precompiles = Precompiles::default();
98 precompiles.extend([
99 secp256k1::ECRECOVER,
100 hash::SHA256,
101 hash::RIPEMD160,
102 identity::FUN,
103 ]);
104 Box::new(precompiles)
105 })
106 }
107
108 pub fn inner(&self) -> &HashMap<Address, PrecompileFn> {
110 &self.inner
111 }
112
113 pub fn byzantium() -> &'static Self {
115 static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
116 INSTANCE.get_or_init(|| {
117 let mut precompiles = Self::homestead().clone();
118 precompiles.extend([
119 modexp::BYZANTIUM,
121 bn128::add::BYZANTIUM,
124 bn128::mul::BYZANTIUM,
125 bn128::pair::BYZANTIUM,
126 ]);
127 Box::new(precompiles)
128 })
129 }
130
131 pub fn istanbul() -> &'static Self {
133 static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
134 INSTANCE.get_or_init(|| {
135 let mut precompiles = Self::byzantium().clone();
136 precompiles.extend([
137 bn128::add::ISTANBUL,
139 bn128::mul::ISTANBUL,
140 bn128::pair::ISTANBUL,
141 blake2::FUN,
143 ]);
144 Box::new(precompiles)
145 })
146 }
147
148 pub fn berlin() -> &'static Self {
150 static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
151 INSTANCE.get_or_init(|| {
152 let mut precompiles = Self::istanbul().clone();
153 precompiles.extend([
154 modexp::BERLIN,
156 ]);
157 Box::new(precompiles)
158 })
159 }
160
161 pub fn cancun() -> &'static Self {
166 static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
167 INSTANCE.get_or_init(|| {
168 let mut precompiles = Self::berlin().clone();
169
170 cfg_if! {
172 if #[cfg(any(feature = "c-kzg", feature = "kzg-rs"))] {
173 let precompile = kzg_point_evaluation::POINT_EVALUATION.clone();
174 } else {
175 let precompile = PrecompileWithAddress(u64_to_address(0x0A), |_,_| Err(PrecompileError::Fatal("c-kzg feature is not enabled".into())));
176 }
177 }
178
179
180 precompiles.extend([
181 precompile,
182 ]);
183
184 Box::new(precompiles)
185 })
186 }
187
188 pub fn prague() -> &'static Self {
190 static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
191 INSTANCE.get_or_init(|| {
192 let mut precompiles = Self::cancun().clone();
193 precompiles.extend(bls12_381::precompiles());
194 Box::new(precompiles)
195 })
196 }
197
198 pub fn osaka() -> &'static Self {
200 static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
201 INSTANCE.get_or_init(|| {
202 let mut precompiles = Self::prague().clone();
203 precompiles.extend([modexp::OSAKA, secp256r1::P256VERIFY]);
204 Box::new(precompiles)
205 })
206 }
207
208 pub fn latest() -> &'static Self {
210 Self::osaka()
211 }
212
213 #[inline]
215 pub fn addresses(&self) -> impl ExactSizeIterator<Item = &Address> {
216 self.inner.keys()
217 }
218
219 #[inline]
221 pub fn into_addresses(self) -> impl ExactSizeIterator<Item = Address> {
222 self.inner.into_keys()
223 }
224
225 #[inline]
227 pub fn contains(&self, address: &Address) -> bool {
228 self.inner.contains_key(address)
229 }
230
231 #[inline]
233 pub fn get(&self, address: &Address) -> Option<&PrecompileFn> {
234 self.inner.get(address)
235 }
236
237 #[inline]
239 pub fn get_mut(&mut self, address: &Address) -> Option<&mut PrecompileFn> {
240 self.inner.get_mut(address)
241 }
242
243 pub fn is_empty(&self) -> bool {
245 self.inner.len() == 0
246 }
247
248 pub fn len(&self) -> usize {
250 self.inner.len()
251 }
252
253 pub fn addresses_set(&self) -> &HashSet<Address> {
255 &self.addresses
256 }
257
258 #[inline]
262 pub fn extend(&mut self, other: impl IntoIterator<Item = PrecompileWithAddress>) {
263 let items: Vec<PrecompileWithAddress> = other.into_iter().collect::<Vec<_>>();
264 self.addresses.extend(items.iter().map(|p| *p.address()));
265 self.inner.extend(items.into_iter().map(|p| (p.0, p.1)));
266 }
267
268 pub fn difference(&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 pub fn intersection(&self, other: &Self) -> Self {
289 let Self { inner, .. } = self;
290
291 let inner = inner
292 .iter()
293 .filter(|(a, _)| other.inner.contains_key(*a))
294 .map(|(a, p)| (*a, *p))
295 .collect::<HashMap<_, _>>();
296
297 let addresses = inner.keys().cloned().collect::<HashSet<_>>();
298
299 Self { inner, addresses }
300 }
301}
302
303#[derive(Clone, Debug)]
305pub struct PrecompileWithAddress(pub Address, pub PrecompileFn);
306
307impl From<(Address, PrecompileFn)> for PrecompileWithAddress {
308 fn from(value: (Address, PrecompileFn)) -> Self {
309 PrecompileWithAddress(value.0, value.1)
310 }
311}
312
313impl From<PrecompileWithAddress> for (Address, PrecompileFn) {
314 fn from(value: PrecompileWithAddress) -> Self {
315 (value.0, value.1)
316 }
317}
318
319impl PrecompileWithAddress {
320 #[inline]
322 pub fn address(&self) -> &Address {
323 &self.0
324 }
325
326 #[inline]
328 pub fn precompile(&self) -> &PrecompileFn {
329 &self.1
330 }
331}
332
333#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
335pub enum PrecompileSpecId {
336 HOMESTEAD,
338 BYZANTIUM,
343 ISTANBUL,
348 BERLIN,
351 CANCUN,
354 PRAGUE,
363 OSAKA,
367}
368
369impl From<SpecId> for PrecompileSpecId {
370 fn from(spec_id: SpecId) -> Self {
371 Self::from_spec_id(spec_id)
372 }
373}
374
375impl PrecompileSpecId {
376 pub const fn from_spec_id(spec_id: primitives::hardfork::SpecId) -> Self {
378 use primitives::hardfork::SpecId::*;
379 match spec_id {
380 FRONTIER | FRONTIER_THAWING | HOMESTEAD | DAO_FORK | TANGERINE | SPURIOUS_DRAGON => {
381 Self::HOMESTEAD
382 }
383 BYZANTIUM | CONSTANTINOPLE | PETERSBURG => Self::BYZANTIUM,
384 ISTANBUL | MUIR_GLACIER => Self::ISTANBUL,
385 BERLIN | LONDON | ARROW_GLACIER | GRAY_GLACIER | MERGE | SHANGHAI => Self::BERLIN,
386 CANCUN => Self::CANCUN,
387 PRAGUE => Self::PRAGUE,
388 OSAKA => Self::OSAKA,
389 }
390 }
391}
392
393#[inline]
399pub const fn u64_to_address(x: u64) -> Address {
400 let x = x.to_be_bytes();
401 Address::new([
402 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],
403 ])
404}
405
406#[cfg(test)]
407mod test {
408 use crate::Precompiles;
409
410 #[test]
411 fn test_difference_precompile_sets() {
412 let difference = Precompiles::istanbul().difference(Precompiles::berlin());
413 assert!(difference.is_empty());
414 }
415
416 #[test]
417 fn test_intersection_precompile_sets() {
418 let intersection = Precompiles::homestead().intersection(Precompiles::byzantium());
419
420 assert_eq!(intersection.len(), 4)
421 }
422}