evm_precompile/
lib.rs

1//! Standard EVM precompiles.
2
3#![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
51/// The standard precompile set on Ethereum mainnet.
52pub 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}