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 bn254;
16pub mod hash;
17pub mod identity;
18pub mod interface;
19pub mod kzg_point_evaluation;
20pub mod modexp;
21pub mod secp256k1;
22pub mod secp256r1;
23pub mod utilities;
24
25pub use interface::*;
26
27cfg_if::cfg_if! {
29 if #[cfg(feature = "bn")]{
30 use ark_bn254 as _;
31 use ark_ff as _;
32 use ark_ec as _;
33 use ark_serialize as _;
34 }
35}
36
37use arrayref as _;
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
53#[cfg(feature = "gmp")]
55use aurora_engine_modexp as _;
56
57use core::hash::Hash;
58use primitives::{hardfork::SpecId, Address, HashMap, HashSet, OnceLock};
59use std::vec::Vec;
60
61pub fn calc_linear_cost_u32(len: usize, base: u64, word: u64) -> u64 {
63 (len as u64).div_ceil(32) * word + base
64}
65
66#[derive(Clone, Default, Debug)]
68pub struct Precompiles {
69 inner: HashMap<Address, PrecompileFn>,
71 addresses: HashSet<Address>,
73}
74
75impl Precompiles {
76 pub fn new(spec: PrecompileSpecId) -> &'static Self {
78 match spec {
79 PrecompileSpecId::HOMESTEAD => Self::homestead(),
80 PrecompileSpecId::BYZANTIUM => Self::byzantium(),
81 PrecompileSpecId::ISTANBUL => Self::istanbul(),
82 PrecompileSpecId::BERLIN => Self::berlin(),
83 PrecompileSpecId::CANCUN => Self::cancun(),
84 PrecompileSpecId::PRAGUE => Self::prague(),
85 PrecompileSpecId::OSAKA => Self::osaka(),
86 }
87 }
88
89 pub fn homestead() -> &'static Self {
91 static INSTANCE: OnceLock<Precompiles> = OnceLock::new();
92 INSTANCE.get_or_init(|| {
93 let mut precompiles = Precompiles::default();
94 precompiles.extend([
95 secp256k1::ECRECOVER,
96 hash::SHA256,
97 hash::RIPEMD160,
98 identity::FUN,
99 ]);
100 precompiles
101 })
102 }
103
104 pub fn inner(&self) -> &HashMap<Address, PrecompileFn> {
106 &self.inner
107 }
108
109 pub fn byzantium() -> &'static Self {
111 static INSTANCE: OnceLock<Precompiles> = OnceLock::new();
112 INSTANCE.get_or_init(|| {
113 let mut precompiles = Self::homestead().clone();
114 precompiles.extend([
115 modexp::BYZANTIUM,
117 bn254::add::BYZANTIUM,
120 bn254::mul::BYZANTIUM,
121 bn254::pair::BYZANTIUM,
122 ]);
123 precompiles
124 })
125 }
126
127 pub fn istanbul() -> &'static Self {
129 static INSTANCE: OnceLock<Precompiles> = OnceLock::new();
130 INSTANCE.get_or_init(|| {
131 let mut precompiles = Self::byzantium().clone();
132 precompiles.extend([
133 bn254::add::ISTANBUL,
135 bn254::mul::ISTANBUL,
136 bn254::pair::ISTANBUL,
137 blake2::FUN,
139 ]);
140 precompiles
141 })
142 }
143
144 pub fn berlin() -> &'static Self {
146 static INSTANCE: OnceLock<Precompiles> = OnceLock::new();
147 INSTANCE.get_or_init(|| {
148 let mut precompiles = Self::istanbul().clone();
149 precompiles.extend([
150 modexp::BERLIN,
152 ]);
153 precompiles
154 })
155 }
156
157 pub fn cancun() -> &'static Self {
162 static INSTANCE: OnceLock<Precompiles> = OnceLock::new();
163 INSTANCE.get_or_init(|| {
164 let mut precompiles = Self::berlin().clone();
165 precompiles.extend([
166 kzg_point_evaluation::POINT_EVALUATION,
168 ]);
169 precompiles
170 })
171 }
172
173 pub fn prague() -> &'static Self {
175 static INSTANCE: OnceLock<Precompiles> = OnceLock::new();
176 INSTANCE.get_or_init(|| {
177 let mut precompiles = Self::cancun().clone();
178 precompiles.extend(bls12_381::precompiles());
179 precompiles
180 })
181 }
182
183 pub fn osaka() -> &'static Self {
185 static INSTANCE: OnceLock<Precompiles> = OnceLock::new();
186 INSTANCE.get_or_init(|| {
187 let mut precompiles = Self::prague().clone();
188 precompiles.extend([modexp::OSAKA, secp256r1::P256VERIFY_OSAKA]);
189 precompiles
190 })
191 }
192
193 pub fn latest() -> &'static Self {
195 Self::osaka()
196 }
197
198 #[inline]
200 pub fn addresses(&self) -> impl ExactSizeIterator<Item = &Address> {
201 self.inner.keys()
202 }
203
204 #[inline]
206 pub fn into_addresses(self) -> impl ExactSizeIterator<Item = Address> {
207 self.inner.into_keys()
208 }
209
210 #[inline]
212 pub fn contains(&self, address: &Address) -> bool {
213 self.inner.contains_key(address)
214 }
215
216 #[inline]
218 pub fn get(&self, address: &Address) -> Option<&PrecompileFn> {
219 self.inner.get(address)
220 }
221
222 #[inline]
224 pub fn get_mut(&mut self, address: &Address) -> Option<&mut PrecompileFn> {
225 self.inner.get_mut(address)
226 }
227
228 pub fn is_empty(&self) -> bool {
230 self.inner.len() == 0
231 }
232
233 pub fn len(&self) -> usize {
235 self.inner.len()
236 }
237
238 pub fn addresses_set(&self) -> &HashSet<Address> {
240 &self.addresses
241 }
242
243 #[inline]
247 pub fn extend(&mut self, other: impl IntoIterator<Item = PrecompileWithAddress>) {
248 let items: Vec<PrecompileWithAddress> = other.into_iter().collect::<Vec<_>>();
249 self.addresses.extend(items.iter().map(|p| *p.address()));
250 self.inner.extend(items.into_iter().map(|p| (p.0, p.1)));
251 }
252
253 pub fn difference(&self, other: &Self) -> Self {
257 let Self { inner, .. } = self;
258
259 let inner = inner
260 .iter()
261 .filter(|(a, _)| !other.inner.contains_key(*a))
262 .map(|(a, p)| (*a, *p))
263 .collect::<HashMap<_, _>>();
264
265 let addresses = inner.keys().cloned().collect::<HashSet<_>>();
266
267 Self { inner, addresses }
268 }
269
270 pub fn intersection(&self, other: &Self) -> Self {
274 let Self { inner, .. } = self;
275
276 let inner = inner
277 .iter()
278 .filter(|(a, _)| other.inner.contains_key(*a))
279 .map(|(a, p)| (*a, *p))
280 .collect::<HashMap<_, _>>();
281
282 let addresses = inner.keys().cloned().collect::<HashSet<_>>();
283
284 Self { inner, addresses }
285 }
286}
287
288#[derive(Clone, Debug)]
290pub struct PrecompileWithAddress(pub Address, pub PrecompileFn);
291
292impl From<(Address, PrecompileFn)> for PrecompileWithAddress {
293 fn from(value: (Address, PrecompileFn)) -> Self {
294 PrecompileWithAddress(value.0, value.1)
295 }
296}
297
298impl From<PrecompileWithAddress> for (Address, PrecompileFn) {
299 fn from(value: PrecompileWithAddress) -> Self {
300 (value.0, value.1)
301 }
302}
303
304impl PrecompileWithAddress {
305 #[inline]
307 pub fn address(&self) -> &Address {
308 &self.0
309 }
310
311 #[inline]
313 pub fn precompile(&self) -> &PrecompileFn {
314 &self.1
315 }
316}
317
318#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
320pub enum PrecompileSpecId {
321 HOMESTEAD,
323 BYZANTIUM,
328 ISTANBUL,
333 BERLIN,
336 CANCUN,
339 PRAGUE,
348 OSAKA,
352}
353
354impl From<SpecId> for PrecompileSpecId {
355 fn from(spec_id: SpecId) -> Self {
356 Self::from_spec_id(spec_id)
357 }
358}
359
360impl PrecompileSpecId {
361 pub const fn from_spec_id(spec_id: primitives::hardfork::SpecId) -> Self {
363 use primitives::hardfork::SpecId::*;
364 match spec_id {
365 FRONTIER | FRONTIER_THAWING | HOMESTEAD | DAO_FORK | TANGERINE | SPURIOUS_DRAGON => {
366 Self::HOMESTEAD
367 }
368 BYZANTIUM | CONSTANTINOPLE | PETERSBURG => Self::BYZANTIUM,
369 ISTANBUL | MUIR_GLACIER => Self::ISTANBUL,
370 BERLIN | LONDON | ARROW_GLACIER | GRAY_GLACIER | MERGE | SHANGHAI => Self::BERLIN,
371 CANCUN => Self::CANCUN,
372 PRAGUE => Self::PRAGUE,
373 OSAKA => Self::OSAKA,
374 }
375 }
376}
377
378#[inline]
384pub const fn u64_to_address(x: u64) -> Address {
385 let x = x.to_be_bytes();
386 Address::new([
387 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],
388 ])
389}
390
391#[cfg(test)]
392mod test {
393 use crate::Precompiles;
394
395 #[test]
396 fn test_difference_precompile_sets() {
397 let difference = Precompiles::istanbul().difference(Precompiles::berlin());
398 assert!(difference.is_empty());
399 }
400
401 #[test]
402 fn test_intersection_precompile_sets() {
403 let intersection = Precompiles::homestead().intersection(Precompiles::byzantium());
404
405 assert_eq!(intersection.len(), 4)
406 }
407}