revm_precompile/bls12_381/
g2_add.rs

1//! BLS12-381 G2 add precompile. More details in [`g2_add`]
2use super::utils::{pad_g2_point, remove_g2_padding};
3use crate::bls12_381_const::{
4    G2_ADD_ADDRESS, G2_ADD_BASE_GAS_FEE, G2_ADD_INPUT_LENGTH, PADDED_G2_LENGTH,
5};
6use crate::{
7    crypto, Precompile, PrecompileError, PrecompileId, PrecompileOutput, PrecompileResult,
8};
9
10/// [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537#specification) BLS12_G2ADD precompile.
11pub const PRECOMPILE: Precompile =
12    Precompile::new(PrecompileId::Bls12G2Add, G2_ADD_ADDRESS, g2_add);
13
14/// G2 addition call expects `512` bytes as an input that is interpreted as byte
15/// concatenation of two G2 points (`256` bytes each).
16///
17/// Output is an encoding of addition operation result - single G2 point (`256`
18/// bytes).
19/// See also <https://eips.ethereum.org/EIPS/eip-2537#abi-for-g2-addition>
20pub fn g2_add(input: &[u8], gas_limit: u64) -> PrecompileResult {
21    if G2_ADD_BASE_GAS_FEE > gas_limit {
22        return Err(PrecompileError::OutOfGas);
23    }
24
25    if input.len() != G2_ADD_INPUT_LENGTH {
26        return Err(PrecompileError::Other(format!(
27            "G2ADD input should be {G2_ADD_INPUT_LENGTH} bytes, was {}",
28            input.len()
29        )));
30    }
31
32    // Extract coordinates from padded input
33    let [a_x_0, a_x_1, a_y_0, a_y_1] = remove_g2_padding(&input[..PADDED_G2_LENGTH])?;
34    let [b_x_0, b_x_1, b_y_0, b_y_1] = remove_g2_padding(&input[PADDED_G2_LENGTH..])?;
35
36    let a = (*a_x_0, *a_x_1, *a_y_0, *a_y_1);
37    let b = (*b_x_0, *b_x_1, *b_y_0, *b_y_1);
38
39    let unpadded_result = crypto().bls12_381_g2_add(a, b)?;
40
41    // Pad the result for EVM compatibility
42    let padded_result = pad_g2_point(&unpadded_result);
43
44    Ok(PrecompileOutput::new(
45        G2_ADD_BASE_GAS_FEE,
46        padded_result.into(),
47    ))
48}