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
97
98
99
100
101
102
103
104
105
106
107
use snarkvm_curves::traits::{AffineCurve, ProjectiveCurve};
use snarkvm_fields::{FpParameters, One, PrimeField, Zero};
use snarkvm_utilities::biginteger::BigInteger;
#[cfg(feature = "parallel")]
use rayon::prelude::*;
pub struct VariableBaseMSM;
impl VariableBaseMSM {
fn msm_inner<G: AffineCurve>(bases: &[G], scalars: &[<G::ScalarField as PrimeField>::BigInteger]) -> G::Projective {
let c = if scalars.len() < 32 {
3
} else {
(2.0 / 3.0 * (f64::from(scalars.len() as u32)).log2() + 2.0).ceil() as usize
};
let num_bits = <G::ScalarField as PrimeField>::Parameters::MODULUS_BITS as usize;
let fr_one = G::ScalarField::one().into_repr();
let zero = G::zero().into_projective();
let window_starts: Vec<_> = (0..num_bits).step_by(c).collect();
let window_sums: Vec<_> = cfg_into_iter!(window_starts)
.map(|w_start| {
let mut res = zero;
let mut buckets = vec![zero; (1 << c) - 1];
scalars
.iter()
.zip(bases)
.filter(|(s, _)| !s.is_zero())
.for_each(|(&scalar, base)| {
if scalar == fr_one {
if w_start == 0 {
res.add_assign_mixed(base);
}
} else {
let mut scalar = scalar;
scalar.divn(w_start as u32);
let scalar = scalar.as_ref()[0] % (1 << c);
if scalar != 0 {
buckets[(scalar - 1) as usize].add_assign_mixed(&base);
}
}
});
G::Projective::batch_normalization(&mut buckets);
let mut running_sum = G::Projective::zero();
for b in buckets.into_iter().map(|g| g.into_affine()).rev() {
running_sum.add_assign_mixed(&b);
res += &running_sum;
}
res
})
.collect();
let lowest = window_sums.first().unwrap();
window_sums[1..].iter().rev().fold(zero, |mut total, sum_i| {
total += sum_i;
for _ in 0..c {
total.double_in_place();
}
total
}) + lowest
}
pub fn multi_scalar_mul<G: AffineCurve>(
bases: &[G],
scalars: &[<G::ScalarField as PrimeField>::BigInteger],
) -> G::Projective {
Self::msm_inner(bases, scalars)
}
}