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;
17mod id;
18pub mod identity;
19pub mod interface;
20pub mod kzg_point_evaluation;
21pub mod modexp;
22pub mod secp256k1;
23pub mod secp256r1;
24pub mod utilities;
25
26pub use id::PrecompileId;
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
39use arrayref as _;
40
41cfg_if::cfg_if! {
43 if #[cfg(feature = "blst")]{
44 use ark_bls12_381 as _;
45 use ark_ff as _;
46 use ark_ec as _;
47 use ark_serialize as _;
48 }
49}
50
51#[cfg(feature = "gmp")]
53use aurora_engine_modexp as _;
54
55#[cfg(feature = "p256-aws-lc-rs")]
57use p256 as _;
58
59use core::hash::Hash;
60use primitives::{
61 hardfork::SpecId, short_address, Address, AddressMap, AddressSet, HashMap, OnceLock,
62 SHORT_ADDRESS_CAP,
63};
64use std::vec::Vec;
65
66#[inline]
68pub fn calc_linear_cost(len: usize, base: u64, word: u64) -> u64 {
69 (len as u64).div_ceil(32) * word + base
70}
71
72#[deprecated(note = "please use `calc_linear_cost` instead")]
74pub fn calc_linear_cost_u32(len: usize, base: u64, word: u64) -> u64 {
75 calc_linear_cost(len, base, word)
76}
77
78#[derive(Clone, Debug)]
80pub struct Precompiles {
81 inner: AddressMap<Precompile>,
83 addresses: AddressSet,
85 optimized_access: Vec<Option<Precompile>>,
87 all_short_addresses: bool,
89}
90
91impl Default for Precompiles {
92 fn default() -> Self {
93 Self {
94 inner: HashMap::default(),
95 addresses: AddressSet::default(),
96 optimized_access: vec![None; SHORT_ADDRESS_CAP],
97 all_short_addresses: true,
98 }
99 }
100}
101
102impl Precompiles {
103 pub fn new(spec: PrecompileSpecId) -> &'static Self {
105 match spec {
106 PrecompileSpecId::HOMESTEAD => Self::homestead(),
107 PrecompileSpecId::BYZANTIUM => Self::byzantium(),
108 PrecompileSpecId::ISTANBUL => Self::istanbul(),
109 PrecompileSpecId::BERLIN => Self::berlin(),
110 PrecompileSpecId::CANCUN => Self::cancun(),
111 PrecompileSpecId::PRAGUE => Self::prague(),
112 PrecompileSpecId::OSAKA => Self::osaka(),
113 }
114 }
115
116 pub fn homestead() -> &'static Self {
118 static INSTANCE: OnceLock<Precompiles> = OnceLock::new();
119 INSTANCE.get_or_init(|| {
120 let mut precompiles = Precompiles::default();
121 precompiles.extend([
122 secp256k1::ECRECOVER,
123 hash::SHA256,
124 hash::RIPEMD160,
125 identity::FUN,
126 ]);
127 precompiles
128 })
129 }
130
131 pub fn inner(&self) -> &AddressMap<Precompile> {
133 &self.inner
134 }
135
136 pub fn byzantium() -> &'static Self {
138 static INSTANCE: OnceLock<Precompiles> = OnceLock::new();
139 INSTANCE.get_or_init(|| {
140 let mut precompiles = Self::homestead().clone();
141 precompiles.extend([
142 modexp::BYZANTIUM,
144 bn254::add::BYZANTIUM,
147 bn254::mul::BYZANTIUM,
148 bn254::pair::BYZANTIUM,
149 ]);
150 precompiles
151 })
152 }
153
154 pub fn istanbul() -> &'static Self {
156 static INSTANCE: OnceLock<Precompiles> = OnceLock::new();
157 INSTANCE.get_or_init(|| {
158 let mut precompiles = Self::byzantium().clone();
159 precompiles.extend([
160 bn254::add::ISTANBUL,
162 bn254::mul::ISTANBUL,
163 bn254::pair::ISTANBUL,
164 blake2::FUN,
166 ]);
167 precompiles
168 })
169 }
170
171 pub fn berlin() -> &'static Self {
173 static INSTANCE: OnceLock<Precompiles> = OnceLock::new();
174 INSTANCE.get_or_init(|| {
175 let mut precompiles = Self::istanbul().clone();
176 precompiles.extend([
177 modexp::BERLIN,
179 ]);
180 precompiles
181 })
182 }
183
184 pub fn cancun() -> &'static Self {
189 static INSTANCE: OnceLock<Precompiles> = OnceLock::new();
190 INSTANCE.get_or_init(|| {
191 let mut precompiles = Self::berlin().clone();
192 precompiles.extend([
193 kzg_point_evaluation::POINT_EVALUATION,
195 ]);
196 precompiles
197 })
198 }
199
200 pub fn prague() -> &'static Self {
202 static INSTANCE: OnceLock<Precompiles> = OnceLock::new();
203 INSTANCE.get_or_init(|| {
204 let mut precompiles = Self::cancun().clone();
205 precompiles.extend(bls12_381::precompiles());
206 precompiles
207 })
208 }
209
210 pub fn osaka() -> &'static Self {
212 static INSTANCE: OnceLock<Precompiles> = OnceLock::new();
213 INSTANCE.get_or_init(|| {
214 let mut precompiles = Self::prague().clone();
215 precompiles.extend([modexp::OSAKA, secp256r1::P256VERIFY_OSAKA]);
216 precompiles
217 })
218 }
219
220 pub fn latest() -> &'static Self {
222 Self::osaka()
223 }
224
225 #[inline]
227 pub fn addresses(&self) -> impl ExactSizeIterator<Item = &Address> {
228 self.inner.keys()
229 }
230
231 #[inline]
233 pub fn into_addresses(self) -> impl ExactSizeIterator<Item = Address> {
234 self.inner.into_keys()
235 }
236
237 #[inline]
239 pub fn contains(&self, address: &Address) -> bool {
240 self.inner.contains_key(address)
241 }
242
243 #[inline]
245 pub fn get(&self, address: &Address) -> Option<&Precompile> {
246 if let Some(short_address) = short_address(address) {
247 return self.optimized_access[short_address].as_ref();
248 }
249 self.inner.get(address)
250 }
251
252 #[inline]
254 pub fn get_mut(&mut self, address: &Address) -> Option<&mut Precompile> {
255 self.inner.get_mut(address)
256 }
257
258 pub fn is_empty(&self) -> bool {
260 self.inner.is_empty()
261 }
262
263 pub fn len(&self) -> usize {
265 self.inner.len()
266 }
267
268 pub fn addresses_set(&self) -> &AddressSet {
270 &self.addresses
271 }
272
273 #[inline]
277 pub fn extend(&mut self, other: impl IntoIterator<Item = Precompile>) {
278 let iter = other.into_iter();
279 let (lower, _) = iter.size_hint();
280 self.addresses.reserve(lower);
281 self.inner.reserve(lower);
282 for item in iter {
283 let address = *item.address();
284 if let Some(short_idx) = short_address(&address) {
285 self.optimized_access[short_idx] = Some(item.clone());
286 } else {
287 self.all_short_addresses = false;
288 }
289 self.addresses.insert(address);
290 self.inner.insert(address, item);
291 }
292 }
293
294 pub fn difference(&self, other: &Self) -> Self {
298 let Self { inner, .. } = self;
299
300 let inner = inner
301 .iter()
302 .filter(|(a, _)| !other.inner.contains_key(*a))
303 .map(|(a, p)| (*a, p.clone()))
304 .collect::<AddressMap<_>>();
305
306 let mut precompiles = Self::default();
307 precompiles.extend(inner.into_iter().map(|p| p.1));
308 precompiles
309 }
310
311 pub fn intersection(&self, other: &Self) -> Self {
315 let Self { inner, .. } = self;
316
317 let inner = inner
318 .iter()
319 .filter(|(a, _)| other.inner.contains_key(*a))
320 .map(|(a, p)| (*a, p.clone()))
321 .collect::<AddressMap<_>>();
322
323 let mut precompiles = Self::default();
324 precompiles.extend(inner.into_iter().map(|p| p.1));
325 precompiles
326 }
327}
328
329#[derive(Clone, Debug)]
331pub struct Precompile {
332 id: PrecompileId,
334 address: Address,
336 fn_: PrecompileFn,
338}
339
340impl From<(PrecompileId, Address, PrecompileFn)> for Precompile {
341 fn from((id, address, fn_): (PrecompileId, Address, PrecompileFn)) -> Self {
342 Precompile { id, address, fn_ }
343 }
344}
345
346impl From<Precompile> for (PrecompileId, Address, PrecompileFn) {
347 fn from(value: Precompile) -> Self {
348 (value.id, value.address, value.fn_)
349 }
350}
351
352impl Precompile {
353 pub const fn new(id: PrecompileId, address: Address, fn_: PrecompileFn) -> Self {
355 Self { id, address, fn_ }
356 }
357
358 #[inline]
360 pub fn id(&self) -> &PrecompileId {
361 &self.id
362 }
363
364 #[inline]
366 pub fn address(&self) -> &Address {
367 &self.address
368 }
369
370 #[inline]
372 pub fn precompile(&self) -> &PrecompileFn {
373 &self.fn_
374 }
375
376 #[inline]
378 pub fn into_precompile(self) -> PrecompileFn {
379 self.fn_
380 }
381
382 #[inline]
384 pub fn execute(&self, input: &[u8], gas_limit: u64) -> PrecompileResult {
385 (self.fn_)(input, gas_limit)
386 }
387}
388
389#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
391pub enum PrecompileSpecId {
392 HOMESTEAD,
394 BYZANTIUM,
399 ISTANBUL,
404 BERLIN,
407 CANCUN,
410 PRAGUE,
419 OSAKA,
423}
424
425impl From<SpecId> for PrecompileSpecId {
426 fn from(spec_id: SpecId) -> Self {
427 Self::from_spec_id(spec_id)
428 }
429}
430
431impl PrecompileSpecId {
432 pub const fn from_spec_id(spec_id: primitives::hardfork::SpecId) -> Self {
434 use primitives::hardfork::SpecId::*;
435 match spec_id {
436 FRONTIER | FRONTIER_THAWING | HOMESTEAD | DAO_FORK | TANGERINE | SPURIOUS_DRAGON => {
437 Self::HOMESTEAD
438 }
439 BYZANTIUM | CONSTANTINOPLE | PETERSBURG => Self::BYZANTIUM,
440 ISTANBUL | MUIR_GLACIER => Self::ISTANBUL,
441 BERLIN | LONDON | ARROW_GLACIER | GRAY_GLACIER | MERGE | SHANGHAI => Self::BERLIN,
442 CANCUN => Self::CANCUN,
443 PRAGUE => Self::PRAGUE,
444 OSAKA | AMSTERDAM => Self::OSAKA,
445 }
446 }
447}
448
449#[inline]
455pub const fn u64_to_address(x: u64) -> Address {
456 let x = x.to_be_bytes();
457 Address::new([
458 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],
459 ])
460}
461
462#[cfg(test)]
463mod test {
464 use super::*;
465
466 fn temp_precompile(_input: &[u8], _gas_limit: u64) -> PrecompileResult {
467 PrecompileResult::Err(PrecompileError::OutOfGas)
468 }
469
470 #[test]
471 fn test_optimized_access() {
472 let mut precompiles = Precompiles::istanbul().clone();
473 assert!(precompiles.optimized_access[9].is_some());
474 assert!(precompiles.optimized_access[10].is_none());
475
476 precompiles.extend([Precompile::new(
477 PrecompileId::Custom("test".into()),
478 u64_to_address(100),
479 temp_precompile,
480 )]);
481 precompiles.extend([Precompile::new(
482 PrecompileId::Custom("test".into()),
483 u64_to_address(101),
484 temp_precompile,
485 )]);
486
487 assert_eq!(
488 precompiles.optimized_access[100]
489 .as_ref()
490 .unwrap()
491 .execute(&[], u64::MAX),
492 PrecompileResult::Err(PrecompileError::OutOfGas)
493 );
494
495 assert_eq!(
496 precompiles
497 .get(&Address::left_padding_from(&[101]))
498 .unwrap()
499 .execute(&[], u64::MAX),
500 PrecompileResult::Err(PrecompileError::OutOfGas)
501 );
502 }
503
504 #[test]
505 fn test_difference_precompile_sets() {
506 let difference = Precompiles::istanbul().difference(Precompiles::berlin());
507 assert!(difference.is_empty());
508 }
509
510 #[test]
511 fn test_intersection_precompile_sets() {
512 let intersection = Precompiles::homestead().intersection(Precompiles::byzantium());
513
514 assert_eq!(intersection.len(), 4)
515 }
516}