revm_precompile/bls12_381/
pairing.rs1use super::{g1::extract_g1_input, g2::extract_g2_input};
2use crate::bls12_381_const::{
3 G1_INPUT_ITEM_LENGTH, G2_INPUT_ITEM_LENGTH, PAIRING_ADDRESS, PAIRING_INPUT_LENGTH,
4 PAIRING_PAIRING_MULTIPLIER_BASE, PAIRING_PAIRING_OFFSET_BASE,
5};
6use crate::{
7 u64_to_address, PrecompileError, PrecompileOutput, PrecompileResult, PrecompileWithAddress,
8};
9use blst::{blst_final_exp, blst_fp12, blst_fp12_is_one, blst_fp12_mul, blst_miller_loop};
10use primitives::{Bytes, B256};
11
12pub const PRECOMPILE: PrecompileWithAddress =
14 PrecompileWithAddress(u64_to_address(PAIRING_ADDRESS), pairing);
15
16pub(super) fn pairing(input: &Bytes, gas_limit: u64) -> PrecompileResult {
29 let input_len = input.len();
30 if input_len == 0 || input_len % PAIRING_INPUT_LENGTH != 0 {
31 return Err(PrecompileError::Other(format!(
32 "Pairing input length should be multiple of {PAIRING_INPUT_LENGTH}, was {input_len}"
33 )));
34 }
35
36 let k = input_len / PAIRING_INPUT_LENGTH;
37 let required_gas: u64 =
38 PAIRING_PAIRING_MULTIPLIER_BASE * k as u64 + PAIRING_PAIRING_OFFSET_BASE;
39 if required_gas > gas_limit {
40 return Err(PrecompileError::OutOfGas);
41 }
42
43 let mut acc = blst_fp12::default();
45 for i in 0..k {
46 let p1_aff = &extract_g1_input(
50 &input[i * PAIRING_INPUT_LENGTH..i * PAIRING_INPUT_LENGTH + G1_INPUT_ITEM_LENGTH],
51 true,
52 )?;
53
54 let p2_aff = &extract_g2_input(
58 &input[i * PAIRING_INPUT_LENGTH + G1_INPUT_ITEM_LENGTH
59 ..i * PAIRING_INPUT_LENGTH + G1_INPUT_ITEM_LENGTH + G2_INPUT_ITEM_LENGTH],
60 true,
61 )?;
62
63 if i > 0 {
64 let mut cur_ml = blst_fp12::default();
68 let mut res = blst_fp12::default();
69 unsafe {
71 blst_miller_loop(&mut cur_ml, p2_aff, p1_aff);
72 blst_fp12_mul(&mut res, &acc, &cur_ml);
73 }
74 acc = res;
75 } else {
76 unsafe {
80 blst_miller_loop(&mut acc, p2_aff, p1_aff);
81 }
82 }
83 }
84
85 let mut ret = blst_fp12::default();
87 unsafe {
88 blst_final_exp(&mut ret, &acc);
89 }
90
91 let mut result: u8 = 0;
92 unsafe {
94 if blst_fp12_is_one(&ret) {
95 result = 1;
96 }
97 }
98 Ok(PrecompileOutput::new(
99 required_gas,
100 B256::with_last_byte(result).into(),
101 ))
102}