Skip to content

Commit 650ab60

Browse files
committed
Use optimized map_to_curve_elligator2_curve448()
1 parent 538020d commit 650ab60

File tree

2 files changed

+184
-53
lines changed

2 files changed

+184
-53
lines changed

ed448-goldilocks/src/edwards/affine.rs

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -86,36 +86,36 @@ impl AffinePoint {
8686
}
8787
}
8888

89-
pub(crate) fn isogeny(&self) -> Self {
90-
let x = self.x;
91-
let y = self.y;
92-
let mut t0 = x.square(); // x^2
93-
let t1 = t0 + FieldElement::ONE; // x^2+1
94-
t0 -= FieldElement::ONE; // x^2-1
95-
let mut t2 = y.square(); // y^2
96-
t2 = t2.double(); // 2y^2
97-
let t3 = x.double(); // 2x
98-
99-
let mut t4 = t0 * y; // y(x^2-1)
100-
t4 = t4.double(); // 2y(x^2-1)
101-
let xNum = t4.double(); // xNum = 4y(x^2-1)
102-
103-
let mut t5 = t0.square(); // x^4-2x^2+1
104-
t4 = t5 + t2; // x^4-2x^2+1+2y^2
105-
let xDen = t4 + t2; // xDen = x^4-2x^2+1+4y^2
106-
107-
t5 *= x; // x^5-2x^3+x
108-
t4 = t2 * t3; // 4xy^2
109-
let yNum = t4 - t5; // yNum = -(x^5-2x^3+x-4xy^2)
110-
111-
t4 = t1 * t2; // 2x^2y^2+2y^2
112-
let yDen = t5 - t4; // yDen = x^5-2x^3+x-2x^2y^2-2y^2
113-
114-
Self {
115-
x: xNum * xDen.invert(),
116-
y: yNum * yDen.invert(),
117-
}
118-
}
89+
// pub(crate) fn isogeny(&self) -> Self {
90+
// let x = self.x;
91+
// let y = self.y;
92+
// let mut t0 = x.square(); // x^2
93+
// let t1 = t0 + FieldElement::ONE; // x^2+1
94+
// t0 -= FieldElement::ONE; // x^2-1
95+
// let mut t2 = y.square(); // y^2
96+
// t2 = t2.double(); // 2y^2
97+
// let t3 = x.double(); // 2x
98+
99+
// let mut t4 = t0 * y; // y(x^2-1)
100+
// t4 = t4.double(); // 2y(x^2-1)
101+
// let xNum = t4.double(); // xNum = 4y(x^2-1)
102+
103+
// let mut t5 = t0.square(); // x^4-2x^2+1
104+
// t4 = t5 + t2; // x^4-2x^2+1+2y^2
105+
// let xDen = t4 + t2; // xDen = x^4-2x^2+1+4y^2
106+
107+
// t5 *= x; // x^5-2x^3+x
108+
// t4 = t2 * t3; // 4xy^2
109+
// let yNum = t4 - t5; // yNum = -(x^5-2x^3+x-4xy^2)
110+
111+
// t4 = t1 * t2; // 2x^2y^2+2y^2
112+
// let yDen = t5 - t4; // yDen = x^5-2x^3+x-2x^2y^2-2y^2
113+
114+
// Self {
115+
// x: xNum * xDen.invert(),
116+
// y: yNum * yDen.invert(),
117+
// }
118+
// }
119119

