LCOV - code coverage report
Current view: top level - ballet/secp256k1 - fd_secp256k1_s2n.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 333 333 100.0 %
Date: 2026-05-16 06:43:53 Functions: 31 31 100.0 %

          Line data    Source code
       1             : #include <stdint.h>
       2             : #include <s2n-bignum.h>
       3             : 
       4             : /* On CPUs without ADX (mulx/adcx/adox), redirect the ADX-optimized
       5             :    s2n-bignum symbols to their _alt equivalents, which use only base
       6             :    x86-64 instructions and are functionally identical. */
       7             : #ifndef __ADX__
       8    62402808 : #define bignum_montmul_p256k1  bignum_montmul_p256k1_alt
       9    20795400 : #define bignum_montsqr_p256k1  bignum_montsqr_p256k1_alt
      10       60102 : #define bignum_tomont_p256k1   bignum_tomont_p256k1_alt
      11     2504882 : #define bignum_triple_p256k1   bignum_triple_p256k1_alt
      12             : #endif
      13             : 
      14             : /* Scalars */
      15             : 
      16             : static inline int
      17      120213 : fd_secp256k1_scalar_is_zero( fd_secp256k1_scalar_t const *r ) {
      18      120213 :   return fd_uint256_eq( r, fd_secp256k1_const_zero );
      19      120213 : }
      20             : 
      21             : /* Returns the scalar in NON Montgomery form. */
      22             : static inline fd_secp256k1_scalar_t *
      23             : fd_secp256k1_scalar_frombytes( fd_secp256k1_scalar_t * r,
      24      120231 :                                uchar const             input[ 32 ] ) {
      25      120231 :   memcpy( r, input, 32 );
      26      120231 :   fd_uint256_bswap( r, r );
      27             : 
      28             :   /*
      29             :     The verifier SHALL check that 0 < r' < q and 0 < s' < q.
      30             :     The r' element is parsed as a scalar, and checked against r' < n.
      31             :     Later it is re-used as fp_t, however n < p, so we do not need to
      32             :     perform any additional checks after this.
      33             :   */
      34      120231 :   if( FD_UNLIKELY( fd_uint256_cmp( r, fd_secp256k1_const_n ) >= 0 ) ) {
      35          18 :     return NULL;
      36          18 :   }
      37      120213 :   if( FD_UNLIKELY( fd_secp256k1_scalar_is_zero( r ) ) ) {
      38          15 :     return NULL;
      39          15 :   }
      40      120198 :   return r;
      41      120213 : }
      42             : 
      43             : /* r = 1 / a
      44             :    Operates on scalars NOT in the montgomery domain.
      45             :    a MUST not be 0. */
      46             : fd_secp256k1_scalar_t *
      47             : fd_secp256k1_scalar_invert( fd_secp256k1_scalar_t *       r,
      48       30060 :                             fd_secp256k1_scalar_t const * a ) {
      49       30060 :   ulong t[ 12 ];
      50       30060 :   bignum_modinv( 4, r->limbs, (ulong *)a->limbs, (ulong *)fd_secp256k1_const_n[ 0 ].limbs, t );
      51       30060 :   return r;
      52       30060 : }
      53             : 
      54             : /* None of the arguments may alias. */
      55             : static inline fd_secp256k1_scalar_t *
      56             : fd_secp256k1_scalar_mul( fd_secp256k1_scalar_t *       restrict r,
      57             :                          fd_secp256k1_scalar_t const * restrict a,
      58       60120 :                          fd_secp256k1_scalar_t const * restrict b ) {
      59       60120 :   bignum_montmul( 4, r->limbs, (ulong *)a->limbs, (ulong *)b->limbs, (ulong *)fd_secp256k1_const_n[0].limbs );
      60       60120 :   return r;
      61       60120 : }
      62             : 
      63             : /* r = -a */
      64             : static inline fd_secp256k1_scalar_t *
      65             : fd_secp256k1_scalar_negate( fd_secp256k1_scalar_t *       r,
      66       30060 :                             fd_secp256k1_scalar_t const * a ) {
      67             :   /* We cannot use bignum_modsub() as it requires a < n /\ b < n.
      68             : 
      69             :      The best way to implement it using the current API is to use
      70             :      bignum_sub(n, a), getting a result bounded within [0, n+1). Then
      71             :      we perform a second reduction from [0, n+1) to [0, n) with
      72             :      bignum_mod_n256k1_4(). */
      73             : 
      74             :   /* t \in [0, n + 1). There is no carry-out, as a < n. */
      75       30060 :   ulong t[4];
      76       30060 :   bignum_sub( 4, t, 4, (ulong *)fd_secp256k1_const_n[ 0 ].limbs, 4, (ulong *)a->limbs );
      77       30060 :   bignum_mod_n256k1_4( r->limbs, t );
      78       30060 :   return r;
      79       30060 : }
      80             : 
      81             : static inline fd_secp256k1_scalar_t *
      82             : fd_secp256k1_scalar_tomont( fd_secp256k1_scalar_t *       r,
      83       90180 :                             fd_secp256k1_scalar_t const * a ) {
      84             :   /* bignum_montmul has an undocumented restriction
      85             :      that the input and outputs may not alias. */
      86       90180 :   ulong t[4];
      87       90180 :   memcpy( t, a->limbs, 32 );
      88       90180 :   bignum_montmul( 4, r->limbs, t, (ulong *)fd_secp256k1_const_scalar_rr_mont, (ulong *)fd_secp256k1_const_n[ 0 ].limbs );
      89       90180 :   return r;
      90       90180 : }
      91             : 
      92             : static inline fd_secp256k1_scalar_t *
      93             : fd_secp256k1_scalar_demont( fd_secp256k1_scalar_t *       r,
      94       60120 :                             fd_secp256k1_scalar_t const * a ) {
      95       60120 :   bignum_demont( 4, r->limbs, (ulong *)a->limbs, (ulong *)fd_secp256k1_const_n[ 0 ].limbs );
      96       60120 :   return r;
      97       60120 : }
      98             : 
      99             : /* Field */
     100             : 
     101             : static inline fd_secp256k1_fp_t *
     102             : fd_secp256k1_fp_set( fd_secp256k1_fp_t *       r,
     103     4687968 :                      fd_secp256k1_fp_t const * a ) {
     104     4687968 :   r->limbs[ 0 ] = a->limbs[ 0 ];
     105     4687968 :   r->limbs[ 1 ] = a->limbs[ 1 ];
     106     4687968 :   r->limbs[ 2 ] = a->limbs[ 2 ];
     107     4687968 :   r->limbs[ 3 ] = a->limbs[ 3 ];
     108     4687968 :   return r;
     109     4687968 : }
     110             : 
     111             : /* r = (a == b) */
     112             : static inline int
     113             : fd_secp256k1_fp_eq( fd_secp256k1_fp_t const * a,
     114      180324 :                     fd_secp256k1_fp_t const * b ) {
     115      180324 :   return fd_uint256_eq( a, b );
     116      180324 : }
     117             : 
     118             : /* r = a + b */
     119             : static inline fd_secp256k1_fp_t *
     120             : fd_secp256k1_fp_add( fd_secp256k1_fp_t *       r,
     121             :                      fd_secp256k1_fp_t const * a,
     122    99856464 :                      fd_secp256k1_fp_t const * b ) {
     123    99856464 :   bignum_add_p256k1( r->limbs, (ulong *)a->limbs, (ulong *)b->limbs );
     124    99856464 :   return r;
     125    99856464 : }
     126             : 
     127             : /* r = a - b */
     128             : static inline fd_secp256k1_fp_t *
     129             : fd_secp256k1_fp_sub( fd_secp256k1_fp_t *       r,
     130             :                      fd_secp256k1_fp_t const * a,
     131    26722455 :                      fd_secp256k1_fp_t const * b ) {
     132    26722455 :   bignum_sub_p256k1( r->limbs, (ulong *)a->limbs, (ulong *)b->limbs );
     133    26722455 :   return r;
     134    26722455 : }
     135             : 
     136             : /* r = 2 * a */
     137             : static inline fd_secp256k1_fp_t *
     138             : fd_secp256k1_fp_dbl( fd_secp256k1_fp_t *       r,
     139   101481144 :                      fd_secp256k1_fp_t const * a ) {
     140   101481144 :   bignum_double_p256k1( r->limbs, (ulong *)a->limbs );
     141   101481144 :   return r;
     142   101481144 : }
     143             : 
     144             : /* r = a * b */
     145             : static inline fd_secp256k1_fp_t *
     146             : fd_secp256k1_fp_mul( fd_secp256k1_fp_t *       r,
     147             :                      fd_secp256k1_fp_t const * a,
     148    93604212 :                      fd_secp256k1_fp_t const * b ) {
     149    93604212 :   bignum_montmul_p256k1( r->limbs, (ulong *)a->limbs, (ulong *)b->limbs );
     150    93604212 :   return r;
     151    93604212 : }
     152             : 
     153             : /* r = a^2 */
     154             : static inline fd_secp256k1_fp_t *
     155             : fd_secp256k1_fp_sqr( fd_secp256k1_fp_t *       r,
     156    31193100 :                      fd_secp256k1_fp_t const * a ) {
     157    31193100 :   bignum_montsqr_p256k1( r->limbs, (ulong *)a->limbs );
     158    31193100 :   return r;
     159    31193100 : }
     160             : 
     161             : /* r = -a */
     162             : static inline fd_secp256k1_fp_t *
     163             : fd_secp256k1_fp_negate( fd_secp256k1_fp_t *       r,
     164     2043414 :                         fd_secp256k1_fp_t const * a ) {
     165     2043414 :   bignum_neg_p256k1( r->limbs, (ulong *)a->limbs );
     166     2043414 :   return r;
     167     2043414 : }
     168             : 
     169             : static inline int
     170       30060 : fd_secp256k1_fp_is_odd( fd_secp256k1_fp_t const *r ) {
     171       30060 :   fd_secp256k1_fp_t scratch[1];
     172       30060 :   bignum_demont_p256k1( scratch->limbs, (ulong *)r->limbs );
     173       30060 :   return scratch->limbs[ 0 ] & 1;
     174       30060 : }
     175             : 
     176             : /* r = 1 / a
     177             :    a MUST not be 0. */
     178             : static inline fd_secp256k1_fp_t *
     179             : fd_secp256k1_fp_invert( fd_secp256k1_fp_t *       r,
     180       30060 :                         fd_secp256k1_fp_t const * a ) {
     181       30060 :   fd_secp256k1_fp_t ad[1];
     182       30060 :   bignum_demont_p256k1( ad->limbs, (ulong *)a->limbs );
     183       30060 :   ulong t[ 12 ];
     184       30060 :   bignum_modinv( 4, r->limbs, (ulong *)ad->limbs, (ulong *)fd_secp256k1_const_p[0].limbs, t );
     185       30060 :   bignum_tomont_p256k1( r->limbs, (ulong *)r->limbs );
     186       30060 :   return r;
     187       30060 : }
     188             : 
     189             : static inline uchar *
     190             : fd_secp256k1_fp_tobytes( uchar                    r[ 32 ],
     191       60120 :                          fd_secp256k1_fp_t const *a ) {
     192       60120 :   fd_secp256k1_fp_t swapped[1];
     193       60120 :   bignum_demont_p256k1( swapped->limbs, (ulong *)a->limbs );
     194       60120 :   fd_uint256_bswap( swapped, swapped );
     195       60120 :   memcpy( r, swapped->buf, 32 );
     196       60120 :   return r;
     197       60120 : }
     198             : 
     199             : /*
     200             :   Returns NULL if a is not a square.
     201             :   r may NOT alias a
     202             : 
     203             :   r = a^((p + 1) / 4) mod p
     204             : 
     205             :   We know that a^((p-1)/2) = 1 when a is a quadratic residue.
     206             :   So for a valid square, we can show that re-squaring recovers a with:
     207             :     (a^((p+1)/4))^2 = a^((p+1)/1)
     208             :                     = a * a^((p-1)/2)
     209             :                     = a (if a is a square)
     210             : 
     211             :   We use a more optimal addition-chain which takes advantage that quite
     212             :   a few of the powers consist of all 1s when in binary form. We build up:
     213             :     x2    = a^3
     214             :     x3    = a^7
     215             :     x6    = a^63
     216             :     x9    = a^511
     217             :     x11   = a^2047
     218             :     x22   = a^(2^22 − 1) # All of these are all 1s
     219             :     x44   = a^(2^44 − 1)
     220             :     x88   = a^(2^88 − 1)
     221             :     x176  = a^(2^176 − 1)
     222             :     x220  = a^(2^220 − 1)
     223             :     x223  = a^(2^223 − 1)
     224             : 
     225             :   These "all 1s" exponents are convenient because:
     226             :     (2^k - 1)*(2^m)+(2^m - 1) = 2^(k+m) - 1
     227             :   Allowing us to quickly build them.
     228             : 
     229             :   If a is NOT a square, then
     230             :     a^((p-1)/2) = -1
     231             :   and the result will fail the final verification.
     232             : */
     233             : static inline fd_secp256k1_fp_t *
     234             : fd_secp256k1_fp_sqrt( fd_secp256k1_fp_t *       restrict r,
     235       60084 :                       fd_secp256k1_fp_t const * restrict a ) {
     236       60084 :   fd_secp256k1_fp_t x2;
     237       60084 :   fd_secp256k1_fp_t x3;
     238             : 
     239       60084 :   fd_secp256k1_fp_sqr( &x2, a );
     240       60084 :   fd_secp256k1_fp_mul( &x2, &x2, a );
     241             : 
     242       60084 :   fd_secp256k1_fp_sqr( &x3, &x2 );
     243       60084 :   fd_secp256k1_fp_mul( &x3, &x3, a );
     244             : 
     245       60084 :   fd_secp256k1_fp_t x6 = x3;
     246      240336 :   for( int j=0; j<3; j++ ) fd_secp256k1_fp_sqr( &x6, &x6 );
     247       60084 :   fd_secp256k1_fp_mul( &x6, &x6, &x3 );
     248             : 
     249       60084 :   fd_secp256k1_fp_t x9 = x6;
     250      240336 :   for( int j=0; j<3; j++ ) fd_secp256k1_fp_sqr( &x9, &x9 );
     251       60084 :   fd_secp256k1_fp_mul( &x9, &x9, &x3 );
     252             : 
     253       60084 :   fd_secp256k1_fp_t x11 = x9;
     254      180252 :   for( int j=0; j<2; j++ ) fd_secp256k1_fp_sqr( &x11, &x11 );
     255       60084 :   fd_secp256k1_fp_mul( &x11, &x11, &x2 );
     256             : 
     257       60084 :   fd_secp256k1_fp_t x22 = x11;
     258      721008 :   for( int j=0; j<11; j++ ) fd_secp256k1_fp_sqr( &x22, &x22 );
     259       60084 :   fd_secp256k1_fp_mul( &x22, &x22, &x11 );
     260             : 
     261       60084 :   fd_secp256k1_fp_t x44 = x22;
     262     1381932 :   for( int j=0; j<22; j++ ) fd_secp256k1_fp_sqr( &x44, &x44 );
     263       60084 :   fd_secp256k1_fp_mul( &x44, &x44, &x22 );
     264             : 
     265       60084 :   fd_secp256k1_fp_t x88 = x44;
     266     2703780 :   for( int j=0; j<44; j++ ) fd_secp256k1_fp_sqr( &x88, &x88 );
     267       60084 :   fd_secp256k1_fp_mul( &x88, &x88, &x44 );
     268             : 
     269       60084 :   fd_secp256k1_fp_t x176 = x88;
     270     5347476 :   for( int j=0; j<88; j++ ) fd_secp256k1_fp_sqr( &x176, &x176 );
     271       60084 :   fd_secp256k1_fp_mul( &x176, &x176, &x88 );
     272             : 
     273       60084 :   fd_secp256k1_fp_t x220 = x176;
     274     2703780 :   for( int j=0; j<44; j++ ) fd_secp256k1_fp_sqr( &x220, &x220 );
     275       60084 :   fd_secp256k1_fp_mul( &x220, &x220, &x44 );
     276             : 
     277       60084 :   fd_secp256k1_fp_t x223 = x220;
     278      240336 :   for( int j=0; j<3; j++ ) fd_secp256k1_fp_sqr( &x223, &x223 );
     279       60084 :   fd_secp256k1_fp_mul( &x223, &x223, &x3 );
     280             : 
     281       60084 :   fd_secp256k1_fp_t t1 = x223;
     282     1442016 :   for( int j=0; j<23; j++ ) fd_secp256k1_fp_sqr( &t1, &t1 );
     283       60084 :   fd_secp256k1_fp_mul( &t1, &t1, &x22 );
     284             : 
     285      420588 :   for( int j=0; j<6; j++ ) fd_secp256k1_fp_sqr( &t1, &t1 );
     286       60084 :   fd_secp256k1_fp_mul( &t1, &t1, &x2 );
     287       60084 :   fd_secp256k1_fp_sqr( &t1, &t1 );
     288       60084 :   fd_secp256k1_fp_sqr( r, &t1 );
     289             : 
     290       60084 :   fd_secp256k1_fp_sqr( &t1, r );
     291       60084 :   if( FD_UNLIKELY( !fd_secp256k1_fp_eq( &t1, a ) ) ) {
     292       30024 :     return NULL;
     293       30024 :   }
     294             : 
     295       30060 :   return r;
     296       60084 : }
     297             : 
     298             : /* Point */
     299             : 
     300             : /* Sets a group element to the identity element in Jacobian coordinates */
     301             : static inline void
     302       90180 : fd_secp256k1_point_set_identity( fd_secp256k1_point_t *r ) {
     303       90180 :   fd_secp256k1_fp_set( r->x, fd_secp256k1_const_zero );
     304       90180 :   fd_secp256k1_fp_set( r->y, fd_secp256k1_const_one_mont );
     305       90180 :   fd_secp256k1_fp_set( r->z, fd_secp256k1_const_zero );
     306       90180 : }
     307             : 
     308             : /* Sets a group element to the base element in Jacobian coordinates */
     309             : static inline void
     310       30060 : fd_secp256k1_point_set_base( fd_secp256k1_point_t *r ) {
     311       30060 :   fd_secp256k1_fp_set( r->x, fd_secp256k1_const_base_x_mont );
     312       30060 :   fd_secp256k1_fp_set( r->y, fd_secp256k1_const_base_y_mont );
     313       30060 :   fd_secp256k1_fp_set( r->z, fd_secp256k1_const_one_mont );
     314       30060 : }
     315             : 
     316             : /* r = a */
     317             : static inline void
     318             : fd_secp256k1_point_set( fd_secp256k1_point_t *       r,
     319       60120 :                         fd_secp256k1_point_t const * a ) {
     320       60120 :   fd_secp256k1_fp_set( r->x, a->x );
     321       60120 :   fd_secp256k1_fp_set( r->y, a->y );
     322       60120 :   fd_secp256k1_fp_set( r->z, a->z );
     323       60120 : }
     324             : 
     325             : /* https://eprint.iacr.org/2015/1060.pdf, Algorithm 7 */
     326             : static inline fd_secp256k1_point_t *
     327             : fd_secp256k1_point_add( fd_secp256k1_point_t *       r,
     328             :                         fd_secp256k1_point_t const * a,
     329     3757323 :                         fd_secp256k1_point_t const * b ) {
     330     3757323 :   fd_secp256k1_fp_t t0[ 1 ];
     331     3757323 :   fd_secp256k1_fp_t t1[ 1 ];
     332     3757323 :   fd_secp256k1_fp_t t2[ 1 ];
     333     3757323 :   fd_secp256k1_fp_t t3[ 1 ];
     334     3757323 :   fd_secp256k1_fp_t t4[ 1 ];
     335             : 
     336     3757323 :   fd_secp256k1_fp_t X3[ 1 ];
     337     3757323 :   fd_secp256k1_fp_t Y3[ 1 ];
     338     3757323 :   fd_secp256k1_fp_t Z3[ 1 ];
     339             : 
     340             :   /* t0 = X1 * X2 */
     341     3757323 :   fd_secp256k1_fp_mul( t0, a->x, b->x );
     342             :   /* t1 = Y1 * Y2 */
     343     3757323 :   fd_secp256k1_fp_mul( t1, a->y, b->y );
     344             :   /* t2 = Z1 * Z2 */
     345     3757323 :   fd_secp256k1_fp_mul( t2, a->z, b->z );
     346             : 
     347             :   /* t3 = (a.x + a.y) * (b.x + b.y) - (t0 + t1) */
     348     3757323 :   fd_secp256k1_fp_add( t3, a->x, a->y );
     349     3757323 :   fd_secp256k1_fp_add( t4, b->x, b->y );
     350     3757323 :   fd_secp256k1_fp_mul( t3, t3, t4 );
     351     3757323 :   fd_secp256k1_fp_add( t4, t0, t1 );
     352     3757323 :   fd_secp256k1_fp_sub( t3, t3, t4 );
     353             : 
     354             :   /* t4 = (a.y + a.z) * (b.y + b.z) - (t1 + t2) */
     355     3757323 :   fd_secp256k1_fp_add( t4, a->y, a->z );
     356     3757323 :   fd_secp256k1_fp_add( X3, b->y, b->z );
     357     3757323 :   fd_secp256k1_fp_mul( t4, t4, X3 );
     358     3757323 :   fd_secp256k1_fp_add( X3, t1, t2 );
     359     3757323 :   fd_secp256k1_fp_sub( t4, t4, X3 );
     360             : 
     361             :   /* Y3 = (a.x + a.z) * (b.x + b.z) - (t0 + t2) */
     362     3757323 :   fd_secp256k1_fp_add( X3, a->x, a->z );
     363     3757323 :   fd_secp256k1_fp_add( Y3, b->x, b->z );
     364     3757323 :   fd_secp256k1_fp_mul( X3, X3, Y3 );
     365     3757323 :   fd_secp256k1_fp_add( Y3, t0, t2 );
     366     3757323 :   fd_secp256k1_fp_sub( Y3, X3, Y3 );
     367             : 
     368             :   /* t0 = 3 * t0 */
     369     3757323 :   bignum_triple_p256k1( t0->limbs, (ulong *)t0->limbs );
     370             : 
     371             :   /* b3 = (2^2)^2 + 2^2 + 1 = 21 */
     372     3757323 :   fd_secp256k1_fp_t t2_4[ 1 ];
     373     3757323 :   fd_secp256k1_fp_t t5[ 1 ];
     374     3757323 :   fd_secp256k1_fp_dbl( t2_4, t2 );
     375     3757323 :   fd_secp256k1_fp_dbl( t2_4, t2_4 );
     376     3757323 :   fd_secp256k1_fp_dbl( t5, t2_4 );
     377     3757323 :   fd_secp256k1_fp_dbl( t5, t5 );
     378     3757323 :   fd_secp256k1_fp_add( t5, t5, t2_4 );
     379     3757323 :   fd_secp256k1_fp_add( t2, t5, t2 );
     380             : 
     381             :   /* Z3 = t1 * t2
     382             :      t1 = t1 - t2 */
     383     3757323 :   fd_secp256k1_fp_add( Z3, t1, t2 );
     384     3757323 :   fd_secp256k1_fp_sub( t1, t1, t2 );
     385             : 
     386     3757323 :   fd_secp256k1_fp_t Y3_4[ 1 ];
     387     3757323 :   fd_secp256k1_fp_dbl( Y3_4, Y3 );
     388     3757323 :   fd_secp256k1_fp_dbl( Y3_4, Y3_4 );
     389     3757323 :   fd_secp256k1_fp_dbl( t5, Y3_4 );
     390     3757323 :   fd_secp256k1_fp_dbl( t5, t5 );
     391     3757323 :   fd_secp256k1_fp_add( t5, t5, Y3_4 );
     392     3757323 :   fd_secp256k1_fp_add( Y3, t5, Y3 );
     393             : 
     394     3757323 :   fd_secp256k1_fp_mul( X3, t4, Y3 );
     395     3757323 :   fd_secp256k1_fp_mul( t2, t3, t1 );
     396     3757323 :   fd_secp256k1_fp_sub( r->x, t2, X3 );
     397     3757323 :   fd_secp256k1_fp_mul( Y3, Y3, t0 );
     398     3757323 :   fd_secp256k1_fp_mul( t1, t1, Z3 );
     399     3757323 :   fd_secp256k1_fp_add( r->y, t1, Y3 );
     400     3757323 :   fd_secp256k1_fp_mul( t0, t0, t3 );
     401     3757323 :   fd_secp256k1_fp_mul( Z3, Z3, t4 );
     402     3757323 :   fd_secp256k1_fp_add( r->z, Z3, t0 );
     403             : 
     404     3757323 :   return r;
     405     3757323 : }
     406             : 
     407             : /* https://eprint.iacr.org/2015/1060.pdf, Algorithm 9 */
     408             : static inline fd_secp256k1_point_t *
     409             : fd_secp256k1_point_dbl( fd_secp256k1_point_t *       r,
     410     7935840 :                         fd_secp256k1_point_t const * a ) {
     411     7935840 :   fd_secp256k1_fp_t t0[ 1 ];
     412     7935840 :   fd_secp256k1_fp_t t1[ 1 ];
     413     7935840 :   fd_secp256k1_fp_t t2[ 1 ];
     414             : 
     415     7935840 :   fd_secp256k1_fp_t X3[ 1 ];
     416     7935840 :   fd_secp256k1_fp_t Y3[ 1 ];
     417     7935840 :   fd_secp256k1_fp_t Z3[ 1 ];
     418             : 
     419             :   /* t0 = Y * Y*/
     420     7935840 :   fd_secp256k1_fp_sqr( t0, a->y );
     421             :   /* Z3 = 8 * t0 */
     422     7935840 :   fd_secp256k1_fp_dbl( Z3, t0 );
     423     7935840 :   fd_secp256k1_fp_dbl( Z3, Z3 );
     424     7935840 :   fd_secp256k1_fp_dbl( Z3, Z3 );
     425             : 
     426             :   /* t1 = Y * Z */
     427     7935840 :   fd_secp256k1_fp_mul( t1, a->y, a->z );
     428             :   /* t2 = Z * Z */
     429     7935840 :   fd_secp256k1_fp_sqr( t2, a->z );
     430             : 
     431             :   /* b3 = (2^2)^2 + 2^2 + 1
     432             :      t2 = b3 * t2 */
     433     7935840 :   fd_secp256k1_fp_t t2_4[1], t5[1];
     434     7935840 :   fd_secp256k1_fp_dbl( t2_4, t2 );
     435     7935840 :   fd_secp256k1_fp_dbl( t2_4, t2_4 );
     436     7935840 :   fd_secp256k1_fp_dbl( t5, t2_4 );
     437     7935840 :   fd_secp256k1_fp_dbl( t5, t5 );
     438     7935840 :   fd_secp256k1_fp_add( t5, t5, t2_4 );
     439     7935840 :   fd_secp256k1_fp_add( t2, t5, t2 );
     440             : 
     441             :   /* X3 = t2 * Z3 */
     442     7935840 :   fd_secp256k1_fp_mul( X3, t2, Z3 );
     443             :   /* Y3 = t0 + t2 */
     444     7935840 :   fd_secp256k1_fp_add( Y3, t0, t2 );
     445             : 
     446     7935840 :   fd_secp256k1_fp_mul( r->z, t1, Z3 );
     447             : 
     448     7935840 :   fd_secp256k1_fp_dbl( t1, t2 );
     449     7935840 :   fd_secp256k1_fp_add( t2, t1, t2 );
     450     7935840 :   fd_secp256k1_fp_sub( t0, t0, t2 );
     451     7935840 :   fd_secp256k1_fp_mul( Y3, t0, Y3 );
     452             :   /* compute t1 first, as the next add may overwrite a->y */
     453     7935840 :   fd_secp256k1_fp_mul( t1, a->x, a->y );
     454     7935840 :   fd_secp256k1_fp_add( r->y, X3, Y3 );
     455             : 
     456     7935840 :   fd_secp256k1_fp_mul( X3, t0, t1 );
     457     7935840 :   fd_secp256k1_fp_dbl( r->x, X3 );
     458             : 
     459     7935840 :   return r;
     460     7935840 : }
     461             : 
     462             : /* r = -a */
     463             : static inline fd_secp256k1_point_t *
     464             : fd_secp256k1_point_neg( fd_secp256k1_point_t *       r,
     465     2043384 :                         fd_secp256k1_point_t const * a ) {
     466     2043384 :   fd_secp256k1_fp_set( r->x, a->x );
     467     2043384 :   fd_secp256k1_fp_set( r->z, a->z );
     468     2043384 :   fd_secp256k1_fp_negate( r->y, a->y );
     469     2043384 :   return r;
     470     2043384 : }
     471             : 
     472             : /* r = a - b */
     473             : static inline fd_secp256k1_point_t *
     474             : fd_secp256k1_point_sub( fd_secp256k1_point_t *       r,
     475             :                         fd_secp256k1_point_t const * a,
     476     2043384 :                         fd_secp256k1_point_t const * b ) {
     477     2043384 :   fd_secp256k1_point_t tmp[ 1 ];
     478     2043384 :   fd_secp256k1_point_neg( tmp, b );
     479     2043384 :   return fd_secp256k1_point_add( r, a, tmp );
     480     2043384 : }
     481             : 
     482             : /* Double base multiplication */
     483             : 
     484             : static inline schar *
     485             : fd_secp256k1_slide( schar       r[ 2 * 32 + 1 ],
     486       60120 :                     uchar const s[ 32 ] ) {
     487     1983960 :   for(int i = 0; i<32; i++) {
     488     1923840 :     uchar x = s[i];
     489     1923840 :     r[i * 2 + 0] = x & 0xF;
     490     1923840 :     r[i * 2 + 1] = (x >> 4) & 0xF;
     491     1923840 :   }
     492             :   /* Now, r[0..63] is between 0 and 15, r[63] is between 0 and 7 */
     493       60120 :   schar carry = 0;
     494     3907800 :   for(int i = 0; i<64; i++) {
     495     3847680 :     r[i] += carry;
     496     3847680 :     carry = (schar)(r[i] + 8) >> 4;
     497     3847680 :     r[i] -= (schar)(carry * 16);
     498             :     /* r[i] MUST be between [-8, 8] */
     499     3847680 :   }
     500       60120 :   r[64] = carry;
     501             :   /* carry MUST be between [-8, 8] */
     502       60120 :   return r;
     503       60120 : }
     504             : 
     505             : static inline fd_secp256k1_point_t *
     506             : fd_secp256k1_precompute( fd_secp256k1_point_t         r[ 9 ],
     507       60120 :                          fd_secp256k1_point_t const * a ) {
     508       60120 :   fd_secp256k1_point_set_identity( &r[0] );
     509       60120 :   fd_secp256k1_point_set( &r[1], a );
     510      480960 :   for(int i = 2; i <= 8; i++) {
     511      420840 :     if(i % 2) {
     512      180360 :       fd_secp256k1_point_add( &r[i], &r[i - 1], a );
     513      240480 :     } else {
     514      240480 :       fd_secp256k1_point_dbl( &r[i], &r[i / 2]    );
     515      240480 :     }
     516      420840 :   }
     517       60120 :   return r;
     518       60120 : }
     519             : 
     520             : /* Computes s1*G + s2*P2, where G is the base point */
     521             : static inline fd_secp256k1_point_t *
     522             : fd_secp256k1_double_base_mul( fd_secp256k1_point_t *        r,
     523             :                               fd_secp256k1_scalar_t const * s1,
     524             :                               fd_secp256k1_point_t  const * p2,
     525       30060 :                               fd_secp256k1_scalar_t const * s2 ) {
     526       30060 :   fd_secp256k1_point_t base[ 1 ];
     527       30060 :   fd_secp256k1_point_set_base( base );
     528             : 
     529       30060 :   fd_secp256k1_point_t pc1[ 9 ];
     530       30060 :   fd_secp256k1_point_t pc2[ 9 ];
     531             :   /* TODO: Precompute the basepoint table in a generated table */
     532       30060 :   fd_secp256k1_precompute( pc1, base );
     533       30060 :   fd_secp256k1_precompute( pc2, p2 );
     534             : 
     535       30060 :   schar e1[ 2 * 32 + 1 ];
     536       30060 :   schar e2[ 2 * 32 + 1 ];
     537       30060 :   fd_secp256k1_slide( e1, s1->buf );
     538       30060 :   fd_secp256k1_slide( e2, s2->buf );
     539             : 
     540       30060 :   fd_secp256k1_point_set_identity( r );
     541     1953900 :   for( int pos = 2 * 32; ; pos -= 1 ) {
     542     1953900 :     schar slot1 = e1[pos];
     543     1953900 :     if( slot1 > 0 ) {
     544      781878 :       fd_secp256k1_point_add( r, r, &pc1[(ulong)slot1] );
     545     1172022 :     } else if( slot1 < 0 ) {
     546      961515 :       fd_secp256k1_point_sub( r, r, &pc1[(ulong)(-slot1)] );
     547      961515 :     }
     548             : 
     549     1953900 :     schar slot2 = e2[pos];
     550     1953900 :     if( slot2 > 0 ) {
     551      751701 :       fd_secp256k1_point_add( r, r, &pc2[(ulong)slot2] );
     552     1202199 :     } else if( slot2 < 0 ) {
     553     1081869 :       fd_secp256k1_point_sub( r, r, &pc2[(ulong)(-slot2)] );
     554     1081869 :     }
     555             : 
     556     1953900 :     if( pos == 0 ) break;
     557     1923840 :     fd_secp256k1_point_dbl( r, r );
     558     1923840 :     fd_secp256k1_point_dbl( r, r );
     559     1923840 :     fd_secp256k1_point_dbl( r, r );
     560     1923840 :     fd_secp256k1_point_dbl( r, r );
     561     1923840 :   }
     562             : 
     563       30060 :   return r;
     564       30060 : }
     565             : 
     566             : static inline fd_secp256k1_point_t *
     567             : fd_secp256k1_point_to_affine( fd_secp256k1_point_t *       r,
     568       30060 :                               fd_secp256k1_point_t const * a ) {
     569       30060 :   fd_secp256k1_fp_t z[1];
     570       30060 :   fd_secp256k1_fp_invert( z, a->z );
     571       30060 :   fd_secp256k1_fp_mul( r->x, a->x, z );
     572       30060 :   fd_secp256k1_fp_mul( r->y, a->y, z );
     573       30060 :   return r;
     574       30060 : }
     575             : 
     576             : static inline int
     577       30060 : fd_secp256k1_point_is_identity( fd_secp256k1_point_t const *a ) {
     578       30060 :   int affine =
     579       30060 :      fd_secp256k1_fp_eq( a->x, fd_secp256k1_const_zero ) &
     580       30060 :      ( fd_secp256k1_fp_eq( a->y, fd_secp256k1_const_zero     ) |
     581       30060 :        fd_secp256k1_fp_eq( a->y, fd_secp256k1_const_one_mont ) );
     582       30060 :   return fd_secp256k1_fp_eq( a->z, fd_secp256k1_const_zero ) | affine;
     583       30060 : }

Generated by: LCOV version 1.14