1use context_interface::result::AnyError;
4use core::fmt::{self, Debug};
5use primitives::{Bytes, OnceLock};
6use std::{borrow::Cow, boxed::Box, string::String, vec::Vec};
7
8use crate::bls12_381::{G1Point, G1PointScalar, G2Point, G2PointScalar};
9
10static CRYPTO: OnceLock<Box<dyn Crypto>> = OnceLock::new();
12
13pub fn install_crypto<C: Crypto + 'static>(crypto: C) -> bool {
15 CRYPTO.set(Box::new(crypto)).is_ok()
16}
17
18pub fn crypto() -> &'static dyn Crypto {
20 CRYPTO.get_or_init(|| Box::new(DefaultCrypto)).as_ref()
21}
22
23pub type EthPrecompileResult = Result<EthPrecompileOutput, PrecompileHalt>;
27
28pub type PrecompileResult = Result<PrecompileOutput, PrecompileError>;
33
34#[derive(Clone, Debug, PartialEq, Eq, Hash)]
39pub struct EthPrecompileOutput {
40 pub gas_used: u64,
42 pub bytes: Bytes,
44}
45
46impl EthPrecompileOutput {
47 pub fn new(gas_used: u64, bytes: Bytes) -> Self {
49 Self { gas_used, bytes }
50 }
51}
52
53#[derive(Clone, Debug, PartialEq, Eq, Hash)]
55pub enum PrecompileStatus {
56 Success,
58 Revert,
60 Halt(PrecompileHalt),
62}
63
64impl PrecompileStatus {
65 #[inline]
67 pub fn is_success_or_revert(&self) -> bool {
68 matches!(self, PrecompileStatus::Success | PrecompileStatus::Revert)
69 }
70
71 #[inline]
73 pub fn is_revert_or_halt(&self) -> bool {
74 matches!(self, PrecompileStatus::Revert | PrecompileStatus::Halt(_))
75 }
76
77 #[inline]
79 pub fn halt_reason(&self) -> Option<&PrecompileHalt> {
80 match &self {
81 PrecompileStatus::Halt(reason) => Some(reason),
82 _ => None,
83 }
84 }
85
86 #[inline]
88 pub fn is_success(&self) -> bool {
89 matches!(self, PrecompileStatus::Success)
90 }
91
92 #[inline]
94 pub fn is_revert(&self) -> bool {
95 matches!(self, PrecompileStatus::Revert)
96 }
97
98 #[inline]
100 pub fn is_halt(&self) -> bool {
101 matches!(self, PrecompileStatus::Halt(_))
102 }
103}
104
105#[derive(Clone, Debug, PartialEq, Eq, Hash)]
110pub struct PrecompileOutput {
111 pub status: PrecompileStatus,
113 pub gas_used: u64,
115 pub state_gas_used: u64,
117 pub reservoir: u64,
119 pub bytes: Bytes,
121}
122
123impl PrecompileOutput {
124 pub fn from_eth_result(result: EthPrecompileResult, reservoir: u64) -> Self {
126 match result {
127 Ok(output) => Self::new(output.gas_used, output.bytes, reservoir),
128 Err(halt) => Self::halt(halt, reservoir),
129 }
130 }
131 pub fn new(gas_used: u64, bytes: Bytes, reservoir: u64) -> Self {
133 Self {
134 status: PrecompileStatus::Success,
135 gas_used,
136 state_gas_used: 0,
137 reservoir,
138 bytes,
139 }
140 }
141
142 pub fn halt(reason: PrecompileHalt, reservoir: u64) -> Self {
144 Self {
145 status: PrecompileStatus::Halt(reason),
146 gas_used: 0,
147 state_gas_used: 0,
148 reservoir,
149 bytes: Bytes::new(),
150 }
151 }
152
153 pub fn revert(gas_used: u64, bytes: Bytes, reservoir: u64) -> Self {
155 Self {
156 status: PrecompileStatus::Revert,
157 gas_used,
158 state_gas_used: 0,
159 reservoir,
160 bytes,
161 }
162 }
163
164 pub fn is_success(&self) -> bool {
166 matches!(self.status, PrecompileStatus::Success)
167 }
168
169 #[deprecated(note = "use `is_success` instead")]
171 pub fn is_ok(&self) -> bool {
172 self.is_success()
173 }
174
175 pub fn is_revert(&self) -> bool {
177 matches!(self.status, PrecompileStatus::Revert)
178 }
179
180 pub fn is_halt(&self) -> bool {
182 matches!(self.status, PrecompileStatus::Halt(_))
183 }
184
185 #[inline]
187 pub fn halt_reason(&self) -> Option<&PrecompileHalt> {
188 self.status.halt_reason()
189 }
190}
191
192pub trait Crypto: Send + Sync + Debug {
194 #[inline]
196 fn sha256(&self, input: &[u8]) -> [u8; 32] {
197 use sha2::Digest;
198 let output = sha2::Sha256::digest(input);
199 output.into()
200 }
201
202 #[inline]
204 fn ripemd160(&self, input: &[u8]) -> [u8; 32] {
205 use ripemd::Digest;
206 let mut hasher = ripemd::Ripemd160::new();
207 hasher.update(input);
208
209 let mut output = [0u8; 32];
210 hasher.finalize_into((&mut output[12..]).into());
211 output
212 }
213
214 #[inline]
216 fn bn254_g1_add(&self, p1: &[u8], p2: &[u8]) -> Result<[u8; 64], PrecompileHalt> {
217 crate::bn254::crypto_backend::g1_point_add(p1, p2)
218 }
219
220 #[inline]
222 fn bn254_g1_mul(&self, point: &[u8], scalar: &[u8]) -> Result<[u8; 64], PrecompileHalt> {
223 crate::bn254::crypto_backend::g1_point_mul(point, scalar)
224 }
225
226 #[inline]
228 fn bn254_pairing_check(&self, pairs: &[(&[u8], &[u8])]) -> Result<bool, PrecompileHalt> {
229 crate::bn254::crypto_backend::pairing_check(pairs)
230 }
231
232 #[inline]
234 fn secp256k1_ecrecover(
235 &self,
236 sig: &[u8; 64],
237 recid: u8,
238 msg: &[u8; 32],
239 ) -> Result<[u8; 32], PrecompileHalt> {
240 crate::secp256k1::ecrecover_bytes(sig, recid, msg)
241 .ok_or(PrecompileHalt::Secp256k1RecoverFailed)
242 }
243
244 #[inline]
246 fn modexp(&self, base: &[u8], exp: &[u8], modulus: &[u8]) -> Result<Vec<u8>, PrecompileHalt> {
247 Ok(crate::modexp::modexp(base, exp, modulus))
248 }
249
250 #[inline]
252 fn blake2_compress(&self, rounds: u32, h: &mut [u64; 8], m: &[u64; 16], t: &[u64; 2], f: bool) {
253 crate::blake2::algo::compress(rounds as usize, h, m, t, f);
254 }
255
256 #[inline]
258 fn secp256r1_verify_signature(&self, msg: &[u8; 32], sig: &[u8; 64], pk: &[u8; 64]) -> bool {
259 crate::secp256r1::verify_signature(msg, sig, pk).is_some()
260 }
261
262 #[inline]
264 fn verify_kzg_proof(
265 &self,
266 z: &[u8; 32],
267 y: &[u8; 32],
268 commitment: &[u8; 48],
269 proof: &[u8; 48],
270 ) -> Result<(), PrecompileHalt> {
271 if !crate::kzg_point_evaluation::verify_kzg_proof(commitment, z, y, proof) {
272 return Err(PrecompileHalt::BlobVerifyKzgProofFailed);
273 }
274
275 Ok(())
276 }
277
278 fn bls12_381_g1_add(&self, a: G1Point, b: G1Point) -> Result<[u8; 96], PrecompileHalt> {
280 crate::bls12_381::crypto_backend::p1_add_affine_bytes(a, b)
281 }
282
283 fn bls12_381_g1_msm(
285 &self,
286 pairs: &mut dyn Iterator<Item = Result<G1PointScalar, PrecompileHalt>>,
287 ) -> Result<[u8; 96], PrecompileHalt> {
288 crate::bls12_381::crypto_backend::p1_msm_bytes(pairs)
289 }
290
291 fn bls12_381_g2_add(&self, a: G2Point, b: G2Point) -> Result<[u8; 192], PrecompileHalt> {
293 crate::bls12_381::crypto_backend::p2_add_affine_bytes(a, b)
294 }
295
296 fn bls12_381_g2_msm(
298 &self,
299 pairs: &mut dyn Iterator<Item = Result<G2PointScalar, PrecompileHalt>>,
300 ) -> Result<[u8; 192], PrecompileHalt> {
301 crate::bls12_381::crypto_backend::p2_msm_bytes(pairs)
302 }
303
304 fn bls12_381_pairing_check(
306 &self,
307 pairs: &[(G1Point, G2Point)],
308 ) -> Result<bool, PrecompileHalt> {
309 crate::bls12_381::crypto_backend::pairing_check_bytes(pairs)
310 }
311
312 fn bls12_381_fp_to_g1(&self, fp: &[u8; 48]) -> Result<[u8; 96], PrecompileHalt> {
314 crate::bls12_381::crypto_backend::map_fp_to_g1_bytes(fp)
315 }
316
317 fn bls12_381_fp2_to_g2(&self, fp2: ([u8; 48], [u8; 48])) -> Result<[u8; 192], PrecompileHalt> {
319 crate::bls12_381::crypto_backend::map_fp2_to_g2_bytes(&fp2.0, &fp2.1)
320 }
321}
322
323pub type PrecompileEthFn = fn(&[u8], u64) -> EthPrecompileResult;
328
329pub type PrecompileFn = fn(&[u8], u64, u64) -> PrecompileResult;
334
335#[macro_export]
348macro_rules! eth_precompile_fn {
349 ($name:ident, $eth_fn:expr) => {
350 fn $name(input: &[u8], gas_limit: u64, reservoir: u64) -> $crate::PrecompileResult {
351 Ok($crate::call_eth_precompile(
352 $eth_fn, input, gas_limit, reservoir,
353 ))
354 }
355 };
356}
357
358#[inline]
367pub fn call_eth_precompile(
368 f: PrecompileEthFn,
369 input: &[u8],
370 gas_limit: u64,
371 reservoir: u64,
372) -> PrecompileOutput {
373 match f(input, gas_limit) {
374 Ok(output) => PrecompileOutput::new(output.gas_used, output.bytes, reservoir),
375 Err(halt) => PrecompileOutput::halt(halt, reservoir),
376 }
377}
378
379#[derive(Clone, Debug, PartialEq, Eq, Hash)]
385pub enum PrecompileHalt {
386 OutOfGas,
388 Blake2WrongLength,
390 Blake2WrongFinalIndicatorFlag,
392 ModexpExpOverflow,
394 ModexpBaseOverflow,
396 ModexpModOverflow,
398 ModexpEip7823LimitSize,
400 Bn254FieldPointNotAMember,
402 Bn254AffineGFailedToCreate,
404 Bn254PairLength,
406 BlobInvalidInputLength,
409 BlobMismatchedVersion,
411 BlobVerifyKzgProofFailed,
413 NonCanonicalFp,
415 Bls12381G1NotOnCurve,
417 Bls12381G1NotInSubgroup,
419 Bls12381G2NotOnCurve,
421 Bls12381G2NotInSubgroup,
423 Bls12381ScalarInputLength,
425 Bls12381G1AddInputLength,
427 Bls12381G1MsmInputLength,
429 Bls12381G2AddInputLength,
431 Bls12381G2MsmInputLength,
433 Bls12381PairingInputLength,
435 Bls12381MapFpToG1InputLength,
437 Bls12381MapFp2ToG2InputLength,
439 Bls12381FpPaddingInvalid,
441 Bls12381FpPaddingLength,
443 Bls12381G1PaddingLength,
445 Bls12381G2PaddingLength,
447 KzgInvalidG1Point,
449 KzgG1PointNotOnCurve,
451 KzgG1PointNotInSubgroup,
453 KzgInvalidInputLength,
455 Secp256k1RecoverFailed,
457 Other(Cow<'static, str>),
459}
460
461impl PrecompileHalt {
462 pub fn other(err: impl Into<String>) -> Self {
464 Self::Other(Cow::Owned(err.into()))
465 }
466
467 pub const fn other_static(err: &'static str) -> Self {
469 Self::Other(Cow::Borrowed(err))
470 }
471
472 pub fn is_oog(&self) -> bool {
474 matches!(self, Self::OutOfGas)
475 }
476}
477
478impl core::error::Error for PrecompileHalt {}
479
480impl fmt::Display for PrecompileHalt {
481 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
482 let s = match self {
483 Self::OutOfGas => "out of gas",
484 Self::Blake2WrongLength => "wrong input length for blake2",
485 Self::Blake2WrongFinalIndicatorFlag => "wrong final indicator flag for blake2",
486 Self::ModexpExpOverflow => "modexp exp overflow",
487 Self::ModexpBaseOverflow => "modexp base overflow",
488 Self::ModexpModOverflow => "modexp mod overflow",
489 Self::ModexpEip7823LimitSize => "Modexp limit all input sizes.",
490 Self::Bn254FieldPointNotAMember => "field point not a member of bn254 curve",
491 Self::Bn254AffineGFailedToCreate => "failed to create affine g point for bn254 curve",
492 Self::Bn254PairLength => "bn254 invalid pair length",
493 Self::BlobInvalidInputLength => "invalid blob input length",
494 Self::BlobMismatchedVersion => "mismatched blob version",
495 Self::BlobVerifyKzgProofFailed => "verifying blob kzg proof failed",
496 Self::NonCanonicalFp => "non-canonical field element",
497 Self::Bls12381G1NotOnCurve => "bls12-381 g1 point not on curve",
498 Self::Bls12381G1NotInSubgroup => "bls12-381 g1 point not in correct subgroup",
499 Self::Bls12381G2NotOnCurve => "bls12-381 g2 point not on curve",
500 Self::Bls12381G2NotInSubgroup => "bls12-381 g2 point not in correct subgroup",
501 Self::Bls12381ScalarInputLength => "bls12-381 scalar input length error",
502 Self::Bls12381G1AddInputLength => "bls12-381 g1 add input length error",
503 Self::Bls12381G1MsmInputLength => "bls12-381 g1 msm input length error",
504 Self::Bls12381G2AddInputLength => "bls12-381 g2 add input length error",
505 Self::Bls12381G2MsmInputLength => "bls12-381 g2 msm input length error",
506 Self::Bls12381PairingInputLength => "bls12-381 pairing input length error",
507 Self::Bls12381MapFpToG1InputLength => "bls12-381 map fp to g1 input length error",
508 Self::Bls12381MapFp2ToG2InputLength => "bls12-381 map fp2 to g2 input length error",
509 Self::Bls12381FpPaddingInvalid => "bls12-381 fp 64 top bytes of input are not zero",
510 Self::Bls12381FpPaddingLength => "bls12-381 fp padding length error",
511 Self::Bls12381G1PaddingLength => "bls12-381 g1 padding length error",
512 Self::Bls12381G2PaddingLength => "bls12-381 g2 padding length error",
513 Self::KzgInvalidG1Point => "kzg invalid g1 point",
514 Self::KzgG1PointNotOnCurve => "kzg g1 point not on curve",
515 Self::KzgG1PointNotInSubgroup => "kzg g1 point not in correct subgroup",
516 Self::KzgInvalidInputLength => "kzg invalid input length",
517 Self::Secp256k1RecoverFailed => "secp256k1 signature recovery failed",
518 Self::Other(s) => s,
519 };
520 f.write_str(s)
521 }
522}
523
524#[derive(Clone, Debug, PartialEq, Eq, Hash)]
532pub enum PrecompileError {
533 Fatal(String),
535 FatalAny(AnyError),
537}
538
539impl PrecompileError {
540 pub fn is_fatal(&self) -> bool {
542 true
543 }
544}
545
546impl core::error::Error for PrecompileError {}
547
548impl fmt::Display for PrecompileError {
549 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
550 match self {
551 Self::Fatal(s) => write!(f, "fatal: {s}"),
552 Self::FatalAny(s) => write!(f, "fatal: {s}"),
553 }
554 }
555}
556
557#[derive(Clone, Debug)]
559pub struct DefaultCrypto;
560
561impl Crypto for DefaultCrypto {}