revm_precompile/bls12_381/
g1_add.rs

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