revm_precompile/bls12_381/
g2_add.rs

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