forked from bluealloy/revm
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathg1_msm.rs
96 lines (82 loc) · 4.23 KB
/
g1_msm.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
use super::{
g1::{encode_g1_point, extract_g1_input},
msm::msm_required_gas,
utils::extract_scalar_input
};
use crate::{u64_to_address, PrecompileWithAddress};
use crate::{PrecompileError, PrecompileOutput, PrecompileResult};
use blst::{blst_p1, blst_p1_affine, blst_p1_from_affine, blst_p1_to_affine, p1_affines};
use primitives::Bytes;
use crate::bls12_381::bls12_381_const::{G1_MSM_ADDRESS, G1_MSM_BASE_GAS_FEE, G1_MSM_INPUT_LENGTH, G1_INPUT_ITEM_LENGTH,UTILS_SCALAR_LENGTH, UTILS_NBITS};
/// [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);
/// 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
/// as byte concatenation of `k` slices each of them being a byte concatenation
/// of encoding of G1 point (`128` bytes) and encoding of a scalar value (`32`
/// bytes).
/// Output is an encoding of multi-scalar-multiplication operation result - single G1
/// point (`128` bytes).
/// 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 {
return Err(PrecompileError::Other(format!(
"G1MSM input length should be multiple of {}, was {}",
G1_MSM_INPUT_LENGTH, input_len
))
.into());
}
let k = input_len / G1_MSM_INPUT_LENGTH;
let required_gas = msm_required_gas(k, &DISCOUNT_TABLE, G1_MSM_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 * UTILS_SCALAR_LENGTH);
for i in 0..k {
let slice = &input[i * G1_MSM_INPUT_LENGTH..i * G1_MSM_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.
if slice.iter().all(|i| *i == 0) {
continue;
}
// NB: Scalar multiplications, MSMs and pairings MUST perform a subgroup check.
//
// So we set the subgroup_check flag to `true`
let p0_aff = &extract_g1_input(slice, true)?;
let mut p0 = blst_p1::default();
// SAFETY: `p0` and `p0_aff` are blst values.
unsafe { blst_p1_from_affine(&mut p0, p0_aff) };
g1_points.push(p0);
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 + UTILS_SCALAR_LENGTH],
)?
.b,
);
}
// Return infinity point if all points are infinity
if g1_points.is_empty() {
return Ok(PrecompileOutput::new(required_gas, [0; 128].into()));
}
let points = p1_affines::from(&g1_points);
let multiexp = points.mult(&scalars, UTILS_NBITS);
let mut multiexp_aff = blst_p1_affine::default();
// SAFETY: `multiexp_aff` and `multiexp` are blst values.
unsafe { blst_p1_to_affine(&mut multiexp_aff, &multiexp) };
let out = encode_g1_point(&multiexp_aff);
Ok(PrecompileOutput::new(required_gas, out))
}