LCOV - code coverage report
Current view: top level - ballet/secp256r1 - fd_secp256r1_s2n.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 166 169 98.2 %
Date: 2026-05-16 06:43:53 Functions: 26 28 92.9 %

          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       44038 : #define bignum_demont_p256     bignum_demont_p256_alt
       9      204018 : #define bignum_mod_n256        bignum_mod_n256_alt
      10      340274 : #define bignum_montmul_p256    bignum_montmul_p256_alt
      11    10721170 : #define bignum_montsqr_p256    bignum_montsqr_p256_alt
      12      204018 : #define bignum_mul_4_8         bignum_mul_4_8_alt
      13       26044 : #define bignum_tomont_p256     bignum_tomont_p256_alt
      14           4 : #define p256_montjdouble       p256_montjdouble_alt
      15        2012 : #define p256_montjmixadd       p256_montjmixadd_alt
      16        2010 : #define p256_montjscalarmul    p256_montjscalarmul_alt
      17        2010 : #define p256_scalarmulbase     p256_scalarmulbase_alt
      18             : #endif
      19             : 
      20             : #include "fd_secp256r1_table.c"
      21             : 
      22             : /* Scalars */
      23             : 
      24             : static inline int
      25        6024 : fd_secp256r1_scalar_is_zero( fd_secp256r1_scalar_t const * a ) {
      26        6024 :   return fd_uint256_eq( a, fd_secp256r1_const_zero );
      27        6024 : }
      28             : 
      29             : static inline fd_secp256r1_scalar_t *
      30             : fd_secp256r1_scalar_frombytes( fd_secp256r1_scalar_t * r,
      31     3003045 :                                uchar const             in[ 32 ] ) {
      32     3003045 :   memcpy( r->buf, in, 32 );
      33     3003045 :   fd_uint256_bswap( r, r );
      34     3003045 :   if( FD_LIKELY( fd_uint256_cmp( r, fd_secp256r1_const_n )<0 ) ) {
      35     3003045 :     return r;
      36     3003045 :   };
      37           0 :   return NULL;
      38     3003045 : }
      39             : 
      40             : static inline fd_secp256r1_scalar_t *
      41             : fd_secp256r1_scalar_frombytes_positive( fd_secp256r1_scalar_t * r,
      42     3003021 :                                         uchar const             in[ 32 ] ) {
      43     3003021 :   memcpy( r->buf, in, 32 );
      44     3003021 :   fd_uint256_bswap( r, r );
      45     3003021 :   if( FD_LIKELY( fd_uint256_cmp( r, fd_secp256r1_const_n_m1_half )<=0 ) ) {
      46     3003015 :     return r;
      47     3003015 :   };
      48           6 :   return NULL;
      49     3003021 : }
      50             : 
      51             : static inline void
      52             : fd_secp256r1_scalar_from_digest( fd_secp256r1_scalar_t * r,
      53        3012 :                                  uchar const             in[ 32 ] ) {
      54        3012 :   memcpy( r->buf, in, 32 );
      55        3012 :   fd_uint256_bswap( r, r );
      56        3012 :   bignum_mod_n256_4( r->limbs, r->limbs );
      57        3012 : }
      58             : 
      59             : static inline fd_secp256r1_scalar_t *
      60             : fd_secp256r1_scalar_mul( fd_secp256r1_scalar_t *       r,
      61             :                          fd_secp256r1_scalar_t const * a,
      62      306027 :                          fd_secp256r1_scalar_t const * b ) {
      63      306027 :   ulong t[ 8 ];
      64      306027 :   bignum_mul_4_8( t, (ulong *)a->limbs, (ulong *)b->limbs );
      65      306027 :   bignum_mod_n256( r->limbs, 8, t );
      66      306027 :   return r;
      67      306027 : }
      68             : 
      69             : static inline fd_secp256r1_scalar_t *
      70             : fd_secp256r1_scalar_inv( fd_secp256r1_scalar_t       * r,
      71       33015 :                          fd_secp256r1_scalar_t const * a ) {
      72       33015 :   ulong t[ 12 ];
      73       33015 :   bignum_modinv( 4, r->limbs, (ulong *)a->limbs, (ulong *)fd_secp256r1_const_n[0].limbs, t );
      74       33015 :   return r;
      75       33015 : }
      76             : 
      77             : /* Field */
      78             : 
      79             : static inline fd_secp256r1_fp_t *
      80             : fd_secp256r1_fp_set( fd_secp256r1_fp_t * r,
      81       96072 :                      fd_secp256r1_fp_t const * a ) {
      82       96072 :   r->limbs[0] = a->limbs[0];
      83       96072 :   r->limbs[1] = a->limbs[1];
      84       96072 :   r->limbs[2] = a->limbs[2];
      85       96072 :   r->limbs[3] = a->limbs[3];
      86       96072 :   return r;
      87       96072 : }
      88             : 
      89             : static inline fd_secp256r1_fp_t *
      90             : fd_secp256r1_fp_frombytes( fd_secp256r1_fp_t * r,
      91     3033051 :                            uchar const             in[ 32 ] ) {
      92     3033051 :   memcpy( r->buf, in, 32 );
      93     3033051 :   fd_uint256_bswap( r, r );
      94     3033051 :   if( FD_LIKELY( fd_uint256_cmp( r, fd_secp256r1_const_p )<0 ) ) {
      95     3033048 :     return r;
      96     3033048 :   };
      97           3 :   return NULL;
      98     3033051 : }
      99             : 
     100             : static inline fd_secp256r1_fp_t *
     101             : fd_secp256r1_fp_sqrt( fd_secp256r1_fp_t *       r,
     102       63042 :                       fd_secp256r1_fp_t const * a ) {
     103             :   /* https://github.com/golang/go/blob/master/src/crypto/internal/fips140/nistec/p256.go#L656 */
     104       63042 :   fd_secp256r1_fp_t _t0[1], _t1[1];
     105       63042 :   ulong * t0 = _t0->limbs;
     106       63042 :   ulong * t1 = _t1->limbs;
     107       63042 :   ulong * x = (ulong *)a->limbs;
     108             : 
     109       63042 :         bignum_montsqr_p256( t0, x );
     110       63042 :         bignum_montmul_p256( t0, t0, x );
     111      126084 :         bignum_montsqr_p256( t1, t0 ); for( int i=1; i<2; i++ ) bignum_montsqr_p256( t1, t1 );
     112       63042 :         bignum_montmul_p256( t0, t0, t1);
     113      252168 :         bignum_montsqr_p256( t1, t0 ); for( int i=1; i<4; i++ ) bignum_montsqr_p256( t1, t1 );
     114       63042 :         bignum_montmul_p256( t0, t0, t1);
     115      504336 :         bignum_montsqr_p256( t1, t0 ); for( int i=1; i<8; i++ ) bignum_montsqr_p256( t1, t1 );
     116       63042 :         bignum_montmul_p256( t0, t0, t1);
     117     1008672 :         bignum_montsqr_p256( t1, t0 ); for( int i=1; i<16; i++ ) bignum_montsqr_p256( t1, t1 );
     118       63042 :         bignum_montmul_p256( t0, t0, t1);
     119     2080386 :         for( int i=0; i<32; i++ ) bignum_montsqr_p256( t0, t0 );
     120       63042 :         bignum_montmul_p256( t0, t0, x );
     121     6115074 :         for( int i=0; i<96; i++ ) bignum_montsqr_p256( t0, t0 );
     122       63042 :         bignum_montmul_p256( t0, t0, x );
     123     5988990 :         for( int i=0; i<94; i++ ) bignum_montsqr_p256( t0, t0 );
     124             : 
     125       63042 :   bignum_montsqr_p256( t1, t0 );
     126       63042 :   if( FD_UNLIKELY( !fd_uint256_eq( _t1, a ) ) ) {
     127           6 :     return NULL;
     128           6 :   }
     129             : 
     130       63036 :   return fd_secp256r1_fp_set( r, _t0 );
     131       63042 : }
     132             : 
     133             : /* Points */
     134             : 
     135             : static inline fd_secp256r1_point_t *
     136             : fd_secp256r1_point_frombytes( fd_secp256r1_point_t * r,
     137       33042 :                               uchar const            in[ 33 ] ) {
     138       33042 :   fd_secp256r1_fp_t y2[1], demont_y[1];
     139             : 
     140       33042 :   uchar sgn = in[0];
     141       33042 :   if( FD_UNLIKELY( sgn!=2U && sgn!=3U ) ) {
     142           3 :     return FD_SECP256R1_FAILURE;
     143           3 :   }
     144             : 
     145       33039 :   if( FD_UNLIKELY( !fd_secp256r1_fp_frombytes( r->x, in+1 ) ) ) {
     146           3 :     return FD_SECP256R1_FAILURE;
     147           3 :   }
     148             : 
     149       33036 :   bignum_tomont_p256( r->x->limbs, r->x->limbs );
     150             : 
     151             :   /* y^2 = x^3 + ax + b */
     152       33036 :   bignum_montsqr_p256( y2->limbs, r->x->limbs );
     153       33036 :   bignum_add_p256    ( y2->limbs, y2->limbs, (ulong *)fd_secp256r1_const_a_mont[0].limbs );
     154       33036 :   bignum_montmul_p256( y2->limbs, y2->limbs, r->x->limbs );
     155       33036 :   bignum_add_p256    ( y2->limbs, y2->limbs, (ulong *)fd_secp256r1_const_b_mont[0].limbs );
     156             : 
     157             :   /* y = sqrt(y^2) */
     158       33036 :   if( FD_UNLIKELY( !fd_secp256r1_fp_sqrt( r->y, y2 ) ) ) {
     159           3 :     return FD_SECP256R1_FAILURE;
     160           3 :   }
     161             : 
     162             :   /* choose y or -y */
     163       33033 :   bignum_demont_p256( demont_y->limbs, r->y->limbs );
     164       33033 :   ulong cond = (demont_y->limbs[0] % 2) != (sgn == 3U);
     165       33033 :   bignum_optneg_p256( r->y->limbs, cond, r->y->limbs );
     166             : 
     167       33033 :   fd_secp256r1_fp_set( r->z, fd_secp256r1_const_one_mont );
     168             : 
     169       33033 :   return r;
     170       33036 : }
     171             : 
     172             : static inline int
     173             : fd_secp256r1_point_eq_x( fd_secp256r1_point_t const *  p,
     174       33027 :                          fd_secp256r1_scalar_t const * r ) {
     175       33027 :   fd_secp256r1_fp_t affine_x[1];
     176       33027 :   fd_secp256r1_scalar_t * affine_x_mod_n = affine_x;
     177             : 
     178       33027 :   if( FD_UNLIKELY( fd_uint256_eq( p->z, fd_secp256r1_const_zero ) ) ) {
     179           3 :     return FD_SECP256R1_FAILURE;
     180           3 :   }
     181             : 
     182             :   /* x = demont(X / Z^2) mod n */
     183       33024 :   bignum_montinv_p256( affine_x->limbs, (ulong *)p->z->limbs );
     184       33024 :   bignum_montsqr_p256( affine_x->limbs, affine_x->limbs );
     185       33024 :   bignum_montmul_p256( affine_x->limbs, affine_x->limbs, (ulong *)p->x->limbs );
     186       33024 :   bignum_demont_p256( affine_x_mod_n->limbs, affine_x->limbs );
     187       33024 :   bignum_mod_n256_4 ( affine_x_mod_n->limbs, affine_x_mod_n->limbs );
     188             : 
     189       33024 :   if( FD_LIKELY( fd_uint256_eq( r, affine_x_mod_n ) ) ) {
     190       33021 :     return FD_SECP256R1_SUCCESS;
     191       33021 :   }
     192           3 :   return FD_SECP256R1_FAILURE;
     193       33024 : }
     194             : 
     195             : /* Given the projective point `r` and the affine point `p`,
     196             :    returns 1 if they are equal and 0 otherwise.
     197             :    Assumes that `p` X and Y coordinates are in Montgomery domain. */
     198             : static inline int
     199             : fd_secp256r1_point_eq_mixed( fd_secp256r1_point_t const * a,
     200        3033 :                              ulong                const   b[ 8 ] ) {
     201        3033 :   fd_secp256r1_fp_t x[1], y[1];
     202        3033 :   fd_memcpy( x->limbs, b+0, sizeof(fd_secp256r1_fp_t) );
     203        3033 :   fd_memcpy( y->limbs, b+4, sizeof(fd_secp256r1_fp_t) );
     204             :   /* Indicates if the affine point is zero. */
     205        3033 :   int is_zero = fd_uint256_eq( x, fd_secp256r1_const_zero ) & fd_uint256_eq( y, fd_secp256r1_const_zero );
     206             : 
     207             :   /* Easy cases */
     208        3033 :   if( FD_UNLIKELY( fd_uint256_eq( a->z, fd_secp256r1_const_zero ) ) ) {
     209           6 :     return is_zero;
     210           6 :   }
     211        3027 :   if( FD_UNLIKELY( is_zero ) ) {
     212           0 :     return 0;
     213           0 :   }
     214             : 
     215        3027 :   fd_secp256r1_fp_t z1z1[1];
     216        3027 :   bignum_montsqr_p256( z1z1->limbs, (ulong *)a->z->limbs );
     217             : 
     218        3027 :   fd_secp256r1_fp_t temp[1];
     219        3027 :   bignum_montmul_p256( temp->limbs, (ulong *)x->limbs, z1z1->limbs );
     220             : 
     221        3027 :   if( FD_UNLIKELY( fd_uint256_eq( a->x, temp ) ) ) {
     222          15 :     bignum_montmul_p256( temp->limbs, z1z1->limbs,  (ulong *)a->z->limbs );
     223          15 :     bignum_montmul_p256( temp->limbs, temp->limbs, (ulong *)y->limbs );
     224          15 :     return fd_uint256_eq( a->y, temp );
     225        3012 :   } else {
     226        3012 :     return 0;
     227        3012 :   }
     228        3027 : }
     229             : 
     230             : /* Adds projective point `a` and affine-Montgomery point `b`, both
     231             :    in Montgomery domain. Handles identity elements and the equal-point
     232             :    (doubling) case. */
     233             : static inline void
     234             : fd_secp256r1_point_add_mixed( fd_secp256r1_point_t *       r,
     235             :                               fd_secp256r1_point_t const * a,
     236        3030 :                               ulong                        b[ 8 ] ) {
     237        3030 :   int b_is_zero = fd_uint256_eq( (fd_uint256_t const *)(b+0), fd_secp256r1_const_zero ) &
     238        3030 :                   fd_uint256_eq( (fd_uint256_t const *)(b+4), fd_secp256r1_const_zero );
     239             : 
     240        3030 :   if( FD_UNLIKELY( b_is_zero ) ) {
     241             :     /* a + 0 = a */
     242           6 :     if( r != a ) fd_memcpy( r, a, sizeof(fd_secp256r1_point_t) );
     243           6 :     return;
     244           6 :   }
     245             : 
     246        3024 :   if( FD_UNLIKELY( fd_secp256r1_point_eq_mixed( a, b ) ) ) {
     247           6 :     p256_montjdouble( (ulong *)r, (ulong *)a );
     248        3018 :   } else {
     249             :     /* Also handles a == 0 and a == -b */
     250        3018 :     p256_montjmixadd( (ulong *)r, (ulong *)a, b );
     251        3018 :   }
     252        3024 : }
     253             : 
     254             : static inline void
     255             : fd_secp256r1_double_scalar_mul_base( fd_secp256r1_point_t *        r,
     256             :                                      fd_secp256r1_scalar_t const * u1,
     257             :                                      fd_secp256r1_point_t const *  a,
     258        3015 :                                      fd_secp256r1_scalar_t const * u2 ) {
     259             :   /* u1*G */
     260        3015 :   ulong rtmp[ 8 ];
     261        3015 :   p256_scalarmulbase( rtmp, (ulong *)u1->limbs, 6, (ulong *)fd_secp256r1_base_point_table );
     262        3015 :   bignum_tomont_p256( rtmp, rtmp );
     263        3015 :   bignum_tomont_p256( rtmp+4, rtmp+4 );
     264             : 
     265             :   /* u2*A */
     266        3015 :   p256_montjscalarmul( (ulong *)r, (ulong *)u2->limbs, (ulong *)a );
     267             : 
     268             :   /* u1*G + u2*A */
     269        3015 :   fd_secp256r1_point_add_mixed( r, r, rtmp );
     270        3015 : }

Generated by: LCOV version 1.14