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