revm_precompile/bls12_381/
pairing.rs

1use 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
12/// [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537#specification) BLS12_PAIRING precompile.
13pub const PRECOMPILE: PrecompileWithAddress =
14    PrecompileWithAddress(u64_to_address(PAIRING_ADDRESS), pairing);
15
16/// Pairing call expects 384*k (k being a positive integer) bytes as an inputs
17/// that is interpreted as byte concatenation of k slices. Each slice has the
18/// following structure:
19///    * 128 bytes of G1 point encoding
20///    * 256 bytes of G2 point encoding
21///
22/// Each point is expected to be in the subgroup of order q.
23/// Output is 32 bytes where first 31 bytes are equal to 0x00 and the last byte
24/// is 0x01 if pairing result is equal to the multiplicative identity in a pairing
25/// target field and 0x00 otherwise.
26///
27/// See also: <https://eips.ethereum.org/EIPS/eip-2537#abi-for-pairing>
28pub(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    // Accumulator for the fp12 multiplications of the miller loops.
44    let mut acc = blst_fp12::default();
45    for i in 0..k {
46        // NB: Scalar multiplications, MSMs and pairings MUST perform a subgroup check.
47        //
48        // So we set the subgroup_check flag to `true`
49        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        // NB: Scalar multiplications, MSMs and pairings MUST perform a subgroup check.
55        //
56        // So we set the subgroup_check flag to `true`
57        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            // After the first slice (i>0) we use cur_ml to store the current
65            // miller loop and accumulate with the previous results using a fp12
66            // multiplication.
67            let mut cur_ml = blst_fp12::default();
68            let mut res = blst_fp12::default();
69            // SAFETY: `res`, `acc`, `cur_ml`, `p1_aff` and `p2_aff` are blst values.
70            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            // On the first slice (i==0) there is no previous results and no need
77            // to accumulate.
78            // SAFETY: `acc`, `p1_aff` and `p2_aff` are blst values.
79            unsafe {
80                blst_miller_loop(&mut acc, p2_aff, p1_aff);
81            }
82        }
83    }
84
85    // SAFETY: `ret` and `acc` are blst values.
86    let mut ret = blst_fp12::default();
87    unsafe {
88        blst_final_exp(&mut ret, &acc);
89    }
90
91    let mut result: u8 = 0;
92    // SAFETY: `ret` is a blst value.
93    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}