1#![deny(warnings)]
4#![forbid(unsafe_code, unused_variables)]
5#![warn(missing_docs)]
6#![cfg_attr(not(feature = "std"), no_std)]
7
8macro_rules! try_some {
9 ($e:expr) => {
10 match $e {
11 Ok(v) => v,
12 Err(err) => return (Err(err.into()), Vec::new()),
13 }
14 };
15}
16
17extern crate alloc;
18
19mod blake2;
20mod bn128;
21mod kzg;
22mod modexp;
23mod simple;
24
25use alloc::vec::Vec;
26
27use crate::{
28 blake2::Blake2F,
29 bn128::{
30 Bn128AddByzantium, Bn128AddIstanbul, Bn128MulByzantium, Bn128MulIstanbul,
31 Bn128PairingByzantium, Bn128PairingIstanbul,
32 },
33 kzg::KZGPointEvaluation,
34 modexp::{ModexpBerlin, ModexpByzantium},
35 simple::{ECRecover, Identity, Ripemd160, Sha256},
36};
37use evm::{
38 GasMutState,
39 interpreter::{
40 ExitError, ExitException, ExitResult,
41 runtime::{RuntimeBackend, RuntimeState, TouchKind},
42 },
43 standard::{Config, PrecompileSet},
44};
45use primitive_types::H160;
46
47trait PurePrecompile<G> {
48 fn execute(&self, input: &[u8], gasometer: &mut G) -> (ExitResult, Vec<u8>);
49}
50
51pub struct StandardPrecompileSet;
53
54impl<G: AsRef<RuntimeState> + AsRef<Config> + GasMutState, H: RuntimeBackend> PrecompileSet<G, H>
55 for StandardPrecompileSet
56{
57 fn on_transaction(&self, state: &mut G, handler: &mut H) {
58 handler.mark_hot(address(1), TouchKind::Access);
59 handler.mark_hot(address(2), TouchKind::Access);
60 handler.mark_hot(address(3), TouchKind::Access);
61 handler.mark_hot(address(4), TouchKind::Access);
62
63 if AsRef::<Config>::as_ref(state).eip198_modexp_precompile {
64 handler.mark_hot(address(5), TouchKind::Access);
65 }
66
67 if AsRef::<Config>::as_ref(state).eip196_ec_add_mul_precompile {
68 handler.mark_hot(address(6), TouchKind::Access);
69 handler.mark_hot(address(7), TouchKind::Access);
70 }
71
72 if AsRef::<Config>::as_ref(state).eip197_ec_pairing_precompile {
73 handler.mark_hot(address(8), TouchKind::Access);
74 }
75
76 if AsRef::<Config>::as_ref(state).eip152_blake_2f_precompile {
77 handler.mark_hot(address(9), TouchKind::Access);
78 }
79
80 if AsRef::<Config>::as_ref(state).eip4844_shard_blob {
81 handler.mark_hot(address(10), TouchKind::Access);
82 }
83 }
84
85 fn execute(
86 &self,
87 code_address: H160,
88 input: &[u8],
89 gasometer: &mut G,
90 _handler: &mut H,
91 ) -> Option<(ExitResult, Vec<u8>)> {
92 if code_address == address(1) {
93 Some(ECRecover.execute(input, gasometer))
94 } else if code_address == address(2) {
95 Some(Sha256.execute(input, gasometer))
96 } else if code_address == address(3) {
97 Some(Ripemd160.execute(input, gasometer))
98 } else if code_address == address(4) {
99 Some(Identity.execute(input, gasometer))
100 } else if AsRef::<Config>::as_ref(gasometer).eip198_modexp_precompile
101 && code_address == address(5)
102 {
103 if AsRef::<Config>::as_ref(gasometer).eip2565_lower_modexp {
104 Some(ModexpBerlin.execute(input, gasometer))
105 } else {
106 Some(ModexpByzantium.execute(input, gasometer))
107 }
108 } else if AsRef::<Config>::as_ref(gasometer).eip196_ec_add_mul_precompile
109 && code_address == address(6)
110 {
111 if AsRef::<Config>::as_ref(gasometer).eip1108_ec_add_mul_pairing_decrease {
112 Some(Bn128AddIstanbul.execute(input, gasometer))
113 } else {
114 Some(Bn128AddByzantium.execute(input, gasometer))
115 }
116 } else if AsRef::<Config>::as_ref(gasometer).eip196_ec_add_mul_precompile
117 && code_address == address(7)
118 {
119 if AsRef::<Config>::as_ref(gasometer).eip1108_ec_add_mul_pairing_decrease {
120 Some(Bn128MulIstanbul.execute(input, gasometer))
121 } else {
122 Some(Bn128MulByzantium.execute(input, gasometer))
123 }
124 } else if AsRef::<Config>::as_ref(gasometer).eip197_ec_pairing_precompile
125 && code_address == address(8)
126 {
127 if AsRef::<Config>::as_ref(gasometer).eip1108_ec_add_mul_pairing_decrease {
128 Some(Bn128PairingIstanbul.execute(input, gasometer))
129 } else {
130 Some(Bn128PairingByzantium.execute(input, gasometer))
131 }
132 } else if AsRef::<Config>::as_ref(gasometer).eip152_blake_2f_precompile
133 && code_address == address(9)
134 {
135 Some(Blake2F.execute(input, gasometer))
136 } else if AsRef::<Config>::as_ref(gasometer).eip4844_shard_blob
137 && code_address == address(10)
138 {
139 Some(KZGPointEvaluation.execute(input, gasometer))
140 } else {
141 None
142 }
143 }
144}
145
146fn linear_cost(len: u64, base: u64, word: u64) -> Result<u64, ExitError> {
147 let cost = base
148 .checked_add(
149 word.checked_mul(len.saturating_add(31) / 32)
150 .ok_or(ExitException::OutOfGas)?,
151 )
152 .ok_or(ExitException::OutOfGas)?;
153
154 Ok(cost)
155}
156
157const fn address(last: u8) -> H160 {
158 H160([
159 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, last,
160 ])
161}