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