LCOV - code coverage report
Current view: top level - ballet/ed25519 - fd_curve25519.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 137 159 86.2 %
Date: 2026-04-18 06:15:07 Functions: 6 9 66.7 %

          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     8782668 : #define WNAF_BIT_SZ 4
      16     7806816 : #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     1131098 :                             uchar const          buf[ 32 ] ) {
      37     1131098 :   fd_f25519_t x[1], y[1], t[1];
      38     1131098 :   fd_f25519_frombytes( y, buf );
      39     1131098 :   uchar expected_x_sign = buf[31] >> 7;
      40             : 
      41     1131098 :   fd_f25519_t u[1];
      42     1131098 :   fd_f25519_t v[1];
      43     1131098 :   fd_f25519_sqr( u, y                );
      44     1131098 :   fd_f25519_mul( v, u, fd_f25519_d   );
      45     1131098 :   fd_f25519_sub( u, u, fd_f25519_one ); /* u = y^2-1 */
      46     1131098 :   fd_f25519_add( v, v, fd_f25519_one ); /* v = dy^2+1 */
      47             : 
      48     1131098 :   int was_square = fd_f25519_sqrt_ratio( x, u, v );
      49     1131098 :   if( FD_UNLIKELY( !was_square ) ) {
      50       89173 :     return NULL;
      51       89173 :   }
      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     1041925 :   if( fd_f25519_sgn(x)!=expected_x_sign ) { /* 50% prob */
      59      631998 :     fd_f25519_neg( x, x );
      60      631998 :   }
      61             : 
      62     1041925 :   fd_f25519_mul( t, x, y );
      63     1041925 :   fd_ed25519_point_from( r, x, y, fd_f25519_one, t );
      64             : 
      65     1041925 :   return r;
      66     1131098 : }
      67             : 
      68             : uchar *
      69             : fd_ed25519_point_tobytes( uchar                      out[ 32 ],
      70     1696179 :                           fd_ed25519_point_t const * a ) {
      71     1696179 :   fd_f25519_t x[1], y[1], z[1], t[1];
      72     1696179 :   fd_ed25519_point_to( x, y, z, t, a );
      73     1696179 :   fd_f25519_inv( t, z );
      74     1696179 :   fd_f25519_mul2( x, x, t,
      75     1696179 :                   y, y, t );
      76     1696179 :   fd_f25519_tobytes( out, y );
      77     1696179 :   out[31] ^= (uchar)(fd_f25519_sgn( x ) << 7);
      78     1696179 :   return out;
      79     1696179 : }
      80             : 
      81             : /*
      82             :  * Scalar multiplication
      83             :  */
      84             : 
      85             : fd_ed25519_point_t *
      86             : fd_ed25519_scalar_mul( fd_ed25519_point_t *       r,
      87             :                        uchar const                n[ 32 ],
      88       30024 :                        fd_ed25519_point_t const * a ) {
      89       30024 :   short nslide[256];
      90       30024 :   fd_curve25519_scalar_wnaf( nslide, n, WNAF_BIT_SZ );
      91             : 
      92       30024 :   fd_ed25519_point_t ai[WNAF_TBL_SZ]; /* A,3A,5A,7A,9A,11A,13A,15A */
      93       30024 :   fd_ed25519_point_t a2[1];           /* 2A (temp) */
      94       30024 :   fd_ed25519_point_t t[1];
      95             : 
      96             :   /* pre-computed table */
      97       30024 :   fd_ed25519_point_set( &ai[0], a );
      98       30024 :   fd_ed25519_point_dbln( a2, a, 1 ); // note: a is affine, we could save 1mul
      99       30024 :   fd_curve25519_into_precomputed( &ai[0] );
     100      240192 :   for( int i=1; i<WNAF_TBL_SZ; i++ ) {
     101      210168 :     fd_ed25519_point_add_with_opts( t, a2, &ai[i-1], i==1, 1, 1 );
     102      210168 :     fd_ed25519_point_add_final_mul( &ai[i], t );
     103             :     /* pre-compute kT, to save 1mul during the loop */
     104      210168 :     fd_curve25519_into_precomputed( &ai[i] );
     105      210168 :   }
     106             : 
     107             :   /* main dbl-and-add loop. note: last iter unrolled */
     108       30024 :   fd_ed25519_point_set_zero( r );
     109       30024 :   int i;
     110      121686 :   for( i=255; i>=0; i-- ) { if( nslide[i] ) break; }
     111     7624506 :   for(      ; i>=0; i-- ) {
     112     7594482 :     fd_ed25519_partial_dbl( t, r );
     113     7594482 :     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 ); }
     114     7294194 :     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 ); }
     115             : 
     116             :     /* ignore r->T because dbl doesn't need it, except in the last cycle */
     117     7594482 :     if (i == 0) {
     118       30024 :       fd_ed25519_point_add_final_mul( r, t );            // compute r->T
     119     7564458 :     } else {
     120     7564458 :       fd_ed25519_point_add_final_mul_projective( r, t ); // ignore r->T
     121     7564458 :     }
     122     7594482 :   }
     123       30024 :   return r;
     124       30024 : }
     125             : 
     126             : fd_ed25519_point_t *
     127             : fd_ed25519_double_scalar_mul_base( fd_ed25519_point_t *       r,
     128             :                                    uchar const                n1[ 32 ],
     129             :                                    fd_ed25519_point_t const * a,
     130      768696 :                                    uchar const                n2[ 32 ] ) {
     131             : 
     132      768696 :   short n1slide[256]; fd_curve25519_scalar_wnaf( n1slide, n1, WNAF_BIT_SZ );
     133      768696 :   short n2slide[256]; fd_curve25519_scalar_wnaf( n2slide, n2, 8 );
     134             : 
     135      768696 :   fd_ed25519_point_t ai[WNAF_TBL_SZ]; /* A,3A,5A,7A,9A,11A,13A,15A */
     136      768696 :   fd_ed25519_point_t a2[1];           /* 2A (temp) */
     137      768696 :   fd_ed25519_point_t t[1];
     138             : 
     139             :   /* pre-computed table */
     140      768696 :   fd_ed25519_point_set( &ai[0], a );
     141      768696 :   fd_ed25519_point_dbln( a2, a, 1 ); // note: a is affine, we could save 1mul
     142      768696 :   fd_curve25519_into_precomputed( &ai[0] );
     143     6149568 :   for( int i=1; i<WNAF_TBL_SZ; i++ ) {
     144     5380872 :     fd_ed25519_point_add_with_opts( t, a2, &ai[i-1], i==1, 1, 1 );
     145     5380872 :     fd_ed25519_point_add_final_mul( &ai[i], t );
     146             :     /* pre-compute kT, to save 1mul during the loop */
     147     5380872 :     fd_curve25519_into_precomputed( &ai[i] );
     148     5380872 :   }
     149             : 
     150             :   /* main dbl-and-add loop */
     151      768696 :   fd_ed25519_point_set_zero( r );
     152             : 
     153      768696 :   int i;
     154     4778898 :   for( i=255; i>=0; i-- ) { if( n1slide[i] || n2slide[i] ) break; }
     155   193544670 :   for(      ; i>=0; i-- ) {
     156   192775974 :     fd_ed25519_partial_dbl( t, r );
     157   192775974 :     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 ); }
     158   176005722 :     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 ); }
     159   192775974 :     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 ); }
     160   182633425 :     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 ); }
     161             : 
     162             :     /* ignore r->T because dbl doesn't need it, except in the last cycle */
     163   192775974 :     if (i == 0) {
     164      768696 :       fd_ed25519_point_add_final_mul( r, t );            // compute r->T
     165   192007278 :     } else {
     166   192007278 :       fd_ed25519_point_add_final_mul_projective( r, t ); // ignore r->T
     167   192007278 :     }
     168   192775974 :   }
     169      768696 :   return r;
     170      768696 : }
     171             : 
     172             : 
     173             : FD_25519_INLINE fd_ed25519_point_t *
     174             : fd_ed25519_multi_scalar_mul_with_opts( fd_ed25519_point_t *     r,
     175             :                                        uchar const              n[], /* sz * 32 */
     176             :                                        fd_ed25519_point_t const a[], /* sz */
     177             :                                        ulong const              sz,
     178        5559 :                                        ulong const              base_sz ) {
     179        5559 :   short nslide[FD_BALLET_CURVE25519_MSM_BATCH_SZ][256];
     180        5559 :   fd_ed25519_point_t ai[FD_BALLET_CURVE25519_MSM_BATCH_SZ][WNAF_TBL_SZ]; /* A,3A,5A,7A,9A,11A,13A,15A */
     181        5559 :   fd_ed25519_point_t a2[1];                          /* 2A (temp) */
     182        5559 :   fd_ed25519_point_t t[1];                           /* temp */
     183             : 
     184        5559 :   if( base_sz ) {
     185           0 :     fd_curve25519_scalar_wnaf( nslide[0], &n[32*0], 8 );
     186           0 :   }
     187      182691 :   for( ulong j=base_sz; j<sz; j++ ) {
     188      177132 :     fd_curve25519_scalar_wnaf( nslide[j], &n[32*j], WNAF_BIT_SZ );
     189             : 
     190             :     /* pre-computed table */
     191      177132 :     fd_ed25519_point_set( &ai[j][0], &a[j] );
     192      177132 :     fd_ed25519_point_dbln( a2, &a[j], 1 ); // note: a is affine, we could save 1mul
     193      177132 :     fd_curve25519_into_precomputed( &ai[j][0] );
     194     1417056 :     for( int i=1; i<WNAF_TBL_SZ; i++ ) {
     195     1239924 :       fd_ed25519_point_add_with_opts( t, a2, &ai[j][i-1], i==1, 1, 1 );
     196     1239924 :       fd_ed25519_point_add_final_mul( &ai[j][i], t );
     197             :       /* pre-compute kT, to save 1mul during the loop */
     198     1239924 :       fd_curve25519_into_precomputed( &ai[j][i] );
     199     1239924 :     }
     200      177132 :   }
     201             : 
     202             :   /* main dbl-and-add loop */
     203        5559 :   fd_ed25519_point_set_zero( r );
     204     1428663 :   for( int i=255; i>=0; i-- ) {
     205     1423104 :     fd_ed25519_partial_dbl( t, r );
     206     1423104 :     if( base_sz ) {
     207           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 ); }
     208           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 ); }
     209           0 :     }
     210    46768896 :     for( ulong j=base_sz; j<sz; j++ ) {
     211    45345792 :       short n = nslide[j][i];
     212    45345792 :       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 ); }
     213    41551481 :       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 ); }
     214    45345792 :     }
     215             : 
     216             :     /* ignore r->T because dbl doesn't need it, except in the last cycle */
     217     1423104 :     if (i == 0) {
     218        5559 :       fd_ed25519_point_add_final_mul( r, t );            // compute r->T
     219     1417545 :     } else {
     220     1417545 :       fd_ed25519_point_add_final_mul_projective( r, t ); // ignore r->T
     221     1417545 :     }
     222     1423104 :   }
     223        5559 :   return r;
     224        5559 : }
     225             : 
     226             : fd_ed25519_point_t *
     227             : fd_ed25519_multi_scalar_mul( fd_ed25519_point_t *     r,
     228             :                              uchar const              n[], /* sz * 32 */
     229             :                              fd_ed25519_point_t const a[], /* sz */
     230        1869 :                              ulong const              sz ) {
     231             : 
     232        1869 :   fd_ed25519_point_t h[1];
     233        1869 :   fd_ed25519_point_set_zero( r );
     234             : 
     235        7428 :   for( ulong i=0; i<sz; i+=FD_BALLET_CURVE25519_MSM_BATCH_SZ ) {
     236        5559 :     ulong batch_sz = fd_ulong_min(sz-i, FD_BALLET_CURVE25519_MSM_BATCH_SZ);
     237             : 
     238        5559 :     fd_ed25519_multi_scalar_mul_with_opts( h, &n[ 32*i ], &a[ i ], batch_sz, 0 );
     239        5559 :     fd_ed25519_point_add( r, r, h );
     240        5559 :   }
     241             : 
     242        1869 :   return r;
     243        1869 : }
     244             : 
     245             : /*
     246             :  * Init
     247             :  */
     248             : 
     249             : fd_ed25519_point_t *
     250             : fd_curve25519_affine_add( fd_ed25519_point_t *       r,
     251             :                           fd_ed25519_point_t const * a,
     252           0 :                           fd_ed25519_point_t const * b ) {
     253           0 :   fd_ed25519_point_add_with_opts( r, a, b, 1, 0, 0 );
     254           0 :   return fd_curve25519_into_affine( r );
     255           0 : }
     256             : 
     257             : fd_ed25519_point_t *
     258             : fd_curve25519_affine_dbln( fd_ed25519_point_t *       r,
     259             :                            fd_ed25519_point_t const * a,
     260           0 :                            int const                  n ) {
     261           0 :   fd_ed25519_point_dbln( r, a, n );
     262           0 :   return fd_curve25519_into_affine( r );
     263           0 : }

Generated by: LCOV version 1.14