LCOV - code coverage report
Current view: top level - ballet/bn254 - fd_bn254.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 168 0.0 %
Date: 2025-03-20 12:08:36 Functions: 0 7 0.0 %

          Line data    Source code
       1             : #include "./fd_bn254_internal.h"
       2             : 
       3             : #include "./fd_bn254_field.c"
       4             : #include "./fd_bn254_field_ext.c"
       5             : #include "./fd_bn254_g1.c"
       6             : #include "./fd_bn254_g2.c"
       7             : #include "./fd_bn254_pairing.c"
       8             : 
       9             : /* Compress/Decompress */
      10             : 
      11             : uchar *
      12             : fd_bn254_g1_compress( uchar       out[32],
      13           0 :                       uchar const in [64] ) {
      14           0 :   fd_bn254_g1_t p[1] = { 0 };
      15           0 :   if( FD_UNLIKELY( !fd_bn254_g1_frombytes_internal( p, in ) ) ) {
      16           0 :     return NULL;
      17           0 :   }
      18           0 :   int is_inf   = fd_bn254_g1_is_zero( p );
      19           0 :   int flag_inf = in[32] & FLAG_INF;
      20             : 
      21             :   /* Serialize compressed point:
      22             :      https://github.com/arkworks-rs/algebra/blob/v0.4.2/ec/src/models/short_weierstrass/mod.rs#L122
      23             : 
      24             :      1. If the infinity flags is set, return point at infinity
      25             :      2. Else, copy x and set neg_y flag */
      26             : 
      27           0 :   if( FD_UNLIKELY( is_inf ) ) {
      28           0 :     fd_memset( out, 0, 32 );
      29             :     /* The infinity flag in the result is set iff the infinity flag is set in the Y coordinate */
      30           0 :     out[0] = (uchar)( out[0] | flag_inf );
      31           0 :     return out;
      32           0 :   }
      33             : 
      34           0 :   int is_neg = fd_bn254_fp_is_neg_nm( &p->Y );
      35           0 :   memmove( out, in, 32 );
      36           0 :   if( is_neg ) {
      37           0 :     out[0] = (uchar)( out[0] | FLAG_NEG );
      38           0 :   }
      39           0 :   return out;
      40           0 : }
      41             : 
      42             : uchar *
      43             : fd_bn254_g1_decompress( uchar       out[64],
      44           0 :                         uchar const in [32] ) {
      45             :   /* Special case: all zeros in => all zeros out, no flags */
      46           0 :   const uchar zero[32] = { 0 };
      47           0 :   if( fd_memeq( in, zero, 32 ) ) {
      48           0 :     return fd_memset( out, 0, 64UL );
      49           0 :   }
      50             : 
      51           0 :   fd_bn254_fp_t x[1], x2[1], x3_plus_b[1], y[1];
      52           0 :   int is_inf, is_neg;
      53           0 :   if( FD_UNLIKELY( !fd_bn254_fp_frombytes_be_nm( x, in, &is_inf, &is_neg ) ) ) {
      54           0 :     return NULL;
      55           0 :   }
      56             : 
      57             :   /* Point at infinity.
      58             :      If the point at infinity flag is set (bit 6), return the point at
      59             :      infinity with no check on coords.
      60             :      https://github.com/arkworks-rs/algebra/blob/v0.4.2/ec/src/models/short_weierstrass/mod.rs#L156-L160
      61             :   */
      62           0 :   if( is_inf ) {
      63           0 :     fd_memset( out, 0, 64UL );
      64             :     /* no flags */
      65           0 :     return out;
      66           0 :   }
      67             : 
      68           0 :   fd_bn254_fp_to_mont( x, x );
      69           0 :   fd_bn254_fp_sqr( x2, x );
      70           0 :   fd_bn254_fp_mul( x3_plus_b, x2, x );
      71           0 :   fd_bn254_fp_add( x3_plus_b, x3_plus_b, fd_bn254_const_b_mont );
      72           0 :   if( FD_UNLIKELY( !fd_bn254_fp_sqrt( y, x3_plus_b ) ) ) {
      73           0 :     return NULL;
      74           0 :   }
      75             : 
      76           0 :   fd_bn254_fp_from_mont( y, y );
      77           0 :   if( is_neg != fd_bn254_fp_is_neg_nm( y ) ) {
      78           0 :     fd_bn254_fp_neg_nm( y, y );
      79           0 :   }
      80             : 
      81           0 :   memmove( out, in, 32 ); out[0] &= FLAG_MASK;
      82           0 :   fd_bn254_fp_tobytes_be_nm( &out[32], y );
      83             :   /* no flags */
      84           0 :   return out;
      85           0 : }
      86             : 
      87             : uchar *
      88             : fd_bn254_g2_compress( uchar       out[64],
      89           0 :                       uchar const in[128] ) {
      90           0 :   fd_bn254_g2_t p[1] = { 0 };
      91           0 :   if( FD_UNLIKELY( !fd_bn254_g2_frombytes_internal( p, in ) ) ) {
      92           0 :     return NULL;
      93           0 :   }
      94           0 :   int is_inf   = fd_bn254_g2_is_zero( p );
      95           0 :   int flag_inf = in[64] & FLAG_INF;
      96             : 
      97             :   /* Serialize compressed point */
      98             : 
      99           0 :   if( FD_UNLIKELY( is_inf ) ) {
     100           0 :     fd_memset( out, 0, 64 );
     101             :     /* The infinity flag in the result is set iff the infinity flag is set in the Y coordinate */
     102           0 :     out[0] = (uchar)( out[0] | flag_inf );
     103           0 :     return out;
     104           0 :   }
     105             : 
     106             :   /* Serialize x coordinate. The flags are on the 2nd element.
     107             :      https://github.com/arkworks-rs/algebra/blob/v0.4.2/ff/src/fields/models/quadratic_extension.rs#L700-L702 */
     108           0 :   int is_neg = fd_bn254_fp2_is_neg_nm( &p->Y );
     109           0 :   memmove( out, in, 64 );
     110           0 :   if( is_neg ) {
     111           0 :     out[0] = (uchar)( out[0] | FLAG_NEG );
     112           0 :   }
     113           0 :   return out;
     114           0 : }
     115             : 
     116             : uchar *
     117             : fd_bn254_g2_decompress( uchar       out[128],
     118           0 :                         uchar const in  [64] ) {
     119             :   /* Special case: all zeros in => all zeros out, no flags */
     120           0 :   const uchar zero[64] = { 0 };
     121           0 :   if( fd_memeq( in, zero, 64 ) ) {
     122           0 :     return fd_memset( out, 0, 128UL );
     123           0 :   }
     124             : 
     125           0 :   fd_bn254_fp2_t x[1], x2[1], x3_plus_b[1], y[1];
     126           0 :   int is_inf, is_neg;
     127           0 :   if( FD_UNLIKELY( !fd_bn254_fp2_frombytes_be_nm( x, in, &is_inf, &is_neg ) ) ) {
     128           0 :     return NULL;
     129           0 :   }
     130             : 
     131             :   /* Point at infinity.
     132             :      If the point at infinity flag is set (bit 6), return the point at
     133             :      infinity with no check on coords.
     134             :      https://github.com/arkworks-rs/algebra/blob/v0.4.2/ec/src/models/short_weierstrass/mod.rs#L156-L160 */
     135           0 :   if( is_inf ) {
     136           0 :     fd_memset( out, 0, 128UL );
     137             :     /* no flags */
     138           0 :     return out;
     139           0 :   }
     140             : 
     141           0 :   fd_bn254_fp2_to_mont( x, x );
     142           0 :   fd_bn254_fp2_sqr( x2, x );
     143           0 :   fd_bn254_fp2_mul( x3_plus_b, x2, x );
     144           0 :   fd_bn254_fp2_add( x3_plus_b, x3_plus_b, fd_bn254_const_twist_b_mont );
     145           0 :   if( FD_UNLIKELY( !fd_bn254_fp2_sqrt( y, x3_plus_b ) ) ) {
     146           0 :     return NULL;
     147           0 :   }
     148             : 
     149           0 :   fd_bn254_fp2_from_mont( y, y );
     150           0 :   if( is_neg != fd_bn254_fp2_is_neg_nm( y ) ) {
     151           0 :     fd_bn254_fp2_neg_nm( y, y );
     152           0 :   }
     153             : 
     154           0 :   memmove( out, in, 64 ); out[0] &= FLAG_MASK;
     155           0 :   fd_bn254_fp2_tobytes_be_nm( &out[64], y );
     156             :   /* no flags */
     157           0 :   return out;
     158           0 : }
     159             : 
     160             : /* Ops */
     161             : 
     162             : int
     163             : fd_bn254_g1_add_syscall( uchar       out[64],
     164             :                          uchar const in[],
     165           0 :                          ulong       in_sz ) {
     166             :   /* Expected 128-byte input (2 points). Pad input with 0s. */
     167           0 :   if( FD_UNLIKELY( in_sz > 128UL ) ) {
     168           0 :     return -1;
     169           0 :   }
     170           0 :   uchar FD_ALIGNED buf[128] = { 0 };
     171           0 :   fd_memcpy( buf, in, in_sz );
     172             : 
     173             :   /* Validate inputs */
     174           0 :   fd_bn254_g1_t r[1], a[1], b[1];
     175           0 :   if( FD_UNLIKELY( !fd_bn254_g1_frombytes_check_subgroup( a, &buf[ 0] ) ) ) {
     176           0 :     return -1;
     177           0 :   }
     178           0 :   if( FD_UNLIKELY( !fd_bn254_g1_frombytes_check_subgroup( b, &buf[64] ) ) ) {
     179           0 :     return -1;
     180           0 :   }
     181             : 
     182             :   /* Compute point add and serialize result */
     183           0 :   fd_bn254_g1_affine_add( r, a, b );
     184           0 :   fd_bn254_g1_tobytes( out, r );
     185           0 :   return 0;
     186           0 : }
     187             : 
     188             : int
     189             : fd_bn254_g1_scalar_mul_syscall( uchar       out[64],
     190             :                                 uchar const in[],
     191             :                                 ulong       in_sz,
     192           0 :                                 int         check_correct_sz ) {
     193             :   /* Expected 96-byte input (1 point + 1 scalar). Pad input with 0s.
     194             :      Note: Agave checks for 128 bytes instead of 96. We have to do the same check.
     195             :      https://github.com/anza-xyz/agave/blob/v1.18.6/sdk/program/src/alt_bn128/mod.rs#L17
     196             :      Update: https://github.com/anza-xyz/agave/blob/d2df66d3/programs/bpf_loader/src/syscalls/mod.rs#L1654-L1658 */
     197           0 :   ulong check_sz = check_correct_sz ? 96UL : 128UL;
     198           0 :   if( FD_UNLIKELY( in_sz > check_sz ) ) {
     199           0 :     return -1;
     200           0 :   }
     201           0 :   uchar FD_ALIGNED buf[96] = { 0 };
     202           0 :   fd_memcpy( buf, in, fd_ulong_min( in_sz, 96UL ) );
     203             : 
     204             :   /* Validate inputs */
     205           0 :   fd_bn254_g1_t r[1], a[1];
     206           0 :   fd_bn254_scalar_t s[1];
     207           0 :   if( FD_UNLIKELY( !fd_bn254_g1_frombytes_check_subgroup( a, &buf[ 0] ) ) ) {
     208           0 :     return -1;
     209           0 :   }
     210             : 
     211             :   /* Scalar is big endian and NOT validated
     212             :      https://github.com/anza-xyz/agave/blob/v1.18.6/sdk/program/src/alt_bn128/mod.rs#L211-L214 */
     213           0 :   fd_uint256_bswap( s, fd_type_pun_const( &buf[64] ) ); /* &buf[64] is always FD_ALIGNED */
     214             :   // no: if( FD_UNLIKELY( !fd_bn254_scalar_validate( s ) ) ) return -1;
     215             : 
     216             :   /* Compute scalar mul and serialize result */
     217           0 :   fd_bn254_g1_scalar_mul( r, a, s );
     218           0 :   fd_bn254_g1_tobytes( out, r );
     219           0 :   return 0;
     220           0 : }
     221             : 
     222             : int
     223             : fd_bn254_pairing_is_one_syscall( uchar       out[32],
     224             :                                  uchar const in[],
     225           0 :                                  ulong       in_sz ) {
     226             :   /* https://github.com/anza-xyz/agave/blob/v1.18.6/sdk/program/src/alt_bn128/mod.rs#L244
     227             :      Note: this check doesn't do anything because
     228             :      192usize.checked_rem(192) = Some(0)
     229             :      i.e., this is NOT checking that in_sz % 192 == 0.
     230             :      i.e., this is NOT needed:
     231             :      if( FD_UNLIKELY( (in_sz%192UL)!=0 ) ) return -1; */
     232           0 :   ulong elements_len = in_sz / 192UL;
     233           0 :   fd_bn254_g1_t p[FD_BN254_PAIRING_BATCH_MAX];
     234           0 :   fd_bn254_g2_t q[FD_BN254_PAIRING_BATCH_MAX];
     235             : 
     236             :   /* Important: set r=1 so that the result of 0 pairings is 1. */
     237           0 :   fd_bn254_fp12_t r[1];
     238           0 :   fd_bn254_fp12_set_one( r );
     239             : 
     240           0 :   ulong sz=0;
     241           0 :   for( ulong i=0; i<elements_len; i++ ) {
     242             :     /* G1: deserialize and check subgroup membership */
     243           0 :     if( FD_UNLIKELY( !fd_bn254_g1_frombytes_check_subgroup( &p[sz], &in[i*192   ] ) ) ) {
     244           0 :       return -1;
     245           0 :     }
     246             :     /* G2: deserialize and check subgroup membership */
     247           0 :     if( FD_UNLIKELY( !fd_bn254_g2_frombytes_check_subgroup( &q[sz], &in[i*192+64] ) ) ) {
     248           0 :       return -1;
     249           0 :     }
     250             :     /* Skip any pair where either P or Q is the point at infinity */
     251           0 :     if( FD_UNLIKELY( fd_bn254_g1_is_zero(&p[sz]) || fd_bn254_g2_is_zero(&q[sz]) ) ) {
     252           0 :       continue;
     253           0 :     }
     254           0 :     ++sz;
     255             :     /* Compute the Miller loop and aggegate into r */
     256           0 :     if( sz==FD_BN254_PAIRING_BATCH_MAX || i==elements_len-1 ) {
     257           0 :       fd_bn254_fp12_t tmp[1];
     258           0 :       fd_bn254_miller_loop( tmp, p, q, sz );
     259           0 :       fd_bn254_fp12_mul( r, r, tmp );
     260           0 :       sz = 0;
     261           0 :     }
     262           0 :   }
     263           0 :   if( sz>0 ) {
     264           0 :     fd_bn254_fp12_t tmp[1];
     265           0 :     fd_bn254_miller_loop( tmp, p, q, sz );
     266           0 :     fd_bn254_fp12_mul( r, r, tmp );
     267           0 :     sz = 0;
     268           0 :   }
     269             : 
     270             :   /* Compute the final exponentiation */
     271           0 :   fd_bn254_final_exp( r, r );
     272             : 
     273             :   /* Output is 0 or 1, serialized as big endian uint256. */
     274           0 :   fd_memset( out, 0, 32 );
     275           0 :   if( FD_LIKELY( fd_bn254_fp12_is_one( r ) ) ) {
     276           0 :     out[31] = 1;
     277           0 :   }
     278           0 :   return 0;
     279           0 : }

Generated by: LCOV version 1.14