@@ -197,7 +197,7 @@ impl MapToCurve for Ed448 {
197
197
type FieldElement = Ed448FieldElement ;
198
198
199
199
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 ( )
201
201
}
202
202
203
203
fn map_to_subgroup ( point : EdwardsPoint ) -> EdwardsPoint {
@@ -246,6 +246,7 @@ impl FieldElement {
246
246
"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000262a8" ,
247
247
) ) ) ;
248
248
pub const ONE : Self = Self ( ConstMontyType :: new ( & U448 :: ONE ) ) ;
249
+ pub const TWO : Self = Self ( ConstMontyType :: new ( & U448 :: from_u64 ( 2 ) ) ) ;
249
250
pub const TWISTED_D : Self = Self ( ConstMontyType :: new ( & U448 :: from_be_hex (
250
251
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffff6755" ,
251
252
) ) ) ;
@@ -256,6 +257,11 @@ impl FieldElement {
256
257
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffffffffffffffffffffffffffffffffffffffffffffffffffffe" ,
257
258
) ) ) ;
258
259
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
+ ) ;
259
265
260
266
pub fn is_negative ( & self ) -> Choice {
261
267
let bytes = self . to_bytes ( ) ;
@@ -372,27 +378,154 @@ impl FieldElement {
372
378
( inv_sqrt_x * u, zero_u | is_res)
373
379
}
374
380
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
+ }
396
529
}
397
530
398
531
// See https://www.shiftleft.org/papers/decaf/decaf.pdf#section.A.3.
0 commit comments