@@ -563,6 +563,28 @@ impl EdwardsPoint {
563
563
MontgomeryPoint ( u. as_bytes ( ) )
564
564
}
565
565
566
+ /// Converts a large batch of points to Edwards at once. This has the same
567
+ /// behavior on identity elements as [`Self::to_montgomery`].
568
+ #[ cfg( feature = "alloc" ) ]
569
+ pub fn to_montgomery_batch ( eds : & [ Self ] ) -> Vec < MontgomeryPoint > {
570
+ // Do the same thing as the above function. u = (1+y)/(1-y) = (Z+Y)/(Z-Y).
571
+ // We will do this in a batch, ie compute (Z-Y) for all the input
572
+ // points, then invert them all at once
573
+
574
+ // Compute the denominators in a batch
575
+ let mut denominators = eds. iter ( ) . map ( |p| & p. Z - & p. Y ) . collect :: < Vec < _ > > ( ) ;
576
+ FieldElement :: batch_invert ( & mut denominators) ;
577
+
578
+ // Now compute the Montgomery u coordinate for every point
579
+ let mut ret = Vec :: with_capacity ( eds. len ( ) ) ;
580
+ for ( ed, d) in eds. iter ( ) . zip ( denominators. iter ( ) ) {
581
+ let u = & ( & ed. Z + & ed. Y ) * d;
582
+ ret. push ( MontgomeryPoint ( u. as_bytes ( ) ) ) ;
583
+ }
584
+
585
+ ret
586
+ }
587
+
566
588
/// Compress this point to `CompressedEdwardsY` format.
567
589
pub fn compress ( & self ) -> CompressedEdwardsY {
568
590
let recip = self . Z . invert ( ) ;
@@ -2189,6 +2211,31 @@ mod test {
2189
2211
}
2190
2212
}
2191
2213
2214
+ #[ test]
2215
+ #[ cfg( feature = "alloc" ) ]
2216
+ fn batch_to_montgomery ( ) {
2217
+ let mut rng = rand:: thread_rng ( ) ;
2218
+
2219
+ let scalars = ( 0 ..128 )
2220
+ . map ( |_| Scalar :: random ( & mut rng) )
2221
+ . collect :: < Vec < _ > > ( ) ;
2222
+
2223
+ let points = scalars
2224
+ . iter ( )
2225
+ . map ( EdwardsPoint :: mul_base)
2226
+ . collect :: < Vec < _ > > ( ) ;
2227
+
2228
+ let single_monts = points
2229
+ . iter ( )
2230
+ . map ( EdwardsPoint :: to_montgomery)
2231
+ . collect :: < Vec < _ > > ( ) ;
2232
+
2233
+ for i in [ 0 , 1 , 2 , 3 , 10 , 50 , 128 ] {
2234
+ let invs = EdwardsPoint :: to_montgomery_batch ( & points[ ..i] ) ;
2235
+ assert_eq ! ( & invs, & single_monts[ ..i] ) ;
2236
+ }
2237
+ }
2238
+
2192
2239
#[ test]
2193
2240
#[ cfg( feature = "alloc" ) ]
2194
2241
fn vartime_precomputed_vs_nonprecomputed_multiscalar ( ) {
0 commit comments