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(all(feature = "c-kzg", feature = "kzg-rs"))]
39use kzg_rs as _;
41
42cfg_if::cfg_if! {
44 if #[cfg(feature = "blst")]{
45 use ark_bls12_381 as _;
46 use ark_ff as _;
47 use ark_ec as _;
48 use ark_serialize as _;
49 }
50}
51
52#[cfg(feature = "gmp")]
54use aurora_engine_modexp as _;
55
56use cfg_if::cfg_if;
57use core::hash::Hash;
58use once_cell::race::OnceBox;
59use primitives::{hardfork::SpecId, Address, HashMap, HashSet};
60use std::{boxed::Box, vec::Vec};
61
62pub fn calc_linear_cost_u32(len: usize, base: u64, word: u64) -> u64 {
64 (len as u64).div_ceil(32) * word + base
65}
66
67#[derive(Clone, Default, Debug)]
69pub struct Precompiles {
70 inner: HashMap<Address, PrecompileFn>,
72 addresses: HashSet<Address>,
74}
75
76impl Precompiles {
77 pub fn new(spec: PrecompileSpecId) -> &'static Self {
79 match spec {
80 PrecompileSpecId::HOMESTEAD => Self::homestead(),
81 PrecompileSpecId::BYZANTIUM => Self::byzantium(),
82 PrecompileSpecId::ISTANBUL => Self::istanbul(),
83 PrecompileSpecId::BERLIN => Self::berlin(),
84 PrecompileSpecId::CANCUN => Self::cancun(),
85 PrecompileSpecId::PRAGUE => Self::prague(),
86 PrecompileSpecId::OSAKA => Self::osaka(),
87 }
88 }
89
90 pub fn homestead() -> &'static Self {
92 static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
93 INSTANCE.get_or_init(|| {
94 let mut precompiles = Precompiles::default();
95 precompiles.extend([
96 secp256k1::ECRECOVER,
97 hash::SHA256,
98 hash::RIPEMD160,
99 identity::FUN,
100 ]);
101 Box::new(precompiles)
102 })
103 }
104
105 pub fn inner(&self) -> &HashMap<Address, PrecompileFn> {
107 &self.inner
108 }
109
110 pub fn byzantium() -> &'static Self {
112 static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
113 INSTANCE.get_or_init(|| {
114 let mut precompiles = Self::homestead().clone();
115 precompiles.extend([
116 modexp::BYZANTIUM,
118 bn128::add::BYZANTIUM,
121 bn128::mul::BYZANTIUM,
122 bn128::pair::BYZANTIUM,
123 ]);
124 Box::new(precompiles)
125 })
126 }
127
128 pub fn istanbul() -> &'static Self {
130 static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
131 INSTANCE.get_or_init(|| {
132 let mut precompiles = Self::byzantium().clone();
133 precompiles.extend([
134 bn128::add::ISTANBUL,
136 bn128::mul::ISTANBUL,
137 bn128::pair::ISTANBUL,
138 blake2::FUN,
140 ]);
141 Box::new(precompiles)
142 })
143 }
144
145 pub fn berlin() -> &'static Self {
147 static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
148 INSTANCE.get_or_init(|| {
149 let mut precompiles = Self::istanbul().clone();
150 precompiles.extend([
151 modexp::BERLIN,
153 ]);
154 Box::new(precompiles)
155 })
156 }
157
158 pub fn cancun() -> &'static Self {
163 static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
164 INSTANCE.get_or_init(|| {
165 let mut precompiles = Self::berlin().clone();
166
167 cfg_if! {
169 if #[cfg(any(feature = "c-kzg", feature = "kzg-rs"))] {
170 let precompile = kzg_point_evaluation::POINT_EVALUATION.clone();
171 } else {
172 let precompile = PrecompileWithAddress(u64_to_address(0x0A), |_,_| Err(PrecompileError::Fatal("c-kzg feature is not enabled".into())));
173 }
174 }
175
176
177 precompiles.extend([
178 precompile,
179 ]);
180
181 Box::new(precompiles)
182 })
183 }
184
185 pub fn prague() -> &'static Self {
187 static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
188 INSTANCE.get_or_init(|| {
189 let mut precompiles = Self::cancun().clone();
190 precompiles.extend(bls12_381::precompiles());
191 Box::new(precompiles)
192 })
193 }
194
195 pub fn osaka() -> &'static Self {
197 static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
198 INSTANCE.get_or_init(|| {
199 let mut precompiles = Self::prague().clone();
200 precompiles.extend([modexp::OSAKA, secp256r1::P256VERIFY]);
201 Box::new(precompiles)
202 })
203 }
204
205 pub fn latest() -> &'static Self {
207 Self::osaka()
208 }
209
210 #[inline]
212 pub fn addresses(&self) -> impl ExactSizeIterator<Item = &Address> {
213 self.inner.keys()
214 }
215
216 #[inline]
218 pub fn into_addresses(self) -> impl ExactSizeIterator<Item = Address> {
219 self.inner.into_keys()
220 }
221
222 #[inline]
224 pub fn contains(&self, address: &Address) -> bool {
225 self.inner.contains_key(address)
226 }
227
228 #[inline]
230 pub fn get(&self, address: &Address) -> Option<&PrecompileFn> {
231 self.inner.get(address)
232 }
233
234 #[inline]
236 pub fn get_mut(&mut self, address: &Address) -> Option<&mut PrecompileFn> {
237 self.inner.get_mut(address)
238 }
239
240 pub fn is_empty(&self) -> bool {
242 self.inner.len() == 0
243 }
244
245 pub fn len(&self) -> usize {
247 self.inner.len()
248 }
249
250 pub fn addresses_set(&self) -> &HashSet<Address> {
252 &self.addresses
253 }
254
255 #[inline]
259 pub fn extend(&mut self, other: impl IntoIterator<Item = PrecompileWithAddress>) {
260 let items: Vec<PrecompileWithAddress> = other.into_iter().collect::<Vec<_>>();
261 self.addresses.extend(items.iter().map(|p| *p.address()));
262 self.inner.extend(items.into_iter().map(|p| (p.0, p.1)));
263 }
264
265 pub fn difference(&self, other: &Self) -> Self {
269 let Self { inner, .. } = self;
270
271 let inner = inner
272 .iter()
273 .filter(|(a, _)| !other.inner.contains_key(*a))
274 .map(|(a, p)| (*a, *p))
275 .collect::<HashMap<_, _>>();
276
277 let addresses = inner.keys().cloned().collect::<HashSet<_>>();
278
279 Self { inner, addresses }
280 }
281
282 pub fn intersection(&self, other: &Self) -> Self {
286 let Self { inner, .. } = self;
287
288 let inner = inner
289 .iter()
290 .filter(|(a, _)| other.inner.contains_key(*a))
291 .map(|(a, p)| (*a, *p))
292 .collect::<HashMap<_, _>>();
293
294 let addresses = inner.keys().cloned().collect::<HashSet<_>>();
295
296 Self { inner, addresses }
297 }
298}
299
300#[derive(Clone, Debug)]
302pub struct PrecompileWithAddress(pub Address, pub PrecompileFn);
303
304impl From<(Address, PrecompileFn)> for PrecompileWithAddress {
305 fn from(value: (Address, PrecompileFn)) -> Self {
306 PrecompileWithAddress(value.0, value.1)
307 }
308}
309
310impl From<PrecompileWithAddress> for (Address, PrecompileFn) {
311 fn from(value: PrecompileWithAddress) -> Self {
312 (value.0, value.1)
313 }
314}
315
316impl PrecompileWithAddress {
317 #[inline]
319 pub fn address(&self) -> &Address {
320 &self.0
321 }
322
323 #[inline]
325 pub fn precompile(&self) -> &PrecompileFn {
326 &self.1
327 }
328}
329
330#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
332pub enum PrecompileSpecId {
333 HOMESTEAD,
335 BYZANTIUM,
340 ISTANBUL,
345 BERLIN,
348 CANCUN,
351 PRAGUE,
360 OSAKA,
364}
365
366impl From<SpecId> for PrecompileSpecId {
367 fn from(spec_id: SpecId) -> Self {
368 Self::from_spec_id(spec_id)
369 }
370}
371
372impl PrecompileSpecId {
373 pub const fn from_spec_id(spec_id: primitives::hardfork::SpecId) -> Self {
375 use primitives::hardfork::SpecId::*;
376 match spec_id {
377 FRONTIER | FRONTIER_THAWING | HOMESTEAD | DAO_FORK | TANGERINE | SPURIOUS_DRAGON => {
378 Self::HOMESTEAD
379 }
380 BYZANTIUM | CONSTANTINOPLE | PETERSBURG => Self::BYZANTIUM,
381 ISTANBUL | MUIR_GLACIER => Self::ISTANBUL,
382 BERLIN | LONDON | ARROW_GLACIER | GRAY_GLACIER | MERGE | SHANGHAI => Self::BERLIN,
383 CANCUN => Self::CANCUN,
384 PRAGUE => Self::PRAGUE,
385 OSAKA => Self::OSAKA,
386 }
387 }
388}
389
390#[inline]
396pub const fn u64_to_address(x: u64) -> Address {
397 let x = x.to_be_bytes();
398 Address::new([
399 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],
400 ])
401}
402
403#[cfg(test)]
404mod test {
405 use crate::Precompiles;
406
407 #[test]
408 fn test_difference_precompile_sets() {
409 let difference = Precompiles::istanbul().difference(Precompiles::berlin());
410 assert!(difference.is_empty());
411 }
412
413 #[test]
414 fn test_intersection_precompile_sets() {
415 let intersection = Precompiles::homestead().intersection(Precompiles::byzantium());
416
417 assert_eq!(intersection.len(), 4)
418 }
419}