LCOV - code coverage report
Current view: top level - ballet/bn254 - fd_bn254_g1.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 225 240 93.8 %
Date: 2026-10-22 18:10:43 Functions: 10 10 100.0 %

          Line data    Source code
       1             : #include "./fd_bn254_field_inl.h"
       2             : #include "./fd_bn254_glv.h"
       3             : 
       4             : /* G1 */
       5             : 
       6             : /* GLV consts (fd_bn254_glv.h), shared with fd_bn254_g2.c; the lattice
       7             :    constants are in fd_bn254_field.c. */
       8             : 
       9             : /* beta in Montgomery form.
      10             :    0x30644e72e131a0295e6dd9e7e0acccb0c28f069fbb966e3de4bd44e5607cfd48 */
      11             : const fd_bn254_fp_t fd_bn254_const_beta_mont[1] = {{{
      12             :   0x3350c88e13e80b9cUL, 0x7dce557cdb5e56b9UL, 0x6001b4b8b615564aUL, 0x2682e617020217e0UL
      13             : }}};
      14             : 
      15             : static inline fd_bn254_g1_t *
      16             : fd_bn254_g1_set( fd_bn254_g1_t *       r,
      17         385 :                  fd_bn254_g1_t const * p ) {
      18         385 :   fd_bn254_fp_set( &r->X, &p->X );
      19         385 :   fd_bn254_fp_set( &r->Y, &p->Y );
      20         385 :   fd_bn254_fp_set( &r->Z, &p->Z );
      21         385 :   return r;
      22         385 : }
      23             : 
      24             : static inline fd_bn254_g1_t *
      25         480 : fd_bn254_g1_set_zero( fd_bn254_g1_t * r ) {
      26             :   // fd_bn254_fp_set_zero( &r->X );
      27             :   // fd_bn254_fp_set_zero( &r->Y );
      28         480 :   fd_bn254_fp_set_zero( &r->Z );
      29         480 :   return r;
      30         480 : }
      31             : 
      32             : static inline fd_bn254_g1_t *
      33             : fd_bn254_g1_to_affine( fd_bn254_g1_t *       r,
      34         315 :                        fd_bn254_g1_t const * p ) {
      35         315 :   if( FD_UNLIKELY( fd_bn254_fp_is_zero( &p->Z ) || fd_bn254_fp_is_one( &p->Z ) ) ) {
      36          84 :     return fd_bn254_g1_set( r, p );
      37          84 :   }
      38             : 
      39         231 :   fd_bn254_fp_t iz[1], iz2[1];
      40         231 :   fd_bn254_fp_inv( iz, &p->Z );
      41         231 :   fd_bn254_fp_sqr( iz2, iz );
      42             : 
      43             :   /* X / Z^2, Y / Z^3 */
      44         231 :   fd_bn254_fp_mul( &r->X, &p->X, iz2 );
      45         231 :   fd_bn254_fp_mul( &r->Y, &p->Y, iz2 );
      46         231 :   fd_bn254_fp_mul( &r->Y, &r->Y, iz );
      47         231 :   fd_bn254_fp_set_one( &r->Z );
      48         231 :   return r;
      49         315 : }
      50             : 
      51             : uchar *
      52             : fd_bn254_g1_tobytes( uchar                 out[64],
      53             :                      fd_bn254_g1_t const * p,
      54         571 :                      int                   big_endian ) {
      55         571 :   if( FD_UNLIKELY( fd_bn254_g1_is_zero( p ) ) ) {
      56         256 :     fd_memset( out, 0, 64UL );
      57             :     /* no flags */
      58         256 :     return out;
      59         256 :   }
      60             : 
      61         315 :   fd_bn254_g1_t r[1];
      62         315 :   fd_bn254_g1_to_affine( r, p );
      63             : 
      64         315 :   fd_bn254_fp_from_mont( &r->X, &r->X );
      65         315 :   fd_bn254_fp_from_mont( &r->Y, &r->Y );
      66             : 
      67         315 :   fd_bn254_fp_tobytes_nm( &out[ 0], &r->X, big_endian );
      68         315 :   fd_bn254_fp_tobytes_nm( &out[32], &r->Y, big_endian );
      69             :   /* no flags */
      70         315 :   return out;
      71         571 : }
      72             : 
      73             : /* fd_bn254_g1_affine_add computes r = p + q.
      74             :    Both p, q are affine, i.e. Z==1. */
      75             : fd_bn254_g1_t *
      76             : fd_bn254_g1_affine_add( fd_bn254_g1_t *       r,
      77             :                         fd_bn254_g1_t const * p,
      78         349 :                         fd_bn254_g1_t const * q ) {
      79             :   /* p==0, return q */
      80         349 :   if( FD_UNLIKELY( fd_bn254_g1_is_zero( p ) ) ) {
      81           6 :     return fd_bn254_g1_set( r, q );
      82           6 :   }
      83             :   /* q==0, return p */
      84         343 :   if( FD_UNLIKELY( fd_bn254_g1_is_zero( q ) ) ) {
      85           3 :     return fd_bn254_g1_set( r, p );
      86           3 :   }
      87             : 
      88         340 :   fd_bn254_fp_t lambda[1], x[1], y[1];
      89             : 
      90             :   /* same X, either the points are equal or opposite */
      91         340 :   if( fd_bn254_fp_eq( &p->X, &q->X ) ) {
      92           1 :     if( fd_bn254_fp_eq( &p->Y, &q->Y ) ) {
      93             :       /* p==q => point double: lambda = 3 * x1^2 / (2 * y1) */
      94           1 :       fd_bn254_fp_sqr( x, &p->X ); /* x =   x1^2 */
      95           1 :       fd_bn254_fp_add( y, x, x );  /* y = 2 x1^2 */
      96           1 :       fd_bn254_fp_add( x, x, y );  /* x = 3 x1^2 */
      97           1 :       fd_bn254_fp_add( y, &p->Y, &p->Y );
      98           1 :       fd_bn254_fp_inv( lambda, y );
      99           1 :       fd_bn254_fp_mul( lambda, lambda, x );
     100           1 :     } else {
     101             :       /* p==-q => r=0 */
     102             :       /* COV: this may never happen with real data */
     103           0 :       return fd_bn254_g1_set_zero( r );
     104           0 :     }
     105         339 :   } else {
     106             :     /* point add: lambda = (y1 - y2) / (x1 - x2) */
     107         339 :     fd_bn254_fp_sub( x, &p->X, &q->X );
     108         339 :     fd_bn254_fp_sub( y, &p->Y, &q->Y );
     109         339 :     fd_bn254_fp_inv( lambda, x );
     110         339 :     fd_bn254_fp_mul( lambda, lambda, y );
     111         339 :   }
     112             : 
     113             :   /* x3 = lambda^2 - x1 - x2 */
     114         340 :   fd_bn254_fp_sqr( x, lambda );
     115         340 :   fd_bn254_fp_sub( x, x, &p->X );
     116         340 :   fd_bn254_fp_sub( x, x, &q->X );
     117             : 
     118             :   /* y3 = lambda * (x1 - x3) - y1 */
     119         340 :   fd_bn254_fp_sub( y, &p->X, x );
     120         340 :   fd_bn254_fp_mul( y, y, lambda );
     121         340 :   fd_bn254_fp_sub( y, y, &p->Y );
     122             : 
     123         340 :   fd_bn254_fp_set( &r->X, x );
     124         340 :   fd_bn254_fp_set( &r->Y, y );
     125         340 :   fd_bn254_fp_set_one( &r->Z );
     126         340 :   return r;
     127         340 : }
     128             : 
     129             : /* fd_bn254_g1_dbl computes r = 2p.
     130             :    https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l */
     131             : fd_bn254_g1_t *
     132             : fd_bn254_g1_dbl( fd_bn254_g1_t *       r,
     133       30288 :                  fd_bn254_g1_t const * p ) {
     134             :   /* p==0, return 0 */
     135       30288 :   if( FD_UNLIKELY( fd_bn254_g1_is_zero( p ) ) ) {
     136           0 :     return fd_bn254_g1_set_zero( r );
     137           0 :   }
     138             : 
     139       30288 :   fd_bn254_fp_t a[1], b[1], c[1];
     140       30288 :   fd_bn254_fp_t d[1], e[1], f[1];
     141             : 
     142             :   /* A = X1^2 */
     143       30288 :   fd_bn254_fp_sqr( a, &p->X );
     144             :   /* B = Y1^2 */
     145       30288 :   fd_bn254_fp_sqr( b, &p->Y );
     146             :   /* C = B^2 */
     147       30288 :   fd_bn254_fp_sqr( c, b );
     148             :   /* D = 2*((X1+B)^2-A-C)
     149             :      (X1+B)^2 = X1^2 + 2*X1*B + B^2
     150             :      D = 2*(X1^2 + 2*X1*B + B^2 - A    - C)
     151             :      D = 2*(X1^2 + 2*X1*B + B^2 - X1^2 - B^2)
     152             :             ^               ^     ^      ^
     153             :             |---------------|-----|      |
     154             :                             |------------|
     155             :      These terms cancel each other out, and we're left with:
     156             :      D = 2*(2*X1*B) */
     157       30288 :   fd_bn254_fp_mul( d, &p->X, b );
     158       30288 :   fd_bn254_fp_add( d, d, d );
     159       30288 :   fd_bn254_fp_add( d, d, d );
     160             :   /* E = 3*A */
     161       30288 :   fd_bn254_fp_add( e, a, a );
     162       30288 :   fd_bn254_fp_add( e, a, e );
     163             :   /* F = E^2 */
     164       30288 :   fd_bn254_fp_sqr( f, e );
     165             :   /* X3 = F-2*D */
     166       30288 :   fd_bn254_fp_add( &r->X, d, d );
     167       30288 :   fd_bn254_fp_sub( &r->X, f, &r->X );
     168             :   /* Z3 = (Y1+Z1)^2-YY-ZZ
     169             :      note: compute Z3 before Y3 because it depends on p->Y,
     170             :      that might be overwritten if r==p. */
     171             :   /* Z3 = 2*Y1*Z1 */
     172       30288 :   fd_bn254_fp_mul( &r->Z, &p->Y, &p->Z );
     173       30288 :   fd_bn254_fp_add( &r->Z, &r->Z, &r->Z );
     174             :   /* Y3 = E*(D-X3)-8*C */
     175       30288 :   fd_bn254_fp_sub( &r->Y, d, &r->X );
     176       30288 :   fd_bn254_fp_mul( &r->Y, e, &r->Y );
     177       30288 :   fd_bn254_fp_add( c, c, c ); /* 2*c */
     178       30288 :   fd_bn254_fp_add( c, c, c ); /* 4*y */
     179       30288 :   fd_bn254_fp_add( c, c, c ); /* 8*y */
     180       30288 :   fd_bn254_fp_sub( &r->Y, &r->Y, c );
     181       30288 :   return r;
     182       30288 : }
     183             : 
     184             : /* fd_bn254_g1_add_mixed computes r = p + q, when q->Z==1.
     185             :    http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl */
     186             : fd_bn254_g1_t *
     187             : fd_bn254_g1_add_mixed( fd_bn254_g1_t *       r,
     188             :                        fd_bn254_g1_t const * p,
     189       20695 :                        fd_bn254_g1_t const * q ) {
     190             :   /* p==0, return q */
     191       20695 :   if( FD_UNLIKELY( fd_bn254_g1_is_zero( p ) ) ) {
     192           0 :     return fd_bn254_g1_set( r, q );
     193           0 :   }
     194       20695 :   fd_bn254_fp_t zz[1], u2[1], s2[1];
     195       20695 :   fd_bn254_fp_t h[1], hh[1];
     196       20695 :   fd_bn254_fp_t i[1], j[1];
     197       20695 :   fd_bn254_fp_t rr[1], v[1];
     198             :   /* Z1Z1 = Z1^2 */
     199       20695 :   fd_bn254_fp_sqr( zz, &p->Z );
     200             :   /* U2 = X2*Z1Z1 */
     201       20695 :   fd_bn254_fp_mul( u2, &q->X, zz );
     202             :   /* S2 = Y2*Z1*Z1Z1 */
     203       20695 :   fd_bn254_fp_mul( s2, &q->Y, &p->Z );
     204       20695 :   fd_bn254_fp_mul( s2, s2, zz );
     205             : 
     206             :   /* if p==q, call fd_bn254_g1_dbl */
     207       20695 :   if( FD_UNLIKELY( fd_bn254_fp_eq( u2, &p->X ) && fd_bn254_fp_eq( s2, &p->Y ) ) ) {
     208             :     /* COV: this may never happen with real data */
     209           0 :     return fd_bn254_g1_dbl( r, p );
     210           0 :   }
     211             : 
     212             :   /* H = U2-X1 */
     213       20695 :   fd_bn254_fp_sub( h, u2, &p->X );
     214             :   /* HH = H^2 */
     215       20695 :   fd_bn254_fp_sqr( hh, h );
     216             :   /* I = 4*HH */
     217       20695 :   fd_bn254_fp_add( i, hh, hh );
     218       20695 :   fd_bn254_fp_add( i, i, i );
     219             :   /* J = H*I */
     220       20695 :   fd_bn254_fp_mul( j, h, i );
     221             :   /* r = 2*(S2-Y1) */
     222       20695 :   fd_bn254_fp_sub( rr, s2, &p->Y );
     223       20695 :   fd_bn254_fp_add( rr, rr, rr );
     224             :   /* V = X1*I */
     225       20695 :   fd_bn254_fp_mul( v, &p->X, i );
     226             :   /* X3 = r^2-J-2*V */
     227       20695 :   fd_bn254_fp_sqr( &r->X, rr );
     228       20695 :   fd_bn254_fp_sub( &r->X, &r->X, j );
     229       20695 :   fd_bn254_fp_sub( &r->X, &r->X, v );
     230       20695 :   fd_bn254_fp_sub( &r->X, &r->X, v );
     231             :   /* Y3 = r*(V-X3)-2*Y1*J
     232             :      note: i no longer used */
     233       20695 :   fd_bn254_fp_mul( i, &p->Y, j ); /* i =   Y1*J */
     234       20695 :   fd_bn254_fp_add( i, i, i );     /* i = 2*Y1*J */
     235       20695 :   fd_bn254_fp_sub( &r->Y, v, &r->X );
     236       20695 :   fd_bn254_fp_mul( &r->Y, &r->Y, rr );
     237       20695 :   fd_bn254_fp_sub( &r->Y, &r->Y, i );
     238             :   /* Z3 = (Z1+H)^2-Z1Z1-HH */
     239       20695 :   fd_bn254_fp_add( &r->Z, &p->Z, h );
     240       20695 :   fd_bn254_fp_sqr( &r->Z, &r->Z );
     241       20695 :   fd_bn254_fp_sub( &r->Z, &r->Z, zz );
     242       20695 :   fd_bn254_fp_sub( &r->Z, &r->Z, hh );
     243       20695 :   return r;
     244       20695 : }
     245             : 
     246             : /* fd_bn254_g1_scalar_mul computes r = [s]P.
     247             :    p must be in affine form (p->Z == 1).
     248             :    The result is in projective coordinates. */
     249             : fd_bn254_g1_t *
     250             : fd_bn254_g1_scalar_mul( fd_bn254_g1_t *           r,
     251             :                         fd_bn254_g1_t const *     p,
     252         513 :                         fd_bn254_scalar_t const * s ) {
     253         513 :   if( FD_UNLIKELY( fd_uint256_is_zero( s ) || fd_bn254_g1_is_zero( p ) ) ) {
     254         222 :     return fd_bn254_g1_set_zero( r );
     255         222 :   }
     256         291 :   ulong b1[ 3 ];
     257         291 :   ulong b2[ 2 ];
     258         291 :   fd_bn254_glv_sxg3( b1, s, g1_const_g1 );
     259         291 :   fd_bn254_glv_sxg2( b2, s, g2_const );
     260             : 
     261             :   /* k1 = s - b1*N_A - b2*N_B (always non-negative for G1) */
     262         291 :   fd_uint256_t k1[1];
     263         291 :   {
     264         291 :     ulong p11[ 4 ];
     265             :     /* b2*nb will produce at most 3 limbs, but we want the 4th zeroed for the addition. */
     266         291 :     ulong p21[ 4 ] = {0};
     267         291 :     ulong  t[ 4 ];
     268         291 :     fd_bn254_glv_mul3x2( p11, b1, na );
     269         291 :     fd_bn254_glv_mul2x1( p21, b2, nb );
     270         291 :     fd_bn254_glv_add4( t, p11, p21 );
     271         291 :     fd_bn254_glv_sub4( k1->limbs, s->limbs, t );
     272         291 :   }
     273             : 
     274             :   /* k2 = b1*N_B - b2*N_C (may be negative) */
     275         291 :   fd_uint256_t k2_abs[1];
     276         291 :   int k2_neg = 0;
     277         291 :   {
     278         291 :     ulong pos[ 4 ], neg[ 4 ];
     279         291 :     fd_bn254_glv_mul3x1( pos, b1, nb );
     280         291 :     fd_bn254_glv_mul2x2( neg, b2, nc );
     281         291 :     ulong borrow = fd_bn254_glv_sub4( k2_abs->limbs, pos, neg );
     282         291 :     if( borrow ) {
     283           0 :       k2_neg = 1;
     284           0 :       fd_bn254_glv_negate4( k2_abs->limbs );
     285           0 :     }
     286         291 :   }
     287             : 
     288             :   /* pt2 = phi(P) = (beta * P.x, P.y). If k2 < 0, negate pt2. */
     289         291 :   fd_bn254_g1_t pt2[1];
     290         291 :   fd_bn254_fp_mul    ( &pt2->X, &p->X, fd_bn254_const_beta_mont );
     291         291 :   fd_bn254_fp_set    ( &pt2->Y, &p->Y );
     292         291 :   fd_bn254_fp_set_one( &pt2->Z );
     293         291 :   if( k2_neg ) {
     294           0 :     fd_bn254_fp_neg( &pt2->Y, &pt2->Y );
     295           0 :   }
     296             : 
     297         291 :   fd_bn254_g1_t pt12[1];
     298         291 :   fd_bn254_g1_affine_add( pt12, p, pt2 );
     299             : 
     300             :   /* Shamir's trick: simultaneous double-and-add on k1, k2. */
     301         291 :   int i = 255;
     302       42276 :   for( ; i>=0; i-- ) {
     303       42276 :     int k1b = !!fd_uint256_bit( k1, i );
     304       42276 :     int k2b = !!fd_uint256_bit( k2_abs, i );
     305       42276 :     if( k1b || k2b ) {
     306         292 :       fd_bn254_g1_set( r, ( k1b && k2b ) ? pt12 : ( k1b ? p : pt2 ) );
     307         292 :       break;
     308         292 :     }
     309       42276 :   }
     310         291 :   if( FD_UNLIKELY( i<0 ) ) {
     311           0 :     return fd_bn254_g1_set_zero( r );
     312           0 :   }
     313       30580 :   for( i--; i >= 0; i-- ) {
     314       30289 :     fd_bn254_g1_dbl( r, r );
     315       30289 :     int k1b = !!fd_uint256_bit( k1, i );
     316       30289 :     int k2b = !!fd_uint256_bit( k2_abs, i );
     317       30289 :     if( k1b && k2b ) {
     318        9192 :       fd_bn254_g1_add_mixed( r, r, pt12 );
     319       21097 :     } else if( k1b ) {
     320        5945 :       fd_bn254_g1_add_mixed( r, r, p );
     321       15152 :     } else if( k2b ) {
     322        6155 :       fd_bn254_g1_add_mixed( r, r, pt2 );
     323        6155 :     }
     324       30289 :   }
     325             : 
     326         291 :   return r;
     327         291 : }
     328             : 
     329             : /* fd_bn254_g1_frombytes_internal extracts (x, y) and performs basic checks.
     330             :    This is used by fd_bn254_g1_compress() and fd_bn254_g1_frombytes_check_subgroup().
     331             :    https://github.com/arkworks-rs/algebra/blob/v0.4.2/ec/src/models/short_weierstrass/mod.rs#L173-L178 */
     332             : fd_bn254_g1_t *
     333             : fd_bn254_g1_frombytes_internal( fd_bn254_g1_t * p,
     334             :                                 uchar const     in[64],
     335        3126 :                                 int             big_endian ) {
     336             :   /* Special case: all zeros => point at infinity */
     337        3126 :   const uchar zero[64] = { 0 };
     338        3126 :   if( FD_UNLIKELY( fd_memeq( in, zero, 64 ) ) ) {
     339          36 :     return fd_bn254_g1_set_zero( p );
     340          36 :   }
     341             : 
     342             :   /* Check x < p */
     343        3090 :   if( FD_UNLIKELY( !fd_bn254_fp_frombytes_nm( &p->X, &in[0], big_endian, NULL, NULL ) ) ) {
     344        1221 :     return NULL;
     345        1221 :   }
     346             : 
     347             :   /* Check flags and y < p */
     348        1869 :   int is_inf, is_neg;
     349        1869 :   if( FD_UNLIKELY( !fd_bn254_fp_frombytes_nm( &p->Y, &in[32], big_endian, &is_inf, &is_neg ) ) ) {
     350         367 :     return NULL;
     351         367 :   }
     352             : 
     353        1502 :   if( FD_UNLIKELY( is_inf ) ) {
     354         222 :     return fd_bn254_g1_set_zero( p );
     355         222 :   }
     356             : 
     357        1280 :   fd_bn254_fp_set_one( &p->Z );
     358        1280 :   return p;
     359        1502 : }
     360             : 
     361             : /* fd_bn254_g1_frombytes_check_subgroup performs frombytes AND checks subgroup membership. */
     362             : fd_bn254_g1_t *
     363             : fd_bn254_g1_frombytes_check_subgroup( fd_bn254_g1_t * p,
     364             :                                       uchar const     in[64],
     365        2864 :                                       int             big_endian ) {
     366        2864 :   if( FD_UNLIKELY( !fd_bn254_g1_frombytes_internal( p, in, big_endian ) ) ) {
     367        1425 :     return NULL;
     368        1425 :   }
     369        1439 :   if( FD_UNLIKELY( fd_bn254_g1_is_zero( p ) ) ) {
     370         235 :     return p;
     371         235 :   }
     372             : 
     373        1204 :   fd_bn254_fp_to_mont( &p->X, &p->X );
     374        1204 :   fd_bn254_fp_to_mont( &p->Y, &p->Y );
     375        1204 :   fd_bn254_fp_set_one( &p->Z );
     376             : 
     377             :   /* Check that y^2 = x^3 + b */
     378        1204 :   fd_bn254_fp_t y2[1], x3b[1];
     379        1204 :   fd_bn254_fp_sqr( y2, &p->Y );
     380        1204 :   fd_bn254_fp_sqr( x3b, &p->X );
     381        1204 :   fd_bn254_fp_mul( x3b, x3b, &p->X );
     382        1204 :   fd_bn254_fp_add( x3b, x3b, fd_bn254_const_b_mont );
     383        1204 :   if( FD_UNLIKELY( !fd_bn254_fp_eq( y2, x3b ) ) ) {
     384         123 :     return NULL;
     385         123 :   }
     386             : 
     387             :   /* G1 has prime order, so we don't need to do any further checks. */
     388             : 
     389        1081 :   return p;
     390        1204 : }

Generated by: LCOV version 1.14