revm_precompile/bls12_381/
g2_msm.rs1use super::utils::{pad_g2_point, remove_g2_padding};
3use crate::bls12_381_const::{
4 DISCOUNT_TABLE_G2_MSM, G2_MSM_ADDRESS, G2_MSM_BASE_GAS_FEE, G2_MSM_INPUT_LENGTH,
5 PADDED_G2_LENGTH, SCALAR_LENGTH,
6};
7use crate::bls12_381_utils::msm_required_gas;
8use crate::{
9 crypto, Precompile, PrecompileError, PrecompileId, PrecompileOutput, PrecompileResult,
10};
11
12pub const PRECOMPILE: Precompile =
14 Precompile::new(PrecompileId::Bls12G2Msm, G2_MSM_ADDRESS, g2_msm);
15
16pub fn g2_msm(input: &[u8], gas_limit: u64) -> PrecompileResult {
25 let input_len = input.len();
26 if input_len == 0 || !input_len.is_multiple_of(G2_MSM_INPUT_LENGTH) {
27 return Err(PrecompileError::Bls12381G2MsmInputLength);
28 }
29
30 let k = input_len / G2_MSM_INPUT_LENGTH;
31 let required_gas = msm_required_gas(k, &DISCOUNT_TABLE_G2_MSM, G2_MSM_BASE_GAS_FEE);
32 if required_gas > gas_limit {
33 return Err(PrecompileError::OutOfGas);
34 }
35
36 let mut valid_pairs_iter = (0..k).map(|i| {
37 let start = i * G2_MSM_INPUT_LENGTH;
38 let padded_g2 = &input[start..start + PADDED_G2_LENGTH];
39 let scalar_bytes = &input[start + PADDED_G2_LENGTH..start + G2_MSM_INPUT_LENGTH];
40
41 let [x_0, x_1, y_0, y_1] = remove_g2_padding(padded_g2)?;
43 let scalar_array: [u8; SCALAR_LENGTH] = scalar_bytes.try_into().unwrap();
44
45 Ok(((*x_0, *x_1, *y_0, *y_1), scalar_array))
46 });
47
48 let unpadded_result = crypto().bls12_381_g2_msm(&mut valid_pairs_iter)?;
49
50 let padded_result = pad_g2_point(&unpadded_result);
52
53 Ok(PrecompileOutput::new(required_gas, padded_result.into()))
54}