LCOV - code coverage report
Current view: top level - ballet/ed25519 - fd_curve25519.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 147 255 57.6 %
Date: 2026-10-22 18:10:43 Functions: 7 17 41.2 %

          Line data    Source code
       1             : #include "fd_curve25519.h"
       2             : #include "../hex/fd_hex.h"
       3             : 
       4             : /*
       5             :  * Secure implementations (const time + clean temp vars)
       6             :  */
       7             : #include "fd_curve25519_secure.c"
       8             : 
       9             : #if FD_HAS_AVX512
      10             : #include "avx512/fd_curve25519.c"
      11             : #else
      12             : #include "ref/fd_curve25519.c"
      13             : #endif
      14             : 
      15     1340763 : #define WNAF_BIT_SZ 4
      16     1173046 : #define WNAF_TBL_SZ (2*WNAF_BIT_SZ)
      17             : 
      18             : /*
      19             :  * Ser/de
      20             :  */
      21             : 
      22             :  void
      23             :  fd_ed25519_debug( char const *               name,
      24           0 :                    fd_ed25519_point_t const * a ) {
      25           0 :   fd_f25519_t x[1], y[1], z[1], t[1];
      26           0 :   fd_ed25519_point_to( x, y, z, t, a );
      27           0 :   FD_LOG_WARNING(( "%s", name ));
      28           0 :   fd_f25519_debug( "x", x );
      29           0 :   fd_f25519_debug( "y", y );
      30           0 :   fd_f25519_debug( "z", z );
      31           0 :   fd_f25519_debug( "t", t );
      32           0 :  }
      33             : 
      34             : fd_ed25519_point_t *
      35             : fd_ed25519_point_frombytes( fd_ed25519_point_t * r,
      36         944 :                             uchar const          buf[ 32 ] ) {
      37         944 :   fd_f25519_t x[1], y[1], t[1];
      38         944 :   fd_f25519_frombytes( y, buf );
      39         944 :   uchar expected_x_sign = buf[31] >> 7;
      40             : 
      41         944 :   fd_f25519_t u[1];
      42         944 :   fd_f25519_t v[1];
      43         944 :   fd_f25519_sqr( u, y                );
      44         944 :   fd_f25519_mul( v, u, fd_f25519_d   );
      45         944 :   fd_f25519_sub( u, u, fd_f25519_one ); /* u = y^2-1 */
      46         944 :   fd_f25519_add( v, v, fd_f25519_one ); /* v = dy^2+1 */
      47             : 
      48         944 :   int was_square = fd_f25519_sqrt_ratio( x, u, v );
      49         944 :   if( FD_UNLIKELY( !was_square ) ) {
      50          19 :     return NULL;
      51          19 :   }
      52             : 
      53             :   /* Note: RFC 8032 Section 5.1.3 says "if x=0 and x_0=1, decoding
      54             :      fails", but Dalek does not enforce this — neg(0)==0 so it silently
      55             :      accepts the point.  We match Dalek for compatibility.
      56             :      https://github.com/dalek-cryptography/curve25519-dalek/blob/curve25519-4.1.3/curve25519-dalek/src/edwards.rs#L194-L240
      57             :      https://github.com/dalek-cryptography/curve25519-dalek/blob/3.2.1/src/edwards.rs#L193-L209 */
      58         925 :   if( fd_f25519_sgn(x)!=expected_x_sign ) { /* 50% prob */
      59         443 :     fd_f25519_neg( x, x );
      60         443 :   }
      61             : 
      62         925 :   fd_f25519_mul( t, x, y );
      63         925 :   fd_ed25519_point_from( r, x, y, fd_f25519_one, t );
      64             : 
      65         925 :   return r;
      66         944 : }
      67             : 
      68             : /* fd_ed25519_point_frombytes (like Dalek's decompress) takes y mod p
      69             :    (non-canonical y accepted), ignores the sign bit for validity (x=0
      70             :    with sign 1 is accepted) and succeeds iff u/v is a square or zero,
      71             :    with u=y^2-1 and v=d*y^2+1.  v is never 0 as d is a non-square and -1
      72             :    is a square, so this is the same as u*v being a square or zero, which
      73             :    a Jacobi symbol decides much faster than a square root. */
      74             : int
      75        2002 : fd_ed25519_point_validate( uchar const buf[ 32 ] ) {
      76        2002 :   fd_f25519_t y[1], u[1], v[1];
      77        2002 :   fd_f25519_frombytes( y, buf );
      78        2002 :   fd_f25519_sqr( u, y                );
      79        2002 :   fd_f25519_mul( v, u, fd_f25519_d   );
      80        2002 :   fd_f25519_sub( u, u, fd_f25519_one ); /* u = y^2-1 */
      81        2002 :   fd_f25519_add( v, v, fd_f25519_one ); /* v = dy^2+1 */
      82        2002 :   fd_f25519_mul( u, u, v             );
      83        2002 :   return fd_f25519_is_square_var( u );
      84        2002 : }
      85             : 
      86             : uchar *
      87             : fd_ed25519_point_tobytes_batch8( uchar                      out[],  /* 32*n */
      88             :                                  fd_ed25519_point_t const * pt,     /* n */
      89           0 :                                  ulong                      n ) {   /* in [1,8] */
      90           0 :   FD_TEST( 0UL<n && n<=8UL );
      91             : 
      92           0 :   fd_f25519_t x[8], y[8], z[8], t[1];
      93           0 :   for( ulong i=0UL; i<n; i++ ) fd_ed25519_point_to( &x[i], &y[i], &z[i], t, &pt[i] );
      94             : 
      95             :   /* batch inv */
      96             : 
      97           0 :   fd_f25519_t c[8], iz[8], u[1];
      98           0 :   c[0] = z[0];
      99           0 :   for( ulong i=1UL; i<n; i++ ) fd_f25519_mul( &c[i], &c[i-1], &z[i] );
     100           0 :   fd_f25519_inv( u, &c[n-1UL] );
     101           0 :   for( ulong i=n-1UL; i>0UL; i-- ) {
     102           0 :     fd_f25519_mul( &iz[i], u, &c[i-1] );
     103           0 :     fd_f25519_mul( u, u, &z[i] );
     104           0 :   }
     105           0 :   iz[0] = *u;
     106             : 
     107           0 :   ulong i=0UL;
     108           0 :   for( ; i+2UL<=n; i+=2UL ) fd_f25519_mul4( &x[i  ], &x[i  ], &iz[i  ],
     109           0 :                                             &y[i  ], &y[i  ], &iz[i  ],
     110           0 :                                             &x[i+1], &x[i+1], &iz[i+1],
     111           0 :                                             &y[i+1], &y[i+1], &iz[i+1] );
     112           0 :   if( i<n ) fd_f25519_mul2( &x[i], &x[i], &iz[i],
     113           0 :                             &y[i], &y[i], &iz[i] );
     114             : 
     115           0 :   for( ulong j=0UL; j<n; j++ ) {
     116           0 :     fd_f25519_tobytes( out+32UL*j, &y[j] );
     117           0 :     out[ 32UL*j+31UL ] ^= (uchar)(fd_f25519_sgn( &x[j] ) << 7);
     118           0 :   }
     119           0 :   return out;
     120           0 : }
     121             : 
     122             : uchar *
     123             : fd_ed25519_point_tobytes( uchar                      out[ 32 ],
     124         283 :                           fd_ed25519_point_t const * a ) {
     125             :   /* equivalent to: return fd_ed25519_point_tobytes_batch8( out, a, 1UL ) */
     126         283 :   fd_f25519_t x[1], y[1], z[1], t[1];
     127         283 :   fd_ed25519_point_to( x, y, z, t, a );
     128         283 :   fd_f25519_inv( t, z );
     129         283 :   fd_f25519_mul2( x, x, t,
     130         283 :                   y, y, t );
     131         283 :   fd_f25519_tobytes( out, y );
     132         283 :   out[31] ^= (uchar)(fd_f25519_sgn( x ) << 7);
     133         283 :   return out;
     134         283 : }
     135             : 
     136             : /*
     137             :  * Scalar multiplication
     138             :  */
     139             : 
     140             : fd_ed25519_point_t *
     141             : fd_ed25519_scalar_mul( fd_ed25519_point_t *       r,
     142             :                        uchar const                n[ 32 ],
     143         104 :                        fd_ed25519_point_t const * a ) {
     144         104 :   short nslide[256];
     145         104 :   fd_curve25519_scalar_wnaf( nslide, n, WNAF_BIT_SZ );
     146             : 
     147         104 :   fd_ed25519_point_t ai[WNAF_TBL_SZ]; /* A,3A,5A,7A,9A,11A,13A,15A */
     148         104 :   fd_ed25519_point_t a2[1];           /* 2A (temp) */
     149         104 :   fd_ed25519_point_t t[1];
     150             : 
     151             :   /* pre-computed table */
     152         104 :   fd_ed25519_point_set( &ai[0], a );
     153         104 :   fd_ed25519_point_dbln( a2, a, 1 ); // note: a is affine, we could save 1mul
     154         104 :   fd_curve25519_into_precomputed( &ai[0] );
     155         832 :   for( int i=1; i<WNAF_TBL_SZ; i++ ) {
     156         728 :     fd_ed25519_point_add_with_opts( t, a2, &ai[i-1], i==1, 1, 1 );
     157         728 :     fd_ed25519_point_add_final_mul( &ai[i], t );
     158             :     /* pre-compute kT, to save 1mul during the loop */
     159         728 :     fd_curve25519_into_precomputed( &ai[i] );
     160         728 :   }
     161             : 
     162             :   /* main dbl-and-add loop. note: last iter unrolled */
     163         104 :   fd_ed25519_point_set_zero( r );
     164         104 :   int i;
     165        2200 :   for( i=255; i>=0; i-- ) { if( nslide[i] ) break; }
     166       23995 :   for(      ; i>=0; i-- ) {
     167       23891 :     fd_ed25519_partial_dbl( t, r );
     168       23891 :     if(      nslide[i] > 0 ) { fd_ed25519_point_add_final_mul( r, t ); fd_ed25519_point_add_with_opts( t, r, &ai[  nslide[i]  / 2], nslide[i]==1, 1, 1 ); }
     169       21746 :     else if( nslide[i] < 0 ) { fd_ed25519_point_add_final_mul( r, t ); fd_ed25519_point_sub_with_opts( t, r, &ai[(-nslide[i]) / 2], nslide[i]==-1, 1, 1 ); }
     170             : 
     171             :     /* ignore r->T because dbl doesn't need it, except in the last cycle */
     172       23891 :     if (i == 0) {
     173         101 :       fd_ed25519_point_add_final_mul( r, t );            // compute r->T
     174       23790 :     } else {
     175       23790 :       fd_ed25519_point_add_final_mul_projective( r, t ); // ignore r->T
     176       23790 :     }
     177       23891 :   }
     178         104 :   return r;
     179         104 : }
     180             : 
     181             : fd_ed25519_point_t *
     182             : fd_ed25519_double_scalar_mul_base( fd_ed25519_point_t *       r,
     183             :                                    uchar const                n1[ 32 ],
     184             :                                    fd_ed25519_point_t const * a,
     185        2419 :                                    uchar const                n2[ 32 ] ) {
     186             : 
     187        2419 :   short n1slide[256]; fd_curve25519_scalar_wnaf( n1slide, n1, WNAF_BIT_SZ );
     188        2419 :   short n2slide[256]; fd_curve25519_scalar_wnaf( n2slide, n2, 8 );
     189             : 
     190        2419 :   fd_ed25519_point_t ai[WNAF_TBL_SZ]; /* A,3A,5A,7A,9A,11A,13A,15A */
     191        2419 :   fd_ed25519_point_t a2[1];           /* 2A (temp) */
     192        2419 :   fd_ed25519_point_t t[1];
     193             : 
     194             :   /* pre-computed table */
     195        2419 :   fd_ed25519_point_set( &ai[0], a );
     196        2419 :   fd_ed25519_point_dbln( a2, a, 1 ); // note: a is affine, we could save 1mul
     197        2419 :   fd_curve25519_into_precomputed( &ai[0] );
     198       19327 :   for( int i=1; i<WNAF_TBL_SZ; i++ ) {
     199       16908 :     fd_ed25519_point_add_with_opts( t, a2, &ai[i-1], i==1, 1, 1 );
     200       16908 :     fd_ed25519_point_add_final_mul( &ai[i], t );
     201             :     /* pre-compute kT, to save 1mul during the loop */
     202       16908 :     fd_curve25519_into_precomputed( &ai[i] );
     203       16908 :   }
     204             : 
     205             :   /* main dbl-and-add loop */
     206        2419 :   fd_ed25519_point_set_zero( r );
     207             : 
     208        2419 :   int i;
     209       13999 :   for( i=255; i>=0; i-- ) { if( n1slide[i] || n2slide[i] ) break; }
     210      597521 :   for(      ; i>=0; i-- ) {
     211      595102 :     fd_ed25519_partial_dbl( t, r );
     212      595102 :     if(      n1slide[i] > 0 ) { fd_ed25519_point_add_final_mul( r, t ); fd_ed25519_point_add_with_opts( t, r, &ai[  n1slide[i]  / 2], n1slide[i]==1, 1, 1 ); }
     213      544561 :     else if( n1slide[i] < 0 ) { fd_ed25519_point_add_final_mul( r, t ); fd_ed25519_point_sub_with_opts( t, r, &ai[(-n1slide[i]) / 2], n1slide[i]==-1, 1, 1 ); }
     214      595102 :     if(      n2slide[i] > 0 ) { fd_ed25519_point_add_final_mul( r, t ); fd_ed25519_point_add_with_opts( t, r, &fd_ed25519_base_point_wnaf_table[  n2slide[i]  / 2], 1, 1, 1 ); }
     215      563635 :     else if( n2slide[i] < 0 ) { fd_ed25519_point_add_final_mul( r, t ); fd_ed25519_point_sub_with_opts( t, r, &fd_ed25519_base_point_wnaf_table[(-n2slide[i]) / 2], 1, 1, 1 ); }
     216             : 
     217             :     /* ignore r->T because dbl doesn't need it, except in the last cycle */
     218      595102 :     if (i == 0) {
     219        2420 :       fd_ed25519_point_add_final_mul( r, t );            // compute r->T
     220      592682 :     } else {
     221      592682 :       fd_ed25519_point_add_final_mul_projective( r, t ); // ignore r->T
     222      592682 :     }
     223      595102 :   }
     224        2419 :   return r;
     225        2419 : }
     226             : 
     227             : 
     228             : /* split_odd_table fills tbl[0,n) with p,3p,..,(2n-1)p in precomputed
     229             :    form. */
     230             : 
     231             : static void
     232             : split_odd_table( fd_ed25519_point_t *       tbl,
     233             :                  fd_ed25519_point_t const * p,
     234           0 :                  int                        n ) {
     235           0 :   fd_ed25519_point_t p2[1];
     236           0 :   fd_ed25519_point_set( &tbl[0], p );
     237           0 :   fd_ed25519_point_dbln( p2, p, 1 );
     238           0 :   for( int i=1; i<n; i++ ) fd_ed25519_point_add( &tbl[i], p2, &tbl[i-1] );
     239           0 :   for( int i=0; i<n; i++ ) fd_curve25519_into_precomputed( &tbl[i] );
     240           0 : }
     241             : 
     242             : void
     243             : fd_ed25519_split_table_a( fd_ed25519_point_t         tbl[ FD_ED25519_SPLIT_A_TBL_CNT ],
     244           0 :                           fd_ed25519_point_t const * a ) {
     245           0 :   fd_ed25519_point_t p[1];
     246           0 :   fd_ed25519_point_set( p, a );
     247           0 :   for( int j=0; j<FD_ED25519_SPLIT_SEG_CNT; j++ ) {
     248           0 :     if( j ) fd_ed25519_point_dbln( p, p, FD_ED25519_SPLIT_SEG_BITS );
     249           0 :     split_odd_table( tbl+FD_ED25519_SPLIT_A_SEG_CNT*j, p, FD_ED25519_SPLIT_A_SEG_CNT );
     250           0 :   }
     251           0 : }
     252             : 
     253             : void
     254           0 : fd_ed25519_split_table_b( fd_ed25519_point_t tbl[ FD_ED25519_SPLIT_B_TBL_CNT ] ) {
     255           0 :   fd_ed25519_point_t p[1];
     256           0 :   fd_ed25519_point_set( p, fd_ed25519_base_point );
     257           0 :   for( int j=1; j<FD_ED25519_SPLIT_SEG_CNT; j++ ) {
     258           0 :     fd_ed25519_point_dbln( p, p, FD_ED25519_SPLIT_SEG_BITS );
     259           0 :     split_odd_table( tbl+128*(j-1), p, 128 );
     260           0 :   }
     261           0 : }
     262             : 
     263             : /* double_scalar_mul_base_split also advances dec (if non-NULL) by
     264             :    DEC_STEP chain ops after each point op (3 measured best). */
     265             : 
     266           0 : #define DEC_STEP (3UL)
     267             : 
     268             : static inline fd_ed25519_point_t *
     269             : double_scalar_mul_base_split( fd_ed25519_point_t *        r,
     270             :                               uchar const                 n1[ 32 ],
     271             :                               fd_ed25519_point_t const *  a_tbl,
     272             :                               uchar const                 n2[ 32 ],
     273             :                               fd_ed25519_point_t const *  b_tbl,
     274           0 :                               fd_ed25519_point_decode_t * dec ) {
     275             : 
     276             :   /* Digit d at position b*j+i contributes [d 2^i][2^(b*j)]P, so the
     277             :      segments of each wNAF share a single b doubling loop. */
     278             : 
     279           0 :   short n1slide[256]; fd_curve25519_scalar_wnaf( n1slide, n1, FD_ED25519_SPLIT_A_BITS );
     280           0 :   short n2slide[256]; fd_curve25519_scalar_wnaf( n2slide, n2, 8 );
     281             : 
     282           0 :   fd_ed25519_point_t const * bt[ FD_ED25519_SPLIT_SEG_CNT ];
     283           0 :   bt[0] = fd_ed25519_base_point_wnaf_table;
     284           0 :   for( int j=1; j<FD_ED25519_SPLIT_SEG_CNT; j++ ) bt[j] = b_tbl + 128*(j-1);
     285           0 :   fd_ed25519_point_t t[1];
     286             : 
     287           0 :   fd_ed25519_point_set_zero( r );
     288             : 
     289           0 :   int i;
     290           0 :   for( i=FD_ED25519_SPLIT_SEG_BITS-1; i>=0; i-- ) {
     291           0 :     short nz = 0;
     292           0 :     for( int j=0; j<FD_ED25519_SPLIT_SEG_CNT; j++ ) nz |= n1slide[ FD_ED25519_SPLIT_SEG_BITS*j+i ] | n2slide[ FD_ED25519_SPLIT_SEG_BITS*j+i ];
     293           0 :     if( nz ) break;
     294           0 :   }
     295           0 :   for( ; i>=0; i-- ) {
     296           0 :     fd_ed25519_partial_dbl( t, r );
     297           0 :     if( dec ) fd_ed25519_point_decode_step( dec, DEC_STEP );
     298           0 :     for( int j=0; j<FD_ED25519_SPLIT_SEG_CNT; j++ ) {
     299           0 :       short d1 = n1slide[ FD_ED25519_SPLIT_SEG_BITS*j+i ];
     300           0 :       short d2 = n2slide[ FD_ED25519_SPLIT_SEG_BITS*j+i ];
     301           0 :       if(      d1 > 0 ) { fd_ed25519_point_add_final_mul( r, t ); fd_ed25519_point_add_with_opts( t, r, &a_tbl[ FD_ED25519_SPLIT_A_SEG_CNT*j + d1/2    ], 0,    1, 1 ); if( dec ) fd_ed25519_point_decode_step( dec, DEC_STEP ); }
     302           0 :       else if( d1 < 0 ) { fd_ed25519_point_add_final_mul( r, t ); fd_ed25519_point_sub_with_opts( t, r, &a_tbl[ FD_ED25519_SPLIT_A_SEG_CNT*j + (-d1)/2 ], 0,    1, 1 ); if( dec ) fd_ed25519_point_decode_step( dec, DEC_STEP ); }
     303           0 :       if(      d2 > 0 ) { fd_ed25519_point_add_final_mul( r, t ); fd_ed25519_point_add_with_opts( t, r, &bt[j][ d2/2    ],                              j==0, 1, 1 ); if( dec ) fd_ed25519_point_decode_step( dec, DEC_STEP ); }
     304           0 :       else if( d2 < 0 ) { fd_ed25519_point_add_final_mul( r, t ); fd_ed25519_point_sub_with_opts( t, r, &bt[j][ (-d2)/2 ],                              j==0, 1, 1 ); if( dec ) fd_ed25519_point_decode_step( dec, DEC_STEP ); }
     305           0 :     }
     306             : 
     307             :     /* ignore r->T because dbl doesn't need it, except in the last cycle */
     308           0 :     if( i==0 ) fd_ed25519_point_add_final_mul( r, t );
     309           0 :     else       fd_ed25519_point_add_final_mul_projective( r, t );
     310           0 :   }
     311           0 :   return r;
     312           0 : }
     313             : 
     314             : fd_ed25519_point_t *
     315             : fd_ed25519_double_scalar_mul_base_split( fd_ed25519_point_t *       r,
     316             :                                          uchar const                n1[ 32 ],
     317             :                                          fd_ed25519_point_t const * a_tbl,
     318             :                                          uchar const                n2[ 32 ],
     319           0 :                                          fd_ed25519_point_t const * b_tbl ) {
     320           0 :   return double_scalar_mul_base_split( r, n1, a_tbl, n2, b_tbl, NULL );
     321           0 : }
     322             : 
     323             : fd_ed25519_point_t *
     324             : fd_ed25519_double_scalar_mul_base_split_decode( fd_ed25519_point_t *        r,
     325             :                                                 uchar const                 n1[ 32 ],
     326             :                                                 fd_ed25519_point_t const *  a_tbl,
     327             :                                                 uchar const                 n2[ 32 ],
     328             :                                                 fd_ed25519_point_t const *  b_tbl,
     329           0 :                                                 fd_ed25519_point_decode_t * dec ) {
     330           0 :   return double_scalar_mul_base_split( r, n1, a_tbl, n2, b_tbl, dec );
     331           0 : }
     332             : 
     333             : FD_25519_INLINE fd_ed25519_point_t *
     334             : fd_ed25519_multi_scalar_mul_with_opts( fd_ed25519_point_t *     r,
     335             :                                        uchar const              n[], /* sz * 32 */
     336             :                                        fd_ed25519_point_t const a[], /* sz */
     337             :                                        ulong const              sz,
     338        7461 :                                        ulong const              base_sz ) {
     339        7461 :   short nslide[FD_BALLET_CURVE25519_MSM_BATCH_SZ][256];
     340        7461 :   fd_ed25519_point_t ai[FD_BALLET_CURVE25519_MSM_BATCH_SZ][WNAF_TBL_SZ]; /* A,3A,5A,7A,9A,11A,13A,15A */
     341        7461 :   fd_ed25519_point_t a2[1];                          /* 2A (temp) */
     342        7461 :   fd_ed25519_point_t t[1];                           /* temp */
     343             : 
     344        7461 :   if( base_sz ) {
     345           0 :     fd_curve25519_scalar_wnaf( nslide[0], &n[32*0], 8 );
     346           0 :   }
     347      172655 :   for( ulong j=base_sz; j<sz; j++ ) {
     348      165194 :     fd_curve25519_scalar_wnaf( nslide[j], &n[32*j], WNAF_BIT_SZ );
     349             : 
     350             :     /* pre-computed table */
     351      165194 :     fd_ed25519_point_set( &ai[j][0], &a[j] );
     352      165194 :     fd_ed25519_point_dbln( a2, &a[j], 1 ); // note: a is affine, we could save 1mul
     353      165194 :     fd_curve25519_into_precomputed( &ai[j][0] );
     354     1152887 :     for( int i=1; i<WNAF_TBL_SZ; i++ ) {
     355      987693 :       fd_ed25519_point_add_with_opts( t, a2, &ai[j][i-1], i==1, 1, 1 );
     356      987693 :       fd_ed25519_point_add_final_mul( &ai[j][i], t );
     357             :       /* pre-compute kT, to save 1mul during the loop */
     358      987693 :       fd_curve25519_into_precomputed( &ai[j][i] );
     359      987693 :     }
     360      165194 :   }
     361             : 
     362             :   /* main dbl-and-add loop */
     363        7461 :   fd_ed25519_point_set_zero( r );
     364      612901 :   for( int i=255; i>=0; i-- ) {
     365      605440 :     fd_ed25519_partial_dbl( t, r );
     366      605440 :     if( base_sz ) {
     367           0 :       if(      nslide[0][i] > 0 ) { fd_ed25519_point_add_final_mul( r, t ); fd_ed25519_point_add_with_opts( t, r, &fd_ed25519_base_point_wnaf_table[  nslide[0][i]  / 2], 1, 1, 1 ); }
     368           0 :       else if( nslide[0][i] < 0 ) { fd_ed25519_point_add_final_mul( r, t ); fd_ed25519_point_sub_with_opts( t, r, &fd_ed25519_base_point_wnaf_table[(-nslide[0][i]) / 2], 1, 1, 1 ); }
     369           0 :     }
     370    13756160 :     for( ulong j=base_sz; j<sz; j++ ) {
     371    13150720 :       short n = nslide[j][i];
     372    13150720 :       if(      n > 0 ) { fd_ed25519_point_add_final_mul( r, t ); fd_ed25519_point_add_with_opts( t, r, &ai[j][  n  / 2], (n==1), 1, 1 ); }
     373    11759906 :       else if( n < 0 ) { fd_ed25519_point_add_final_mul( r, t ); fd_ed25519_point_sub_with_opts( t, r, &ai[j][(-n) / 2], (n==-1), 1, 1 ); }
     374    13150720 :     }
     375             : 
     376             :     /* ignore r->T because dbl doesn't need it, except in the last cycle */
     377      605440 :     if (i == 0) {
     378        7382 :       fd_ed25519_point_add_final_mul( r, t );            // compute r->T
     379      598058 :     } else {
     380      598058 :       fd_ed25519_point_add_final_mul_projective( r, t ); // ignore r->T
     381      598058 :     }
     382      605440 :   }
     383        7461 :   return r;
     384        7461 : }
     385             : 
     386             : fd_ed25519_point_t *
     387             : fd_ed25519_multi_scalar_mul( fd_ed25519_point_t *     r,
     388             :                              uchar const              n[], /* sz * 32 */
     389             :                              fd_ed25519_point_t const a[], /* sz */
     390        2712 :                              ulong const              sz ) {
     391             : 
     392        2712 :   fd_ed25519_point_t h[1];
     393        2712 :   fd_ed25519_point_set_zero( r );
     394             : 
     395       10175 :   for( ulong i=0; i<sz; i+=FD_BALLET_CURVE25519_MSM_BATCH_SZ ) {
     396        7463 :     ulong batch_sz = fd_ulong_min(sz-i, FD_BALLET_CURVE25519_MSM_BATCH_SZ);
     397             : 
     398        7463 :     fd_ed25519_multi_scalar_mul_with_opts( h, &n[ 32*i ], &a[ i ], batch_sz, 0 );
     399        7463 :     fd_ed25519_point_add( r, r, h );
     400        7463 :   }
     401             : 
     402        2712 :   return r;
     403        2712 : }
     404             : 
     405             : /*
     406             :  * Init
     407             :  */
     408             : 
     409             : fd_ed25519_point_t *
     410             : fd_curve25519_affine_add( fd_ed25519_point_t *       r,
     411             :                           fd_ed25519_point_t const * a,
     412           0 :                           fd_ed25519_point_t const * b ) {
     413           0 :   fd_ed25519_point_add_with_opts( r, a, b, 1, 0, 0 );
     414           0 :   return fd_curve25519_into_affine( r );
     415           0 : }
     416             : 
     417             : fd_ed25519_point_t *
     418             : fd_curve25519_affine_dbln( fd_ed25519_point_t *       r,
     419             :                            fd_ed25519_point_t const * a,
     420           0 :                            int const                  n ) {
     421           0 :   fd_ed25519_point_dbln( r, a, n );
     422           0 :   return fd_curve25519_into_affine( r );
     423           0 : }

Generated by: LCOV version 1.14