LCOV - code coverage report
Current view: top level - ballet/secp256r1 - fd_secp256r1.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 4 190 2.1 %
Date: 2026-11-11 12:40:43 Functions: 0 14 0.0 %

          Line data    Source code
       1             : #include "fd_secp256r1_private.h"
       2             : 
       3             : #define PCURVE_NAME       fd_secp256r1
       4           0 : #define PCURVE_SCALAR_SZ  32
       5       13088 : #define PCURVE_SCALAR_T   fd_secp256r1_scalar_t
       6       13088 : #define PCURVE_POINT_T    fd_secp256r1_point_t
       7             : #define PCURVE_SHA_NAME   fd_sha256
       8             : #define PCURVE_SHA_T      fd_sha256_t
       9             : #define PCURVE_SHA_SZ     FD_SHA256_HASH_SZ
      10        4642 : #define PCURVE_SUCCESS    FD_SECP256R1_SUCCESS
      11        8446 : #define PCURVE_FAILURE    FD_SECP256R1_FAILURE
      12             : 
      13             : #include "../pcurves/fd_pcurve_tmpl.c"
      14             : 
      15             : /* Syscalls */
      16             : 
      17             : /* Loads a 32 byte integer, big or little endian, as plain limbs. */
      18             : static inline fd_uint256_t *
      19             : fd_secp256r1_uint256_frombytes( fd_uint256_t * r,
      20             :                                 uchar const    in[ 32 ],
      21           0 :                                 int            big_endian ) {
      22           0 :   memcpy( r->buf, in, 32 );
      23           0 :   if( big_endian ) fd_uint256_bswap( r, r );
      24           0 :   return r;
      25           0 : }
      26             : 
      27             : static inline uchar *
      28             : fd_secp256r1_uint256_tobytes( uchar                out[ 32 ],
      29             :                               fd_uint256_t const * a,
      30           0 :                               int                  big_endian ) {
      31           0 :   fd_uint256_t t[1];
      32           0 :   if( big_endian ) a = fd_uint256_bswap( t, a );
      33           0 :   memcpy( out, a->buf, 32 );
      34           0 :   return out;
      35           0 : }
      36             : 
      37             : /* Loads a scalar, NULL if not canonical (>= n). */
      38             : static inline fd_secp256r1_scalar_t *
      39             : fd_secp256r1_scalar_frombytes_syscall( fd_secp256r1_scalar_t * r,
      40             :                                        uchar const             in[ 32 ],
      41           0 :                                        int                     big_endian ) {
      42           0 :   fd_secp256r1_uint256_frombytes( r, in, big_endian );
      43           0 :   if( FD_LIKELY( fd_uint256_cmp( r, fd_secp256r1_const_n )<0 ) ) return r;
      44           0 :   return NULL;
      45           0 : }
      46             : 
      47             : /* Decodes x || y into affine-Montgomery (x, y) as 8 limbs.  64 zero
      48             :    bytes decode to (0, 0), infinity.  Returns NULL if a coordinate is
      49             :    not canonical (>= p) or the point is not on the curve. */
      50             : static ulong *
      51             : fd_secp256r1_affine_frombytes( ulong       r[ 8 ],
      52             :                                uchar const in[ 64 ],
      53           0 :                                int         big_endian ) {
      54           0 :   fd_secp256r1_fp_t x[1], y[1];
      55           0 :   fd_secp256r1_uint256_frombytes( x, in,    big_endian );
      56           0 :   fd_secp256r1_uint256_frombytes( y, in+32, big_endian );
      57             : 
      58           0 :   if( FD_UNLIKELY( fd_uint256_is_zero( x ) & fd_uint256_is_zero( y ) ) ) {
      59           0 :     memset( r, 0, 64 );
      60           0 :     return r;
      61           0 :   }
      62           0 :   if( FD_UNLIKELY( fd_uint256_cmp( x, fd_secp256r1_const_p )>=0 ) ) return NULL;
      63           0 :   if( FD_UNLIKELY( fd_uint256_cmp( y, fd_secp256r1_const_p )>=0 ) ) return NULL;
      64             : 
      65           0 :   fd_secp256r1_fp_tomont( x, x );
      66           0 :   fd_secp256r1_fp_tomont( y, y );
      67           0 :   if( FD_UNLIKELY( !fd_secp256r1_point_on_curve( x, y ) ) ) return NULL;
      68             : 
      69           0 :   memcpy( r,   x->limbs, 32 );
      70           0 :   memcpy( r+4, y->limbs, 32 );
      71           0 :   return r;
      72           0 : }
      73             : 
      74             : /* Encodes affine-Montgomery (x, y) as x || y.  (0, 0) encodes to 64
      75             :    zero bytes. */
      76             : static uchar *
      77             : fd_secp256r1_affine_tobytes( uchar       out[ 64 ],
      78             :                              ulong const a[ 8 ],
      79           0 :                              int         big_endian ) {
      80           0 :   fd_secp256r1_fp_t x[1], y[1];
      81           0 :   memcpy( x->limbs, a,   32 );
      82           0 :   memcpy( y->limbs, a+4, 32 );
      83           0 :   fd_secp256r1_fp_demont( x, x );
      84           0 :   fd_secp256r1_fp_demont( y, y );
      85           0 :   fd_secp256r1_uint256_tobytes( out,    x, big_endian );
      86           0 :   fd_secp256r1_uint256_tobytes( out+32, y, big_endian );
      87           0 :   return out;
      88           0 : }
      89             : 
      90             : static inline fd_secp256r1_point_t *
      91             : fd_secp256r1_point_from_affine( fd_secp256r1_point_t * r,
      92           0 :                                 ulong const            a[ 8 ] ) {
      93           0 :   memcpy( r->x->limbs, a,   32 );
      94           0 :   memcpy( r->y->limbs, a+4, 32 );
      95           0 :   if( FD_UNLIKELY( fd_uint256_is_zero( r->x ) & fd_uint256_is_zero( r->y ) ) ) {
      96           0 :     fd_secp256r1_point_set_inf( r );
      97           0 :   } else {
      98           0 :     fd_secp256r1_fp_set( r->z, fd_secp256r1_const_one_mont );
      99           0 :   }
     100           0 :   return r;
     101           0 : }
     102             : 
     103             : static inline uchar *
     104             : fd_secp256r1_point_tobytes_syscall( uchar                        out[ 64 ],
     105             :                                     fd_secp256r1_point_t const * a,
     106           0 :                                     int                          big_endian ) {
     107           0 :   ulong aff[ 8 ];
     108           0 :   fd_secp256r1_point_toaffine_mont( aff, a );
     109           0 :   return fd_secp256r1_affine_tobytes( out, aff, big_endian );
     110           0 : }
     111             : 
     112             : int
     113             : fd_secp256r1_validate_syscall( uchar const _a[ 64 ],
     114           0 :                                int         big_endian ) {
     115           0 :   ulong a[ 8 ];
     116           0 :   return !!fd_secp256r1_affine_frombytes( a, _a, big_endian );
     117           0 : }
     118             : 
     119             : int
     120             : fd_secp256r1_decompress_syscall( uchar       _r[ 64 ],
     121             :                                  uchar const _a[ 33 ],
     122           0 :                                  int         big_endian ) {
     123             :   /* fd_secp256r1_point_frombytes expects big endian x */
     124           0 :   uchar be[ 33 ];
     125           0 :   if( !big_endian ) {
     126           0 :     be[ 0 ] = _a[ 0 ];
     127           0 :     for( ulong i=0UL; i<32UL; i++ ) be[ 1UL+i ] = _a[ 32UL-i ];
     128           0 :     _a = be;
     129           0 :   }
     130             : 
     131           0 :   fd_secp256r1_point_t a[1];
     132           0 :   if( FD_UNLIKELY( !fd_secp256r1_point_frombytes( a, _a ) ) ) {
     133           0 :     return -1;
     134           0 :   }
     135             : 
     136           0 :   fd_secp256r1_point_tobytes_syscall( _r, a, big_endian );
     137           0 :   return 0;
     138           0 : }
     139             : 
     140             : int
     141             : fd_secp256r1_add_syscall( uchar       _r[ 64 ],
     142             :                           uchar const _a[ 64 ],
     143             :                           uchar const _b[ 64 ],
     144           0 :                           int         big_endian ) {
     145           0 :   ulong a[ 8 ], b[ 8 ];
     146           0 :   if( FD_UNLIKELY( !fd_secp256r1_affine_frombytes( a, _a, big_endian ) ) ) {
     147           0 :     return -1;
     148           0 :   }
     149           0 :   if( FD_UNLIKELY( !fd_secp256r1_affine_frombytes( b, _b, big_endian ) ) ) {
     150           0 :     return -1;
     151           0 :   }
     152             : 
     153           0 :   fd_secp256r1_point_t r[1];
     154           0 :   fd_secp256r1_point_from_affine( r, a );
     155           0 :   fd_secp256r1_point_add_mixed( r, r, b );
     156             : 
     157           0 :   fd_secp256r1_point_tobytes_syscall( _r, r, big_endian );
     158           0 :   return 0;
     159           0 : }
     160             : 
     161             : int
     162             : fd_secp256r1_sub_syscall( uchar       _r[ 64 ],
     163             :                           uchar const _a[ 64 ],
     164             :                           uchar const _b[ 64 ],
     165           0 :                           int         big_endian ) {
     166           0 :   ulong a[ 8 ], b[ 8 ];
     167           0 :   if( FD_UNLIKELY( !fd_secp256r1_affine_frombytes( a, _a, big_endian ) ) ) {
     168           0 :     return -1;
     169           0 :   }
     170           0 :   if( FD_UNLIKELY( !fd_secp256r1_affine_frombytes( b, _b, big_endian ) ) ) {
     171           0 :     return -1;
     172           0 :   }
     173             : 
     174             :   /* -b, it works also with b=0 */
     175           0 :   fd_secp256r1_fp_t y[1];
     176           0 :   memcpy( y->limbs, b+4, 32 );
     177           0 :   fd_secp256r1_fp_neg( y, y );
     178           0 :   memcpy( b+4, y->limbs, 32 );
     179             : 
     180           0 :   fd_secp256r1_point_t r[1];
     181           0 :   fd_secp256r1_point_from_affine( r, a );
     182           0 :   fd_secp256r1_point_add_mixed( r, r, b );
     183             : 
     184           0 :   fd_secp256r1_point_tobytes_syscall( _r, r, big_endian );
     185           0 :   return 0;
     186           0 : }
     187             : 
     188             : int
     189             : fd_secp256r1_mul_syscall( uchar       _r[ 64 ],
     190             :                           uchar const _n[ 32 ],
     191             :                           uchar const _a[ 64 ],
     192           0 :                           int         big_endian ) {
     193           0 :   fd_secp256r1_scalar_t n[1];
     194           0 :   ulong a[ 8 ];
     195           0 :   if( FD_UNLIKELY( !fd_secp256r1_scalar_frombytes_syscall( n, _n, big_endian ) ) ) {
     196           0 :     return -1;
     197           0 :   }
     198           0 :   if( FD_UNLIKELY( !fd_secp256r1_affine_frombytes( a, _a, big_endian ) ) ) {
     199           0 :     return -1;
     200           0 :   }
     201             : 
     202           0 :   fd_secp256r1_point_t p[1], r[1];
     203           0 :   fd_secp256r1_point_from_affine( p, a );
     204           0 :   fd_secp256r1_point_scalarmul( r, n->limbs, p );
     205             : 
     206           0 :   fd_secp256r1_point_tobytes_syscall( _r, r, big_endian );
     207           0 :   return 0;
     208           0 : }
     209             : 
     210             : /* Points per MSM batch, bounds the stack: 32*16*64B = 32kB of tables. */
     211           0 : #define FD_SECP256R1_MSM_BATCH_SZ 32UL
     212             : 
     213             : /* tbl[k] = k*P for k in [0,16), affine-Montgomery, (0,0) for infinity.
     214             :    Entries are computed in Jacobian and normalized with one inversion. */
     215             : static void
     216             : fd_secp256r1_msm_table( ulong       tbl[ 16 ][ 8 ],
     217           0 :                         ulong const p[ 8 ] ) {
     218           0 :   fd_secp256r1_point_t jac[ 16 ];
     219           0 :   fd_secp256r1_point_from_affine( jac+1, p );
     220           0 :   if( FD_UNLIKELY( fd_secp256r1_point_is_inf( jac+1 ) ) ) {
     221           0 :     memset( tbl, 0, 16*64 );
     222           0 :     return;
     223           0 :   }
     224           0 :   for( ulong k=2UL; k<16UL; k++ ) {
     225           0 :     if( k&1UL ) fd_secp256r1_point_add_mixed( jac+k, jac+k-1, p );
     226           0 :     else        fd_secp256r1_point_double( jac+k, jac+(k>>1) );
     227           0 :   }
     228             : 
     229             :   /* P has prime order > 16, so no entry in [1,16) is infinity. */
     230           0 :   fd_secp256r1_fp_t acc[ 16 ], inv[1], zinv[1], zinv2[1], t[1];
     231           0 :   fd_secp256r1_fp_set( acc, fd_secp256r1_const_one_mont );
     232           0 :   for( ulong k=1UL; k<16UL; k++ ) fd_secp256r1_fp_mul( acc+k, acc+k-1, jac[k].z );
     233           0 :   fd_secp256r1_fp_inv( inv, acc+15 );
     234           0 :   for( ulong k=15UL; k; k-- ) {
     235           0 :     fd_secp256r1_fp_mul( zinv, inv, acc+k-1 );
     236           0 :     fd_secp256r1_fp_mul( inv, inv, jac[k].z );
     237           0 :     fd_secp256r1_fp_sqr( zinv2, zinv );
     238           0 :     fd_secp256r1_fp_mul( t, jac[k].x, zinv2 );  memcpy( tbl[k],   t->limbs, 32 );
     239           0 :     fd_secp256r1_fp_mul( t, zinv2, zinv );
     240           0 :     fd_secp256r1_fp_mul( t, t, jac[k].y );       memcpy( tbl[k]+4, t->limbs, 32 );
     241           0 :   }
     242           0 :   memset( tbl[0], 0, 64 );
     243           0 : }
     244             : 
     245             : /* Straus with 4-bit windows, variable time: inputs are public. */
     246             : int
     247             : fd_secp256r1_msm_syscall( uchar       _r[ 64 ],
     248             :                           uchar const _n[], /* 32*cnt */
     249             :                           uchar const _a[], /* 64*cnt */
     250             :                           ulong       cnt,
     251           0 :                           int         big_endian ) {
     252           0 :   fd_secp256r1_point_t r[1];
     253           0 :   fd_secp256r1_point_set_inf( r );
     254             : 
     255           0 :   for( ulong off=0UL; off<cnt; off+=FD_SECP256R1_MSM_BATCH_SZ ) {
     256           0 :     ulong bcnt = fd_ulong_min( cnt-off, FD_SECP256R1_MSM_BATCH_SZ );
     257           0 :     fd_secp256r1_scalar_t n[ FD_SECP256R1_MSM_BATCH_SZ ];
     258           0 :     ulong tbl[ FD_SECP256R1_MSM_BATCH_SZ ][ 16 ][ 8 ];
     259             : 
     260           0 :     for( ulong i=0UL; i<bcnt; i++ ) {
     261           0 :       ulong a[ 8 ];
     262           0 :       if( FD_UNLIKELY( !fd_secp256r1_scalar_frombytes_syscall( n+i, _n+32UL*(off+i), big_endian ) ) ) {
     263           0 :         return -1;
     264           0 :       }
     265           0 :       if( FD_UNLIKELY( !fd_secp256r1_affine_frombytes( a, _a+64UL*(off+i), big_endian ) ) ) {
     266           0 :         return -1;
     267           0 :       }
     268           0 :       fd_secp256r1_msm_table( tbl[i], a );
     269           0 :     }
     270             : 
     271           0 :     fd_secp256r1_point_t acc[1];
     272           0 :     fd_secp256r1_point_set_inf( acc );
     273           0 :     for( ulong w=64UL; w; w-- ) { /* nibbles, most significant first */
     274           0 :       if( FD_LIKELY( !fd_secp256r1_point_is_inf( acc ) ) ) {
     275           0 :         fd_secp256r1_point_double( acc, acc );
     276           0 :         fd_secp256r1_point_double( acc, acc );
     277           0 :         fd_secp256r1_point_double( acc, acc );
     278           0 :         fd_secp256r1_point_double( acc, acc );
     279           0 :       }
     280           0 :       for( ulong i=0UL; i<bcnt; i++ ) {
     281           0 :         ulong d = ( n[i].limbs[ (w-1UL)>>4 ] >> ( 4UL*((w-1UL)&15UL) ) ) & 15UL;
     282           0 :         if( d ) fd_secp256r1_point_add_mixed( acc, acc, tbl[i][d] );
     283           0 :       }
     284           0 :     }
     285           0 :     fd_secp256r1_point_add( r, r, acc );
     286           0 :   }
     287             : 
     288           0 :   fd_secp256r1_point_tobytes_syscall( _r, r, big_endian );
     289           0 :   return 0;
     290           0 : }

Generated by: LCOV version 1.14