LCOV - code coverage report
Current view: top level - ballet/bn254 - fd_bn254_g1.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 180 198 90.9 %
Date: 2025-08-05 05:04:49 Functions: 11 11 100.0 %

          Line data    Source code
       1             : #include "./fd_bn254.h"
       2             : 
       3             : /* G1 */
       4             : 
       5             : static inline int
       6      598422 : fd_bn254_g1_is_zero( fd_bn254_g1_t const * p ) {
       7      598422 :   return fd_bn254_fp_is_zero( &p->Z );
       8      598422 : }
       9             : 
      10             : static inline fd_bn254_g1_t *
      11             : fd_bn254_g1_set( fd_bn254_g1_t *       r,
      12       63174 :                  fd_bn254_g1_t const * p ) {
      13       63174 :   fd_bn254_fp_set( &r->X, &p->X );
      14       63174 :   fd_bn254_fp_set( &r->Y, &p->Y );
      15       63174 :   fd_bn254_fp_set( &r->Z, &p->Z );
      16       63174 :   return r;
      17       63174 : }
      18             : 
      19             : static inline fd_bn254_g1_t *
      20       30039 : 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       30039 :   fd_bn254_fp_set_zero( &r->Z );
      24       30039 :   return r;
      25       30039 : }
      26             : 
      27             : static inline fd_bn254_g1_t *
      28             : fd_bn254_g1_to_affine( fd_bn254_g1_t *       r,
      29       33135 :                        fd_bn254_g1_t const * p ) {
      30       33135 :   if( FD_UNLIKELY( fd_bn254_fp_is_zero( &p->Z ) || fd_bn254_fp_is_one( &p->Z ) ) ) {
      31       30039 :     return fd_bn254_g1_set( r, p );
      32       30039 :   }
      33             : 
      34        3096 :   fd_bn254_fp_t iz[1], iz2[1];
      35        3096 :   fd_bn254_fp_inv( iz, &p->Z );
      36        3096 :   fd_bn254_fp_sqr( iz2, iz );
      37             : 
      38             :   /* X / Z^2, Y / Z^3 */
      39        3096 :   fd_bn254_fp_mul( &r->X, &p->X, iz2 );
      40        3096 :   fd_bn254_fp_mul( &r->Y, &p->Y, iz2 );
      41        3096 :   fd_bn254_fp_mul( &r->Y, &r->Y, iz );
      42        3096 :   fd_bn254_fp_set_one( &r->Z );
      43        3096 :   return r;
      44       33135 : }
      45             : 
      46             : uchar *
      47             : fd_bn254_g1_tobytes( uchar                 out[64],
      48       33153 :                      fd_bn254_g1_t const * p ) {
      49       33153 :   if( FD_UNLIKELY( fd_bn254_g1_is_zero( p ) ) ) {
      50          18 :     fd_memset( out, 0, 64UL );
      51             :     /* no flags */
      52          18 :     return out;
      53          18 :   }
      54             : 
      55       33135 :   fd_bn254_g1_t r[1];
      56       33135 :   fd_bn254_g1_to_affine( r, p );
      57             : 
      58       33135 :   fd_bn254_fp_from_mont( &r->X, &r->X );
      59       33135 :   fd_bn254_fp_from_mont( &r->Y, &r->Y );
      60             : 
      61       33135 :   fd_bn254_fp_tobytes_be_nm( &out[ 0], &r->X );
      62       33135 :   fd_bn254_fp_tobytes_be_nm( &out[32], &r->Y );
      63             :   /* no flags */
      64       33135 :   return out;
      65       33153 : }
      66             : 
      67             : /* fd_bn254_g1_affine_add computes r = p + q.
      68             :    Both p, q are affine, i.e. Z==1. */
      69             : fd_bn254_g1_t *
      70             : fd_bn254_g1_affine_add( fd_bn254_g1_t *       r,
      71             :                         fd_bn254_g1_t const * p,
      72       30033 :                         fd_bn254_g1_t const * q ) {
      73             :   /* p==0, return q */
      74       30033 :   if( FD_UNLIKELY( fd_bn254_g1_is_zero( p ) ) ) {
      75          15 :     return fd_bn254_g1_set( r, q );
      76          15 :   }
      77             :   /* q==0, return p */
      78       30018 :   if( FD_UNLIKELY( fd_bn254_g1_is_zero( q ) ) ) {
      79       30006 :     return fd_bn254_g1_set( r, p );
      80       30006 :   }
      81             : 
      82          12 :   fd_bn254_fp_t lambda[1], x[1], y[1];
      83             : 
      84             :   /* same X, either the points are equal or opposite */
      85          12 :   if( fd_bn254_fp_eq( &p->X, &q->X ) ) {
      86           3 :     if( fd_bn254_fp_eq( &p->Y, &q->Y ) ) {
      87             :       /* p==q => point double: lambda = 3 * x1^2 / (2 * y1) */
      88           3 :       fd_bn254_fp_sqr( x, &p->X ); /* x =   x1^2 */
      89           3 :       fd_bn254_fp_add( y, x, x );  /* y = 2 x1^2 */
      90           3 :       fd_bn254_fp_add( x, x, y );  /* x = 3 x1^2 */
      91           3 :       fd_bn254_fp_add( y, &p->Y, &p->Y );
      92           3 :       fd_bn254_fp_inv( lambda, y );
      93           3 :       fd_bn254_fp_mul( lambda, lambda, x );
      94           3 :     } else {
      95             :       /* p==-q => r=0 */
      96             :       /* COV: this may never happen with real data */
      97           0 :       return fd_bn254_g1_set_zero( r );
      98           0 :     }
      99           9 :   } else {
     100             :     /* point add: lambda = (y1 - y2) / (x1 - x2) */
     101           9 :     fd_bn254_fp_sub( x, &p->X, &q->X );
     102           9 :     fd_bn254_fp_sub( y, &p->Y, &q->Y );
     103           9 :     fd_bn254_fp_inv( lambda, x );
     104           9 :     fd_bn254_fp_mul( lambda, lambda, y );
     105           9 :   }
     106             : 
     107             :   /* x3 = lambda^2 - x1 - x2 */
     108          12 :   fd_bn254_fp_sqr( x, lambda );
     109          12 :   fd_bn254_fp_sub( x, x, &p->X );
     110          12 :   fd_bn254_fp_sub( x, x, &q->X );
     111             : 
     112             :   /* y3 = lambda * (x1 - x3) - y1 */
     113          12 :   fd_bn254_fp_sub( y, &p->X, x );
     114          12 :   fd_bn254_fp_mul( y, y, lambda );
     115          12 :   fd_bn254_fp_sub( y, y, &p->Y );
     116             : 
     117          12 :   fd_bn254_fp_set( &r->X, x );
     118          12 :   fd_bn254_fp_set( &r->Y, y );
     119          12 :   fd_bn254_fp_set_one( &r->Z );
     120          12 :   return r;
     121          12 : }
     122             : 
     123             : /* fd_bn254_g1_dbl computes r = 2p.
     124             :    https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl */
     125             : fd_bn254_g1_t *
     126             : fd_bn254_g1_dbl( fd_bn254_g1_t *       r,
     127      399660 :                  fd_bn254_g1_t const * p ) {
     128             :   /* p==0, return 0 */
     129      399660 :   if( FD_UNLIKELY( fd_bn254_g1_is_zero( p ) ) ) {
     130           0 :     return fd_bn254_g1_set_zero( r );
     131           0 :   }
     132             : 
     133      399660 :   fd_bn254_fp_t xx[1], yy[1], zz[1];
     134      399660 :   fd_bn254_fp_t y4[1], s[1], m[1];
     135             :   /* XX = X1^2 */
     136      399660 :   fd_bn254_fp_sqr( xx, &p->X );
     137             :   /* YY = Y1^2 */
     138      399660 :   fd_bn254_fp_sqr( yy, &p->Y );
     139             :   /* YYYY = YY^2 */
     140      399660 :   fd_bn254_fp_sqr( y4, yy );
     141             :   /* ZZ = Z1^2 */
     142      399660 :   fd_bn254_fp_sqr( zz, &p->Z );
     143             :   /* S = 2*((X1+YY)^2-XX-YYYY) */
     144      399660 :   fd_bn254_fp_add( s, &p->X, yy );
     145      399660 :   fd_bn254_fp_sqr( s, s );
     146      399660 :   fd_bn254_fp_sub( s, s, xx );
     147      399660 :   fd_bn254_fp_sub( s, s, y4 );
     148      399660 :   fd_bn254_fp_add( s, s, s );
     149             :   /* M = 3*XX+a*ZZ^2, a=0 */
     150      399660 :   fd_bn254_fp_add( m, xx, xx );
     151      399660 :   fd_bn254_fp_add( m, m, xx );
     152             :   /* T = M^2-2*S
     153             :      X3 = T */
     154      399660 :   fd_bn254_fp_sqr( &r->X, m );
     155      399660 :   fd_bn254_fp_sub( &r->X, &r->X, s );
     156      399660 :   fd_bn254_fp_sub( &r->X, &r->X, s );
     157             :   /* Z3 = (Y1+Z1)^2-YY-ZZ
     158             :      note: compute Z3 before Y3 because it depends on p->Y,
     159             :      that might be overwritten if r==p. */
     160      399660 :   fd_bn254_fp_add( &r->Z, &p->Z, &p->Y );
     161      399660 :   fd_bn254_fp_sqr( &r->Z, &r->Z );
     162      399660 :   fd_bn254_fp_sub( &r->Z, &r->Z, yy );
     163      399660 :   fd_bn254_fp_sub( &r->Z, &r->Z, zz );
     164             :   /* Y3 = M*(S-T)-8*YYYY */
     165      399660 :   fd_bn254_fp_sub( &r->Y, s, &r->X );
     166      399660 :   fd_bn254_fp_mul( &r->Y, &r->Y, m );
     167      399660 :   fd_bn254_fp_add( y4, y4, y4 ); /* 2 y^4 */
     168      399660 :   fd_bn254_fp_add( y4, y4, y4 ); /* 4 y^4 */
     169      399660 :   fd_bn254_fp_add( y4, y4, y4 ); /* 8 y^4 */
     170      399660 :   fd_bn254_fp_sub( &r->Y, &r->Y, y4 );
     171      399660 :   return r;
     172      399660 : }
     173             : 
     174             : /* fd_bn254_g1_add_mixed computes r = p + q, when q->Z==1.
     175             :    http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl */
     176             : fd_bn254_g1_t *
     177             : fd_bn254_g1_add_mixed( fd_bn254_g1_t *       r,
     178             :                        fd_bn254_g1_t const * p,
     179       10860 :                        fd_bn254_g1_t const * q ) {
     180             :   /* p==0, return q */
     181       10860 :   if( FD_UNLIKELY( fd_bn254_g1_is_zero( p ) ) ) {
     182           0 :     return fd_bn254_g1_set( r, q );
     183           0 :   }
     184       10860 :   fd_bn254_fp_t zz[1], u2[1], s2[1];
     185       10860 :   fd_bn254_fp_t h[1], hh[1];
     186       10860 :   fd_bn254_fp_t i[1], j[1];
     187       10860 :   fd_bn254_fp_t rr[1], v[1];
     188             :   /* Z1Z1 = Z1^2 */
     189       10860 :   fd_bn254_fp_sqr( zz, &p->Z );
     190             :   /* U2 = X2*Z1Z1 */
     191       10860 :   fd_bn254_fp_mul( u2, &q->X, zz );
     192             :   /* S2 = Y2*Z1*Z1Z1 */
     193       10860 :   fd_bn254_fp_mul( s2, &q->Y, &p->Z );
     194       10860 :   fd_bn254_fp_mul( s2, s2, zz );
     195             : 
     196             :   /* if p==q, call fd_bn254_g1_dbl */
     197       10860 :   if( FD_UNLIKELY( fd_bn254_fp_eq( u2, &p->X ) && fd_bn254_fp_eq( s2, &p->Y ) ) ) {
     198             :     /* COV: this may never happen with real data */
     199           0 :     return fd_bn254_g1_dbl( r, p );
     200           0 :   }
     201             : 
     202             :   /* H = U2-X1 */
     203       10860 :   fd_bn254_fp_sub( h, u2, &p->X );
     204             :   /* HH = H^2 */
     205       10860 :   fd_bn254_fp_sqr( hh, h );
     206             :   /* I = 4*HH */
     207       10860 :   fd_bn254_fp_add( i, hh, hh );
     208       10860 :   fd_bn254_fp_add( i, i, i );
     209             :   /* J = H*I */
     210       10860 :   fd_bn254_fp_mul( j, h, i );
     211             :   /* r = 2*(S2-Y1) */
     212       10860 :   fd_bn254_fp_sub( rr, s2, &p->Y );
     213       10860 :   fd_bn254_fp_add( rr, rr, rr );
     214             :   /* V = X1*I */
     215       10860 :   fd_bn254_fp_mul( v, &p->X, i );
     216             :   /* X3 = r^2-J-2*V */
     217       10860 :   fd_bn254_fp_sqr( &r->X, rr );
     218       10860 :   fd_bn254_fp_sub( &r->X, &r->X, j );
     219       10860 :   fd_bn254_fp_sub( &r->X, &r->X, v );
     220       10860 :   fd_bn254_fp_sub( &r->X, &r->X, v );
     221             :   /* Y3 = r*(V-X3)-2*Y1*J
     222             :      note: i no longer used */
     223       10860 :   fd_bn254_fp_mul( i, &p->Y, j ); /* i =   Y1*J */
     224       10860 :   fd_bn254_fp_add( i, i, i );     /* i = 2*Y1*J */
     225       10860 :   fd_bn254_fp_sub( &r->Y, v, &r->X );
     226       10860 :   fd_bn254_fp_mul( &r->Y, &r->Y, rr );
     227       10860 :   fd_bn254_fp_sub( &r->Y, &r->Y, i );
     228             :   /* Z3 = (Z1+H)^2-Z1Z1-HH */
     229       10860 :   fd_bn254_fp_add( &r->Z, &p->Z, h );
     230       10860 :   fd_bn254_fp_sqr( &r->Z, &r->Z );
     231       10860 :   fd_bn254_fp_sub( &r->Z, &r->Z, zz );
     232       10860 :   fd_bn254_fp_sub( &r->Z, &r->Z, hh );
     233       10860 :   return r;
     234       10860 : }
     235             : 
     236             : /* fd_bn254_g1_scalar_mul computes r = s * p.
     237             :    This assumes that p is affine, i.e. p->Z==1. */
     238             : fd_bn254_g1_t *
     239             : fd_bn254_g1_scalar_mul( fd_bn254_g1_t *           r,
     240             :                         fd_bn254_g1_t const *     p,
     241        3120 :                         fd_bn254_scalar_t const * s ) {
     242             :   /* TODO: wNAF, GLV */
     243        3120 :   int i = 255;
     244      399066 :   for( ; i>=0 && !fd_uint256_bit( s, i ); i-- ) ; /* do nothing, just i-- */
     245        3120 :   if( FD_UNLIKELY( i<0 ) ) {
     246           6 :     return fd_bn254_g1_set_zero( r );
     247           6 :   }
     248        3114 :   fd_bn254_g1_set( r, p );
     249      402774 :   for( i--; i>=0; i-- ) {
     250      399660 :     fd_bn254_g1_dbl( r, r );
     251      399660 :     if( fd_uint256_bit( s, i ) ) {
     252       10860 :       fd_bn254_g1_add_mixed( r, r, p );
     253       10860 :     }
     254      399660 :   }
     255        3114 :   return r;
     256        3120 : }
     257             : 
     258             : /* fd_bn254_g1_frombytes_internal extracts (x, y) and performs basic checks.
     259             :    This is used by fd_bn254_g1_compress() and fd_bn254_g1_frombytes_check_subgroup().
     260             :    https://github.com/arkworks-rs/algebra/blob/v0.4.2/ec/src/models/short_weierstrass/mod.rs#L173-L178 */
     261             : static inline fd_bn254_g1_t *
     262             : fd_bn254_g1_frombytes_internal( fd_bn254_g1_t * p,
     263       93963 :                                 uchar const     in[64] ) {
     264             :   /* Special case: all zeros => point at infinity */
     265       93963 :   const uchar zero[64] = { 0 };
     266       93963 :   if( FD_UNLIKELY( fd_memeq( in, zero, 64 ) ) ) {
     267       30033 :     return fd_bn254_g1_set_zero( p );
     268       30033 :   }
     269             : 
     270             :   /* Check x < p */
     271       63930 :   if( FD_UNLIKELY( !fd_bn254_fp_frombytes_be_nm( &p->X, &in[0], NULL, NULL ) ) ) {
     272           0 :     return NULL;
     273           0 :   }
     274             : 
     275             :   /* Check flags and y < p */
     276       63930 :   int is_inf, is_neg;
     277       63930 :   if( FD_UNLIKELY( !fd_bn254_fp_frombytes_be_nm( &p->Y, &in[32], &is_inf, &is_neg ) ) ) {
     278           0 :     return NULL;
     279           0 :   }
     280             : 
     281       63930 :   if( FD_UNLIKELY( is_inf ) ) {
     282           0 :     return fd_bn254_g1_set_zero( p );
     283           0 :   }
     284             : 
     285       63930 :   fd_bn254_fp_set_one( &p->Z );
     286       63930 :   return p;
     287       63930 : }
     288             : 
     289             : /* fd_bn254_g1_frombytes_check_subgroup performs frombytes AND checks subgroup membership. */
     290             : static inline fd_bn254_g1_t *
     291             : fd_bn254_g1_frombytes_check_subgroup( fd_bn254_g1_t * p,
     292       63921 :                                       uchar const     in[64] ) {
     293       63921 :   if( FD_UNLIKELY( !fd_bn254_g1_frombytes_internal( p, in ) ) ) {
     294           0 :     return NULL;
     295           0 :   }
     296       63921 :   if( FD_UNLIKELY( fd_bn254_g1_is_zero( p ) ) ) {
     297       30033 :     return p;
     298       30033 :   }
     299             : 
     300       33888 :   fd_bn254_fp_to_mont( &p->X, &p->X );
     301       33888 :   fd_bn254_fp_to_mont( &p->Y, &p->Y );
     302       33888 :   fd_bn254_fp_set_one( &p->Z );
     303             : 
     304             :   /* Check that y^2 = x^3 + b */
     305       33888 :   fd_bn254_fp_t y2[1], x3b[1];
     306       33888 :   fd_bn254_fp_sqr( y2, &p->Y );
     307       33888 :   fd_bn254_fp_sqr( x3b, &p->X );
     308       33888 :   fd_bn254_fp_mul( x3b, x3b, &p->X );
     309       33888 :   fd_bn254_fp_add( x3b, x3b, fd_bn254_const_b_mont );
     310       33888 :   if( FD_UNLIKELY( !fd_bn254_fp_eq( y2, x3b ) ) ) {
     311           0 :     return NULL;
     312           0 :   }
     313             : 
     314             :   /* G1 has prime order, so we don't need to do any further checks. */
     315             : 
     316       33888 :   return p;
     317       33888 : }

Generated by: LCOV version 1.14