1use 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
9static CRYPTO: OnceLock<Box<dyn Crypto>> = OnceLock::new();
11
12pub fn install_crypto<C: Crypto + 'static>(crypto: C) -> bool {
14    CRYPTO.set(Box::new(crypto)).is_ok()
15}
16
17pub fn crypto() -> &'static dyn Crypto {
19    CRYPTO.get_or_init(|| Box::new(DefaultCrypto)).as_ref()
20}
21
22pub type PrecompileResult = Result<PrecompileOutput, PrecompileError>;
26
27#[derive(Clone, Debug, PartialEq, Eq, Hash)]
29pub struct PrecompileOutput {
30    pub gas_used: u64,
32    pub bytes: Bytes,
34    pub reverted: bool,
36}
37
38impl PrecompileOutput {
39    pub fn new(gas_used: u64, bytes: Bytes) -> Self {
41        Self {
42            gas_used,
43            bytes,
44            reverted: false,
45        }
46    }
47
48    pub fn new_reverted(gas_used: u64, bytes: Bytes) -> Self {
50        Self {
51            gas_used,
52            bytes,
53            reverted: true,
54        }
55    }
56
57    pub fn reverted(mut self) -> Self {
59        self.reverted = true;
60        self
61    }
62}
63
64pub trait Crypto: Send + Sync + Debug {
66    #[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    #[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    #[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    #[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    #[inline]
100    fn bn254_pairing_check(&self, pairs: &[(&[u8], &[u8])]) -> Result<bool, PrecompileError> {
101        crate::bn254::crypto_backend::pairing_check(pairs)
102    }
103
104    #[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    #[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    #[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    #[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    #[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    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    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    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    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    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    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    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
195pub type PrecompileFn = fn(&[u8], u64) -> PrecompileResult;
197
198#[derive(Clone, Debug, PartialEq, Eq, Hash)]
200pub enum PrecompileError {
201    OutOfGas,
203    Blake2WrongLength,
205    Blake2WrongFinalIndicatorFlag,
207    ModexpExpOverflow,
209    ModexpBaseOverflow,
211    ModexpModOverflow,
213    ModexpEip7823LimitSize,
215    Bn254FieldPointNotAMember,
217    Bn254AffineGFailedToCreate,
219    Bn254PairLength,
221    BlobInvalidInputLength,
224    BlobMismatchedVersion,
226    BlobVerifyKzgProofFailed,
228    NonCanonicalFp,
230    Bls12381G1NotOnCurve,
232    Bls12381G1NotInSubgroup,
234    Bls12381G2NotOnCurve,
236    Bls12381G2NotInSubgroup,
238    Bls12381ScalarInputLength,
240    Bls12381G1AddInputLength,
242    Bls12381G1MsmInputLength,
244    Bls12381G2AddInputLength,
246    Bls12381G2MsmInputLength,
248    Bls12381PairingInputLength,
250    Bls12381MapFpToG1InputLength,
252    Bls12381MapFp2ToG2InputLength,
254    Bls12381FpPaddingInvalid,
256    Bls12381FpPaddingLength,
258    Bls12381G1PaddingLength,
260    Bls12381G2PaddingLength,
262    KzgInvalidG1Point,
264    KzgG1PointNotOnCurve,
266    KzgG1PointNotInSubgroup,
268    KzgInvalidInputLength,
270    Secp256k1RecoverFailed,
272    Fatal(String),
274    Other(String),
276}
277
278impl PrecompileError {
279    pub fn other(err: impl Into<String>) -> Self {
281        Self::Other(err.into())
282    }
283
284    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#[derive(Clone, Debug)]
339pub struct DefaultCrypto;
340
341impl Crypto for DefaultCrypto {}