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_else(|| PrecompileError::other("ecrecover failed"))
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 Fatal(String),
235 Other(String),
237}
238
239impl PrecompileError {
240 pub fn other(err: impl Into<String>) -> Self {
242 Self::Other(err.into())
243 }
244
245 pub fn is_oog(&self) -> bool {
247 matches!(self, Self::OutOfGas)
248 }
249}
250
251impl core::error::Error for PrecompileError {}
252
253impl fmt::Display for PrecompileError {
254 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
255 let s = match self {
256 Self::OutOfGas => "out of gas",
257 Self::Blake2WrongLength => "wrong input length for blake2",
258 Self::Blake2WrongFinalIndicatorFlag => "wrong final indicator flag for blake2",
259 Self::ModexpExpOverflow => "modexp exp overflow",
260 Self::ModexpBaseOverflow => "modexp base overflow",
261 Self::ModexpModOverflow => "modexp mod overflow",
262 Self::ModexpEip7823LimitSize => "Modexp limit all input sizes.",
263 Self::Bn254FieldPointNotAMember => "field point not a member of bn254 curve",
264 Self::Bn254AffineGFailedToCreate => "failed to create affine g point for bn254 curve",
265 Self::Bn254PairLength => "bn254 invalid pair length",
266 Self::BlobInvalidInputLength => "invalid blob input length",
267 Self::BlobMismatchedVersion => "mismatched blob version",
268 Self::BlobVerifyKzgProofFailed => "verifying blob kzg proof failed",
269 Self::Fatal(s) => s,
270 Self::Other(s) => s,
271 };
272 f.write_str(s)
273 }
274}
275
276#[derive(Clone, Debug)]
278pub struct DefaultCrypto;
279
280impl Crypto for DefaultCrypto {}