revm_precompile/bls12_381/
g2_add.rs

1use super::g2::{encode_g2_point, extract_g2_input, G2_INPUT_ITEM_LENGTH};
2use crate::{u64_to_address, PrecompileWithAddress};
3use blst::{
4    blst_p2, blst_p2_add_or_double_affine, blst_p2_affine, blst_p2_from_affine, blst_p2_to_affine,
5};
6use revm_primitives::{Bytes, Precompile, PrecompileError, PrecompileOutput, PrecompileResult};
7
8/// [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537#specification) BLS12_G2ADD precompile.
9pub const PRECOMPILE: PrecompileWithAddress =
10    PrecompileWithAddress(u64_to_address(ADDRESS), Precompile::Standard(g2_add));
11/// BLS12_G2ADD precompile address.
12pub const ADDRESS: u64 = 0x0e;
13/// Base gas fee for BLS12-381 g2_add operation.
14const BASE_GAS_FEE: u64 = 800;
15
16/// Input length of g2_add operation.
17const INPUT_LENGTH: usize = 512;
18
19/// G2 addition call expects `512` bytes as an input that is interpreted as byte
20/// concatenation of two G2 points (`256` bytes each).
21///
22/// Output is an encoding of addition operation result - single G2 point (`256`
23/// bytes).
24/// See also <https://eips.ethereum.org/EIPS/eip-2537#abi-for-g2-addition>
25pub(super) fn g2_add(input: &Bytes, gas_limit: u64) -> PrecompileResult {
26    if BASE_GAS_FEE > gas_limit {
27        return Err(PrecompileError::OutOfGas.into());
28    }
29
30    if input.len() != INPUT_LENGTH {
31        return Err(PrecompileError::Other(format!(
32            "G2ADD input should be {INPUT_LENGTH} bytes, was {}",
33            input.len()
34        ))
35        .into());
36    }
37
38    // NB: There is no subgroup check for the G2 addition precompile.
39    //
40    // So we set the subgroup checks here to `false`
41    let a_aff = &extract_g2_input(&input[..G2_INPUT_ITEM_LENGTH], false)?;
42    let b_aff = &extract_g2_input(&input[G2_INPUT_ITEM_LENGTH..], false)?;
43
44    let mut b = blst_p2::default();
45    // SAFETY: b and b_aff are blst values.
46    unsafe { blst_p2_from_affine(&mut b, b_aff) };
47
48    let mut p = blst_p2::default();
49    // SAFETY: p, b and a_aff are blst values.
50    unsafe { blst_p2_add_or_double_affine(&mut p, &b, a_aff) };
51
52    let mut p_aff = blst_p2_affine::default();
53    // SAFETY: p_aff and p are blst values.
54    unsafe { blst_p2_to_affine(&mut p_aff, &p) };
55
56    let out = encode_g2_point(&p_aff);
57    Ok(PrecompileOutput::new(BASE_GAS_FEE, out))
58}