13
13
14
14
#![ allow( non_snake_case) ]
15
15
16
+ #[ cfg( feature = "alloc" ) ]
16
17
use alloc:: vec:: Vec ;
17
18
19
+ #[ cfg( feature = "alloc" ) ]
18
20
use core:: borrow:: Borrow ;
19
- use core:: cmp:: Ordering ;
20
21
22
+ use crate :: backend:: serial:: curve_models:: ProjectiveNielsPoint ;
21
23
use crate :: edwards:: EdwardsPoint ;
22
24
use crate :: scalar:: Scalar ;
25
+ use crate :: traits:: Identity ;
23
26
use crate :: traits:: MultiscalarMul ;
27
+ #[ cfg( feature = "alloc" ) ]
24
28
use crate :: traits:: VartimeMultiscalarMul ;
29
+ use crate :: window:: LookupTable ;
25
30
26
31
/// Perform multiscalar multiplication by the interleaved window
27
32
/// method, also known as Straus' method (since it was apparently
@@ -49,68 +54,26 @@ pub struct Straus {}
49
54
impl MultiscalarMul for Straus {
50
55
type Point = EdwardsPoint ;
51
56
52
- /// Constant-time Straus using a fixed window of size \\(4\\).
53
- ///
54
- /// Our goal is to compute
55
- /// \\[
56
- /// Q = s_1 P_1 + \cdots + s_n P_n.
57
- /// \\]
58
- ///
59
- /// For each point \\( P_i \\), precompute a lookup table of
60
- /// \\[
61
- /// P_i, 2P_i, 3P_i, 4P_i, 5P_i, 6P_i, 7P_i, 8P_i.
62
- /// \\]
63
- ///
64
- /// For each scalar \\( s_i \\), compute its radix-\\(2^4\\)
65
- /// signed digits \\( s_{i,j} \\), i.e.,
66
- /// \\[
67
- /// s_i = s_{i,0} + s_{i,1} 16^1 + ... + s_{i,63} 16^{63},
68
- /// \\]
69
- /// with \\( -8 \leq s_{i,j} < 8 \\). Since \\( 0 \leq |s_{i,j}|
70
- /// \leq 8 \\), we can retrieve \\( s_{i,j} P_i \\) from the
71
- /// lookup table with a conditional negation: using signed
72
- /// digits halves the required table size.
73
- ///
74
- /// Then as in the single-base fixed window case, we have
75
- /// \\[
76
- /// \begin{aligned}
77
- /// s_i P_i &= P_i (s_{i,0} + s_{i,1} 16^1 + \cdots + s_{i,63} 16^{63}) \\\\
78
- /// s_i P_i &= P_i s_{i,0} + P_i s_{i,1} 16^1 + \cdots + P_i s_{i,63} 16^{63} \\\\
79
- /// s_i P_i &= P_i s_{i,0} + 16(P_i s_{i,1} + 16( \cdots +16P_i s_{i,63})\cdots )
80
- /// \end{aligned}
81
- /// \\]
82
- /// so each \\( s_i P_i \\) can be computed by alternately adding
83
- /// a precomputed multiple \\( P_i s_{i,j} \\) of \\( P_i \\) and
84
- /// repeatedly doubling.
85
- ///
86
- /// Now consider the two-dimensional sum
87
- /// \\[
88
- /// \begin{aligned}
89
- /// s\_1 P\_1 &=& P\_1 s\_{1,0} &+& 16 (P\_1 s\_{1,1} &+& 16 ( \cdots &+& 16 P\_1 s\_{1,63}&) \cdots ) \\\\
90
- /// + & & + & & + & & & & + & \\\\
91
- /// s\_2 P\_2 &=& P\_2 s\_{2,0} &+& 16 (P\_2 s\_{2,1} &+& 16 ( \cdots &+& 16 P\_2 s\_{2,63}&) \cdots ) \\\\
92
- /// + & & + & & + & & & & + & \\\\
93
- /// \vdots & & \vdots & & \vdots & & & & \vdots & \\\\
94
- /// + & & + & & + & & & & + & \\\\
95
- /// s\_n P\_n &=& P\_n s\_{n,0} &+& 16 (P\_n s\_{n,1} &+& 16 ( \cdots &+& 16 P\_n s\_{n,63}&) \cdots )
96
- /// \end{aligned}
97
- /// \\]
98
- /// The sum of the left-hand column is the result \\( Q \\); by
99
- /// computing the two-dimensional sum on the right column-wise,
100
- /// top-to-bottom, then right-to-left, we need to multiply by \\(
101
- /// 16\\) only once per column, sharing the doublings across all
102
- /// of the input points.
103
- fn multiscalar_mul < I , J > ( scalars : I , points : J ) -> EdwardsPoint
57
+ fn multiscalar_mul < const N : usize > (
58
+ scalars : & [ Scalar ; N ] ,
59
+ points : & [ EdwardsPoint ; N ] ,
60
+ ) -> EdwardsPoint {
61
+ let lookup_tables: [ _ ; N ] =
62
+ core:: array:: from_fn ( |index| LookupTable :: < ProjectiveNielsPoint > :: from ( & points[ index] ) ) ;
63
+
64
+ let scalar_digits: [ _ ; N ] = core:: array:: from_fn ( |index| scalars[ index] . as_radix_16 ( ) ) ;
65
+
66
+ multiscalar_mul ( & scalar_digits, & lookup_tables)
67
+ }
68
+
69
+ #[ cfg( feature = "alloc" ) ]
70
+ fn multiscalar_alloc_mul < I , J > ( scalars : I , points : J ) -> EdwardsPoint
104
71
where
105
72
I : IntoIterator ,
106
73
I :: Item : Borrow < Scalar > ,
107
74
J : IntoIterator ,
108
75
J :: Item : Borrow < EdwardsPoint > ,
109
76
{
110
- use crate :: backend:: serial:: curve_models:: ProjectiveNielsPoint ;
111
- use crate :: traits:: Identity ;
112
- use crate :: window:: LookupTable ;
113
-
114
77
let lookup_tables: Vec < _ > = points
115
78
. into_iter ( )
116
79
. map ( |point| LookupTable :: < ProjectiveNielsPoint > :: from ( point. borrow ( ) ) )
@@ -125,25 +88,86 @@ impl MultiscalarMul for Straus {
125
88
. map ( |s| s. borrow ( ) . as_radix_16 ( ) )
126
89
. collect ( ) ;
127
90
128
- let mut Q = EdwardsPoint :: identity ( ) ;
129
- for j in ( 0 ..64 ) . rev ( ) {
130
- Q = Q . mul_by_pow_2 ( 4 ) ;
131
- let it = scalar_digits. iter ( ) . zip ( lookup_tables. iter ( ) ) ;
132
- for ( s_i, lookup_table_i) in it {
133
- // R_i = s_{i,j} * P_i
134
- let R_i = lookup_table_i. select ( s_i[ j] ) ;
135
- // Q = Q + R_i
136
- Q = ( & Q + & R_i ) . as_extended ( ) ;
137
- }
138
- }
91
+ let Q = multiscalar_mul ( & scalar_digits, & lookup_tables) ;
139
92
140
93
#[ cfg( feature = "zeroize" ) ]
141
- zeroize:: Zeroize :: zeroize ( & mut scalar_digits) ;
94
+ zeroize:: Zeroize :: zeroize ( & mut scalar_digits. iter_mut ( ) ) ;
142
95
143
96
Q
144
97
}
145
98
}
146
99
100
+ /// Constant-time Straus using a fixed window of size \\(4\\).
101
+ ///
102
+ /// Our goal is to compute
103
+ /// \\[
104
+ /// Q = s_1 P_1 + \cdots + s_n P_n.
105
+ /// \\]
106
+ ///
107
+ /// For each point \\( P_i \\), precompute a lookup table of
108
+ /// \\[
109
+ /// P_i, 2P_i, 3P_i, 4P_i, 5P_i, 6P_i, 7P_i, 8P_i.
110
+ /// \\]
111
+ ///
112
+ /// For each scalar \\( s_i \\), compute its radix-\\(2^4\\)
113
+ /// signed digits \\( s_{i,j} \\), i.e.,
114
+ /// \\[
115
+ /// s_i = s_{i,0} + s_{i,1} 16^1 + ... + s_{i,63} 16^{63},
116
+ /// \\]
117
+ /// with \\( -8 \leq s_{i,j} < 8 \\). Since \\( 0 \leq |s_{i,j}|
118
+ /// \leq 8 \\), we can retrieve \\( s_{i,j} P_i \\) from the
119
+ /// lookup table with a conditional negation: using signed
120
+ /// digits halves the required table size.
121
+ ///
122
+ /// Then as in the single-base fixed window case, we have
123
+ /// \\[
124
+ /// \begin{aligned}
125
+ /// s_i P_i &= P_i (s_{i,0} + s_{i,1} 16^1 + \cdots + s_{i,63} 16^{63}) \\\\
126
+ /// s_i P_i &= P_i s_{i,0} + P_i s_{i,1} 16^1 + \cdots + P_i s_{i,63} 16^{63} \\\\
127
+ /// s_i P_i &= P_i s_{i,0} + 16(P_i s_{i,1} + 16( \cdots +16P_i s_{i,63})\cdots )
128
+ /// \end{aligned}
129
+ /// \\]
130
+ /// so each \\( s_i P_i \\) can be computed by alternately adding
131
+ /// a precomputed multiple \\( P_i s_{i,j} \\) of \\( P_i \\) and
132
+ /// repeatedly doubling.
133
+ ///
134
+ /// Now consider the two-dimensional sum
135
+ /// \\[
136
+ /// \begin{aligned}
137
+ /// s\_1 P\_1 &=& P\_1 s\_{1,0} &+& 16 (P\_1 s\_{1,1} &+& 16 ( \cdots &+& 16 P\_1 s\_{1,63}&) \cdots ) \\\\
138
+ /// + & & + & & + & & & & + & \\\\
139
+ /// s\_2 P\_2 &=& P\_2 s\_{2,0} &+& 16 (P\_2 s\_{2,1} &+& 16 ( \cdots &+& 16 P\_2 s\_{2,63}&) \cdots ) \\\\
140
+ /// + & & + & & + & & & & + & \\\\
141
+ /// \vdots & & \vdots & & \vdots & & & & \vdots & \\\\
142
+ /// + & & + & & + & & & & + & \\\\
143
+ /// s\_n P\_n &=& P\_n s\_{n,0} &+& 16 (P\_n s\_{n,1} &+& 16 ( \cdots &+& 16 P\_n s\_{n,63}&) \cdots )
144
+ /// \end{aligned}
145
+ /// \\]
146
+ /// The sum of the left-hand column is the result \\( Q \\); by
147
+ /// computing the two-dimensional sum on the right column-wise,
148
+ /// top-to-bottom, then right-to-left, we need to multiply by \\(
149
+ /// 16\\) only once per column, sharing the doublings across all
150
+ /// of the input points.
151
+ fn multiscalar_mul (
152
+ scalar_digits : & [ [ i8 ; 64 ] ] ,
153
+ lookup_tables : & [ LookupTable < ProjectiveNielsPoint > ] ,
154
+ ) -> EdwardsPoint {
155
+ let mut Q = EdwardsPoint :: identity ( ) ;
156
+ for j in ( 0 ..64 ) . rev ( ) {
157
+ Q = Q . mul_by_pow_2 ( 4 ) ;
158
+ let it = scalar_digits. iter ( ) . zip ( lookup_tables. iter ( ) ) ;
159
+ for ( s_i, lookup_table_i) in it {
160
+ // R_i = s_{i,j} * P_i
161
+ let R_i = lookup_table_i. select ( s_i[ j] ) ;
162
+ // Q = Q + R_i
163
+ Q = ( & Q + & R_i ) . as_extended ( ) ;
164
+ }
165
+ }
166
+
167
+ Q
168
+ }
169
+
170
+ #[ cfg( feature = "alloc" ) ]
147
171
impl VartimeMultiscalarMul for Straus {
148
172
type Point = EdwardsPoint ;
149
173
@@ -167,6 +191,7 @@ impl VartimeMultiscalarMul for Straus {
167
191
} ;
168
192
use crate :: traits:: Identity ;
169
193
use crate :: window:: NafLookupTable5 ;
194
+ use core:: cmp:: Ordering ;
170
195
171
196
let nafs: Vec < _ > = scalars
172
197
. into_iter ( )
0 commit comments