Skip to content

Commit dcd3974

Browse files
authored
curve25519-dalek: add batch montgomery conversion (#722)
1 parent dd5bd10 commit dcd3974

File tree

1 file changed

+47
-0
lines changed

1 file changed

+47
-0
lines changed

curve25519-dalek/src/edwards.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,28 @@ impl EdwardsPoint {
563563
MontgomeryPoint(u.as_bytes())
564564
}
565565

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+
566588
/// Compress this point to `CompressedEdwardsY` format.
567589
pub fn compress(&self) -> CompressedEdwardsY {
568590
let recip = self.Z.invert();
@@ -2189,6 +2211,31 @@ mod test {
21892211
}
21902212
}
21912213

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+
21922239
#[test]
21932240
#[cfg(feature = "alloc")]
21942241
fn vartime_precomputed_vs_nonprecomputed_multiscalar() {

0 commit comments

Comments
 (0)