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