revm_precompile/bls12_381/
pairing.rs1use super::crypto_backend::{pairing_check, read_g1, read_g2};
2use super::utils::{remove_g1_padding, remove_g2_padding};
3use crate::bls12_381_const::{
4 PADDED_G1_LENGTH, PADDED_G2_LENGTH, PAIRING_ADDRESS, PAIRING_INPUT_LENGTH,
5 PAIRING_MULTIPLIER_BASE, PAIRING_OFFSET_BASE,
6};
7use crate::{PrecompileError, PrecompileOutput, PrecompileResult, PrecompileWithAddress};
8use primitives::{Bytes, B256};
9use std::vec::Vec;
10
11pub const PRECOMPILE: PrecompileWithAddress = PrecompileWithAddress(PAIRING_ADDRESS, pairing);
13
14pub(super) fn pairing(input: &Bytes, gas_limit: u64) -> PrecompileResult {
27 let input_len = input.len();
28 if input_len == 0 || input_len % PAIRING_INPUT_LENGTH != 0 {
29 return Err(PrecompileError::Other(format!(
30 "Pairing input length should be multiple of {PAIRING_INPUT_LENGTH}, was {input_len}"
31 )));
32 }
33
34 let k = input_len / PAIRING_INPUT_LENGTH;
35 let required_gas: u64 = PAIRING_MULTIPLIER_BASE * k as u64 + PAIRING_OFFSET_BASE;
36 if required_gas > gas_limit {
37 return Err(PrecompileError::OutOfGas);
38 }
39
40 let mut pairs = Vec::with_capacity(k);
42 for i in 0..k {
43 let encoded_g1_element =
44 &input[i * PAIRING_INPUT_LENGTH..i * PAIRING_INPUT_LENGTH + PADDED_G1_LENGTH];
45 let encoded_g2_element = &input[i * PAIRING_INPUT_LENGTH + PADDED_G1_LENGTH
46 ..i * PAIRING_INPUT_LENGTH + PADDED_G1_LENGTH + PADDED_G2_LENGTH];
47
48 let g1_is_zero = encoded_g1_element.iter().all(|i| *i == 0);
58 let g2_is_zero = encoded_g2_element.iter().all(|i| *i == 0);
59
60 let [a_x, a_y] = remove_g1_padding(encoded_g1_element)?;
61 let [b_x_0, b_x_1, b_y_0, b_y_1] = remove_g2_padding(encoded_g2_element)?;
62
63 let p1_aff = read_g1(a_x, a_y)?;
66 let p2_aff = read_g2(b_x_0, b_x_1, b_y_0, b_y_1)?;
67
68 if !g1_is_zero & !g2_is_zero {
69 pairs.push((p1_aff, p2_aff));
70 }
71 }
72 let result = if pairing_check(&pairs) { 1 } else { 0 };
73
74 Ok(PrecompileOutput::new(
75 required_gas,
76 B256::with_last_byte(result).into(),
77 ))
78}