1use core::fmt::{self, Debug};
4use primitives::{Bytes, OnceLock};
5use std::{borrow::Cow, 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 gas_refunded: i64,
34 pub bytes: Bytes,
36 pub reverted: bool,
38}
39
40impl PrecompileOutput {
41 pub fn new(gas_used: u64, bytes: Bytes) -> Self {
43 Self {
44 gas_used,
45 gas_refunded: 0,
46 bytes,
47 reverted: false,
48 }
49 }
50
51 pub fn new_reverted(gas_used: u64, bytes: Bytes) -> Self {
53 Self {
54 gas_used,
55 gas_refunded: 0,
56 bytes,
57 reverted: true,
58 }
59 }
60
61 pub fn reverted(mut self) -> Self {
63 self.reverted = true;
64 self
65 }
66}
67
68pub trait Crypto: Send + Sync + Debug {
70 #[inline]
72 fn sha256(&self, input: &[u8]) -> [u8; 32] {
73 use sha2::Digest;
74 let output = sha2::Sha256::digest(input);
75 output.into()
76 }
77
78 #[inline]
80 fn ripemd160(&self, input: &[u8]) -> [u8; 32] {
81 use ripemd::Digest;
82 let mut hasher = ripemd::Ripemd160::new();
83 hasher.update(input);
84
85 let mut output = [0u8; 32];
86 hasher.finalize_into((&mut output[12..]).into());
87 output
88 }
89
90 #[inline]
92 fn bn254_g1_add(&self, p1: &[u8], p2: &[u8]) -> Result<[u8; 64], PrecompileError> {
93 crate::bn254::crypto_backend::g1_point_add(p1, p2)
94 }
95
96 #[inline]
98 fn bn254_g1_mul(&self, point: &[u8], scalar: &[u8]) -> Result<[u8; 64], PrecompileError> {
99 crate::bn254::crypto_backend::g1_point_mul(point, scalar)
100 }
101
102 #[inline]
104 fn bn254_pairing_check(&self, pairs: &[(&[u8], &[u8])]) -> Result<bool, PrecompileError> {
105 crate::bn254::crypto_backend::pairing_check(pairs)
106 }
107
108 #[inline]
110 fn secp256k1_ecrecover(
111 &self,
112 sig: &[u8; 64],
113 recid: u8,
114 msg: &[u8; 32],
115 ) -> Result<[u8; 32], PrecompileError> {
116 crate::secp256k1::ecrecover_bytes(*sig, recid, *msg)
117 .ok_or(PrecompileError::Secp256k1RecoverFailed)
118 }
119
120 #[inline]
122 fn modexp(&self, base: &[u8], exp: &[u8], modulus: &[u8]) -> Result<Vec<u8>, PrecompileError> {
123 Ok(crate::modexp::modexp(base, exp, modulus))
124 }
125
126 #[inline]
128 fn blake2_compress(&self, rounds: u32, h: &mut [u64; 8], m: [u64; 16], t: [u64; 2], f: bool) {
129 crate::blake2::algo::compress(rounds as usize, h, m, t, f);
130 }
131
132 #[inline]
134 fn secp256r1_verify_signature(&self, msg: &[u8; 32], sig: &[u8; 64], pk: &[u8; 64]) -> bool {
135 crate::secp256r1::verify_signature(*msg, *sig, *pk).is_some()
136 }
137
138 #[inline]
140 fn verify_kzg_proof(
141 &self,
142 z: &[u8; 32],
143 y: &[u8; 32],
144 commitment: &[u8; 48],
145 proof: &[u8; 48],
146 ) -> Result<(), PrecompileError> {
147 if !crate::kzg_point_evaluation::verify_kzg_proof(commitment, z, y, proof) {
148 return Err(PrecompileError::BlobVerifyKzgProofFailed);
149 }
150
151 Ok(())
152 }
153
154 fn bls12_381_g1_add(&self, a: G1Point, b: G1Point) -> Result<[u8; 96], PrecompileError> {
156 crate::bls12_381::crypto_backend::p1_add_affine_bytes(a, b)
157 }
158
159 fn bls12_381_g1_msm(
161 &self,
162 pairs: &mut dyn Iterator<Item = Result<G1PointScalar, PrecompileError>>,
163 ) -> Result<[u8; 96], PrecompileError> {
164 crate::bls12_381::crypto_backend::p1_msm_bytes(pairs)
165 }
166
167 fn bls12_381_g2_add(&self, a: G2Point, b: G2Point) -> Result<[u8; 192], PrecompileError> {
169 crate::bls12_381::crypto_backend::p2_add_affine_bytes(a, b)
170 }
171
172 fn bls12_381_g2_msm(
174 &self,
175 pairs: &mut dyn Iterator<Item = Result<G2PointScalar, PrecompileError>>,
176 ) -> Result<[u8; 192], PrecompileError> {
177 crate::bls12_381::crypto_backend::p2_msm_bytes(pairs)
178 }
179
180 fn bls12_381_pairing_check(
182 &self,
183 pairs: &[(G1Point, G2Point)],
184 ) -> Result<bool, PrecompileError> {
185 crate::bls12_381::crypto_backend::pairing_check_bytes(pairs)
186 }
187
188 fn bls12_381_fp_to_g1(&self, fp: &[u8; 48]) -> Result<[u8; 96], PrecompileError> {
190 crate::bls12_381::crypto_backend::map_fp_to_g1_bytes(fp)
191 }
192
193 fn bls12_381_fp2_to_g2(&self, fp2: ([u8; 48], [u8; 48])) -> Result<[u8; 192], PrecompileError> {
195 crate::bls12_381::crypto_backend::map_fp2_to_g2_bytes(&fp2.0, &fp2.1)
196 }
197}
198
199pub type PrecompileFn = fn(&[u8], u64) -> PrecompileResult;
201
202#[derive(Clone, Debug, PartialEq, Eq, Hash)]
204pub enum PrecompileError {
205 OutOfGas,
207 Blake2WrongLength,
209 Blake2WrongFinalIndicatorFlag,
211 ModexpExpOverflow,
213 ModexpBaseOverflow,
215 ModexpModOverflow,
217 ModexpEip7823LimitSize,
219 Bn254FieldPointNotAMember,
221 Bn254AffineGFailedToCreate,
223 Bn254PairLength,
225 BlobInvalidInputLength,
228 BlobMismatchedVersion,
230 BlobVerifyKzgProofFailed,
232 NonCanonicalFp,
234 Bls12381G1NotOnCurve,
236 Bls12381G1NotInSubgroup,
238 Bls12381G2NotOnCurve,
240 Bls12381G2NotInSubgroup,
242 Bls12381ScalarInputLength,
244 Bls12381G1AddInputLength,
246 Bls12381G1MsmInputLength,
248 Bls12381G2AddInputLength,
250 Bls12381G2MsmInputLength,
252 Bls12381PairingInputLength,
254 Bls12381MapFpToG1InputLength,
256 Bls12381MapFp2ToG2InputLength,
258 Bls12381FpPaddingInvalid,
260 Bls12381FpPaddingLength,
262 Bls12381G1PaddingLength,
264 Bls12381G2PaddingLength,
266 KzgInvalidG1Point,
268 KzgG1PointNotOnCurve,
270 KzgG1PointNotInSubgroup,
272 KzgInvalidInputLength,
274 Secp256k1RecoverFailed,
276 Fatal(String),
278 Other(Cow<'static, str>),
280}
281
282impl PrecompileError {
283 pub fn other(err: impl Into<String>) -> Self {
285 Self::Other(Cow::Owned(err.into()))
286 }
287
288 pub const fn other_static(err: &'static str) -> Self {
290 Self::Other(Cow::Borrowed(err))
291 }
292
293 pub fn is_oog(&self) -> bool {
295 matches!(self, Self::OutOfGas)
296 }
297}
298
299impl core::error::Error for PrecompileError {}
300
301impl fmt::Display for PrecompileError {
302 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
303 let s = match self {
304 Self::OutOfGas => "out of gas",
305 Self::Blake2WrongLength => "wrong input length for blake2",
306 Self::Blake2WrongFinalIndicatorFlag => "wrong final indicator flag for blake2",
307 Self::ModexpExpOverflow => "modexp exp overflow",
308 Self::ModexpBaseOverflow => "modexp base overflow",
309 Self::ModexpModOverflow => "modexp mod overflow",
310 Self::ModexpEip7823LimitSize => "Modexp limit all input sizes.",
311 Self::Bn254FieldPointNotAMember => "field point not a member of bn254 curve",
312 Self::Bn254AffineGFailedToCreate => "failed to create affine g point for bn254 curve",
313 Self::Bn254PairLength => "bn254 invalid pair length",
314 Self::BlobInvalidInputLength => "invalid blob input length",
315 Self::BlobMismatchedVersion => "mismatched blob version",
316 Self::BlobVerifyKzgProofFailed => "verifying blob kzg proof failed",
317 Self::NonCanonicalFp => "non-canonical field element",
318 Self::Bls12381G1NotOnCurve => "bls12-381 g1 point not on curve",
319 Self::Bls12381G1NotInSubgroup => "bls12-381 g1 point not in correct subgroup",
320 Self::Bls12381G2NotOnCurve => "bls12-381 g2 point not on curve",
321 Self::Bls12381G2NotInSubgroup => "bls12-381 g2 point not in correct subgroup",
322 Self::Bls12381ScalarInputLength => "bls12-381 scalar input length error",
323 Self::Bls12381G1AddInputLength => "bls12-381 g1 add input length error",
324 Self::Bls12381G1MsmInputLength => "bls12-381 g1 msm input length error",
325 Self::Bls12381G2AddInputLength => "bls12-381 g2 add input length error",
326 Self::Bls12381G2MsmInputLength => "bls12-381 g2 msm input length error",
327 Self::Bls12381PairingInputLength => "bls12-381 pairing input length error",
328 Self::Bls12381MapFpToG1InputLength => "bls12-381 map fp to g1 input length error",
329 Self::Bls12381MapFp2ToG2InputLength => "bls12-381 map fp2 to g2 input length error",
330 Self::Bls12381FpPaddingInvalid => "bls12-381 fp 64 top bytes of input are not zero",
331 Self::Bls12381FpPaddingLength => "bls12-381 fp padding length error",
332 Self::Bls12381G1PaddingLength => "bls12-381 g1 padding length error",
333 Self::Bls12381G2PaddingLength => "bls12-381 g2 padding length error",
334 Self::KzgInvalidG1Point => "kzg invalid g1 point",
335 Self::KzgG1PointNotOnCurve => "kzg g1 point not on curve",
336 Self::KzgG1PointNotInSubgroup => "kzg g1 point not in correct subgroup",
337 Self::KzgInvalidInputLength => "kzg invalid input length",
338 Self::Secp256k1RecoverFailed => "secp256k1 signature recovery failed",
339 Self::Fatal(s) => s,
340 Self::Other(s) => s,
341 };
342 f.write_str(s)
343 }
344}
345
346#[derive(Clone, Debug)]
348pub struct DefaultCrypto;
349
350impl Crypto for DefaultCrypto {}