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 {}