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 if CRYPTO.get().is_some() {
15 return false;
16 }
17
18 CRYPTO.get_or_init(|| Box::new(crypto));
19 true
20}
21
22pub fn crypto() -> &'static dyn Crypto {
24 CRYPTO.get_or_init(|| Box::new(DefaultCrypto)).as_ref()
25}
26
27pub type PrecompileResult = Result<PrecompileOutput, PrecompileError>;
31
32#[derive(Clone, Debug, PartialEq, Eq, Hash)]
34pub struct PrecompileOutput {
35 pub gas_used: u64,
37 pub bytes: Bytes,
39 pub reverted: bool,
41}
42
43impl PrecompileOutput {
44 pub fn new(gas_used: u64, bytes: Bytes) -> Self {
46 Self {
47 gas_used,
48 bytes,
49 reverted: false,
50 }
51 }
52
53 pub fn new_reverted(gas_used: u64, bytes: Bytes) -> Self {
55 Self {
56 gas_used,
57 bytes,
58 reverted: true,
59 }
60 }
61
62 pub fn reverted(mut self) -> Self {
64 self.reverted = true;
65 self
66 }
67}
68
69pub trait Crypto: Send + Sync + Debug {
71 #[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 #[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 #[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 #[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 #[inline]
105 fn bn254_pairing_check(&self, pairs: &[(&[u8], &[u8])]) -> Result<bool, PrecompileError> {
106 crate::bn254::crypto_backend::pairing_check(pairs)
107 }
108
109 #[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(PrecompileError::Secp256k1RecoverFailed)
119 }
120
121 #[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 #[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 #[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 #[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 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 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 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 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 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 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 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
200pub type PrecompileFn = fn(&[u8], u64) -> PrecompileResult;
202
203#[derive(Clone, Debug, PartialEq, Eq, Hash)]
205pub enum PrecompileError {
206 OutOfGas,
208 Blake2WrongLength,
210 Blake2WrongFinalIndicatorFlag,
212 ModexpExpOverflow,
214 ModexpBaseOverflow,
216 ModexpModOverflow,
218 ModexpEip7823LimitSize,
220 Bn254FieldPointNotAMember,
222 Bn254AffineGFailedToCreate,
224 Bn254PairLength,
226 BlobInvalidInputLength,
229 BlobMismatchedVersion,
231 BlobVerifyKzgProofFailed,
233 NonCanonicalFp,
235 Bls12381G1NotOnCurve,
237 Bls12381G1NotInSubgroup,
239 Bls12381G2NotOnCurve,
241 Bls12381G2NotInSubgroup,
243 Bls12381ScalarInputLength,
245 Bls12381G1AddInputLength,
247 Bls12381G1MsmInputLength,
249 Bls12381G2AddInputLength,
251 Bls12381G2MsmInputLength,
253 Bls12381PairingInputLength,
255 Bls12381MapFpToG1InputLength,
257 Bls12381MapFp2ToG2InputLength,
259 Bls12381FpPaddingInvalid,
261 Bls12381FpPaddingLength,
263 Bls12381G1PaddingLength,
265 Bls12381G2PaddingLength,
267 KzgInvalidG1Point,
269 KzgG1PointNotOnCurve,
271 KzgG1PointNotInSubgroup,
273 KzgInvalidInputLength,
275 Secp256k1RecoverFailed,
277 Fatal(String),
279 Other(String),
281}
282
283impl PrecompileError {
284 pub fn other(err: impl Into<String>) -> Self {
286 Self::Other(err.into())
287 }
288
289 pub fn is_oog(&self) -> bool {
291 matches!(self, Self::OutOfGas)
292 }
293}
294
295impl core::error::Error for PrecompileError {}
296
297impl fmt::Display for PrecompileError {
298 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
299 let s = match self {
300 Self::OutOfGas => "out of gas",
301 Self::Blake2WrongLength => "wrong input length for blake2",
302 Self::Blake2WrongFinalIndicatorFlag => "wrong final indicator flag for blake2",
303 Self::ModexpExpOverflow => "modexp exp overflow",
304 Self::ModexpBaseOverflow => "modexp base overflow",
305 Self::ModexpModOverflow => "modexp mod overflow",
306 Self::ModexpEip7823LimitSize => "Modexp limit all input sizes.",
307 Self::Bn254FieldPointNotAMember => "field point not a member of bn254 curve",
308 Self::Bn254AffineGFailedToCreate => "failed to create affine g point for bn254 curve",
309 Self::Bn254PairLength => "bn254 invalid pair length",
310 Self::BlobInvalidInputLength => "invalid blob input length",
311 Self::BlobMismatchedVersion => "mismatched blob version",
312 Self::BlobVerifyKzgProofFailed => "verifying blob kzg proof failed",
313 Self::NonCanonicalFp => "non-canonical field element",
314 Self::Bls12381G1NotOnCurve => "bls12-381 g1 point not on curve",
315 Self::Bls12381G1NotInSubgroup => "bls12-381 g1 point not in correct subgroup",
316 Self::Bls12381G2NotOnCurve => "bls12-381 g2 point not on curve",
317 Self::Bls12381G2NotInSubgroup => "bls12-381 g2 point not in correct subgroup",
318 Self::Bls12381ScalarInputLength => "bls12-381 scalar input length error",
319 Self::Bls12381G1AddInputLength => "bls12-381 g1 add input length error",
320 Self::Bls12381G1MsmInputLength => "bls12-381 g1 msm input length error",
321 Self::Bls12381G2AddInputLength => "bls12-381 g2 add input length error",
322 Self::Bls12381G2MsmInputLength => "bls12-381 g2 msm input length error",
323 Self::Bls12381PairingInputLength => "bls12-381 pairing input length error",
324 Self::Bls12381MapFpToG1InputLength => "bls12-381 map fp to g1 input length error",
325 Self::Bls12381MapFp2ToG2InputLength => "bls12-381 map fp2 to g2 input length error",
326 Self::Bls12381FpPaddingInvalid => "bls12-381 fp 64 top bytes of input are not zero",
327 Self::Bls12381FpPaddingLength => "bls12-381 fp padding length error",
328 Self::Bls12381G1PaddingLength => "bls12-381 g1 padding length error",
329 Self::Bls12381G2PaddingLength => "bls12-381 g2 padding length error",
330 Self::KzgInvalidG1Point => "kzg invalid g1 point",
331 Self::KzgG1PointNotOnCurve => "kzg g1 point not on curve",
332 Self::KzgG1PointNotInSubgroup => "kzg g1 point not in correct subgroup",
333 Self::KzgInvalidInputLength => "kzg invalid input length",
334 Self::Secp256k1RecoverFailed => "secp256k1 signature recovery failed",
335 Self::Fatal(s) => s,
336 Self::Other(s) => s,
337 };
338 f.write_str(s)
339 }
340}
341
342#[derive(Clone, Debug)]
344pub struct DefaultCrypto;
345
346impl Crypto for DefaultCrypto {}