Skip to main content

wnaf/
base.rs

1use crate::{WindowSize, WnafScalar, WnafSize, wnaf_multi_exp, wnaf_table};
2use array::Array;
3use core::iter;
4use core::ops::Mul;
5use group::Group;
6
7/// Fixed window table for a group element, precomputed to improve scalar multiplication speed.
8///
9/// By fixing the window size at compile time, we are able to support fully `no_alloc`
10/// stack-allocated operation, and also use the type system to ensure [`WnafBase`] and
11/// [`WnafScalar`] are using the same window size.
12///
13/// Precomputations are guaranteed to only occur once per base and once per scalar. Users should
14/// select their window size based on how long the bases are expected to live; a larger window size
15/// will consume more memory and take longer to precompute, but result in faster scalar
16/// multiplications.
17///
18/// # Examples
19///
20/// ```ignore
21/// type MyWnafBase = WnafBase<ProjectivePoint, U5, U8>;
22/// type MyWnafScalar = WnafScalar<Scalar, U5, U129>;
23///
24/// let base = MyWnafBase::new(ProjectivePoint::GENERATOR);
25/// let scalar = MyWnafScalar::new(&s);
26/// let result = base * scalar;
27/// ```
28///
29/// Note that this pattern requires specifying a fixed window size `W`. This is necessary to ensure
30/// in the type system that the base and scalar `Wnaf`s were computed with the same window
31/// size, allowing the result to be computed infallibly.
32#[derive(Clone, Debug)]
33pub struct WnafBase<G: Group, W: WindowSize> {
34    table: Array<G, W::TableSize>,
35}
36
37impl<G: Group, W: WindowSize> WnafBase<G, W> {
38    /// Computes a window table for the given base with the specified window size `W`.
39    #[inline]
40    pub fn new(base: &G) -> Self {
41        let mut ret = Self::default();
42        ret.init_from_base(base);
43        ret
44    }
45
46    /// Initialize an already allocated window table from the given base.
47    #[inline]
48    pub fn init_from_base(&mut self, base: &G) {
49        wnaf_table(&mut self.table, base, W::USIZE);
50    }
51
52    /// Perform a multiscalar multiplication.
53    ///
54    /// Computes a sum-of-products `aA + bB + ...` in variable time with wNAF multi-exponentiation
55    /// using the interleaved window method, also known as Straus's method.
56    #[must_use]
57    pub fn multiscalar_mul<'a, I>(pairs: I) -> G
58    where
59        G::Scalar: WnafSize,
60        I: Clone + Iterator<Item = (&'a Self, &'a WnafScalar<G::Scalar, W>)>,
61    {
62        wnaf_multi_exp(pairs.map(|(b, s)| (b.table.as_slice(), s.wnaf.as_slice(), s.digits)))
63    }
64}
65
66impl<G: Group, W: WindowSize> Default for WnafBase<G, W> {
67    fn default() -> Self {
68        Self {
69            table: Array::from_fn(|_| G::generator()),
70        }
71    }
72}
73
74impl<G, W> Mul<&WnafScalar<G::Scalar, W>> for &WnafBase<G, W>
75where
76    G: Group<Scalar: WnafSize>,
77    W: WindowSize,
78{
79    type Output = G;
80
81    fn mul(self, rhs: &WnafScalar<G::Scalar, W>) -> Self::Output {
82        WnafBase::multiscalar_mul(iter::once((self, rhs)))
83    }
84}
85
86impl<G, W> Mul<&WnafScalar<G::Scalar, W>> for WnafBase<G, W>
87where
88    G: Group<Scalar: WnafSize>,
89    W: WindowSize,
90{
91    type Output = G;
92
93    #[inline]
94    fn mul(self, rhs: &WnafScalar<G::Scalar, W>) -> Self::Output {
95        &self * rhs
96    }
97}
98
99impl<G, W> Mul<WnafScalar<G::Scalar, W>> for WnafBase<G, W>
100where
101    G: Group<Scalar: WnafSize>,
102    W: WindowSize,
103{
104    type Output = G;
105
106    #[inline]
107    fn mul(self, rhs: WnafScalar<G::Scalar, W>) -> Self::Output {
108        &self * &rhs
109    }
110}