LCOV - code coverage report
Current view: top level - ballet/secp256k1 - fd_secp256k1_point.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 236 236 100.0 %
Date: 2026-11-11 12:40:43 Functions: 13 13 100.0 %

          Line data    Source code
       1             : /* secp256k1 square root and group arithmetic, shared by both backends.
       2             :    Included by fd_secp256k1_private.h after the backend (fd_secp256k1_s2n.c
       3             :    or fd_secp256k1_ref.c) has defined the fd_secp256k1_fp_* and
       4             :    fd_secp256k1_scalar_* primitives. */
       5             : 
       6             : /*
       7             :   Returns NULL if a is not a square.
       8             :   r may NOT alias a
       9             : 
      10             :   r = a^((p + 1) / 4) mod p
      11             : 
      12             :   We know that a^((p-1)/2) = 1 when a is a quadratic residue.
      13             :   So for a valid square, we can show that re-squaring recovers a with:
      14             :     (a^((p+1)/4))^2 = a^((p+1)/1)
      15             :                     = a * a^((p-1)/2)
      16             :                     = a (if a is a square)
      17             : 
      18             :   We use a more optimal addition-chain which takes advantage that quite
      19             :   a few of the powers consist of all 1s when in binary form. We build up:
      20             :     x2    = a^3
      21             :     x3    = a^7
      22             :     x6    = a^63
      23             :     x9    = a^511
      24             :     x11   = a^2047
      25             :     x22   = a^(2^22 − 1) # All of these are all 1s
      26             :     x44   = a^(2^44 − 1)
      27             :     x88   = a^(2^88 − 1)
      28             :     x176  = a^(2^176 − 1)
      29             :     x220  = a^(2^220 − 1)
      30             :     x223  = a^(2^223 − 1)
      31             : 
      32             :   These "all 1s" exponents are convenient because:
      33             :     (2^k - 1)*(2^m)+(2^m - 1) = 2^(k+m) - 1
      34             :   Allowing us to quickly build them.
      35             : 
      36             :   If a is NOT a square, then
      37             :     a^((p-1)/2) = -1
      38             :   and the result will fail the final verification.
      39             : */
      40             : static inline fd_secp256k1_fp_t *
      41             : fd_secp256k1_fp_sqrt( fd_secp256k1_fp_t *       restrict r,
      42        2255 :                       fd_secp256k1_fp_t const * restrict a ) {
      43        2255 :   fd_secp256k1_fp_t x2;
      44        2255 :   fd_secp256k1_fp_t x3;
      45             : 
      46        2255 :   fd_secp256k1_fp_sqr( &x2, a );
      47        2255 :   fd_secp256k1_fp_mul( &x2, &x2, a );
      48             : 
      49        2255 :   fd_secp256k1_fp_sqr( &x3, &x2 );
      50        2255 :   fd_secp256k1_fp_mul( &x3, &x3, a );
      51             : 
      52        2255 :   fd_secp256k1_fp_t x6 = x3;
      53        9023 :   for( int j=0; j<3; j++ ) fd_secp256k1_fp_sqr( &x6, &x6 );
      54        2255 :   fd_secp256k1_fp_mul( &x6, &x6, &x3 );
      55             : 
      56        2255 :   fd_secp256k1_fp_t x9 = x6;
      57        9023 :   for( int j=0; j<3; j++ ) fd_secp256k1_fp_sqr( &x9, &x9 );
      58        2255 :   fd_secp256k1_fp_mul( &x9, &x9, &x3 );
      59             : 
      60        2255 :   fd_secp256k1_fp_t x11 = x9;
      61        6767 :   for( int j=0; j<2; j++ ) fd_secp256k1_fp_sqr( &x11, &x11 );
      62        2255 :   fd_secp256k1_fp_mul( &x11, &x11, &x2 );
      63             : 
      64        2255 :   fd_secp256k1_fp_t x22 = x11;
      65       27035 :   for( int j=0; j<11; j++ ) fd_secp256k1_fp_sqr( &x22, &x22 );
      66        2255 :   fd_secp256k1_fp_mul( &x22, &x22, &x11 );
      67             : 
      68        2255 :   fd_secp256k1_fp_t x44 = x22;
      69       51749 :   for( int j=0; j<22; j++ ) fd_secp256k1_fp_sqr( &x44, &x44 );
      70        2255 :   fd_secp256k1_fp_mul( &x44, &x44, &x22 );
      71             : 
      72        2255 :   fd_secp256k1_fp_t x88 = x44;
      73      101055 :   for( int j=0; j<44; j++ ) fd_secp256k1_fp_sqr( &x88, &x88 );
      74        2255 :   fd_secp256k1_fp_mul( &x88, &x88, &x44 );
      75             : 
      76        2255 :   fd_secp256k1_fp_t x176 = x88;
      77      199029 :   for( int j=0; j<88; j++ ) fd_secp256k1_fp_sqr( &x176, &x176 );
      78        2255 :   fd_secp256k1_fp_mul( &x176, &x176, &x88 );
      79             : 
      80        2255 :   fd_secp256k1_fp_t x220 = x176;
      81      101119 :   for( int j=0; j<44; j++ ) fd_secp256k1_fp_sqr( &x220, &x220 );
      82        2255 :   fd_secp256k1_fp_mul( &x220, &x220, &x44 );
      83             : 
      84        2255 :   fd_secp256k1_fp_t x223 = x220;
      85        9015 :   for( int j=0; j<3; j++ ) fd_secp256k1_fp_sqr( &x223, &x223 );
      86        2255 :   fd_secp256k1_fp_mul( &x223, &x223, &x3 );
      87             : 
      88        2255 :   fd_secp256k1_fp_t t1 = x223;
      89       54005 :   for( int j=0; j<23; j++ ) fd_secp256k1_fp_sqr( &t1, &t1 );
      90        2255 :   fd_secp256k1_fp_mul( &t1, &t1, &x22 );
      91             : 
      92       15773 :   for( int j=0; j<6; j++ ) fd_secp256k1_fp_sqr( &t1, &t1 );
      93        2255 :   fd_secp256k1_fp_mul( &t1, &t1, &x2 );
      94        2255 :   fd_secp256k1_fp_sqr( &t1, &t1 );
      95        2255 :   fd_secp256k1_fp_sqr( r, &t1 );
      96             : 
      97        2255 :   fd_secp256k1_fp_sqr( &t1, r );
      98        2255 :   if( FD_UNLIKELY( !fd_secp256k1_fp_eq( &t1, a ) ) ) {
      99          81 :     return NULL;
     100          81 :   }
     101             : 
     102        2174 :   return r;
     103        2255 : }
     104             : 
     105             : /* Point */
     106             : 
     107             : /* Sets a group element to the identity element in homogeneous projective coordinates */
     108             : static inline void
     109        6525 : fd_secp256k1_point_set_identity( fd_secp256k1_point_t *r ) {
     110        6525 :   fd_secp256k1_fp_set( r->x, fd_secp256k1_const_zero );
     111        6525 :   fd_secp256k1_fp_set( r->y, fd_secp256k1_const_one_mont );
     112        6525 :   fd_secp256k1_fp_set( r->z, fd_secp256k1_const_zero );
     113        6525 : }
     114             : 
     115             : /* Sets a group element to the base element in homogeneous projective coordinates */
     116             : static inline void
     117        2175 : fd_secp256k1_point_set_base( fd_secp256k1_point_t *r ) {
     118        2175 :   fd_secp256k1_fp_set( r->x, fd_secp256k1_const_base_x_mont );
     119        2175 :   fd_secp256k1_fp_set( r->y, fd_secp256k1_const_base_y_mont );
     120        2175 :   fd_secp256k1_fp_set( r->z, fd_secp256k1_const_one_mont );
     121        2175 : }
     122             : 
     123             : /* r = a */
     124             : static inline void
     125             : fd_secp256k1_point_set( fd_secp256k1_point_t *       r,
     126        4349 :                         fd_secp256k1_point_t const * a ) {
     127        4349 :   fd_secp256k1_fp_set( r->x, a->x );
     128        4349 :   fd_secp256k1_fp_set( r->y, a->y );
     129        4349 :   fd_secp256k1_fp_set( r->z, a->z );
     130        4349 : }
     131             : 
     132             : /* https://eprint.iacr.org/2015/1060.pdf, Algorithm 7 */
     133             : static inline fd_secp256k1_point_t *
     134             : fd_secp256k1_point_add( fd_secp256k1_point_t *       r,
     135             :                         fd_secp256k1_point_t const * a,
     136      275044 :                         fd_secp256k1_point_t const * b ) {
     137      275044 :   fd_secp256k1_fp_t t0[ 1 ];
     138      275044 :   fd_secp256k1_fp_t t1[ 1 ];
     139      275044 :   fd_secp256k1_fp_t t2[ 1 ];
     140      275044 :   fd_secp256k1_fp_t t3[ 1 ];
     141      275044 :   fd_secp256k1_fp_t t4[ 1 ];
     142             : 
     143      275044 :   fd_secp256k1_fp_t X3[ 1 ];
     144      275044 :   fd_secp256k1_fp_t Y3[ 1 ];
     145      275044 :   fd_secp256k1_fp_t Z3[ 1 ];
     146             : 
     147             :   /* t0 = X1 * X2 */
     148      275044 :   fd_secp256k1_fp_mul( t0, a->x, b->x );
     149             :   /* t1 = Y1 * Y2 */
     150      275044 :   fd_secp256k1_fp_mul( t1, a->y, b->y );
     151             :   /* t2 = Z1 * Z2 */
     152      275044 :   fd_secp256k1_fp_mul( t2, a->z, b->z );
     153             : 
     154             :   /* t3 = (a.x + a.y) * (b.x + b.y) - (t0 + t1) */
     155      275044 :   fd_secp256k1_fp_add( t3, a->x, a->y );
     156      275044 :   fd_secp256k1_fp_add( t4, b->x, b->y );
     157      275044 :   fd_secp256k1_fp_mul( t3, t3, t4 );
     158      275044 :   fd_secp256k1_fp_add( t4, t0, t1 );
     159      275044 :   fd_secp256k1_fp_sub( t3, t3, t4 );
     160             : 
     161             :   /* t4 = (a.y + a.z) * (b.y + b.z) - (t1 + t2) */
     162      275044 :   fd_secp256k1_fp_add( t4, a->y, a->z );
     163      275044 :   fd_secp256k1_fp_add( X3, b->y, b->z );
     164      275044 :   fd_secp256k1_fp_mul( t4, t4, X3 );
     165      275044 :   fd_secp256k1_fp_add( X3, t1, t2 );
     166      275044 :   fd_secp256k1_fp_sub( t4, t4, X3 );
     167             : 
     168             :   /* Y3 = (a.x + a.z) * (b.x + b.z) - (t0 + t2) */
     169      275044 :   fd_secp256k1_fp_add( X3, a->x, a->z );
     170      275044 :   fd_secp256k1_fp_add( Y3, b->x, b->z );
     171      275044 :   fd_secp256k1_fp_mul( X3, X3, Y3 );
     172      275044 :   fd_secp256k1_fp_add( Y3, t0, t2 );
     173      275044 :   fd_secp256k1_fp_sub( Y3, X3, Y3 );
     174             : 
     175             :   /* t0 = 3 * t0 */
     176      275044 :   fd_secp256k1_fp_triple( t0, t0 );
     177             : 
     178             :   /* b3 = (2^2)^2 + 2^2 + 1 = 21 */
     179      275044 :   fd_secp256k1_fp_t t2_4[ 1 ];
     180      275044 :   fd_secp256k1_fp_t t5[ 1 ];
     181      275044 :   fd_secp256k1_fp_dbl( t2_4, t2 );
     182      275044 :   fd_secp256k1_fp_dbl( t2_4, t2_4 );
     183      275044 :   fd_secp256k1_fp_dbl( t5, t2_4 );
     184      275044 :   fd_secp256k1_fp_dbl( t5, t5 );
     185      275044 :   fd_secp256k1_fp_add( t5, t5, t2_4 );
     186      275044 :   fd_secp256k1_fp_add( t2, t5, t2 );
     187             : 
     188             :   /* Z3 = t1 * t2
     189             :      t1 = t1 - t2 */
     190      275044 :   fd_secp256k1_fp_add( Z3, t1, t2 );
     191      275044 :   fd_secp256k1_fp_sub( t1, t1, t2 );
     192             : 
     193      275044 :   fd_secp256k1_fp_t Y3_4[ 1 ];
     194      275044 :   fd_secp256k1_fp_dbl( Y3_4, Y3 );
     195      275044 :   fd_secp256k1_fp_dbl( Y3_4, Y3_4 );
     196      275044 :   fd_secp256k1_fp_dbl( t5, Y3_4 );
     197      275044 :   fd_secp256k1_fp_dbl( t5, t5 );
     198      275044 :   fd_secp256k1_fp_add( t5, t5, Y3_4 );
     199      275044 :   fd_secp256k1_fp_add( Y3, t5, Y3 );
     200             : 
     201      275044 :   fd_secp256k1_fp_mul( X3, t4, Y3 );
     202      275044 :   fd_secp256k1_fp_mul( t2, t3, t1 );
     203      275044 :   fd_secp256k1_fp_sub( r->x, t2, X3 );
     204      275044 :   fd_secp256k1_fp_mul( Y3, Y3, t0 );
     205      275044 :   fd_secp256k1_fp_mul( t1, t1, Z3 );
     206      275044 :   fd_secp256k1_fp_add( r->y, t1, Y3 );
     207      275044 :   fd_secp256k1_fp_mul( t0, t0, t3 );
     208      275044 :   fd_secp256k1_fp_mul( Z3, Z3, t4 );
     209      275044 :   fd_secp256k1_fp_add( r->z, Z3, t0 );
     210             : 
     211      275044 :   return r;
     212      275044 : }
     213             : 
     214             : /* https://eprint.iacr.org/2015/1060.pdf, Algorithm 9 */
     215             : static inline fd_secp256k1_point_t *
     216             : fd_secp256k1_point_dbl( fd_secp256k1_point_t *       r,
     217      568076 :                         fd_secp256k1_point_t const * a ) {
     218      568076 :   fd_secp256k1_fp_t t0[ 1 ];
     219      568076 :   fd_secp256k1_fp_t t1[ 1 ];
     220      568076 :   fd_secp256k1_fp_t t2[ 1 ];
     221             : 
     222      568076 :   fd_secp256k1_fp_t X3[ 1 ];
     223      568076 :   fd_secp256k1_fp_t Y3[ 1 ];
     224      568076 :   fd_secp256k1_fp_t Z3[ 1 ];
     225             : 
     226             :   /* t0 = Y * Y*/
     227      568076 :   fd_secp256k1_fp_sqr( t0, a->y );
     228             :   /* Z3 = 8 * t0 */
     229      568076 :   fd_secp256k1_fp_dbl( Z3, t0 );
     230      568076 :   fd_secp256k1_fp_dbl( Z3, Z3 );
     231      568076 :   fd_secp256k1_fp_dbl( Z3, Z3 );
     232             : 
     233             :   /* t1 = Y * Z */
     234      568076 :   fd_secp256k1_fp_mul( t1, a->y, a->z );
     235             :   /* t2 = Z * Z */
     236      568076 :   fd_secp256k1_fp_sqr( t2, a->z );
     237             : 
     238             :   /* b3 = (2^2)^2 + 2^2 + 1
     239             :      t2 = b3 * t2 */
     240      568076 :   fd_secp256k1_fp_t t2_4[1], t5[1];
     241      568076 :   fd_secp256k1_fp_dbl( t2_4, t2 );
     242      568076 :   fd_secp256k1_fp_dbl( t2_4, t2_4 );
     243      568076 :   fd_secp256k1_fp_dbl( t5, t2_4 );
     244      568076 :   fd_secp256k1_fp_dbl( t5, t5 );
     245      568076 :   fd_secp256k1_fp_add( t5, t5, t2_4 );
     246      568076 :   fd_secp256k1_fp_add( t2, t5, t2 );
     247             : 
     248             :   /* X3 = t2 * Z3 */
     249      568076 :   fd_secp256k1_fp_mul( X3, t2, Z3 );
     250             :   /* Y3 = t0 + t2 */
     251      568076 :   fd_secp256k1_fp_add( Y3, t0, t2 );
     252             : 
     253      568076 :   fd_secp256k1_fp_mul( r->z, t1, Z3 );
     254             : 
     255      568076 :   fd_secp256k1_fp_dbl( t1, t2 );
     256      568076 :   fd_secp256k1_fp_add( t2, t1, t2 );
     257      568076 :   fd_secp256k1_fp_sub( t0, t0, t2 );
     258      568076 :   fd_secp256k1_fp_mul( Y3, t0, Y3 );
     259             :   /* compute t1 first, as the next add may overwrite a->y */
     260      568076 :   fd_secp256k1_fp_mul( t1, a->x, a->y );
     261      568076 :   fd_secp256k1_fp_add( r->y, X3, Y3 );
     262             : 
     263      568076 :   fd_secp256k1_fp_mul( X3, t0, t1 );
     264      568076 :   fd_secp256k1_fp_dbl( r->x, X3 );
     265             : 
     266      568076 :   return r;
     267      568076 : }
     268             : 
     269             : /* r = -a */
     270             : static inline fd_secp256k1_point_t *
     271             : fd_secp256k1_point_neg( fd_secp256k1_point_t *       r,
     272      138990 :                         fd_secp256k1_point_t const * a ) {
     273      138990 :   fd_secp256k1_fp_set( r->x, a->x );
     274      138990 :   fd_secp256k1_fp_set( r->z, a->z );
     275      138990 :   fd_secp256k1_fp_negate( r->y, a->y );
     276      138990 :   return r;
     277      138990 : }
     278             : 
     279             : /* r = a - b */
     280             : static inline fd_secp256k1_point_t *
     281             : fd_secp256k1_point_sub( fd_secp256k1_point_t *       r,
     282             :                         fd_secp256k1_point_t const * a,
     283      138977 :                         fd_secp256k1_point_t const * b ) {
     284      138977 :   fd_secp256k1_point_t tmp[ 1 ];
     285      138977 :   fd_secp256k1_point_neg( tmp, b );
     286      138977 :   return fd_secp256k1_point_add( r, a, tmp );
     287      138977 : }
     288             : 
     289             : /* Double base multiplication */
     290             : 
     291             : static inline schar *
     292             : fd_secp256k1_slide( schar       r[ 2 * 32 + 1 ],
     293        4350 :                     uchar const s[ 32 ] ) {
     294      143550 :   for( ulong i=0UL; i<32UL; i++ ) {
     295      139200 :     uchar x = s[i];
     296      139200 :     r[i * 2 + 0] = x & 0xF;
     297      139200 :     r[i * 2 + 1] = (x >> 4) & 0xF;
     298      139200 :   }
     299             :   /* Now, r[0..63] is between 0 and 15. */
     300        4350 :   schar carry = 0;
     301      282750 :   for( ulong i=0UL; i<64UL; i++ ) {
     302      278400 :     r[i]  = (schar)(r[i] + carry);
     303      278400 :     carry = (schar)(r[i] + 8) >> 4;
     304      278400 :     r[i]  = (schar)(r[i] - carry * 16);
     305             :     /* r[i] MUST be between [-8, 8] */
     306      278400 :   }
     307        4350 :   r[64] = carry;
     308             :   /* carry MUST be between [-8, 8] */
     309        4350 :   return r;
     310        4350 : }
     311             : 
     312             : static inline fd_secp256k1_point_t *
     313             : fd_secp256k1_precompute( fd_secp256k1_point_t         r[ 9 ],
     314        4350 :                          fd_secp256k1_point_t const * a ) {
     315        4350 :   fd_secp256k1_point_set_identity( &r[0] );
     316        4350 :   fd_secp256k1_point_set( &r[1], a );
     317       34766 :   for( ulong i=2UL; i<=8UL; i++ ) {
     318       30416 :     if( i%2UL ) {
     319       13038 :       fd_secp256k1_point_add( &r[i], &r[i - 1], a );
     320       17378 :     } else {
     321       17378 :       fd_secp256k1_point_dbl( &r[i], &r[i / 2]    );
     322       17378 :     }
     323       30416 :   }
     324        4350 :   return r;
     325        4350 : }
     326             : 
     327             : /* Computes s1*G + s2*P2, where G is the base point */
     328             : static inline fd_secp256k1_point_t *
     329             : fd_secp256k1_double_base_mul( fd_secp256k1_point_t *        r,
     330             :                               fd_secp256k1_scalar_t const * s1,
     331             :                               fd_secp256k1_point_t  const * p2,
     332        2175 :                               fd_secp256k1_scalar_t const * s2 ) {
     333        2175 :   fd_secp256k1_point_t base[ 1 ];
     334        2175 :   fd_secp256k1_point_set_base( base );
     335             : 
     336        2175 :   fd_secp256k1_point_t pc1[ 9 ];
     337        2175 :   fd_secp256k1_point_t pc2[ 9 ];
     338             :   /* TODO: Precompute the basepoint table in a generated table */
     339        2175 :   fd_secp256k1_precompute( pc1, base );
     340        2175 :   fd_secp256k1_precompute( pc2, p2 );
     341             : 
     342        2175 :   schar e1[ 2 * 32 + 1 ];
     343        2175 :   schar e2[ 2 * 32 + 1 ];
     344        2175 :   fd_secp256k1_slide( e1, s1->buf );
     345        2175 :   fd_secp256k1_slide( e2, s2->buf );
     346             : 
     347        2175 :   fd_secp256k1_point_set_identity( r );
     348      141013 :   for( int pos = 2 * 32; ; pos -= 1 ) {
     349      141013 :     schar slot1 = e1[pos];
     350      141013 :     if( slot1 > 0 ) {
     351       62152 :       fd_secp256k1_point_add( r, r, &pc1[(ulong)slot1] );
     352       78861 :     } else if( slot1 < 0 ) {
     353       69504 :       fd_secp256k1_point_sub( r, r, &pc1[(ulong)(-slot1)] );
     354       69504 :     }
     355             : 
     356      141013 :     schar slot2 = e2[pos];
     357      141013 :     if( slot2 > 0 ) {
     358       61868 :       fd_secp256k1_point_add( r, r, &pc2[(ulong)slot2] );
     359       79145 :     } else if( slot2 < 0 ) {
     360       69628 :       fd_secp256k1_point_sub( r, r, &pc2[(ulong)(-slot2)] );
     361       69628 :     }
     362             : 
     363      141013 :     if( pos == 0 ) break;
     364      138838 :     fd_secp256k1_point_dbl( r, r );
     365      138838 :     fd_secp256k1_point_dbl( r, r );
     366      138838 :     fd_secp256k1_point_dbl( r, r );
     367      138838 :     fd_secp256k1_point_dbl( r, r );
     368      138838 :   }
     369             : 
     370        2175 :   return r;
     371        2175 : }
     372             : 
     373             : static inline fd_secp256k1_point_t *
     374             : fd_secp256k1_point_to_affine( fd_secp256k1_point_t *       r,
     375        2173 :                               fd_secp256k1_point_t const * a ) {
     376        2173 :   fd_secp256k1_fp_t z[1];
     377        2173 :   fd_secp256k1_fp_invert( z, a->z );
     378        2173 :   fd_secp256k1_fp_mul( r->x, a->x, z );
     379        2173 :   fd_secp256k1_fp_mul( r->y, a->y, z );
     380        2173 :   return r;
     381        2173 : }
     382             : 
     383             : static inline int
     384        2175 : fd_secp256k1_point_is_identity( fd_secp256k1_point_t const *a ) {
     385        2175 :   int affine =
     386        2175 :      fd_secp256k1_fp_eq( a->x, fd_secp256k1_const_zero ) &
     387        2175 :      ( fd_secp256k1_fp_eq( a->y, fd_secp256k1_const_zero     ) |
     388        2175 :        fd_secp256k1_fp_eq( a->y, fd_secp256k1_const_one_mont ) );
     389        2175 :   return fd_secp256k1_fp_eq( a->z, fd_secp256k1_const_zero ) | affine;
     390        2175 : }

Generated by: LCOV version 1.14