4
4
5
5
use crate :: { AffinePoint , Field , PrimeCurveParams , point_arithmetic:: PointArithmetic } ;
6
6
use core:: {
7
+ array,
7
8
borrow:: Borrow ,
8
9
iter:: Sum ,
9
10
ops:: { Add , AddAssign , Mul , MulAssign , Neg , Sub , SubAssign } ,
@@ -12,7 +13,7 @@ use elliptic_curve::{
12
13
BatchNormalize , CurveGroup , Error , FieldBytes , FieldBytesSize , PrimeField , PublicKey , Result ,
13
14
Scalar ,
14
15
array:: ArraySize ,
15
- bigint:: ArrayEncoding ,
16
+ bigint:: { ArrayEncoding , ByteArray } ,
16
17
group:: {
17
18
Group , GroupEncoding ,
18
19
prime:: { PrimeCurve , PrimeGroup } ,
@@ -109,46 +110,10 @@ where
109
110
where
110
111
Self : Double ,
111
112
{
112
- let k = Into :: < C :: Uint > :: into ( * k) . to_le_byte_array ( ) ;
113
+ let mut k = Into :: < C :: Uint > :: into ( * k) . to_le_byte_array ( ) ;
114
+ let mut pc = LookupTable :: new ( * self ) ;
113
115
114
- let mut pc = [ Self :: default ( ) ; 16 ] ;
115
- pc[ 0 ] = Self :: IDENTITY ;
116
- pc[ 1 ] = * self ;
117
-
118
- for i in 2 ..16 {
119
- pc[ i] = if i % 2 == 0 {
120
- Double :: double ( & pc[ i / 2 ] )
121
- } else {
122
- pc[ i - 1 ] . add ( self )
123
- } ;
124
- }
125
-
126
- let mut q = Self :: IDENTITY ;
127
- let mut pos = ( <Scalar < C > as PrimeField >:: NUM_BITS . div_ceil ( 8 ) * 8 ) as usize - 4 ;
128
-
129
- loop {
130
- let slot = ( k[ pos >> 3 ] >> ( pos & 7 ) ) & 0xf ;
131
-
132
- let mut t = ProjectivePoint :: IDENTITY ;
133
-
134
- for i in 1 ..16 {
135
- t. conditional_assign (
136
- & pc[ i] ,
137
- Choice :: from ( ( ( slot as usize ^ i) . wrapping_sub ( 1 ) >> 8 ) as u8 & 1 ) ,
138
- ) ;
139
- }
140
-
141
- q = q. add ( & t) ;
142
-
143
- if pos == 0 {
144
- break ;
145
- }
146
-
147
- q = Double :: double ( & Double :: double ( & Double :: double ( & Double :: double ( & q) ) ) ) ;
148
- pos -= 4 ;
149
- }
150
-
151
- q
116
+ lincomb ( array:: from_mut ( & mut k) , array:: from_mut ( & mut pc) )
152
117
}
153
118
}
154
119
@@ -403,15 +368,92 @@ where
403
368
C : PrimeCurveParams ,
404
369
FieldBytes < C > : Copy ,
405
370
{
406
- // TODO(tarcieri): optimized implementation
371
+ #[ cfg( feature = "alloc" ) ]
372
+ fn lincomb ( points_and_scalars : & [ ( Self , Scalar < C > ) ] ) -> Self {
373
+ let ( mut ks, mut pcs) : ( Vec < _ > , Vec < _ > ) = points_and_scalars
374
+ . iter ( )
375
+ . map ( |( point, scalar) | {
376
+ (
377
+ Into :: < C :: Uint > :: into ( * scalar) . to_le_byte_array ( ) ,
378
+ LookupTable :: new ( * point) ,
379
+ )
380
+ } )
381
+ . unzip ( ) ;
382
+
383
+ lincomb :: < C > ( & mut ks, & mut pcs)
384
+ }
407
385
}
408
386
409
387
impl < C , const N : usize > LinearCombination < [ ( Self , Scalar < C > ) ; N ] > for ProjectivePoint < C >
410
388
where
411
389
C : PrimeCurveParams ,
412
390
FieldBytes < C > : Copy ,
413
391
{
414
- // TODO(tarcieri): optimized implementation
392
+ fn lincomb ( points_and_scalars : & [ ( Self , Scalar < C > ) ; N ] ) -> Self {
393
+ let mut ks: [ _ ; N ] = array:: from_fn ( |index| {
394
+ Into :: < C :: Uint > :: into ( points_and_scalars[ index] . 1 ) . to_le_byte_array ( )
395
+ } ) ;
396
+ let mut pcs: [ _ ; N ] = array:: from_fn ( |index| LookupTable :: new ( points_and_scalars[ index] . 0 ) ) ;
397
+
398
+ lincomb :: < C > ( & mut ks, & mut pcs)
399
+ }
400
+ }
401
+
402
+ fn lincomb < C : PrimeCurveParams > (
403
+ ks : & mut [ ByteArray < C :: Uint > ] ,
404
+ pcs : & mut [ LookupTable < C > ] ,
405
+ ) -> ProjectivePoint < C > {
406
+ let mut q = ProjectivePoint :: IDENTITY ;
407
+ let mut pos = ( <Scalar < C > as PrimeField >:: NUM_BITS . div_ceil ( 8 ) * 8 ) as usize - 4 ;
408
+
409
+ loop {
410
+ for ( k, pc) in ks. iter ( ) . zip ( pcs. iter ( ) ) {
411
+ let slot = ( k[ pos >> 3 ] >> ( pos & 7 ) ) & 0xf ;
412
+ q = q. add ( & pc. select ( slot) ) ;
413
+ }
414
+
415
+ if pos == 0 {
416
+ break ;
417
+ }
418
+
419
+ q = Double :: double ( & Double :: double ( & Double :: double ( & Double :: double ( & q) ) ) ) ;
420
+ pos -= 4 ;
421
+ }
422
+
423
+ q
424
+ }
425
+
426
+ struct LookupTable < C : PrimeCurveParams > ( [ ProjectivePoint < C > ; 16 ] ) ;
427
+
428
+ impl < C : PrimeCurveParams > LookupTable < C > {
429
+ fn new ( point : ProjectivePoint < C > ) -> Self {
430
+ let mut pc = [ ProjectivePoint :: default ( ) ; 16 ] ;
431
+ pc[ 0 ] = ProjectivePoint :: IDENTITY ;
432
+ pc[ 1 ] = point;
433
+
434
+ for i in 2 ..16 {
435
+ pc[ i] = if i % 2 == 0 {
436
+ Double :: double ( & pc[ i / 2 ] )
437
+ } else {
438
+ pc[ i - 1 ] . add ( point)
439
+ } ;
440
+ }
441
+
442
+ Self ( pc)
443
+ }
444
+
445
+ fn select ( & self , slot : u8 ) -> ProjectivePoint < C > {
446
+ let mut t = ProjectivePoint :: IDENTITY ;
447
+
448
+ for i in 1 ..16 {
449
+ t. conditional_assign (
450
+ & self . 0 [ i] ,
451
+ Choice :: from ( ( ( slot as usize ^ i) . wrapping_sub ( 1 ) >> 8 ) as u8 & 1 ) ,
452
+ ) ;
453
+ }
454
+
455
+ t
456
+ }
415
457
}
416
458
417
459
impl < C > PrimeGroup for ProjectivePoint < C >
0 commit comments