revm_precompile/bls12_381/
g2_msm.rs1use super::utils::{pad_g2_point, remove_g2_padding};
3use crate::{
4 bls12_381_const::{
5 DISCOUNT_TABLE_G2_MSM, G2_MSM_ADDRESS, G2_MSM_BASE_GAS_FEE, G2_MSM_INPUT_LENGTH,
6 PADDED_G2_LENGTH, SCALAR_LENGTH,
7 },
8 bls12_381_utils::msm_required_gas,
9 crypto, eth_precompile_fn, EthPrecompileOutput, EthPrecompileResult, Precompile,
10 PrecompileHalt, PrecompileId,
11};
12
13eth_precompile_fn!(g2_msm_precompile, g2_msm);
14
15pub const PRECOMPILE: Precompile =
17 Precompile::new(PrecompileId::Bls12G2Msm, G2_MSM_ADDRESS, g2_msm_precompile);
18
19pub fn g2_msm(input: &[u8], gas_limit: u64) -> EthPrecompileResult {
28 let input_len = input.len();
29 if input_len == 0 || !input_len.is_multiple_of(G2_MSM_INPUT_LENGTH) {
30 return Err(PrecompileHalt::Bls12381G2MsmInputLength);
31 }
32
33 let input_chunks = input.chunks_exact(G2_MSM_INPUT_LENGTH);
34 let k = input_chunks.len();
35 let required_gas = msm_required_gas(k, &DISCOUNT_TABLE_G2_MSM, G2_MSM_BASE_GAS_FEE);
36 if required_gas > gas_limit {
37 return Err(PrecompileHalt::OutOfGas);
38 }
39
40 let mut valid_pairs_iter = input_chunks.map(|pair| {
41 let (padded_g2, scalar_bytes) = pair.split_at(PADDED_G2_LENGTH);
42
43 let [x_0, x_1, y_0, y_1] = remove_g2_padding(padded_g2)?;
45 let scalar_array: [u8; SCALAR_LENGTH] = scalar_bytes.try_into().unwrap();
46
47 Ok(((*x_0, *x_1, *y_0, *y_1), scalar_array))
48 });
49
50 let unpadded_result = crypto().bls12_381_g2_msm(&mut valid_pairs_iter)?;
51
52 let padded_result = pad_g2_point(&unpadded_result);
54
55 Ok(EthPrecompileOutput::new(required_gas, padded_result.into()))
56}