revm_precompile/
interface.rs

1//! Interface for the precompiles. It contains the precompile result type,
2//! the precompile output type, and the precompile error type.
3use core::fmt::{self, Debug};
4use primitives::{Bytes, OnceLock};
5use std::{boxed::Box, string::String, vec::Vec};
6
7use crate::bls12_381::{G1Point, G1PointScalar, G2Point, G2PointScalar};
8
9/// Global crypto provider instance
10static CRYPTO: OnceLock<Box<dyn Crypto>> = OnceLock::new();
11
12/// Install a custom crypto provider globally.
13pub fn install_crypto<C: Crypto + 'static>(crypto: C) -> bool {
14    if CRYPTO.get().is_some() {
15        return false;
16    }
17
18    CRYPTO.get_or_init(|| Box::new(crypto));
19    true
20}
21
22/// Get the installed crypto provider, or the default if none is installed.
23pub fn crypto() -> &'static dyn Crypto {
24    CRYPTO.get_or_init(|| Box::new(DefaultCrypto)).as_ref()
25}
26
27/// A precompile operation result type
28///
29/// Returns either `Ok((gas_used, return_bytes))` or `Err(error)`.
30pub type PrecompileResult = Result<PrecompileOutput, PrecompileError>;
31
32/// Precompile execution output
33#[derive(Clone, Debug, PartialEq, Eq, Hash)]
34pub struct PrecompileOutput {
35    /// Gas used by the precompile
36    pub gas_used: u64,
37    /// Output bytes
38    pub bytes: Bytes,
39    /// Whether the precompile reverted
40    pub reverted: bool,
41}
42
43impl PrecompileOutput {
44    /// Returns new precompile output with the given gas used and output bytes.
45    pub fn new(gas_used: u64, bytes: Bytes) -> Self {
46        Self {
47            gas_used,
48            bytes,
49            reverted: false,
50        }
51    }
52
53    /// Returns new precompile revert with the given gas used and output bytes.
54    pub fn new_reverted(gas_used: u64, bytes: Bytes) -> Self {
55        Self {
56            gas_used,
57            bytes,
58            reverted: true,
59        }
60    }
61
62    /// Flips [`Self::reverted`] to `true`.
63    pub fn reverted(mut self) -> Self {
64        self.reverted = true;
65        self
66    }
67}
68
69/// Crypto operations trait for precompiles.
70pub trait Crypto: Send + Sync + Debug {
71    /// Compute SHA-256 hash
72    #[inline]
73    fn sha256(&self, input: &[u8]) -> [u8; 32] {
74        use sha2::Digest;
75        let output = sha2::Sha256::digest(input);
76        output.into()
77    }
78
79    /// Compute RIPEMD-160 hash
80    #[inline]
81    fn ripemd160(&self, input: &[u8]) -> [u8; 32] {
82        use ripemd::Digest;
83        let mut hasher = ripemd::Ripemd160::new();
84        hasher.update(input);
85
86        let mut output = [0u8; 32];
87        hasher.finalize_into((&mut output[12..]).into());
88        output
89    }
90
91    /// BN254 elliptic curve addition.
92    #[inline]
93    fn bn254_g1_add(&self, p1: &[u8], p2: &[u8]) -> Result<[u8; 64], PrecompileError> {
94        crate::bn254::crypto_backend::g1_point_add(p1, p2)
95    }
96
97    /// BN254 elliptic curve scalar multiplication.
98    #[inline]
99    fn bn254_g1_mul(&self, point: &[u8], scalar: &[u8]) -> Result<[u8; 64], PrecompileError> {
100        crate::bn254::crypto_backend::g1_point_mul(point, scalar)
101    }
102
103    /// BN254 pairing check.
104    #[inline]
105    fn bn254_pairing_check(&self, pairs: &[(&[u8], &[u8])]) -> Result<bool, PrecompileError> {
106        crate::bn254::crypto_backend::pairing_check(pairs)
107    }
108
109    /// secp256k1 ECDSA signature recovery.
110    #[inline]
111    fn secp256k1_ecrecover(
112        &self,
113        sig: &[u8; 64],
114        recid: u8,
115        msg: &[u8; 32],
116    ) -> Result<[u8; 32], PrecompileError> {
117        crate::secp256k1::ecrecover_bytes(*sig, recid, *msg)
118            .ok_or_else(|| PrecompileError::other("ecrecover failed"))
119    }
120
121    /// Modular exponentiation.
122    #[inline]
123    fn modexp(&self, base: &[u8], exp: &[u8], modulus: &[u8]) -> Result<Vec<u8>, PrecompileError> {
124        Ok(crate::modexp::modexp(base, exp, modulus))
125    }
126
127    /// Blake2 compression function.
128    #[inline]
129    fn blake2_compress(&self, rounds: u32, h: &mut [u64; 8], m: [u64; 16], t: [u64; 2], f: bool) {
130        crate::blake2::algo::compress(rounds as usize, h, m, t, f);
131    }
132
133    /// secp256r1 (P-256) signature verification.
134    #[inline]
135    fn secp256r1_verify_signature(&self, msg: &[u8; 32], sig: &[u8; 64], pk: &[u8; 64]) -> bool {
136        crate::secp256r1::verify_signature(*msg, *sig, *pk).is_some()
137    }
138
139    /// KZG point evaluation.
140    #[inline]
141    fn verify_kzg_proof(
142        &self,
143        z: &[u8; 32],
144        y: &[u8; 32],
145        commitment: &[u8; 48],
146        proof: &[u8; 48],
147    ) -> Result<(), PrecompileError> {
148        if !crate::kzg_point_evaluation::verify_kzg_proof(commitment, z, y, proof) {
149            return Err(PrecompileError::BlobVerifyKzgProofFailed);
150        }
151
152        Ok(())
153    }
154
155    /// BLS12-381 G1 addition (returns 96-byte unpadded G1 point)
156    fn bls12_381_g1_add(&self, a: G1Point, b: G1Point) -> Result<[u8; 96], PrecompileError> {
157        crate::bls12_381::crypto_backend::p1_add_affine_bytes(a, b)
158    }
159
160    /// BLS12-381 G1 multi-scalar multiplication (returns 96-byte unpadded G1 point)
161    fn bls12_381_g1_msm(
162        &self,
163        pairs: &mut dyn Iterator<Item = Result<G1PointScalar, PrecompileError>>,
164    ) -> Result<[u8; 96], PrecompileError> {
165        crate::bls12_381::crypto_backend::p1_msm_bytes(pairs)
166    }
167
168    /// BLS12-381 G2 addition (returns 192-byte unpadded G2 point)
169    fn bls12_381_g2_add(&self, a: G2Point, b: G2Point) -> Result<[u8; 192], PrecompileError> {
170        crate::bls12_381::crypto_backend::p2_add_affine_bytes(a, b)
171    }
172
173    /// BLS12-381 G2 multi-scalar multiplication (returns 192-byte unpadded G2 point)
174    fn bls12_381_g2_msm(
175        &self,
176        pairs: &mut dyn Iterator<Item = Result<G2PointScalar, PrecompileError>>,
177    ) -> Result<[u8; 192], PrecompileError> {
178        crate::bls12_381::crypto_backend::p2_msm_bytes(pairs)
179    }
180
181    /// BLS12-381 pairing check.
182    fn bls12_381_pairing_check(
183        &self,
184        pairs: &[(G1Point, G2Point)],
185    ) -> Result<bool, PrecompileError> {
186        crate::bls12_381::crypto_backend::pairing_check_bytes(pairs)
187    }
188
189    /// BLS12-381 map field element to G1.
190    fn bls12_381_fp_to_g1(&self, fp: &[u8; 48]) -> Result<[u8; 96], PrecompileError> {
191        crate::bls12_381::crypto_backend::map_fp_to_g1_bytes(fp)
192    }
193
194    /// BLS12-381 map field element to G2.
195    fn bls12_381_fp2_to_g2(&self, fp2: ([u8; 48], [u8; 48])) -> Result<[u8; 192], PrecompileError> {
196        crate::bls12_381::crypto_backend::map_fp2_to_g2_bytes(&fp2.0, &fp2.1)
197    }
198}
199
200/// Precompile function type. Takes input, gas limit, and crypto implementation and returns precompile result.
201pub type PrecompileFn = fn(&[u8], u64) -> PrecompileResult;
202
203/// Precompile error type.
204#[derive(Clone, Debug, PartialEq, Eq, Hash)]
205pub enum PrecompileError {
206    /// out of gas is the main error. Others are here just for completeness
207    OutOfGas,
208    /// Blake2 errors
209    Blake2WrongLength,
210    /// Blake2 wrong final indicator flag
211    Blake2WrongFinalIndicatorFlag,
212    /// Modexp errors
213    ModexpExpOverflow,
214    /// Modexp base overflow
215    ModexpBaseOverflow,
216    /// Modexp mod overflow
217    ModexpModOverflow,
218    /// Modexp limit all input sizes.
219    ModexpEip7823LimitSize,
220    /// Bn254 errors
221    Bn254FieldPointNotAMember,
222    /// Bn254 affine g failed to create
223    Bn254AffineGFailedToCreate,
224    /// Bn254 pair length
225    Bn254PairLength,
226    // Blob errors
227    /// The input length is not exactly 192 bytes
228    BlobInvalidInputLength,
229    /// The commitment does not match the versioned hash
230    BlobMismatchedVersion,
231    /// The proof verification failed
232    BlobVerifyKzgProofFailed,
233    /// Fatal error with a custom error message
234    Fatal(String),
235    /// Catch-all variant for other errors
236    Other(String),
237}
238
239impl PrecompileError {
240    /// Returns another error with the given message.
241    pub fn other(err: impl Into<String>) -> Self {
242        Self::Other(err.into())
243    }
244
245    /// Returns `true` if the error is out of gas.
246    pub fn is_oog(&self) -> bool {
247        matches!(self, Self::OutOfGas)
248    }
249}
250
251impl core::error::Error for PrecompileError {}
252
253impl fmt::Display for PrecompileError {
254    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
255        let s = match self {
256            Self::OutOfGas => "out of gas",
257            Self::Blake2WrongLength => "wrong input length for blake2",
258            Self::Blake2WrongFinalIndicatorFlag => "wrong final indicator flag for blake2",
259            Self::ModexpExpOverflow => "modexp exp overflow",
260            Self::ModexpBaseOverflow => "modexp base overflow",
261            Self::ModexpModOverflow => "modexp mod overflow",
262            Self::ModexpEip7823LimitSize => "Modexp limit all input sizes.",
263            Self::Bn254FieldPointNotAMember => "field point not a member of bn254 curve",
264            Self::Bn254AffineGFailedToCreate => "failed to create affine g point for bn254 curve",
265            Self::Bn254PairLength => "bn254 invalid pair length",
266            Self::BlobInvalidInputLength => "invalid blob input length",
267            Self::BlobMismatchedVersion => "mismatched blob version",
268            Self::BlobVerifyKzgProofFailed => "verifying blob kzg proof failed",
269            Self::Fatal(s) => s,
270            Self::Other(s) => s,
271        };
272        f.write_str(s)
273    }
274}
275
276/// Default implementation of the Crypto trait using the existing crypto libraries.
277#[derive(Clone, Debug)]
278pub struct DefaultCrypto;
279
280impl Crypto for DefaultCrypto {}