@@ -4,7 +4,7 @@ use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
44
55use super :: { ConstMontyType , MODULUS } ;
66use crate :: {
7- AffinePoint , Decaf448 , DecafPoint , Ed448 , EdwardsPoint ,
7+ Decaf448 , DecafPoint , Ed448 , EdwardsPoint ,
88 curve:: twedwards:: extended:: ExtendedPoint as TwistedExtendedPoint ,
99} ;
1010use elliptic_curve:: ops:: Reduce ;
@@ -196,7 +196,7 @@ impl MapToCurve for Ed448 {
196196 type ScalarLength = U84 ;
197197
198198 fn map_to_curve ( element : FieldElement ) -> EdwardsPoint {
199- element. map_to_curve_elligator2 ( ) . isogeny ( ) . to_edwards ( )
199+ element. map_to_curve_elligator2_edwards448 ( )
200200 }
201201}
202202
@@ -304,6 +304,11 @@ impl FieldElement {
304304 "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffffffffffffffffffffffffffffffffffffffffffffffffffffe" ,
305305 ) ) ) ;
306306 pub const ZERO : Self = Self ( ConstMontyType :: new ( & U448 :: ZERO ) ) ;
307+ // See https://www.rfc-editor.org/rfc/rfc9380.html#name-curve448-q-3-mod-4-k-1.
308+ // 1. c1 = (q - 3) / 4 # Integer arithmetic
309+ const C1 : U448 = U448 :: from_be_hex (
310+ "3fffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffffffffffffffffffffffffffffffffffffffffffffffffffffff" ,
311+ ) ;
307312
308313 pub fn is_negative ( & self ) -> Choice {
309314 self . 0 . retrieve ( ) . is_odd ( )
@@ -426,27 +431,153 @@ impl FieldElement {
426431 Self ( self . 0 . div_by_2 ( ) )
427432 }
428433
429- pub ( crate ) fn map_to_curve_elligator2 ( & self ) -> AffinePoint {
430- let mut t1 = self . square ( ) ; // 1. t1 = u^2
431- t1 *= Self :: Z ; // 2. t1 = Z * t1 // Z * u^2
432- let e1 = t1. ct_eq ( & Self :: MINUS_ONE ) ; // 3. e1 = t1 == -1 // exceptional case: Z * u^2 == -1
433- t1. conditional_assign ( & Self :: ZERO , e1) ; // 4. t1 = CMOV(t1, 0, e1) // if t1 == -1, set t1 = 0
434- let mut x1 = t1 + Self :: ONE ; // 5. x1 = t1 + 1
435- x1 = x1. invert ( ) ; // 6. x1 = inv0(x1)
436- x1 *= -Self :: J ; // 7. x1 = -A * x1 // x1 = -A / (1 + Z * u^2)
437- let mut gx1 = x1 + Self :: J ; // 8. gx1 = x1 + A
438- gx1 *= x1; // 9. gx1 = gx1 * x1
439- gx1 += Self :: ONE ; // 10. gx1 = gx1 + B
440- gx1 *= x1; // 11. gx1 = gx1 * x1 // gx1 = x1^3 + A * x1^2 + B * x1
441- let x2 = -x1 - Self :: J ; // 12. x2 = -x1 - A
442- let gx2 = t1 * gx1; // 13. gx2 = t1 * gx1
443- let e2 = gx1. is_square ( ) ; // 14. e2 = is_square(gx1)
444- let x = Self :: conditional_select ( & x2, & x1, e2) ; // 15. x = CMOV(x2, x1, e2) // If is_square(gx1), x = x1, else x = x2
445- let y2 = Self :: conditional_select ( & gx2, & gx1, e2) ; // 16. y2 = CMOV(gx2, gx1, e2) // If is_square(gx1), y2 = gx1, else y2 = gx2
446- let mut y = y2. sqrt ( ) ; // 17. y = sqrt(y2)
447- let e3 = y. is_negative ( ) ; // 18. e3 = sgn0(y) == 1
448- y. conditional_negate ( e2 ^ e3) ; // y = CMOV(-y, y, e2 xor e3)
449- AffinePoint { x, y }
434+ // See https://www.rfc-editor.org/rfc/rfc9380.html#name-curve448-q-3-mod-4-k-1.
435+ pub ( crate ) fn map_to_curve_elligator2_curve448 (
436+ & self ,
437+ ) -> ( FieldElement , FieldElement , FieldElement ) {
438+ // 1. tv1 = u^2
439+ let mut tv1 = self . square ( ) ;
440+ // 2. e1 = tv1 == 1
441+ let e1 = tv1. ct_eq ( & FieldElement :: ONE ) ;
442+ // 3. tv1 = CMOV(tv1, 0, e1) # If Z * u^2 == -1, set tv1 = 0
443+ tv1. conditional_assign ( & FieldElement :: ZERO , e1) ;
444+ // 4. xd = 1 - tv1
445+ let xd = FieldElement :: ONE - tv1;
446+ // 5. x1n = -J
447+ let x1n = -Self :: J ;
448+ // 6. tv2 = xd^2
449+ let tv2 = xd. square ( ) ;
450+ // 7. gxd = tv2 * xd # gxd = xd^3
451+ let gxd = tv2 * xd;
452+ // 8. gx1 = -J * tv1 # x1n + J * xd
453+ let mut gx1 = x1n * tv1;
454+ // 9. gx1 = gx1 * x1n # x1n^2 + J * x1n * xd
455+ gx1 *= x1n;
456+ // 10. gx1 = gx1 + tv2 # x1n^2 + J * x1n * xd + xd^2
457+ gx1 += tv2;
458+ // 11. gx1 = gx1 * x1n # x1n^3 + J * x1n^2 * xd + x1n * xd^2
459+ gx1 *= x1n;
460+ // 12. tv3 = gxd^2
461+ let tv3 = gxd. square ( ) ;
462+ // 13. tv2 = gx1 * gxd # gx1 * gxd
463+ let tv2 = gx1 * gxd;
464+ // 14. tv3 = tv3 * tv2 # gx1 * gxd^3
465+ let tv3 = tv3 * tv2;
466+ // 15. y1 = tv3^c1 # (gx1 * gxd^3)^((p - 3) / 4)
467+ let mut y1 = FieldElement ( tv3. 0 . pow ( & Self :: C1 ) ) ;
468+ // 16. y1 = y1 * tv2 # gx1 * gxd * (gx1 * gxd^3)^((p - 3) / 4)
469+ y1 *= tv2;
470+ // 17. x2n = -tv1 * x1n # x2 = x2n / xd = -1 * u^2 * x1n / xd
471+ let x2n = -tv1 * x1n;
472+ // 18. y2 = y1 * u
473+ let mut y2 = y1 * self ;
474+ // 19. y2 = CMOV(y2, 0, e1)
475+ y2. conditional_assign ( & FieldElement :: ZERO , e1) ;
476+ // 20. tv2 = y1^2
477+ let mut tv2 = y1. square ( ) ;
478+ // 21. tv2 = tv2 * gxd
479+ tv2 *= gxd;
480+ // 22. e2 = tv2 == gx1
481+ let e2 = tv2. ct_eq ( & gx1) ;
482+ // 23. xn = CMOV(x2n, x1n, e2) # If e2, x = x1, else x = x2
483+ let xn = FieldElement :: conditional_select ( & x2n, & x1n, e2) ;
484+ // 24. y = CMOV(y2, y1, e2) # If e2, y = y1, else y = y2
485+ let mut y = FieldElement :: conditional_select ( & y2, & y1, e2) ;
486+ // 25. e3 = sgn0(y) == 1 # Fix sign of y
487+ let e3 = y. is_negative ( ) ;
488+ // 26. y = CMOV(y, -y, e2 XOR e3)
489+ y. conditional_negate ( e2 ^ e3) ;
490+ // 27. return (xn, xd, y, 1)
491+
492+ ( xn, xd, y)
493+ }
494+
495+ fn map_to_curve_elligator2_edwards448 ( & self ) -> EdwardsPoint {
496+ // 1. (xn, xd, yn, yd) = map_to_curve_elligator2_curve448(u)
497+ let ( xn, xd, yn) = self . map_to_curve_elligator2_curve448 ( ) ;
498+ // 2. xn2 = xn^2
499+ let xn2 = xn. square ( ) ;
500+ // 3. xd2 = xd^2
501+ let xd2 = xd. square ( ) ;
502+ // 4. xd4 = xd2^2
503+ let xd4 = xd2. square ( ) ;
504+ // 5. yn2 = yn^2
505+ let yn2 = yn. square ( ) ;
506+ // 6. yd2 = yd^2
507+ let yd2 = FieldElement :: ONE ;
508+ // 7. xEn = xn2 - xd2
509+ let mut xEn = xn2 - xd2;
510+ // 8. tv2 = xEn - xd2
511+ let mut tv2 = xEn - xd2;
512+ // 9. xEn = xEn * xd2
513+ xEn *= xd2;
514+ // 10. xEn = xEn * yd
515+ // SKIP: yd = 1
516+ // 11. xEn = xEn * yn
517+ xEn *= yn;
518+ // 12. xEn = xEn * 4
519+ xEn = xEn. double ( ) . double ( ) ;
520+ // 13. tv2 = tv2 * xn2
521+ tv2 *= xn2;
522+ // 14. tv2 = tv2 * yd2
523+ // SKIP: yd2 = 1
524+ // 15. tv3 = 4 * yn2
525+ let tv3 = yn2. double ( ) . double ( ) ;
526+ // 16. tv1 = tv3 + yd2
527+ let mut tv1 = tv3 + yd2;
528+ // 17. tv1 = tv1 * xd4
529+ tv1 *= xd4;
530+ // 18. xEd = tv1 + tv2
531+ let mut xEd = tv1 + tv2;
532+ // 19. tv2 = tv2 * xn
533+ tv2 *= xn;
534+ // 20. tv4 = xn * xd4
535+ let tv4 = xn * xd4;
536+ // 21. yEn = tv3 - yd2
537+ let mut yEn = tv3 - yd2;
538+ // 22. yEn = yEn * tv4
539+ yEn *= tv4;
540+ // 23. yEn = yEn - tv2
541+ yEn -= tv2;
542+ // 24. tv1 = xn2 + xd2
543+ let mut tv1 = xn2 + xd2;
544+ // 25. tv1 = tv1 * xd2
545+ tv1 *= xd2;
546+ // 26. tv1 = tv1 * xd
547+ tv1 *= xd;
548+ // 27. tv1 = tv1 * yn2
549+ tv1 *= yn2;
550+ // 28. tv1 = -2 * tv1
551+ tv1 *= -FieldElement :: TWO ;
552+ // 29. yEd = tv2 + tv1
553+ let mut yEd = tv2 + tv1;
554+ // 30. tv4 = tv4 * yd2
555+ // SKIP: yd2 = 1
556+ // 31. yEd = yEd + tv4
557+ yEd += tv4;
558+ // 32. tv1 = xEd * yEd
559+ let tv1 = xEd * yEd;
560+ // 33. e = tv1 == 0
561+ let e = tv1. ct_eq ( & FieldElement :: ZERO ) ;
562+ // 34. xEn = CMOV(xEn, 0, e)
563+ xEn. conditional_assign ( & FieldElement :: ZERO , e) ;
564+ // 35. xEd = CMOV(xEd, 1, e)
565+ xEd. conditional_assign ( & FieldElement :: ONE , e) ;
566+ // 36. yEn = CMOV(yEn, 1, e)
567+ yEn. conditional_assign ( & FieldElement :: ONE , e) ;
568+ // 37. yEd = CMOV(yEd, 1, e)
569+ yEd. conditional_assign ( & FieldElement :: ONE , e) ;
570+ // 38. return (xEn, xEd, yEn, yEd)
571+
572+ // Output: (xn, xd, yn, yd) such that (xn / xd, yn / yd) is a
573+ // point on edwards448.
574+
575+ EdwardsPoint {
576+ X : xEn * yEd,
577+ Y : xEd * yEn,
578+ Z : xEd * yEd,
579+ T : xEn * yEn,
580+ }
450581 }
451582
452583 // See https://www.shiftleft.org/papers/decaf/decaf.pdf#section.A.3.
0 commit comments