120120
/// Standard compression; store Y and sign of X
121121
pub fn compress(&self) -> CompressedEdwardsY {

ed448-goldilocks/src/field/element.rs

Lines changed: 154 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
44

55
use super::{ConstMontyType, MODULUS};
66
use crate::{
7-
AffinePoint, Decaf448, DecafPoint, Ed448, EdwardsPoint,
7+
Decaf448, DecafPoint, Ed448, EdwardsPoint,
88
curve::twedwards::extended::ExtendedPoint as TwistedExtendedPoint,
99
};
1010
use elliptic_curve::ops::Reduce;
@@ -198,7 +198,7 @@ impl MapToCurve for Ed448 {
198198
type ScalarLength = U84;
199199

200200
fn map_to_curve(element: FieldElement) -> Self::CurvePoint {
201-
element.map_to_curve_elligator2().isogeny().to_edwards()
201+
element.map_to_curve_elligator2_edwards448()
202202
}
203203

204204
fn map_to_subgroup(point: EdwardsPoint) -> EdwardsPoint {
@@ -319,6 +319,11 @@ impl FieldElement {
319319
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffffffffffffffffffffffffffffffffffffffffffffffffffffe",
320320
)));
321321
pub const ZERO: Self = Self(ConstMontyType::new(&U448::ZERO));
322+
// See https://www.rfc-editor.org/rfc/rfc9380.html#name-curve448-q-3-mod-4-k-1.
323+
// 1. c1 = (q - 3) / 4 # Integer arithmetic
324+
const C1: U448 = U448::from_be_hex(
325+
"3fffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffffffffffffffffffffffffffffffffffffffffffffffffffffff",
326+
);
322327

323328
pub fn is_negative(&self) -> Choice {
324329
self.0.retrieve().is_odd()
@@ -441,27 +446,153 @@ impl FieldElement {
441446
Self(self.0.div_by_2())
442447
}
443448

444-
pub(crate) fn map_to_curve_elligator2(&self) -> AffinePoint {
445-
let mut t1 = self.square(); // 1. t1 = u^2
446-
t1 *= Self::Z; // 2. t1 = Z * t1 // Z * u^2
447-
let e1 = t1.ct_eq(&Self::MINUS_ONE); // 3. e1 = t1 == -1 // exceptional case: Z * u^2 == -1
448-
t1.conditional_assign(&Self::ZERO, e1); // 4. t1 = CMOV(t1, 0, e1) // if t1 == -1, set t1 = 0
449-
let mut x1 = t1 + Self::ONE; // 5. x1 = t1 + 1
450-
x1 = x1.invert(); // 6. x1 = inv0(x1)
451-
x1 *= -Self::J; // 7. x1 = -A * x1 // x1 = -A / (1 + Z * u^2)
452-
let mut gx1 = x1 + Self::J; // 8. gx1 = x1 + A
453-
gx1 *= x1; // 9. gx1 = gx1 * x1
454-
gx1 += Self::ONE; // 10. gx1 = gx1 + B
455-
gx1 *= x1; // 11. gx1 = gx1 * x1 // gx1 = x1^3 + A * x1^2 + B * x1
456-
let x2 = -x1 - Self::J; // 12. x2 = -x1 - A
457-
let gx2 = t1 * gx1; // 13. gx2 = t1 * gx1
458-
let e2 = gx1.is_square(); // 14. e2 = is_square(gx1)
459-
let x = Self::conditional_select(&x2, &x1, e2); // 15. x = CMOV(x2, x1, e2) // If is_square(gx1), x = x1, else x = x2
460-
let y2 = Self::conditional_select(&gx2, &gx1, e2); // 16. y2 = CMOV(gx2, gx1, e2) // If is_square(gx1), y2 = gx1, else y2 = gx2
461-
let mut y = y2.sqrt(); // 17. y = sqrt(y2)
462-
let e3 = y.is_negative(); // 18. e3 = sgn0(y) == 1
463-
y.conditional_negate(e2 ^ e3); // y = CMOV(-y, y, e2 xor e3)
464-
AffinePoint { x, y }
449+
// See https://www.rfc-editor.org/rfc/rfc9380.html#name-curve448-q-3-mod-4-k-1.
450+
pub(crate) fn map_to_curve_elligator2_curve448(
451+
&self,
452+
) -> (FieldElement, FieldElement, FieldElement) {
453+
// 1. tv1 = u^2
454+
let mut tv1 = self.square();
455+
// 2. e1 = tv1 == 1
456+
let e1 = tv1.ct_eq(&FieldElement::ONE);
457+
// 3. tv1 = CMOV(tv1, 0, e1) # If Z * u^2 == -1, set tv1 = 0
458+
tv1.conditional_assign(&FieldElement::ZERO, e1);
459+
// 4. xd = 1 - tv1
460+
let xd = FieldElement::ONE - tv1;
461+
// 5. x1n = -J
462+
let x1n = -Self::J;
463+
// 6. tv2 = xd^2
464+
let tv2 = xd.square();
465+
// 7. gxd = tv2 * xd # gxd = xd^3
466+
let gxd = tv2 * xd;
467+
// 8. gx1 = -J * tv1 # x1n + J * xd
468+
let mut gx1 = x1n * tv1;
469+
// 9. gx1 = gx1 * x1n # x1n^2 + J * x1n * xd
470+
gx1 *= x1n;
471+
// 10. gx1 = gx1 + tv2 # x1n^2 + J * x1n * xd + xd^2
472+
gx1 += tv2;
473+
// 11. gx1 = gx1 * x1n # x1n^3 + J * x1n^2 * xd + x1n * xd^2
474+
gx1 *= x1n;
475+
// 12. tv3 = gxd^2
476+
let tv3 = gxd.square();
477+
// 13. tv2 = gx1 * gxd # gx1 * gxd
478+
let tv2 = gx1 * gxd;
479+
// 14. tv3 = tv3 * tv2 # gx1 * gxd^3
480+
let tv3 = tv3 * tv2;
481+
// 15. y1 = tv3^c1 # (gx1 * gxd^3)^((p - 3) / 4)
482+
let mut y1 = FieldElement(tv3.0.pow(&Self::C1));
483+
// 16. y1 = y1 * tv2 # gx1 * gxd * (gx1 * gxd^3)^((p - 3) / 4)
484+
y1 *= tv2;
485+
// 17. x2n = -tv1 * x1n # x2 = x2n / xd = -1 * u^2 * x1n / xd
486+
let x2n = -tv1 * x1n;
487+
// 18. y2 = y1 * u
488+
let mut y2 = y1 * self;
489+
// 19. y2 = CMOV(y2, 0, e1)
490+
y2.conditional_assign(&FieldElement::ZERO, e1);
491+
// 20. tv2 = y1^2
492+
let mut tv2 = y1.square();
493+
// 21. tv2 = tv2 * gxd
494+
tv2 *= gxd;
495+
// 22. e2 = tv2 == gx1
496+
let e2 = tv2.ct_eq(&gx1);
497+
// 23. xn = CMOV(x2n, x1n, e2) # If e2, x = x1, else x = x2
498+
let xn = FieldElement::conditional_select(&x2n, &x1n, e2);
499+
// 24. y = CMOV(y2, y1, e2) # If e2, y = y1, else y = y2
500+
let mut y = FieldElement::conditional_select(&y2, &y1, e2);
501+
// 25. e3 = sgn0(y) == 1 # Fix sign of y
502+
let e3 = y.is_negative();
503+
// 26. y = CMOV(y, -y, e2 XOR e3)
504+
y.conditional_negate(e2 ^ e3);
505+
// 27. return (xn, xd, y, 1)
506+
507+
(xn, xd, y)
508+
}
509+
510+
fn map_to_curve_elligator2_edwards448(&self) -> EdwardsPoint {
511+
// 1. (xn, xd, yn, yd) = map_to_curve_elligator2_curve448(u)
512+
let (xn, xd, yn) = self.map_to_curve_elligator2_curve448();
513+
// 2. xn2 = xn^2
514+
let xn2 = xn.square();
515+
// 3. xd2 = xd^2
516+
let xd2 = xd.square();
517+
// 4. xd4 = xd2^2
518+
let xd4 = xd2.square();
519+
// 5. yn2 = yn^2
520+
let yn2 = yn.square();
521+
// 6. yd2 = yd^2
522+
let yd2 = FieldElement::ONE;
523+
// 7. xEn = xn2 - xd2
524+
let mut xEn = xn2 - xd2;
525+
// 8. tv2 = xEn - xd2
526+
let mut tv2 = xEn - xd2;
527+
// 9. xEn = xEn * xd2
528+
xEn *= xd2;
529+
// 10. xEn = xEn * yd
530+
// SKIP: yd = 1
531+
// 11. xEn = xEn * yn
532+
xEn *= yn;
533+
// 12. xEn = xEn * 4
534+
xEn = xEn.double().double();
535+
// 13. tv2 = tv2 * xn2
536+
tv2 *= xn2;
537+
// 14. tv2 = tv2 * yd2
538+
// SKIP: yd2 = 1
539+
// 15. tv3 = 4 * yn2
540+
let tv3 = yn2.double().double();
541+
// 16. tv1 = tv3 + yd2
542+
let mut tv1 = tv3 + yd2;
543+
// 17. tv1 = tv1 * xd4
544+
tv1 *= xd4;
545+
// 18. xEd = tv1 + tv2
546+
let mut xEd = tv1 + tv2;
547+
// 19. tv2 = tv2 * xn
548+
tv2 *= xn;
549+
// 20. tv4 = xn * xd4
550+
let tv4 = xn * xd4;
551+
// 21. yEn = tv3 - yd2
552+
let mut yEn = tv3 - yd2;
553+
// 22. yEn = yEn * tv4
554+
yEn *= tv4;
555+
// 23. yEn = yEn - tv2
556+
yEn -= tv2;
557+
// 24. tv1 = xn2 + xd2
558+
let mut tv1 = xn2 + xd2;
559+
// 25. tv1 = tv1 * xd2
560+
tv1 *= xd2;
561+
// 26. tv1 = tv1 * xd
562+
tv1 *= xd;
563+
// 27. tv1 = tv1 * yn2
564+
tv1 *= yn2;
565+
// 28. tv1 = -2 * tv1
566+
tv1 *= -FieldElement::TWO;
567+
// 29. yEd = tv2 + tv1
568+
let mut yEd = tv2 + tv1;
569+
// 30. tv4 = tv4 * yd2
570+
// SKIP: yd2 = 1
571+
// 31. yEd = yEd + tv4
572+
yEd += tv4;
573+
// 32. tv1 = xEd * yEd
574+
let tv1 = xEd * yEd;
575+
// 33. e = tv1 == 0
576+
let e = tv1.ct_eq(&FieldElement::ZERO);
577+
// 34. xEn = CMOV(xEn, 0, e)
578+
xEn.conditional_assign(&FieldElement::ZERO, e);
579+
// 35. xEd = CMOV(xEd, 1, e)
580+
xEd.conditional_assign(&FieldElement::ONE, e);
581+
// 36. yEn = CMOV(yEn, 1, e)
582+
yEn.conditional_assign(&FieldElement::ONE, e);
583+
// 37. yEd = CMOV(yEd, 1, e)
584+
yEd.conditional_assign(&FieldElement::ONE, e);
585+
// 38. return (xEn, xEd, yEn, yEd)
586+
587+
// Output: (xn, xd, yn, yd) such that (xn / xd, yn / yd) is a
588+
// point on edwards448.
589+
590+
EdwardsPoint {
591+
X: xEn * yEd,
592+
Y: xEd * yEn,
593+
Z: xEd * yEd,
594+
T: xEn * yEn,
595+
}
465596
}
466597

467598
// See https://www.shiftleft.org/papers/decaf/decaf.pdf#section.A.3.

0 commit comments

Comments
 (0)