revm_precompile/bls12_381/
g1_msm.rs1use crate::{
3 bls12_381::{
4 utils::{pad_g1_point, remove_g1_padding},
5 G1Point,
6 },
7 bls12_381_const::{
8 DISCOUNT_TABLE_G1_MSM, G1_MSM_ADDRESS, G1_MSM_BASE_GAS_FEE, G1_MSM_INPUT_LENGTH,
9 PADDED_G1_LENGTH, SCALAR_LENGTH,
10 },
11 bls12_381_utils::msm_required_gas,
12 crypto, eth_precompile_fn, EthPrecompileOutput, EthPrecompileResult, Precompile,
13 PrecompileHalt, PrecompileId,
14};
15
16eth_precompile_fn!(g1_msm_precompile, g1_msm);
17
18pub const PRECOMPILE: Precompile =
20 Precompile::new(PrecompileId::Bls12G1Msm, G1_MSM_ADDRESS, g1_msm_precompile);
21
22pub fn g1_msm(input: &[u8], gas_limit: u64) -> EthPrecompileResult {
31 let input_len = input.len();
32 if input_len == 0 || !input_len.is_multiple_of(G1_MSM_INPUT_LENGTH) {
33 return Err(PrecompileHalt::Bls12381G1MsmInputLength);
34 }
35
36 let input_chunks = input.chunks_exact(G1_MSM_INPUT_LENGTH);
37 let k = input_chunks.len();
38 let required_gas = msm_required_gas(k, &DISCOUNT_TABLE_G1_MSM, G1_MSM_BASE_GAS_FEE);
39 if required_gas > gas_limit {
40 return Err(PrecompileHalt::OutOfGas);
41 }
42
43 let mut valid_pairs_iter = input_chunks.map(|pair| {
44 let (padded_g1, scalar_bytes) = pair.split_at(PADDED_G1_LENGTH);
45
46 let [x, y] = remove_g1_padding(padded_g1)?;
48 let scalar_array: [u8; SCALAR_LENGTH] = scalar_bytes.try_into().unwrap();
49
50 let point: G1Point = (*x, *y);
51 Ok((point, scalar_array))
52 });
53
54 let unpadded_result = crypto().bls12_381_g1_msm(&mut valid_pairs_iter)?;
55
56 let padded_result = pad_g1_point(&unpadded_result);
58
59 Ok(EthPrecompileOutput::new(required_gas, padded_result.into()))
60}
61
62#[cfg(test)]
63mod test {
64 use super::*;
65 use primitives::{hex, Bytes};
66
67 #[test]
68 fn bls_g1multiexp_g1_not_on_curve_but_in_subgroup() {
69 let input = Bytes::from(hex!("000000000000000000000000000000000a2833e497b38ee3ca5c62828bf4887a9f940c9e426c7890a759c20f248c23a7210d2432f4c98a514e524b5184a0ddac00000000000000000000000000000000150772d56bf9509469f9ebcd6e47570429fd31b0e262b66d512e245c38ec37255529f2271fd70066473e393a8bead0c30000000000000000000000000000000000000000000000000000000000000000"));
70 let fail = g1_msm(&input, G1_MSM_BASE_GAS_FEE);
71 assert_eq!(fail, Err(PrecompileHalt::Bls12381G1NotOnCurve));
72 }
73}