@@ -197,7 +197,7 @@ impl MapToCurve for Ed448 {
197197 type FieldElement = Ed448FieldElement ;
198198
199199 fn map_to_curve ( element : Ed448FieldElement ) -> Self :: CurvePoint {
200- element. 0 . map_to_curve_elligator2 ( ) . isogeny ( ) . to_edwards ( )
200+ element. 0 . map_to_curve_elligator2_edwards448 ( ) . to_edwards ( )
201201 }
202202
203203 fn map_to_subgroup ( point : EdwardsPoint ) -> EdwardsPoint {
@@ -246,6 +246,7 @@ impl FieldElement {
246246 "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000262a8" ,
247247 ) ) ) ;
248248 pub const ONE : Self = Self ( ConstMontyType :: new ( & U448 :: ONE ) ) ;
249+ pub const TWO : Self = Self ( ConstMontyType :: new ( & U448 :: from_u64 ( 2 ) ) ) ;
249250 pub const TWISTED_D : Self = Self ( ConstMontyType :: new ( & U448 :: from_be_hex (
250251 "fffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffff6755" ,
251252 ) ) ) ;
@@ -256,6 +257,11 @@ impl FieldElement {
256257 "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffffffffffffffffffffffffffffffffffffffffffffffffffffe" ,
257258 ) ) ) ;
258259 pub const ZERO : Self = Self ( ConstMontyType :: new ( & U448 :: ZERO ) ) ;
260+ // See https://www.rfc-editor.org/rfc/rfc9380.html#name-curve448-q-3-mod-4-k-1.
261+ // 1. c1 = (q - 3) / 4 # Integer arithmetic
262+ const C1 : U448 = U448 :: from_be_hex (
263+ "3fffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffffffffffffffffffffffffffffffffffffffffffffffffffffff" ,
264+ ) ;
259265
260266 pub fn is_negative ( & self ) -> Choice {
261267 let bytes = self . to_bytes ( ) ;
@@ -372,27 +378,154 @@ impl FieldElement {
372378 ( inv_sqrt_x * u, zero_u | is_res)
373379 }
374380
375- pub ( crate ) fn map_to_curve_elligator2 ( & self ) -> AffinePoint {
376- let mut t1 = self . square ( ) ; // 1. t1 = u^2
377- t1 *= Self :: Z ; // 2. t1 = Z * t1 // Z * u^2
378- let e1 = t1. ct_eq ( & Self :: MINUS_ONE ) ; // 3. e1 = t1 == -1 // exceptional case: Z * u^2 == -1
379- t1. conditional_assign ( & Self :: ZERO , e1) ; // 4. t1 = CMOV(t1, 0, e1) // if t1 == -1, set t1 = 0
380- let mut x1 = t1 + Self :: ONE ; // 5. x1 = t1 + 1
381- x1 = x1. invert ( ) ; // 6. x1 = inv0(x1)
382- x1 *= -Self :: J ; // 7. x1 = -A * x1 // x1 = -A / (1 + Z * u^2)
383- let mut gx1 = x1 + Self :: J ; // 8. gx1 = x1 + A
384- gx1 *= x1; // 9. gx1 = gx1 * x1
385- gx1 += Self :: ONE ; // 10. gx1 = gx1 + B
386- gx1 *= x1; // 11. gx1 = gx1 * x1 // gx1 = x1^3 + A * x1^2 + B * x1
387- let x2 = -x1 - Self :: J ; // 12. x2 = -x1 - A
388- let gx2 = t1 * gx1; // 13. gx2 = t1 * gx1
389- let e2 = gx1. is_square ( ) ; // 14. e2 = is_square(gx1)
390- let x = Self :: conditional_select ( & x2, & x1, e2) ; // 15. x = CMOV(x2, x1, e2) // If is_square(gx1), x = x1, else x = x2
391- let y2 = Self :: conditional_select ( & gx2, & gx1, e2) ; // 16. y2 = CMOV(gx2, gx1, e2) // If is_square(gx1), y2 = gx1, else y2 = gx2
392- let mut y = y2. sqrt ( ) ; // 17. y = sqrt(y2)
393- let e3 = y. is_negative ( ) ; // 18. e3 = sgn0(y) == 1
394- y. conditional_negate ( e2 ^ e3) ; // y = CMOV(-y, y, e2 xor e3)
395- AffinePoint { x, y }
381+ // See https://www.rfc-editor.org/rfc/rfc9380.html#name-curve448-q-3-mod-4-k-1.
382+ pub ( crate ) fn map_to_curve_elligator2_curve448 (
383+ & self ,
384+ ) -> ( FieldElement , FieldElement , FieldElement ) {
385+ // 1. tv1 = u^2
386+ let mut tv1 = self . square ( ) ;
387+ // 2. e1 = tv1 == 1
388+ let e1 = tv1. ct_eq ( & FieldElement :: ONE ) ;
389+ // 3. tv1 = CMOV(tv1, 0, e1) # If Z * u^2 == -1, set tv1 = 0
390+ tv1. conditional_assign ( & FieldElement :: ZERO , e1) ;
391+ // 4. xd = 1 - tv1
392+ let xd = FieldElement :: ONE - tv1;
393+ // 5. x1n = -J
394+ let x1n = -Self :: J ;
395+ // 6. tv2 = xd^2
396+ let tv2 = xd. square ( ) ;
397+ // 7. gxd = tv2 * xd # gxd = xd^3
398+ let gxd = tv2 * xd;
399+ // 8. gx1 = -J * tv1 # x1n + J * xd
400+ let mut gx1 = x1n * tv1;
401+ // 9. gx1 = gx1 * x1n # x1n^2 + J * x1n * xd
402+ gx1 *= x1n;
403+ // 10. gx1 = gx1 + tv2 # x1n^2 + J * x1n * xd + xd^2
404+ gx1 += tv2;
405+ // 11. gx1 = gx1 * x1n # x1n^3 + J * x1n^2 * xd + x1n * xd^2
406+ gx1 *= x1n;
407+ // 12. tv3 = gxd^2
408+ let tv3 = gxd. square ( ) ;
409+ // 13. tv2 = gx1 * gxd # gx1 * gxd
410+ let tv2 = gx1 * gxd;
411+ // 14. tv3 = tv3 * tv2 # gx1 * gxd^3
412+ let tv3 = tv3 * tv2;
413+ // 15. y1 = tv3^c1 # (gx1 * gxd^3)^((p - 3) / 4)
414+ let mut y1 = FieldElement ( tv3. 0 . pow ( & Self :: C1 ) ) ;
415+ // 16. y1 = y1 * tv2 # gx1 * gxd * (gx1 * gxd^3)^((p - 3) / 4)
416+ y1 *= tv2;
417+ // 17. x2n = -tv1 * x1n # x2 = x2n / xd = -1 * u^2 * x1n / xd
418+ let x2n = -tv1 * x1n;
419+ // 18. y2 = y1 * u
420+ let mut y2 = y1 * self ;
421+ // 19. y2 = CMOV(y2, 0, e1)
422+ y2. conditional_assign ( & FieldElement :: ZERO , e1) ;
423+ // 20. tv2 = y1^2
424+ let mut tv2 = y1. square ( ) ;
425+ // 21. tv2 = tv2 * gxd
426+ tv2 *= gxd;
427+ // 22. e2 = tv2 == gx1
428+ let e2 = tv2. ct_eq ( & gx1) ;
429+ // 23. xn = CMOV(x2n, x1n, e2) # If e2, x = x1, else x = x2
430+ let xn = FieldElement :: conditional_select ( & x2n, & x1n, e2) ;
431+ // 24. y = CMOV(y2, y1, e2) # If e2, y = y1, else y = y2
432+ let mut y = FieldElement :: conditional_select ( & y2, & y1, e2) ;
433+ // 25. e3 = sgn0(y) == 1 # Fix sign of y
434+ let e3 = y. is_negative ( ) ;
435+ // 26. y = CMOV(y, -y, e2 XOR e3)
436+ y. conditional_negate ( e2 ^ e3) ;
437+ // 27. return (xn, xd, y, 1)
438+
439+ ( xn, xd, y)
440+ }
441+
442+ fn map_to_curve_elligator2_edwards448 ( & self ) -> AffinePoint {
443+ // 1. (xn, xd, yn, yd) = map_to_curve_elligator2_curve448(u)
444+ let ( xn, xd, yn) = self . map_to_curve_elligator2_curve448 ( ) ;
445+ // 2. xn2 = xn^2
446+ let xn2 = xn. square ( ) ;
447+ // 3. xd2 = xd^2
448+ let xd2 = xd. square ( ) ;
449+ // 4. xd4 = xd2^2
450+ let xd4 = xd2. square ( ) ;
451+ // 5. yn2 = yn^2
452+ let yn2 = yn. square ( ) ;
453+ // 6. yd2 = yd^2
454+ let yd2 = FieldElement :: ONE ;
455+ // 7. xEn = xn2 - xd2
456+ let mut xEn = xn2 - xd2;
457+ // 8. tv2 = xEn - xd2
458+ let mut tv2 = xEn - xd2;
459+ // 9. xEn = xEn * xd2
460+ xEn *= xd2;
461+ // 10. xEn = xEn * yd
462+ // SKIP: yd = 1
463+ // 11. xEn = xEn * yn
464+ xEn *= yn;
465+ // 12. xEn = xEn * 4
466+ xEn = xEn. double ( ) . double ( ) ;
467+ // 13. tv2 = tv2 * xn2
468+ tv2 *= xn2;
469+ // 14. tv2 = tv2 * yd2
470+ // SKIP: yd2 = 1
471+ // 15. tv3 = 4 * yn2
472+ let tv3 = yn2. double ( ) . double ( ) ;
473+ // 16. tv1 = tv3 + yd2
474+ let mut tv1 = tv3 + yd2;
475+ // 17. tv1 = tv1 * xd4
476+ tv1 *= xd4;
477+ // 18. xEd = tv1 + tv2
478+ let mut xEd = tv1 + tv2;
479+ // 19. tv2 = tv2 * xn
480+ tv2 *= xn;
481+ // 20. tv4 = xn * xd4
482+ let tv4 = xn * xd4;
483+ // 21. yEn = tv3 - yd2
484+ let mut yEn = tv3 - yd2;
485+ // 22. yEn = yEn * tv4
486+ yEn *= tv4;
487+ // 23. yEn = yEn - tv2
488+ yEn -= tv2;
489+ // 24. tv1 = xn2 + xd2
490+ let mut tv1 = xn2 + xd2;
491+ // 25. tv1 = tv1 * xd2
492+ tv1 *= xd2;
493+ // 26. tv1 = tv1 * xd
494+ tv1 *= xd;
495+ // 27. tv1 = tv1 * yn2
496+ tv1 *= yn2;
497+ // 28. tv1 = -2 * tv1
498+ tv1 *= -FieldElement :: TWO ;
499+ // 29. yEd = tv2 + tv1
500+ let mut yEd = tv2 + tv1;
501+ // 30. tv4 = tv4 * yd2
502+ // SKIP: yd2 = 1
503+ // 31. yEd = yEd + tv4
504+ yEd += tv4;
505+ // 32. tv1 = xEd * yEd
506+ let tv1 = xEd * yEd;
507+ // 33. e = tv1 == 0
508+ let e = tv1. ct_eq ( & FieldElement :: ZERO ) ;
509+ // 34. xEn = CMOV(xEn, 0, e)
510+ xEn. conditional_assign ( & FieldElement :: ZERO , e) ;
511+ // 35. xEd = CMOV(xEd, 1, e)
512+ xEd. conditional_assign ( & FieldElement :: ONE , e) ;
513+ // 36. yEn = CMOV(yEn, 1, e)
514+ yEn. conditional_assign ( & FieldElement :: ONE , e) ;
515+ // 37. yEd = CMOV(yEd, 1, e)
516+ yEd. conditional_assign ( & FieldElement :: ONE , e) ;
517+ // 38. return (xEn, xEd, yEn, yEd)
518+
519+ // Output: (xn, xd, yn, yd) such that (xn / xd, yn / yd) is a
520+ // point on edwards448.
521+
522+ // Simplified two denominators to a single inversion.
523+ let d = ( xEd * yEd) . invert ( ) ;
524+
525+ AffinePoint {
526+ x : xEn * yEd * d,
527+ y : yEn * xEd * d,
528+ }
396529 }
397530
398531 // See https://www.shiftleft.org/papers/decaf/decaf.pdf#section.A.3.
0 commit comments