revm_precompile/bls12_381/
g2_msm.rs1use super::crypto_backend::{encode_g2_point, p2_msm, read_g2, read_scalar};
2use super::utils::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::{PrecompileError, PrecompileOutput, PrecompileResult, PrecompileWithAddress};
9use primitives::Bytes;
10use std::vec::Vec;
11
12pub const PRECOMPILE: PrecompileWithAddress = PrecompileWithAddress(G2_MSM_ADDRESS, g2_msm);
14
15pub(super) fn g2_msm(input: &Bytes, gas_limit: u64) -> PrecompileResult {
24 let input_len = input.len();
25 if input_len == 0 || input_len % G2_MSM_INPUT_LENGTH != 0 {
26 return Err(PrecompileError::Other(format!(
27 "G2MSM input length should be multiple of {}, was {}",
28 G2_MSM_INPUT_LENGTH, input_len
29 )));
30 }
31
32 let k = input_len / G2_MSM_INPUT_LENGTH;
33 let required_gas = msm_required_gas(k, &DISCOUNT_TABLE_G2_MSM, G2_MSM_BASE_GAS_FEE);
34 if required_gas > gas_limit {
35 return Err(PrecompileError::OutOfGas);
36 }
37
38 let mut g2_points: Vec<_> = Vec::with_capacity(k);
39 let mut scalars = Vec::with_capacity(k);
40 for i in 0..k {
41 let encoded_g2_element =
42 &input[i * G2_MSM_INPUT_LENGTH..i * G2_MSM_INPUT_LENGTH + PADDED_G2_LENGTH];
43 let encoded_scalar = &input[i * G2_MSM_INPUT_LENGTH + PADDED_G2_LENGTH
44 ..i * G2_MSM_INPUT_LENGTH + PADDED_G2_LENGTH + SCALAR_LENGTH];
45
46 if encoded_g2_element.iter().all(|i| *i == 0) {
50 continue;
51 }
52
53 let [a_x_0, a_x_1, a_y_0, a_y_1] = remove_g2_padding(encoded_g2_element)?;
54
55 let p0_aff = read_g2(a_x_0, a_x_1, a_y_0, a_y_1)?;
59
60 if encoded_scalar.iter().all(|i| *i == 0) {
66 continue;
67 }
68
69 g2_points.push(p0_aff);
71 scalars.push(read_scalar(encoded_scalar)?);
72 }
73
74 if g2_points.is_empty() {
76 return Ok(PrecompileOutput::new(
77 required_gas,
78 [0; PADDED_G2_LENGTH].into(),
79 ));
80 }
81
82 let multiexp_aff = p2_msm(g2_points, scalars);
84
85 let out = encode_g2_point(&multiexp_aff);
86 Ok(PrecompileOutput::new(required_gas, out.into()))
87}