@@ -463,8 +463,9 @@ static void secp256k1_gej_add_zinv_var(secp256k1_gej_t *r, const secp256k1_gej_t
463
463
static void secp256k1_gej_add_ge (secp256k1_gej_t * r , const secp256k1_gej_t * a , const secp256k1_ge_t * b ) {
464
464
/* Operations: 7 mul, 5 sqr, 5 normalize, 17 mul_int/add/negate/cmov */
465
465
static const secp256k1_fe_t fe_1 = SECP256K1_FE_CONST (0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 );
466
- secp256k1_fe_t zz , u1 , u2 , s1 , s2 , z , t , m , n , q , rr ;
467
- int infinity ;
466
+ secp256k1_fe_t zz , u1 , u2 , s1 , s2 , z , t , tt , m , n , q , rr ;
467
+ secp256k1_fe_t m_alt , rr_alt ;
468
+ int infinity , degenerate ;
468
469
VERIFY_CHECK (!b -> infinity );
469
470
VERIFY_CHECK (a -> infinity == 0 || a -> infinity == 1 );
470
471
@@ -488,6 +489,34 @@ static void secp256k1_gej_add_ge(secp256k1_gej_t *r, const secp256k1_gej_t *a, c
488
489
* Y3 = 4*(R*(3*Q-2*R^2)-M^4)
489
490
* Z3 = 2*M*Z
490
491
* (Note that the paper uses xi = Xi / Zi and yi = Yi / Zi instead.)
492
+ *
493
+ * This formula has the benefit of being the same for both addition
494
+ * of distinct points and doubling. However, it breaks down in the
495
+ * case that either point is infinity, or that y1 = -y2. We handle
496
+ * these cases in the following ways:
497
+ *
498
+ * - If b is infinity we simply bail by means of a VERIFY_CHECK.
499
+ *
500
+ * - If a is infinity, we detect this, and at the end of the
501
+ * computation replace the result (which will be meaningless,
502
+ * but we compute to be constant-time) with b.x : b.y : 1.
503
+ *
504
+ * - If a = -b, we have y1 = -y2, which is a degenerate case.
505
+ * But here the answer is infinity, so we simply set the
506
+ * infinity flag of the result, overriding the computed values
507
+ * without even needing to cmov.
508
+ *
509
+ * - If y1 = -y2 but x1 != x2, which does occur thanks to certain
510
+ * properties of our curve (specifically, 1 has nontrivial cube
511
+ * roots in our field, and the curve equation has no x coefficient)
512
+ * then the answer is not infinity but also not given by the above
513
+ * equation. In this case, we cmov in place an alternate expression
514
+ * for lambda. Specifically (y1 - y2)/(x1 - x2). Where both these
515
+ * expressions for lambda are defined, they are equal, and can be
516
+ * obtained from each other by multiplication by (y1 + y2)/(y1 + y2)
517
+ * then substitution of x^3 + 7 for y^2 (using the curve equation).
518
+ * For all pairs of nonzero points (a, b) at least one is defined,
519
+ * so this covers everything.
491
520
*/
492
521
493
522
secp256k1_fe_sqr (& zz , & a -> z ); /* z = Z1^2 */
@@ -499,29 +528,55 @@ static void secp256k1_gej_add_ge(secp256k1_gej_t *r, const secp256k1_gej_t *a, c
499
528
z = a -> z ; /* z = Z = Z1*Z2 (8) */
500
529
t = u1 ; secp256k1_fe_add (& t , & u2 ); /* t = T = U1+U2 (2) */
501
530
m = s1 ; secp256k1_fe_add (& m , & s2 ); /* m = M = S1+S2 (2) */
502
- secp256k1_fe_sqr (& n , & m ); /* n = M^2 (1) */
503
- secp256k1_fe_mul (& q , & n , & t ); /* q = Q = T*M^2 (1) */
504
- secp256k1_fe_sqr (& n , & n ); /* n = M^4 (1) */
505
531
secp256k1_fe_sqr (& rr , & t ); /* rr = T^2 (1) */
506
- secp256k1_fe_mul (& t , & u1 , & u2 ); secp256k1_fe_negate (& t , & t , 1 ); /* t = -U1*U2 (2) */
507
- secp256k1_fe_add (& rr , & t ); /* rr = R = T^2-U1*U2 (3) */
508
- secp256k1_fe_sqr (& t , & rr ); /* t = R^2 (1) */
509
- secp256k1_fe_mul (& r -> z , & m , & z ); /* r->z = M*Z (1) */
532
+ secp256k1_fe_mul (& tt , & u1 , & u2 ); secp256k1_fe_negate (& tt , & tt , 1 ); /* tt = -U1*U2 (2) */
533
+ secp256k1_fe_add (& rr , & tt ); /* rr = R = T^2-U1*U2 (3) */
534
+ /** If lambda = R/M = 0/0 we have a problem (except in the "trivial"
535
+ * case that Z = z1z2 = 0, and this is special-cased later on). */
536
+ degenerate = secp256k1_fe_normalizes_to_zero (& m ) &
537
+ secp256k1_fe_normalizes_to_zero (& rr );
538
+ /* This only occurs when y1 == -y2 and x1^3 == x2^3, but x1 != x2.
539
+ * This means either x1 == beta*x2 or beta*x1 == x2, where beta is
540
+ * a nontrivial cube root of one. In either case, an alternate
541
+ * non-indeterminate expression for lambda is (y1 - y2)/(x1 - x2),
542
+ * so we set R/M equal to this. */
543
+ secp256k1_fe_negate (& rr_alt , & s2 , 1 ); /* rr = -Y2*Z1^3 */
544
+ secp256k1_fe_add (& rr_alt , & s1 ); /* rr = Y1*Z2^3 - Y2*Z1^3 */
545
+ secp256k1_fe_negate (& m_alt , & u2 , 1 ); /* m = -X2*Z1^2 */
546
+ secp256k1_fe_add (& m_alt , & u1 ); /* m = X1*Z2^2 - X2*Z1^2 */
547
+
548
+ secp256k1_fe_cmov (& rr_alt , & rr , !degenerate );
549
+ secp256k1_fe_cmov (& m_alt , & m , !degenerate );
550
+ /* Now Ralt / Malt = lambda and is guaranteed not to be 0/0.
551
+ * From here on out Ralt and Malt represent the numerator
552
+ * and denominator of lambda; R and M represent the explicit
553
+ * expressions x1^2 + x2^2 + x1x2 and y1 + y2. */
554
+ secp256k1_fe_sqr (& n , & m_alt ); /* n = Malt^2 (1) */
555
+ secp256k1_fe_mul (& q , & n , & t ); /* q = Q = T*Malt^2 (1) */
556
+ /* These two lines use the observation that either M == Malt or M == 0,
557
+ * so M^3 * Malt is either Malt^4 (which is computed by squaring), or
558
+ * zero (which is "computed" by cmov). So the cost is one squaring
559
+ * versus two multiplications. */
560
+ secp256k1_fe_sqr (& n , & n ); /* n = M^3 * Malt (1) */
561
+ secp256k1_fe_cmov (& n , & m , degenerate );
562
+ secp256k1_fe_normalize_weak (& n );
563
+ secp256k1_fe_sqr (& t , & rr_alt ); /* t = Ralt^2 (1) */
564
+ secp256k1_fe_mul (& r -> z , & m_alt , & z ); /* r->z = Malt*Z (1) */
510
565
infinity = secp256k1_fe_normalizes_to_zero (& r -> z ) * (1 - a -> infinity );
511
- secp256k1_fe_mul_int (& r -> z , 2 ); /* r->z = Z3 = 2*M *Z (2) */
512
- r -> x = t ; /* r->x = R ^2 (1) */
566
+ secp256k1_fe_mul_int (& r -> z , 2 ); /* r->z = Z3 = 2*Malt *Z (2) */
567
+ r -> x = t ; /* r->x = Ralt ^2 (1) */
513
568
secp256k1_fe_negate (& q , & q , 1 ); /* q = -Q (2) */
514
- secp256k1_fe_add (& r -> x , & q ); /* r->x = R ^2-Q (3) */
569
+ secp256k1_fe_add (& r -> x , & q ); /* r->x = Ralt ^2-Q (3) */
515
570
secp256k1_fe_normalize (& r -> x );
516
- secp256k1_fe_mul_int ( & q , 3 ); /* q = -3*Q (6) */
517
- secp256k1_fe_mul_int (& t , 2 ); /* t = 2*R^2 (2) */
518
- secp256k1_fe_add (& t , & q ); /* t = 2*R^2-3*Q (8) */
519
- secp256k1_fe_mul (& t , & t , & rr ); /* t = R *(2*R^2-3* Q) (1) */
520
- secp256k1_fe_add (& t , & n ); /* t = R *(2*R^2-3*Q)+M^4 (2) */
521
- secp256k1_fe_negate (& r -> y , & t , 2 ); /* r->y = R*(3*Q-2*R^2)-M^4 (3) */
571
+ t = r -> x ;
572
+ secp256k1_fe_mul_int (& t , 2 ); /* t = 2*x3 (2) */
573
+ secp256k1_fe_add (& t , & q ); /* t = 2*x3 - Q: (8) */
574
+ secp256k1_fe_mul (& t , & t , & rr_alt ); /* t = Ralt *(2*x3 - Q) (1) */
575
+ secp256k1_fe_add (& t , & n ); /* t = Ralt *(2*x3 - Q) + M^3*Malt (2) */
576
+ secp256k1_fe_negate (& r -> y , & t , 2 ); /* r->y = Ralt*(Q - 2x3) - M^3*Malt (3) */
522
577
secp256k1_fe_normalize_weak (& r -> y );
523
- secp256k1_fe_mul_int (& r -> x , 4 ); /* r->x = X3 = 4*(R ^2-Q) */
524
- secp256k1_fe_mul_int (& r -> y , 4 ); /* r->y = Y3 = 4*R*(3*Q-2*R^2)- 4*M^4 (4) */
578
+ secp256k1_fe_mul_int (& r -> x , 4 ); /* r->x = X3 = 4*(Ralt ^2-Q) */
579
+ secp256k1_fe_mul_int (& r -> y , 4 ); /* r->y = Y3 = 4*Ralt*(Q - 2x3) - 4*M^3*Malt (4) */
525
580
526
581
/** In case a->infinity == 1, replace r with (b->x, b->y, 1). */
527
582
secp256k1_fe_cmov (& r -> x , & b -> x , a -> infinity );
0 commit comments