revm_precompile/bls12_381/
g1_add.rs

1//! BLS12-381 G1 add precompile. More details in [`g1_add`]
2use super::utils::{pad_g1_point, remove_g1_padding};
3use crate::bls12_381_const::{
4    G1_ADD_ADDRESS, G1_ADD_BASE_GAS_FEE, G1_ADD_INPUT_LENGTH, PADDED_G1_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_G1ADD precompile.
11pub const PRECOMPILE: Precompile =
12    Precompile::new(PrecompileId::Bls12G1Add, G1_ADD_ADDRESS, g1_add);
13
14/// G1 addition call expects `256` bytes as an input that is interpreted as byte
15/// concatenation of two G1 points (`128` bytes each).
16/// Output is an encoding of addition operation result - single G1 point (`128`
17/// bytes).
18/// See also: <https://eips.ethereum.org/EIPS/eip-2537#abi-for-g1-addition>
19pub fn g1_add(input: &[u8], gas_limit: u64) -> PrecompileResult {
20    if G1_ADD_BASE_GAS_FEE > gas_limit {
21        return Err(PrecompileError::OutOfGas);
22    }
23
24    if input.len() != G1_ADD_INPUT_LENGTH {
25        return Err(PrecompileError::Other(format!(
26            "G1ADD input should be {G1_ADD_INPUT_LENGTH} bytes, was {}",
27            input.len()
28        )));
29    }
30
31    // Extract coordinates from padded input
32    let [a_x, a_y] = remove_g1_padding(&input[..PADDED_G1_LENGTH])?;
33    let [b_x, b_y] = remove_g1_padding(&input[PADDED_G1_LENGTH..])?;
34
35    let a = (*a_x, *a_y);
36    let b = (*b_x, *b_y);
37
38    let unpadded_result = crypto().bls12_381_g1_add(a, b)?;
39
40    // Pad the result for EVM compatibility
41    let padded_result = pad_g1_point(&unpadded_result);
42
43    Ok(PrecompileOutput::new(
44        G1_ADD_BASE_GAS_FEE,
45        padded_result.into(),
46    ))
47}