revm_precompile/bls12_381/
g1_msm.rs1use super::{
2 g1::{encode_g1_point, extract_g1_input},
3 msm::msm_required_gas,
4 utils::extract_scalar_input,
5};
6use crate::bls12_381_const::{
7 DISCOUNT_TABLE_G1_MSM, G1_INPUT_ITEM_LENGTH, G1_MSM_ADDRESS, G1_MSM_BASE_GAS_FEE,
8 G1_MSM_INPUT_LENGTH, NBITS, SCALAR_LENGTH,
9};
10use crate::{u64_to_address, PrecompileWithAddress};
11use crate::{PrecompileError, PrecompileOutput, PrecompileResult};
12use blst::{blst_p1, blst_p1_affine, blst_p1_from_affine, blst_p1_to_affine, p1_affines};
13use primitives::Bytes;
14
15pub const PRECOMPILE: PrecompileWithAddress =
17 PrecompileWithAddress(u64_to_address(G1_MSM_ADDRESS), g1_msm);
18
19pub(super) fn g1_msm(input: &Bytes, gas_limit: u64) -> PrecompileResult {
28 let input_len = input.len();
29 if input_len == 0 || input_len % G1_MSM_INPUT_LENGTH != 0 {
30 return Err(PrecompileError::Other(format!(
31 "G1MSM input length should be multiple of {}, was {}",
32 G1_MSM_INPUT_LENGTH, input_len
33 )));
34 }
35
36 let k = input_len / G1_MSM_INPUT_LENGTH;
37 let required_gas = msm_required_gas(k, &DISCOUNT_TABLE_G1_MSM, G1_MSM_BASE_GAS_FEE);
38 if required_gas > gas_limit {
39 return Err(PrecompileError::OutOfGas);
40 }
41
42 let mut g1_points: Vec<blst_p1> = Vec::with_capacity(k);
43 let mut scalars: Vec<u8> = Vec::with_capacity(k * SCALAR_LENGTH);
44 for i in 0..k {
45 let slice = &input[i * G1_MSM_INPUT_LENGTH..i * G1_MSM_INPUT_LENGTH + G1_INPUT_ITEM_LENGTH];
46
47 if slice.iter().all(|i| *i == 0) {
50 continue;
51 }
52
53 let p0_aff = &extract_g1_input(slice, true)?;
57
58 let mut p0 = blst_p1::default();
59 unsafe { blst_p1_from_affine(&mut p0, p0_aff) };
61 g1_points.push(p0);
62
63 scalars.extend_from_slice(
64 &extract_scalar_input(
65 &input[i * G1_MSM_INPUT_LENGTH + G1_INPUT_ITEM_LENGTH
66 ..i * G1_MSM_INPUT_LENGTH + G1_INPUT_ITEM_LENGTH + SCALAR_LENGTH],
67 )?
68 .b,
69 );
70 }
71
72 if g1_points.is_empty() {
74 return Ok(PrecompileOutput::new(required_gas, [0; 128].into()));
75 }
76
77 let points = p1_affines::from(&g1_points);
78 let multiexp = points.mult(&scalars, NBITS);
79
80 let mut multiexp_aff = blst_p1_affine::default();
81 unsafe { blst_p1_to_affine(&mut multiexp_aff, &multiexp) };
83
84 let out = encode_g1_point(&multiexp_aff);
85 Ok(PrecompileOutput::new(required_gas, out))
86}