LCOV - code coverage report
Current view: top level - ballet/bls - fd_bls12_381.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 220 256 85.9 %
Date: 2026-01-24 04:58:51 Functions: 20 20 100.0 %

          Line data    Source code
       1             : #include "fd_bls12_381.h"
       2             : #include "../bigint/fd_uint256.h"
       3             : 
       4             : #include <blst.h>
       5             : 
       6             : /* Scalar */
       7             : 
       8             : typedef blst_scalar fd_bls12_381_scalar_t;
       9             : 
      10             : static inline fd_bls12_381_scalar_t *
      11             : fd_bls12_381_scalar_frombytes( fd_bls12_381_scalar_t * n,
      12             :                                uchar const             in[ 32 ],
      13         660 :                                int                     big_endian ) {
      14             :   /* https://github.com/filecoin-project/blstrs/blob/v0.7.1/src/scalar.rs#L551-L569 */
      15         660 :   if( big_endian ) {
      16          30 :     blst_scalar_from_bendian( n, in );
      17         630 :   } else {
      18         630 :     blst_scalar_from_lendian( n, in );
      19         630 :   }
      20         660 :   if( FD_UNLIKELY( !blst_scalar_fr_check( n ) ) ) {
      21           0 :     return NULL;
      22           0 :   }
      23         660 :   return n;
      24         660 : }
      25             : 
      26             : /* G1 serde */
      27             : 
      28             : typedef blst_p1_affine fd_bls12_381_g1aff_t;
      29             : typedef blst_p1        fd_bls12_381_g1_t;
      30             : 
      31             : static inline void
      32             : fd_bls12_381_g1_bswap( uchar       out[ 96 ], /* out can be in */
      33      187377 :                        uchar const in [ 96 ] ) {
      34             :   /* copy into aligned memory */
      35      187377 :   ulong e[ 96/sizeof(ulong) ];
      36      187377 :   memcpy( e, in, 96 );
      37             : 
      38             :   /* bswap X, Y independently (48 bytes each) */
      39      187377 :   fd_ulong_n_bswap( e+0, 6 );
      40      187377 :   fd_ulong_n_bswap( e+6, 6 );
      41             : 
      42             :   /* copy to out */
      43      187377 :   memcpy( out, e, 96 );
      44      187377 : }
      45             : 
      46             : static inline uchar *
      47             : fd_bls12_381_g1_tobytes( uchar                     out[ 96 ],
      48             :                          fd_bls12_381_g1_t const * a,
      49       60393 :                          int                       big_endian ) {
      50       60393 :   blst_p1_serialize( out, a );
      51       60393 :   if( !big_endian ) {
      52       60348 :     fd_bls12_381_g1_bswap( out, out );
      53       60348 :   }
      54       60393 :   return out;
      55       60393 : }
      56             : 
      57             : static inline fd_bls12_381_g1aff_t *
      58             : fd_bls12_381_g1_frombytes_unchecked( fd_bls12_381_g1aff_t * r,
      59             :                                      uchar const            _in[ 96 ],
      60      124134 :                                      int                    big_endian ) {
      61      124134 :   ulong be[ 96/sizeof(ulong) ];
      62      124134 :   uchar const * in = _in;
      63      124134 :   if( !big_endian ) {
      64      124020 :     fd_bls12_381_g1_bswap( (uchar *)be, _in );
      65      124020 :     in = (uchar *)be;
      66      124020 :   }
      67      124134 :   if( FD_UNLIKELY( blst_p1_deserialize( r, in )!=BLST_SUCCESS ) ) {
      68          12 :     return NULL;
      69          12 :   }
      70      124122 :   return r;
      71      124134 : }
      72             : 
      73             : static inline fd_bls12_381_g1aff_t *
      74             : fd_bls12_381_g1_frombytes( fd_bls12_381_g1aff_t * r,
      75             :                            uchar const            in[ 96 ],
      76        4008 :                            int                    big_endian ) {
      77        4008 :   if( FD_UNLIKELY( !fd_bls12_381_g1_frombytes_unchecked( r, in, big_endian ) ) ) {
      78          12 :     return NULL;
      79          12 :   }
      80        3996 :   if( FD_UNLIKELY( !blst_p1_affine_in_g1( r ) ) ) {
      81           0 :     return NULL;
      82           0 :   }
      83        3996 :   return r;
      84        3996 : }
      85             : 
      86             : /* G1 syscalls */
      87             : 
      88             : int
      89             : fd_bls12_381_g1_decompress_syscall( uchar       _r[ 96 ],
      90             :                                     uchar const _a[ 48 ],
      91        3030 :                                     int         big_endian ) {
      92             :   /* blst expects input in big endian. if little endian, bswap. */
      93        3030 :   ulong be[ 48/sizeof(ulong) ];
      94        3030 :   uchar const * in = _a;
      95        3030 :   if( !big_endian ) {
      96        3015 :     in = (uchar *)be;
      97        3015 :     memcpy( be, _a, 48 );
      98        3015 :     fd_ulong_n_bswap( be, 6 );
      99        3015 :   }
     100             : 
     101             :   /* decompress and serialize */
     102        3030 :   fd_bls12_381_g1aff_t r[1];
     103        3030 :   if( FD_UNLIKELY( blst_p1_uncompress( r, in )!=BLST_SUCCESS ) ) {
     104           6 :     return -1;
     105           6 :   }
     106        3024 :   if( FD_UNLIKELY( !blst_p1_affine_in_g1( r ) ) ) {
     107           6 :     return -1;
     108           6 :   }
     109        3018 :   blst_p1_affine_serialize( _r, r );
     110             : 
     111             :   /* blst output is big endian. if we want little endian, bswap. */
     112        3018 :   if( !big_endian ) {
     113        3009 :     fd_bls12_381_g1_bswap( _r, _r );
     114        3009 :   }
     115        3018 :   return 0;
     116        3024 : }
     117             : 
     118             : int
     119             : fd_bls12_381_g1_validate_syscall( uchar const _a[ 96 ],
     120        3030 :                                   int         big_endian ) {
     121        3030 :   fd_bls12_381_g1aff_t a[1];
     122        3030 :   return fd_bls12_381_g1_frombytes( a, _a, big_endian )!=NULL ? 0 : -1;
     123        3030 : }
     124             : 
     125             : int
     126             : fd_bls12_381_g1_add_syscall( uchar       _r[ 96 ],
     127             :                              uchar const _a[ 96 ],
     128             :                              uchar const _b[ 96 ],
     129       30033 :                              int         big_endian ) {
     130             :   /* points a, b are unchecked per SIMD-0388 */
     131       30033 :   fd_bls12_381_g1aff_t a[1], b[1];
     132       30033 :   if( FD_UNLIKELY( fd_bls12_381_g1_frombytes_unchecked( a, _a, big_endian )==NULL ) ) {
     133           0 :     return -1;
     134           0 :   }
     135       30033 :   if( FD_UNLIKELY( fd_bls12_381_g1_frombytes_unchecked( b, _b, big_endian )==NULL ) ) {
     136           0 :     return -1;
     137           0 :   }
     138             : 
     139       30033 :   fd_bls12_381_g1_t r[1], p[1];
     140       30033 :   blst_p1_from_affine( p, a );
     141       30033 :   blst_p1_add_or_double_affine( r, p, b );
     142             : 
     143       30033 :   fd_bls12_381_g1_tobytes( _r, r, big_endian );
     144       30033 :   return 0;
     145       30033 : }
     146             : 
     147             : int
     148             : fd_bls12_381_g1_sub_syscall( uchar       _r[ 96 ],
     149             :                              uchar const _a[ 96 ],
     150             :                              uchar const _b[ 96 ],
     151       30030 :                              int         big_endian ) {
     152             :   /* points a, b are unchecked per SIMD-0388 */
     153       30030 :   fd_bls12_381_g1aff_t a[1], b[1];
     154       30030 :   if( FD_UNLIKELY( fd_bls12_381_g1_frombytes_unchecked( a, _a, big_endian )==NULL ) ) {
     155           0 :     return -1;
     156           0 :   }
     157       30030 :   if( FD_UNLIKELY( fd_bls12_381_g1_frombytes_unchecked( b, _b, big_endian )==NULL ) ) {
     158           0 :     return -1;
     159           0 :   }
     160             : 
     161       30030 :   fd_bls12_381_g1_t r[1], p[1];
     162       30030 :   blst_p1_from_affine( p, a );
     163       30030 :   blst_fp_cneg( &b->y, &b->y, 1 ); /* -b, it works also with b=0 */
     164       30030 :   blst_p1_add_or_double_affine( r, p, b );
     165             : 
     166       30030 :   fd_bls12_381_g1_tobytes( _r, r, big_endian );
     167       30030 :   return 0;
     168       30030 : }
     169             : 
     170             : int
     171             : fd_bls12_381_g1_mul_syscall( uchar       _r[ 96 ],
     172             :                              uchar const _a[ 96 ],
     173             :                              uchar const _n[ 32 ],
     174         330 :                              int         big_endian ) {
     175             :   /* point a, scalar n are validated per SIMD-0388 */
     176         330 :   fd_bls12_381_g1aff_t a[1];
     177         330 :   fd_bls12_381_scalar_t n[1];
     178         330 :   if( FD_UNLIKELY( fd_bls12_381_g1_frombytes( a, _a, big_endian )==NULL ) ) {
     179           0 :     return -1;
     180           0 :   }
     181         330 :   if( FD_UNLIKELY( fd_bls12_381_scalar_frombytes( n, _n, big_endian )==NULL ) ) {
     182           0 :     return -1;
     183           0 :   }
     184             : 
     185         330 :   fd_bls12_381_g1_t r[1], p[1];
     186         330 :   blst_p1_from_affine( p, a );
     187             :   /* https://github.com/filecoin-project/blstrs/blob/v0.7.1/src/g1.rs#L578-L580 */
     188         330 :   blst_p1_mult( r, p, n->b, 255 );
     189             : 
     190         330 :   fd_bls12_381_g1_tobytes( _r, r, big_endian );
     191         330 :   return 0;
     192         330 : }
     193             : 
     194             : /* G2 serde */
     195             : 
     196             : typedef blst_p2_affine fd_bls12_381_g2aff_t;
     197             : typedef blst_p2        fd_bls12_381_g2_t;
     198             : 
     199             : static inline void
     200             : fd_bls12_381_g2_bswap( uchar       out[ 96*2 ], /* out can be in */
     201      187365 :                        uchar const in [ 96*2 ] ) {
     202             :   /* copy into aligned memory */
     203      187365 :   ulong e[ 96*2/sizeof(ulong) ];
     204      187365 :   memcpy( e, in, 96*2 );
     205             : 
     206             :   /* bswap X, Y independently (96 bytes each) */
     207      187365 :   fd_ulong_n_bswap( e+00, 12 );
     208      187365 :   fd_ulong_n_bswap( e+12, 12 );
     209             : 
     210             :   /* copy to out */
     211      187365 :   memcpy( out, e, 96*2 );
     212      187365 : }
     213             : 
     214             : static inline uchar *
     215             : fd_bls12_381_g2_tobytes( uchar                     out[ 96*2 ],
     216             :                          fd_bls12_381_g2_t const * a,
     217       60390 :                          int                       big_endian ) {
     218       60390 :   blst_p2_serialize( out, a );
     219       60390 :   if( !big_endian ) {
     220       60345 :     fd_bls12_381_g2_bswap( out, out );
     221       60345 :   }
     222       60390 :   return out;
     223       60390 : }
     224             : 
     225             : static inline fd_bls12_381_g2aff_t *
     226             : fd_bls12_381_g2_frombytes_unchecked( fd_bls12_381_g2aff_t * r,
     227             :                                      uchar const            _in[ 96*2 ],
     228      124122 :                                      int                    big_endian ) {
     229      124122 :   ulong be[ 96*2/sizeof(ulong) ];
     230      124122 :   uchar const * in = _in;
     231      124122 :   if( !big_endian ) {
     232      124011 :     fd_bls12_381_g2_bswap( (uchar *)be, _in );
     233      124011 :     in = (uchar *)be;
     234      124011 :   }
     235      124122 :   if( FD_UNLIKELY( blst_p2_deserialize( r, in )!=BLST_SUCCESS ) ) {
     236          12 :     return NULL;
     237          12 :   }
     238      124110 :   return r;
     239      124122 : }
     240             : 
     241             : static inline fd_bls12_381_g2aff_t *
     242             : fd_bls12_381_g2_frombytes( fd_bls12_381_g2aff_t * r,
     243             :                            uchar const            in[ 96*2 ],
     244        4002 :                            int                    big_endian ) {
     245        4002 :   if( FD_UNLIKELY( !fd_bls12_381_g2_frombytes_unchecked( r, in, big_endian ) ) ) {
     246          12 :     return NULL;
     247          12 :   }
     248        3990 :   if( FD_UNLIKELY( !blst_p2_affine_in_g2( r ) ) ) {
     249           0 :     return NULL;
     250           0 :   }
     251        3990 :   return r;
     252        3990 : }
     253             : 
     254             : /* G2 syscalls */
     255             : 
     256             : int
     257             : fd_bls12_381_g2_decompress_syscall( uchar       _r[ 96*2 ],
     258             :                                     uchar const _a[ 48*2 ],
     259        3030 :                                     int         big_endian ) {
     260             :   /* blst expects input in big endian. if little endian, bswap. */
     261        3030 :   ulong be[ 48*2/sizeof(ulong) ];
     262        3030 :   uchar const * in = _a;
     263        3030 :   if( !big_endian ) {
     264        3015 :     in = (uchar *)be;
     265        3015 :     memcpy( be, _a, 48*2 );
     266        3015 :     fd_ulong_n_bswap( be, 6*2 );
     267        3015 :   }
     268             : 
     269             :   /* decompress and serialize */
     270        3030 :   fd_bls12_381_g2aff_t r[1];
     271        3030 :   if( FD_UNLIKELY( blst_p2_uncompress( r, in )!=BLST_SUCCESS ) ) {
     272           6 :     return -1;
     273           6 :   }
     274        3024 :   if( FD_UNLIKELY( !blst_p2_affine_in_g2( r ) ) ) {
     275           6 :     return -1;
     276           6 :   }
     277        3018 :   blst_p2_affine_serialize( _r, r );
     278             : 
     279             :   /* blst output is big endian. if we want little endian, bswap. */
     280        3018 :   if( !big_endian ) {
     281        3009 :     fd_bls12_381_g2_bswap( _r, _r );
     282        3009 :   }
     283        3018 :   return 0;
     284        3024 : }
     285             : 
     286             : int
     287             : fd_bls12_381_g2_validate_syscall( uchar const _a[ 96*2 ],
     288        3024 :                                   int         big_endian ) {
     289        3024 :   fd_bls12_381_g2aff_t a[1];
     290        3024 :   return fd_bls12_381_g2_frombytes( a, _a, big_endian )!=NULL ? 0 : -1;
     291        3024 : }
     292             : 
     293             : int
     294             : fd_bls12_381_g2_add_syscall( uchar       _r[ 96*2 ],
     295             :                              uchar const _a[ 96*2 ],
     296             :                              uchar const _b[ 96*2 ],
     297       30030 :                              int         big_endian ) {
     298             :   /* points a, b are unchecked per SIMD-0388 */
     299       30030 :   fd_bls12_381_g2aff_t a[1], b[1];
     300       30030 :   if( FD_UNLIKELY( fd_bls12_381_g2_frombytes_unchecked( a, _a, big_endian )==NULL ) ) {
     301           0 :     return -1;
     302           0 :   }
     303       30030 :   if( FD_UNLIKELY( fd_bls12_381_g2_frombytes_unchecked( b, _b, big_endian )==NULL ) ) {
     304           0 :     return -1;
     305           0 :   }
     306             : 
     307       30030 :   fd_bls12_381_g2_t r[1], p[1];
     308       30030 :   blst_p2_from_affine( p, a );
     309       30030 :   blst_p2_add_or_double_affine( r, p, b );
     310             : 
     311       30030 :   fd_bls12_381_g2_tobytes( _r, r, big_endian );
     312       30030 :   return 0;
     313       30030 : }
     314             : 
     315             : int
     316             : fd_bls12_381_g2_sub_syscall( uchar       _r[ 96*2 ],
     317             :                              uchar const _a[ 96*2 ],
     318             :                              uchar const _b[ 96*2 ],
     319       30030 :                              int         big_endian ) {
     320             :   /* points a, b are unchecked per SIMD-0388 */
     321       30030 :   fd_bls12_381_g2aff_t a[1], b[1];
     322       30030 :   if( FD_UNLIKELY( fd_bls12_381_g2_frombytes_unchecked( a, _a, big_endian )==NULL ) ) {
     323           0 :     return -1;
     324           0 :   }
     325       30030 :   if( FD_UNLIKELY( fd_bls12_381_g2_frombytes_unchecked( b, _b, big_endian )==NULL ) ) {
     326           0 :     return -1;
     327           0 :   }
     328             : 
     329       30030 :   fd_bls12_381_g2_t r[1], p[1];
     330       30030 :   blst_p2_from_affine( p, a );
     331       30030 :   blst_fp2_cneg( &b->y, &b->y, 1 ); /* -b, it works also with b=0 */
     332       30030 :   blst_p2_add_or_double_affine( r, p, b );
     333             : 
     334       30030 :   fd_bls12_381_g2_tobytes( _r, r, big_endian );
     335       30030 :   return 0;
     336       30030 : }
     337             : 
     338             : int
     339             : fd_bls12_381_g2_mul_syscall( uchar       _r[ 96*2 ],
     340             :                              uchar const _a[ 96*2 ],
     341             :                              uchar const _n[ 32 ],
     342         330 :                              int         big_endian ) {
     343             :   /* point a, scalar n are validated per SIMD-0388 */
     344         330 :   fd_bls12_381_g2aff_t a[1];
     345         330 :   fd_bls12_381_scalar_t n[1];
     346         330 :   if( FD_UNLIKELY( fd_bls12_381_g2_frombytes( a, _a, big_endian )==NULL ) ) {
     347           0 :     return -1;
     348           0 :   }
     349         330 :   if( FD_UNLIKELY( fd_bls12_381_scalar_frombytes( n, _n, big_endian )==NULL ) ) {
     350           0 :     return -1;
     351           0 :   }
     352             : 
     353         330 :   fd_bls12_381_g2_t r[1], p[1];
     354         330 :   blst_p2_from_affine( p, a );
     355             :   /* https://github.com/filecoin-project/blstrs/blob/v0.7.1/src/g2.rs#L545-L547 */
     356         330 :   blst_p2_mult( r, p, n->b, 255 );
     357             : 
     358         330 :   fd_bls12_381_g2_tobytes( _r, r, big_endian );
     359         330 :   return 0;
     360         330 : }
     361             : 
     362             : int
     363             : fd_bls12_381_pairing_syscall( uchar       _r[ 48*12 ],
     364             :                               uchar const _a[], /* 96*n */
     365             :                               uchar const _b[], /* 96*2*n */
     366             :                               ulong const _n,
     367         330 :                               int         big_endian ) {
     368             : 
     369         330 :   if( FD_UNLIKELY( _n>FD_BLS12_381_PAIRING_BATCH_SZ ) ) {
     370           0 :     return -1;
     371           0 :   }
     372             : 
     373         330 :   fd_bls12_381_g1aff_t a[ FD_BLS12_381_PAIRING_BATCH_SZ ];
     374         330 :   fd_bls12_381_g2aff_t b[ FD_BLS12_381_PAIRING_BATCH_SZ ];
     375         330 :   fd_bls12_381_g1aff_t const * aptr[ FD_BLS12_381_PAIRING_BATCH_SZ ];
     376         330 :   fd_bls12_381_g2aff_t const * bptr[ FD_BLS12_381_PAIRING_BATCH_SZ ];
     377         330 :   ulong n = 0;
     378         978 :   for( ulong j=0; j<_n; j++ ) {
     379         648 :     if( FD_UNLIKELY( fd_bls12_381_g1_frombytes( &a[ n ], _a+96*j, big_endian )==NULL ) ) {
     380           0 :       return -1;
     381           0 :     }
     382         648 :     if( FD_UNLIKELY( fd_bls12_381_g2_frombytes( &b[ n ], _b+96*2*j, big_endian )==NULL ) ) {
     383           0 :       return -1;
     384           0 :     }
     385             :     /* blst wants an array of pointers (not necessarily a compact array) */
     386         648 :     aptr[ n ] = &a[ n ];
     387         648 :     bptr[ n ] = &b[ n ];
     388         648 :     ++n;
     389         648 :   }
     390             : 
     391         330 :   blst_fp12 r[1];
     392         330 :   memcpy( r, blst_fp12_one(), sizeof(blst_fp12) );
     393             : 
     394         330 :   if( FD_LIKELY ( n>0 ) ) {
     395         324 :     blst_miller_loop_n( r, bptr, aptr, n );
     396         324 :     blst_final_exp( r, r );
     397         324 :   }
     398             : 
     399         330 :   if( big_endian ) {
     400         195 :     for( ulong j=0; j<12; j++ ) {
     401         180 :       blst_bendian_from_fp( _r+48*(12-1-j), &r[ 0 ].fp6[ j/6 ].fp2[ (j/2)%3 ].fp[ j%2 ] );
     402         180 :     }
     403         315 :   } else {
     404        4095 :     for( ulong j=0; j<12; j++ ) {
     405        3780 :       blst_lendian_from_fp( _r+48*j, &r[ 0 ].fp6[ j/6 ].fp2[ (j/2)%3 ].fp[ j%2 ] );
     406        3780 :     }
     407         315 :   }
     408             : 
     409         330 :   return 0;
     410         330 : }

Generated by: LCOV version 1.14