revm_precompile/bls12_381/pairing.rs
1use super::{
2 g1::{extract_g1_input, G1_INPUT_ITEM_LENGTH},
3 g2::{extract_g2_input, G2_INPUT_ITEM_LENGTH},
4};
5use crate::{u64_to_address, PrecompileWithAddress};
6use blst::{blst_final_exp, blst_fp12, blst_fp12_is_one, blst_fp12_mul, blst_miller_loop};
7use revm_primitives::{
8 Bytes, Precompile, PrecompileError, PrecompileOutput, PrecompileResult, B256,
9};
10
11/// [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537#specification) BLS12_PAIRING precompile.
12pub const PRECOMPILE: PrecompileWithAddress =
13 PrecompileWithAddress(u64_to_address(ADDRESS), Precompile::Standard(pairing));
14/// BLS12_PAIRING precompile address.
15pub const ADDRESS: u64 = 0x11;
16
17/// Multiplier gas fee for BLS12-381 pairing operation.
18const PAIRING_MULTIPLIER_BASE: u64 = 43000;
19/// Offset gas fee for BLS12-381 pairing operation.
20const PAIRING_OFFSET_BASE: u64 = 65000;
21/// Input length of pairing operation.
22const INPUT_LENGTH: usize = 384;
23
24/// Pairing call expects 384*k (k being a positive integer) bytes as an inputs
25/// that is interpreted as byte concatenation of k slices. Each slice has the
26/// following structure:
27/// * 128 bytes of G1 point encoding
28/// * 256 bytes of G2 point encoding
29///
30/// Each point is expected to be in the subgroup of order q.
31/// Output is 32 bytes where first 31 bytes are equal to 0x00 and the last byte
32/// is 0x01 if pairing result is equal to the multiplicative identity in a pairing
33/// target field and 0x00 otherwise.
34///
35/// See also: <https://eips.ethereum.org/EIPS/eip-2537#abi-for-pairing>
36pub(super) fn pairing(input: &Bytes, gas_limit: u64) -> PrecompileResult {
37 let input_len = input.len();
38 if input_len == 0 || input_len % INPUT_LENGTH != 0 {
39 return Err(PrecompileError::Other(format!(
40 "Pairing input length should be multiple of {INPUT_LENGTH}, was {input_len}"
41 ))
42 .into());
43 }
44
45 let k = input_len / INPUT_LENGTH;
46 let required_gas: u64 = PAIRING_MULTIPLIER_BASE * k as u64 + PAIRING_OFFSET_BASE;
47 if required_gas > gas_limit {
48 return Err(PrecompileError::OutOfGas.into());
49 }
50
51 // Accumulator for the fp12 multiplications of the miller loops.
52 let mut acc = blst_fp12::default();
53 for i in 0..k {
54 // NB: Scalar multiplications, MSMs and pairings MUST perform a subgroup check.
55 //
56 // So we set the subgroup_check flag to `true`
57 let p1_aff = &extract_g1_input(
58 &input[i * INPUT_LENGTH..i * INPUT_LENGTH + G1_INPUT_ITEM_LENGTH],
59 true,
60 )?;
61
62 // NB: Scalar multiplications, MSMs and pairings MUST perform a subgroup check.
63 //
64 // So we set the subgroup_check flag to `true`
65 let p2_aff = &extract_g2_input(
66 &input[i * INPUT_LENGTH + G1_INPUT_ITEM_LENGTH
67 ..i * INPUT_LENGTH + G1_INPUT_ITEM_LENGTH + G2_INPUT_ITEM_LENGTH],
68 true,
69 )?;
70
71 if i > 0 {
72 // After the first slice (i>0) we use cur_ml to store the current
73 // miller loop and accumulate with the previous results using a fp12
74 // multiplication.
75 let mut cur_ml = blst_fp12::default();
76 let mut res = blst_fp12::default();
77 // SAFETY: res, acc, cur_ml, p1_aff and p2_aff are blst values.
78 unsafe {
79 blst_miller_loop(&mut cur_ml, p2_aff, p1_aff);
80 blst_fp12_mul(&mut res, &acc, &cur_ml);
81 }
82 acc = res;
83 } else {
84 // On the first slice (i==0) there is no previous results and no need
85 // to accumulate.
86 // SAFETY: acc, p1_aff and p2_aff are blst values.
87 unsafe {
88 blst_miller_loop(&mut acc, p2_aff, p1_aff);
89 }
90 }
91 }
92
93 // SAFETY: ret and acc are blst values.
94 let mut ret = blst_fp12::default();
95 unsafe {
96 blst_final_exp(&mut ret, &acc);
97 }
98
99 let mut result: u8 = 0;
100 // SAFETY: ret is a blst value.
101 unsafe {
102 if blst_fp12_is_one(&ret) {
103 result = 1;
104 }
105 }
106 Ok(PrecompileOutput::new(
107 required_gas,
108 B256::with_last_byte(result).into(),
109 ))
110}