Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions crates/precompile/src/bls12_381/g1.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
use super::utils::{fp_from_bendian, fp_to_bytes, remove_padding};
use crate::bls12_381_const::{G1_INPUT_ITEM_LENGTH, G1_OUTPUT_LENGTH, PADDED_FP_LENGTH};
use super::utils::{fp_from_bendian, fp_to_bytes, remove_padding, PADDED_FP_LENGTH};
use crate::PrecompileError;
use blst::{blst_p1_affine, blst_p1_affine_in_g1, blst_p1_affine_on_curve};
use primitives::Bytes;

/// Length of each of the elements in a g1 operation input.
pub(super) const G1_INPUT_ITEM_LENGTH: usize = 128;

/// Output length of a g1 operation.
const G1_OUTPUT_LENGTH: usize = 128;

/// Encodes a G1 point in affine format into byte slice with padded elements.
pub(super) fn encode_g1_point(input: *const blst_p1_affine) -> Bytes {
let mut out = vec![0u8; G1_OUTPUT_LENGTH];
Expand Down
22 changes: 13 additions & 9 deletions crates/precompile/src/bls12_381/g1_add.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
use super::g1::{encode_g1_point, extract_g1_input};
use crate::bls12_381_const::{
G1_ADD_ADDRESS, G1_ADD_BASE_GAS_FEE, G1_ADD_INPUT_LENGTH, G1_INPUT_ITEM_LENGTH,
};
use super::g1::{encode_g1_point, extract_g1_input, G1_INPUT_ITEM_LENGTH};
use crate::{u64_to_address, PrecompileWithAddress};
use crate::{PrecompileError, PrecompileOutput, PrecompileResult};
use blst::{
Expand All @@ -11,21 +8,28 @@ use primitives::Bytes;

/// [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537#specification) BLS12_G1ADD precompile.
pub const PRECOMPILE: PrecompileWithAddress =
PrecompileWithAddress(u64_to_address(G1_ADD_ADDRESS), g1_add);
PrecompileWithAddress(u64_to_address(ADDRESS), g1_add);
/// BLS12_G1ADD precompile address.
pub const ADDRESS: u64 = 0x0b;
/// Base gas fee for BLS12-381 g1_add operation.
const BASE_GAS_FEE: u64 = 375;

/// Input length of g1_add operation.
const INPUT_LENGTH: usize = 256;

/// G1 addition call expects `256` bytes as an input that is interpreted as byte
/// concatenation of two G1 points (`128` bytes each).
/// Output is an encoding of addition operation result - single G1 point (`128`
/// bytes).
/// See also: <https://eips.ethereum.org/EIPS/eip-2537#abi-for-g1-addition>
pub(super) fn g1_add(input: &Bytes, gas_limit: u64) -> PrecompileResult {
if G1_ADD_BASE_GAS_FEE > gas_limit {
if BASE_GAS_FEE > gas_limit {
return Err(PrecompileError::OutOfGas.into());
}

if input.len() != G1_ADD_INPUT_LENGTH {
if input.len() != INPUT_LENGTH {
return Err(PrecompileError::Other(format!(
"G1ADD input should be {G1_ADD_INPUT_LENGTH} bytes, was {}",
"G1ADD input should be {INPUT_LENGTH} bytes, was {}",
input.len()
))
.into());
Expand All @@ -50,5 +54,5 @@ pub(super) fn g1_add(input: &Bytes, gas_limit: u64) -> PrecompileResult {
unsafe { blst_p1_to_affine(&mut p_aff, &p) };

let out = encode_g1_point(&p_aff);
Ok(PrecompileOutput::new(G1_ADD_BASE_GAS_FEE, out))
Ok(PrecompileOutput::new(BASE_GAS_FEE, out))
}
44 changes: 30 additions & 14 deletions crates/precompile/src/bls12_381/g1_msm.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
use super::{
g1::{encode_g1_point, extract_g1_input},
g1::{encode_g1_point, extract_g1_input, G1_INPUT_ITEM_LENGTH},
msm::msm_required_gas,
utils::extract_scalar_input,
};
use crate::bls12_381_const::{
DISCOUNT_TABLE_G1_MSM, G1_INPUT_ITEM_LENGTH, G1_MSM_ADDRESS, G1_MSM_BASE_GAS_FEE,
G1_MSM_INPUT_LENGTH, NBITS, SCALAR_LENGTH,
utils::{extract_scalar_input, NBITS, SCALAR_LENGTH},
};
use crate::{u64_to_address, PrecompileWithAddress};
use crate::{PrecompileError, PrecompileOutput, PrecompileResult};
Expand All @@ -14,7 +10,27 @@ use primitives::Bytes;

/// [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537#specification) BLS12_G1MSM precompile.
pub const PRECOMPILE: PrecompileWithAddress =
PrecompileWithAddress(u64_to_address(G1_MSM_ADDRESS), g1_msm);
PrecompileWithAddress(u64_to_address(ADDRESS), g1_msm);

/// BLS12_G1MSM precompile address.
pub const ADDRESS: u64 = 0x0c;

/// Base gas fee for BLS12-381 g1_mul operation.
pub const BASE_GAS_FEE: u64 = 12000;

/// Input length of g1_mul operation.
pub const INPUT_LENGTH: usize = 160;

/// Discounts table for G1 MSM as a vector of pairs `[k, discount]`.
pub static DISCOUNT_TABLE: [u16; 128] = [
1000, 949, 848, 797, 764, 750, 738, 728, 719, 712, 705, 698, 692, 687, 682, 677, 673, 669, 665,
661, 658, 654, 651, 648, 645, 642, 640, 637, 635, 632, 630, 627, 625, 623, 621, 619, 617, 615,
613, 611, 609, 608, 606, 604, 603, 601, 599, 598, 596, 595, 593, 592, 591, 589, 588, 586, 585,
584, 582, 581, 580, 579, 577, 576, 575, 574, 573, 572, 570, 569, 568, 567, 566, 565, 564, 563,
562, 561, 560, 559, 558, 557, 556, 555, 554, 553, 552, 551, 550, 549, 548, 547, 547, 546, 545,
544, 543, 542, 541, 540, 540, 539, 538, 537, 536, 536, 535, 534, 533, 532, 532, 531, 530, 529,
528, 528, 527, 526, 525, 525, 524, 523, 522, 522, 521, 520, 520, 519,
];

/// Implements EIP-2537 G1MSM precompile.
/// G1 multi-scalar-multiplication call expects `160*k` bytes as an input that is interpreted
Expand All @@ -26,24 +42,24 @@ pub const PRECOMPILE: PrecompileWithAddress =
/// See also: <https://eips.ethereum.org/EIPS/eip-2537#abi-for-g1-multiexponentiation>
pub(super) fn g1_msm(input: &Bytes, gas_limit: u64) -> PrecompileResult {
let input_len = input.len();
if input_len == 0 || input_len % G1_MSM_INPUT_LENGTH != 0 {
if input_len == 0 || input_len % INPUT_LENGTH != 0 {
return Err(PrecompileError::Other(format!(
"G1MSM input length should be multiple of {}, was {}",
G1_MSM_INPUT_LENGTH, input_len
INPUT_LENGTH, input_len
))
.into());
}

let k = input_len / G1_MSM_INPUT_LENGTH;
let required_gas = msm_required_gas(k, &DISCOUNT_TABLE_G1_MSM, G1_MSM_BASE_GAS_FEE);
let k = input_len / INPUT_LENGTH;
let required_gas = msm_required_gas(k, &DISCOUNT_TABLE, BASE_GAS_FEE);
if required_gas > gas_limit {
return Err(PrecompileError::OutOfGas.into());
}

let mut g1_points: Vec<blst_p1> = Vec::with_capacity(k);
let mut scalars: Vec<u8> = Vec::with_capacity(k * SCALAR_LENGTH);
for i in 0..k {
let slice = &input[i * G1_MSM_INPUT_LENGTH..i * G1_MSM_INPUT_LENGTH + G1_INPUT_ITEM_LENGTH];
let slice = &input[i * INPUT_LENGTH..i * INPUT_LENGTH + G1_INPUT_ITEM_LENGTH];

// BLST batch API for p1_affines blows up when you pass it a point at infinity, so we must
// filter points at infinity (and their corresponding scalars) from the input.
Expand All @@ -63,8 +79,8 @@ pub(super) fn g1_msm(input: &Bytes, gas_limit: u64) -> PrecompileResult {

scalars.extend_from_slice(
&extract_scalar_input(
&input[i * G1_MSM_INPUT_LENGTH + G1_INPUT_ITEM_LENGTH
..i * G1_MSM_INPUT_LENGTH + G1_INPUT_ITEM_LENGTH + SCALAR_LENGTH],
&input[i * INPUT_LENGTH + G1_INPUT_ITEM_LENGTH
..i * INPUT_LENGTH + G1_INPUT_ITEM_LENGTH + SCALAR_LENGTH],
)?
.b,
);
Expand Down
9 changes: 7 additions & 2 deletions crates/precompile/src/bls12_381/g2.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
use super::utils::{fp_from_bendian, fp_to_bytes, remove_padding};
use crate::bls12_381_const::{FP_LENGTH, G2_INPUT_ITEM_LENGTH, G2_OUTPUT_LENGTH, PADDED_FP_LENGTH};
use super::utils::{fp_from_bendian, fp_to_bytes, remove_padding, FP_LENGTH, PADDED_FP_LENGTH};
use crate::PrecompileError;
use blst::{blst_fp2, blst_p2_affine, blst_p2_affine_in_g2, blst_p2_affine_on_curve};
use primitives::Bytes;

/// Length of each of the elements in a g2 operation input.
pub(super) const G2_INPUT_ITEM_LENGTH: usize = 256;

/// Output length of a g2 operation.
const G2_OUTPUT_LENGTH: usize = 256;

/// Encodes a G2 point in affine format into byte slice with padded elements.
pub(super) fn encode_g2_point(input: &blst_p2_affine) -> Bytes {
let mut out = vec![0u8; G2_OUTPUT_LENGTH];
Expand Down
22 changes: 13 additions & 9 deletions crates/precompile/src/bls12_381/g2_add.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
use super::g2::{encode_g2_point, extract_g2_input};
use crate::bls12_381_const::{
G2_ADD_ADDRESS, G2_ADD_BASE_GAS_FEE, G2_ADD_INPUT_LENGTH, G2_INPUT_ITEM_LENGTH,
};
use super::g2::{encode_g2_point, extract_g2_input, G2_INPUT_ITEM_LENGTH};
use crate::{u64_to_address, PrecompileWithAddress};
use crate::{PrecompileError, PrecompileOutput, PrecompileResult};
use blst::{
Expand All @@ -11,7 +8,14 @@ use primitives::Bytes;

/// [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537#specification) BLS12_G2ADD precompile.
pub const PRECOMPILE: PrecompileWithAddress =
PrecompileWithAddress(u64_to_address(G2_ADD_ADDRESS), g2_add);
PrecompileWithAddress(u64_to_address(ADDRESS), g2_add);
/// BLS12_G2ADD precompile address.
pub const ADDRESS: u64 = 0x0d;
/// Base gas fee for BLS12-381 g2_add operation.
const BASE_GAS_FEE: u64 = 600;

/// Input length of g2_add operation.
const INPUT_LENGTH: usize = 512;

/// G2 addition call expects `512` bytes as an input that is interpreted as byte
/// concatenation of two G2 points (`256` bytes each).
Expand All @@ -20,13 +24,13 @@ pub const PRECOMPILE: PrecompileWithAddress =
/// bytes).
/// See also <https://eips.ethereum.org/EIPS/eip-2537#abi-for-g2-addition>
pub(super) fn g2_add(input: &Bytes, gas_limit: u64) -> PrecompileResult {
if G2_ADD_BASE_GAS_FEE > gas_limit {
if BASE_GAS_FEE > gas_limit {
return Err(PrecompileError::OutOfGas.into());
}

if input.len() != G2_ADD_INPUT_LENGTH {
if input.len() != INPUT_LENGTH {
return Err(PrecompileError::Other(format!(
"G2ADD input should be {G2_ADD_INPUT_LENGTH} bytes, was {}",
"G2ADD input should be {INPUT_LENGTH} bytes, was {}",
input.len()
))
.into());
Expand All @@ -51,5 +55,5 @@ pub(super) fn g2_add(input: &Bytes, gas_limit: u64) -> PrecompileResult {
unsafe { blst_p2_to_affine(&mut p_aff, &p) };

let out = encode_g2_point(&p_aff);
Ok(PrecompileOutput::new(G2_ADD_BASE_GAS_FEE, out))
Ok(PrecompileOutput::new(BASE_GAS_FEE, out))
}
44 changes: 30 additions & 14 deletions crates/precompile/src/bls12_381/g2_msm.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
use super::{
g2::{encode_g2_point, extract_g2_input},
g2::{encode_g2_point, extract_g2_input, G2_INPUT_ITEM_LENGTH},
msm::msm_required_gas,
utils::extract_scalar_input,
};
use crate::bls12_381_const::{
DISCOUNT_TABLE_G2_MSM, G2_ADD_ADDRESS, G2_ADD_BASE_GAS_FEE, G2_ADD_INPUT_LENGTH,
G2_INPUT_ITEM_LENGTH, NBITS, SCALAR_LENGTH,
utils::{extract_scalar_input, NBITS, SCALAR_LENGTH},
};
use crate::{u64_to_address, PrecompileWithAddress};
use crate::{PrecompileError, PrecompileOutput, PrecompileResult};
Expand All @@ -14,7 +10,27 @@ use primitives::Bytes;

/// [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537#specification) BLS12_G2MSM precompile.
pub const PRECOMPILE: PrecompileWithAddress =
PrecompileWithAddress(u64_to_address(G2_ADD_ADDRESS), g2_msm);
PrecompileWithAddress(u64_to_address(ADDRESS), g2_msm);

/// BLS12_G2MSM precompile address.
pub const ADDRESS: u64 = 0x0e;

/// Base gas fee for BLS12-381 g2_mul operation.
pub const BASE_GAS_FEE: u64 = 22500;

/// Input length of g2_mul operation.
pub const INPUT_LENGTH: usize = 288;

// Discounts table for G2 MSM as a vector of pairs `[k, discount]`:
pub static DISCOUNT_TABLE: [u16; 128] = [
1000, 1000, 923, 884, 855, 832, 812, 796, 782, 770, 759, 749, 740, 732, 724, 717, 711, 704,
699, 693, 688, 683, 679, 674, 670, 666, 663, 659, 655, 652, 649, 646, 643, 640, 637, 634, 632,
629, 627, 624, 622, 620, 618, 615, 613, 611, 609, 607, 606, 604, 602, 600, 598, 597, 595, 593,
592, 590, 589, 587, 586, 584, 583, 582, 580, 579, 578, 576, 575, 574, 573, 571, 570, 569, 568,
567, 566, 565, 563, 562, 561, 560, 559, 558, 557, 556, 555, 554, 553, 552, 552, 551, 550, 549,
548, 547, 546, 545, 545, 544, 543, 542, 541, 541, 540, 539, 538, 537, 537, 536, 535, 535, 534,
533, 532, 532, 531, 530, 530, 529, 528, 528, 527, 526, 526, 525, 524, 524,
];

/// Implements EIP-2537 G2MSM precompile.
/// G2 multi-scalar-multiplication call expects `288*k` bytes as an input that is interpreted
Expand All @@ -26,24 +42,24 @@ pub const PRECOMPILE: PrecompileWithAddress =
/// See also: <https://eips.ethereum.org/EIPS/eip-2537#abi-for-g2-multiexponentiation>
pub(super) fn g2_msm(input: &Bytes, gas_limit: u64) -> PrecompileResult {
let input_len = input.len();
if input_len == 0 || input_len % G2_ADD_INPUT_LENGTH != 0 {
if input_len == 0 || input_len % INPUT_LENGTH != 0 {
return Err(PrecompileError::Other(format!(
"G2MSM input length should be multiple of {}, was {}",
G2_ADD_INPUT_LENGTH, input_len
INPUT_LENGTH, input_len
))
.into());
}

let k = input_len / G2_ADD_INPUT_LENGTH;
let required_gas = msm_required_gas(k, &DISCOUNT_TABLE_G2_MSM, G2_ADD_BASE_GAS_FEE);
let k = input_len / INPUT_LENGTH;
let required_gas = msm_required_gas(k, &DISCOUNT_TABLE, BASE_GAS_FEE);
if required_gas > gas_limit {
return Err(PrecompileError::OutOfGas.into());
}

let mut g2_points: Vec<blst_p2> = Vec::with_capacity(k);
let mut scalars: Vec<u8> = Vec::with_capacity(k * SCALAR_LENGTH);
for i in 0..k {
let slice = &input[i * G2_ADD_INPUT_LENGTH..i * G2_ADD_INPUT_LENGTH + G2_INPUT_ITEM_LENGTH];
let slice = &input[i * INPUT_LENGTH..i * INPUT_LENGTH + G2_INPUT_ITEM_LENGTH];
// BLST batch API for p2_affines blows up when you pass it a point at infinity, so we must
// filter points at infinity (and their corresponding scalars) from the input.
if slice.iter().all(|i| *i == 0) {
Expand All @@ -63,8 +79,8 @@ pub(super) fn g2_msm(input: &Bytes, gas_limit: u64) -> PrecompileResult {

scalars.extend_from_slice(
&extract_scalar_input(
&input[i * G2_ADD_INPUT_LENGTH + G2_INPUT_ITEM_LENGTH
..i * G2_ADD_INPUT_LENGTH + G2_INPUT_ITEM_LENGTH + SCALAR_LENGTH],
&input[i * INPUT_LENGTH + G2_INPUT_ITEM_LENGTH
..i * INPUT_LENGTH + G2_INPUT_ITEM_LENGTH + SCALAR_LENGTH],
)?
.b,
);
Expand Down
19 changes: 13 additions & 6 deletions crates/precompile/src/bls12_381/map_fp2_to_g2.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use super::{g2::check_canonical_fp2, g2::encode_g2_point, utils::remove_padding};
use crate::bls12_381_const::{
MAP_FP2_TO_G2_ADDRESS, MAP_FP2_TO_G2_BASE_GAS_FEE, PADDED_FP2_LENGTH, PADDED_FP_LENGTH,
use super::{
g2::check_canonical_fp2,
g2::encode_g2_point,
utils::{remove_padding, PADDED_FP2_LENGTH, PADDED_FP_LENGTH},
};
use crate::{u64_to_address, PrecompileWithAddress};
use crate::{PrecompileError, PrecompileOutput, PrecompileResult};
Expand All @@ -9,14 +10,20 @@ use primitives::Bytes;

/// [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537#specification) BLS12_MAP_FP2_TO_G2 precompile.
pub const PRECOMPILE: PrecompileWithAddress =
PrecompileWithAddress(u64_to_address(MAP_FP2_TO_G2_ADDRESS), map_fp2_to_g2);
PrecompileWithAddress(u64_to_address(ADDRESS), map_fp2_to_g2);

/// BLS12_MAP_FP2_TO_G2 precompile address.
pub const ADDRESS: u64 = 0x11;

/// Base gas fee for BLS12-381 map_fp2_to_g2 operation.
const BASE_GAS_FEE: u64 = 23800;

/// Field-to-curve call expects 128 bytes as an input that is interpreted as
/// an element of Fp2. Output of this call is 256 bytes and is an encoded G2
/// point.
/// See also: <https://eips.ethereum.org/EIPS/eip-2537#abi-for-mapping-fp2-element-to-g2-point>
pub(super) fn map_fp2_to_g2(input: &Bytes, gas_limit: u64) -> PrecompileResult {
if MAP_FP2_TO_G2_BASE_GAS_FEE > gas_limit {
if BASE_GAS_FEE > gas_limit {
return Err(PrecompileError::OutOfGas.into());
}

Expand All @@ -42,5 +49,5 @@ pub(super) fn map_fp2_to_g2(input: &Bytes, gas_limit: u64) -> PrecompileResult {
unsafe { blst_p2_to_affine(&mut p_aff, &p) };

let out = encode_g2_point(&p_aff);
Ok(PrecompileOutput::new(MAP_FP2_TO_G2_BASE_GAS_FEE, out))
Ok(PrecompileOutput::new(BASE_GAS_FEE, out))
}
17 changes: 11 additions & 6 deletions crates/precompile/src/bls12_381/map_fp_to_g1.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,27 @@
use super::{
g1::encode_g1_point,
utils::{fp_from_bendian, remove_padding},
utils::{fp_from_bendian, remove_padding, PADDED_FP_LENGTH},
};
use crate::bls12_381_const::{MAP_FP_TO_G1_ADDRESS, MAP_FP_TO_G1_BASE_GAS_FEE, PADDED_FP_LENGTH};
use crate::{u64_to_address, PrecompileWithAddress};
use crate::{PrecompileError, PrecompileOutput, PrecompileResult};
use blst::{blst_map_to_g1, blst_p1, blst_p1_affine, blst_p1_to_affine};
use primitives::Bytes;

/// [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537#specification) BLS12_MAP_FP_TO_G1 precompile.
pub const PRECOMPILE: PrecompileWithAddress =
PrecompileWithAddress(u64_to_address(MAP_FP_TO_G1_ADDRESS), map_fp_to_g1);
PrecompileWithAddress(u64_to_address(ADDRESS), map_fp_to_g1);

/// BLS12_MAP_FP_TO_G1 precompile address.
pub const ADDRESS: u64 = 0x10;

/// Base gas fee for BLS12-381 map_fp_to_g1 operation.
const MAP_FP_TO_G1_BASE: u64 = 5500;

/// Field-to-curve call expects 64 bytes as an input that is interpreted as an
/// element of Fp. Output of this call is 128 bytes and is an encoded G1 point.
/// See also: <https://eips.ethereum.org/EIPS/eip-2537#abi-for-mapping-fp-element-to-g1-point>
pub(super) fn map_fp_to_g1(input: &Bytes, gas_limit: u64) -> PrecompileResult {
if MAP_FP_TO_G1_BASE_GAS_FEE > gas_limit {
if MAP_FP_TO_G1_BASE > gas_limit {
return Err(PrecompileError::OutOfGas.into());
}

Expand All @@ -41,7 +46,7 @@ pub(super) fn map_fp_to_g1(input: &Bytes, gas_limit: u64) -> PrecompileResult {
unsafe { blst_p1_to_affine(&mut p_aff, &p) };

let out = encode_g1_point(&p_aff);
Ok(PrecompileOutput::new(MAP_FP_TO_G1_BASE_GAS_FEE, out))
Ok(PrecompileOutput::new(MAP_FP_TO_G1_BASE, out))
}

#[cfg(test)]
Expand All @@ -52,7 +57,7 @@ mod test {
#[test]
fn sanity_test() {
let input = Bytes::from(hex!("000000000000000000000000000000006900000000000000636f6e7472616374595a603f343061cd305a03f40239f5ffff31818185c136bc2595f2aa18e08f17"));
let fail = map_fp_to_g1(&input, MAP_FP_TO_G1_BASE_GAS_FEE);
let fail = map_fp_to_g1(&input, MAP_FP_TO_G1_BASE);
assert_eq!(
fail,
Err(PrecompileError::Other("non-canonical fp value".to_string()).into())
Expand Down
3 changes: 2 additions & 1 deletion crates/precompile/src/bls12_381/msm.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::bls12_381_const::MSM_MULTIPLIER;
/// Amount used to calculate the multi-scalar-multiplication discount
const MSM_MULTIPLIER: u64 = 1000;

/// Implements the gas schedule for G1/G2 Multiscalar-multiplication assuming 30
/// MGas/second, see also: <https://eips.ethereum.org/EIPS/eip-2537#g1g2-multiexponentiation>
Expand Down
Loading