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
use crate::weierstrass::Group;
use crate::weierstrass::curve::CurvePoint;
use crate::weierstrass::CurveParameters;
use crate::integers::MaxGroupSizeUint;
pub(crate) fn peppinger<'a, C: CurveParameters>
(bases: &[CurvePoint<'a, C>], mut scalars: Vec<MaxGroupSizeUint>) -> CurvePoint<'a, C>
{
use crate::representation::*;
debug_assert!(bases.len() == scalars.len());
let c = if bases.len() < 32 {
3u32
} else {
(f64::from(bases.len() as u32)).ln().ceil() as u32
};
let mask = (1u64 << c) - 1u64;
let mut cur = 0;
let num_bits = num_bits(&bases[0].curve.subgroup_order_repr);
let zero_point = CurvePoint::zero(bases[0].curve);
let mut windows = Vec::with_capacity((num_bits / c + 1) as usize);
let mut buckets = Vec::with_capacity((1 << c) - 1);
while cur <= num_bits {
let mut acc = zero_point.clone();
buckets.truncate(0);
buckets.resize((1 << c) - 1, zero_point.clone());
for (s, g) in scalars.iter_mut().zip(bases.iter()) {
let index = (s.as_ref()[0] & mask) as usize;
if index != 0 {
buckets[index - 1].add_assign_mixed(&g);
}
*s >>= c;
}
let mut running_sum = zero_point.clone();
for exp in buckets.iter().rev() {
running_sum.add_assign(exp);
acc.add_assign(&running_sum);
}
windows.push(acc);
cur += c;
}
let mut acc = zero_point.clone();
for window in windows.into_iter().rev() {
for _ in 0..c {
acc.double();
}
acc.add_assign(&window);
}
acc
}