LCOV - code coverage report
Current view: top level - ballet/bn254 - fd_bn254_g1.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 229 244 93.9 %
Date: 2026-03-19 18:19:27 Functions: 11 11 100.0 %

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

Generated by: LCOV version 1.14