@@ -203,6 +203,61 @@ fn mul_windowed(x: &ProjectivePoint, k: &Scalar) -> ProjectivePoint {
203
203
acc
204
204
}
205
205
206
+ /// Calculates `(x * k + y * l)`.
207
+ pub fn lincomb (
208
+ x : & ProjectivePoint ,
209
+ y : & ProjectivePoint ,
210
+ k : & Scalar ,
211
+ l : & Scalar ,
212
+ ) -> ProjectivePoint {
213
+ let ( k_r1, k_r2) = decompose_scalar ( k) ;
214
+ let ( l_r1, l_r2) = decompose_scalar ( l) ;
215
+ let x_beta = x. endomorphism ( ) ;
216
+ let y_beta = y. endomorphism ( ) ;
217
+
218
+ let k_r1_sign = k_r1. is_high ( ) ;
219
+ let k_r1_c = Scalar :: conditional_select ( & k_r1, & -k_r1, k_r1_sign) ;
220
+ let k_r2_sign = k_r2. is_high ( ) ;
221
+ let k_r2_c = Scalar :: conditional_select ( & k_r2, & -k_r2, k_r2_sign) ;
222
+
223
+ let l_r1_sign = l_r1. is_high ( ) ;
224
+ let l_r1_c = Scalar :: conditional_select ( & l_r1, & -l_r1, l_r1_sign) ;
225
+ let l_r2_sign = l_r2. is_high ( ) ;
226
+ let l_r2_c = Scalar :: conditional_select ( & l_r2, & -l_r2, l_r2_sign) ;
227
+
228
+ let x_table1 = LookupTable :: from ( & ProjectivePoint :: conditional_select ( x, & -x, k_r1_sign) ) ;
229
+ let x_table2 = LookupTable :: from ( & ProjectivePoint :: conditional_select (
230
+ & x_beta, & -x_beta, k_r2_sign,
231
+ ) ) ;
232
+
233
+ let y_table1 = LookupTable :: from ( & ProjectivePoint :: conditional_select ( y, & -y, l_r1_sign) ) ;
234
+ let y_table2 = LookupTable :: from ( & ProjectivePoint :: conditional_select (
235
+ & y_beta, & -y_beta, l_r2_sign,
236
+ ) ) ;
237
+
238
+ let k_digits1 = to_radix_16_half ( & k_r1_c) ;
239
+ let k_digits2 = to_radix_16_half ( & k_r2_c) ;
240
+
241
+ let l_digits1 = to_radix_16_half ( & l_r1_c) ;
242
+ let l_digits2 = to_radix_16_half ( & l_r2_c) ;
243
+
244
+ let mut acc = x_table1. select ( k_digits1[ 32 ] )
245
+ + x_table2. select ( k_digits2[ 32 ] )
246
+ + y_table1. select ( l_digits1[ 32 ] )
247
+ + y_table2. select ( l_digits2[ 32 ] ) ;
248
+ for i in ( 0 ..32 ) . rev ( ) {
249
+ for _j in 0 ..4 {
250
+ acc = acc. double ( ) ;
251
+ }
252
+
253
+ acc += & x_table1. select ( k_digits1[ i] ) ;
254
+ acc += & x_table2. select ( k_digits2[ i] ) ;
255
+ acc += & y_table1. select ( l_digits1[ i] ) ;
256
+ acc += & y_table2. select ( l_digits2[ i] ) ;
257
+ }
258
+ acc
259
+ }
260
+
206
261
impl Mul < Scalar > for ProjectivePoint {
207
262
type Output = ProjectivePoint ;
208
263
@@ -238,3 +293,23 @@ impl MulAssign<&Scalar> for ProjectivePoint {
238
293
* self = mul_windowed ( self , rhs) ;
239
294
}
240
295
}
296
+
297
+ #[ cfg( test) ]
298
+ mod tests {
299
+ use super :: lincomb;
300
+ use crate :: arithmetic:: { ProjectivePoint , Scalar } ;
301
+ use elliptic_curve:: rand_core:: OsRng ;
302
+ use elliptic_curve:: { Field , Group } ;
303
+
304
+ #[ test]
305
+ fn test_lincomb ( ) {
306
+ let x = ProjectivePoint :: random ( & mut OsRng ) ;
307
+ let y = ProjectivePoint :: random ( & mut OsRng ) ;
308
+ let k = Scalar :: random ( & mut OsRng ) ;
309
+ let l = Scalar :: random ( & mut OsRng ) ;
310
+
311
+ let reference = & x * & k + & y * & l;
312
+ let test = lincomb ( & x, & y, & k, & l) ;
313
+ assert_eq ! ( reference, test) ;
314
+ }
315
+ }
0 commit comments