LCOV - code coverage report
Current view: top level - ballet/bls - fd_bls12_381.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 279 319 87.5 %
Date: 2026-09-17 04:28:31 Functions: 23 23 100.0 %

          Line data    Source code
       1             : #include "fd_bls12_381.h"
       2             : #include "../bigint/fd_uint256.h"
       3             : 
       4             : #include "../../third_party/blst/bindings/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      187383 :                        uchar const in [ 96 ] ) {
      34             :   /* copy into aligned memory */
      35      187383 :   ulong e[ 96/sizeof(ulong) ];
      36      187383 :   memcpy( e, in, 96 );
      37             : 
      38             :   /* bswap X, Y independently (48 bytes each) */
      39      187383 :   fd_ulong_n_bswap( e+0, 6 );
      40      187383 :   fd_ulong_n_bswap( e+6, 6 );
      41             : 
      42             :   /* copy to out */
      43      187383 :   memcpy( out, e, 96 );
      44      187383 : }
      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      124170 :                                      int                    big_endian ) {
      61      124170 :   ulong be[ 96/sizeof(ulong) ];
      62      124170 :   uchar const * in = _in;
      63      124170 :   if( !big_endian ) {
      64      124023 :     fd_bls12_381_g1_bswap( (uchar *)be, _in );
      65      124023 :     in = (uchar *)be;
      66      124023 :   }
      67             : 
      68             :   /* Reject the point if the compressed or parity flag is set.
      69             :      https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/bls12-381/src/encoding.rs#L57-L60 */
      70      124170 :   if( FD_UNLIKELY( in[ 0 ] & 0xA0 ) ) {
      71           3 :     return NULL;
      72           3 :   }
      73             : 
      74      124167 :   if( FD_UNLIKELY( blst_p1_deserialize( r, in )!=BLST_SUCCESS ) ) {
      75          12 :     return NULL;
      76          12 :   }
      77      124155 :   return r;
      78      124167 : }
      79             : 
      80             : static inline fd_bls12_381_g1aff_t *
      81             : fd_bls12_381_g1_frombytes( fd_bls12_381_g1aff_t * r,
      82             :                            uchar const            in[ 96 ],
      83        4044 :                            int                    big_endian ) {
      84        4044 :   if( FD_UNLIKELY( !fd_bls12_381_g1_frombytes_unchecked( r, in, big_endian ) ) ) {
      85          15 :     return NULL;
      86          15 :   }
      87        4029 :   if( FD_UNLIKELY( !blst_p1_affine_in_g1( r ) ) ) {
      88           0 :     return NULL;
      89           0 :   }
      90        4029 :   return r;
      91        4029 : }
      92             : 
      93             : /* G1 syscalls */
      94             : 
      95             : int
      96             : fd_bls12_381_g1_decompress_syscall( uchar       _r[ 96 ],
      97             :                                     uchar const _a[ 48 ],
      98        3552 :                                     int         big_endian ) {
      99             :   /* blst expects input in big endian. if little endian, bswap. */
     100        3552 :   ulong be[ 48/sizeof(ulong) ];
     101        3552 :   uchar const * in = _a;
     102        3552 :   if( !big_endian ) {
     103        3018 :     in = (uchar *)be;
     104        3018 :     memcpy( be, _a, 48 );
     105        3018 :     fd_ulong_n_bswap( be, 6 );
     106        3018 :   }
     107             : 
     108             :   /* decompress and serialize */
     109        3552 :   fd_bls12_381_g1aff_t r[1];
     110        3552 :   if( FD_UNLIKELY( blst_p1_uncompress( r, in )!=BLST_SUCCESS ) ) {
     111         465 :     return -1;
     112         465 :   }
     113        3087 :   if( FD_UNLIKELY( !blst_p1_affine_in_g1( r ) ) ) {
     114           6 :     return -1;
     115           6 :   }
     116        3081 :   blst_p1_affine_serialize( _r, r );
     117             : 
     118             :   /* blst output is big endian. if we want little endian, bswap. */
     119        3081 :   if( !big_endian ) {
     120        3012 :     fd_bls12_381_g1_bswap( _r, _r );
     121        3012 :   }
     122        3081 :   return 0;
     123        3087 : }
     124             : 
     125             : int
     126             : fd_bls12_381_g1_validate_syscall( uchar const _a[ 96 ],
     127        3033 :                                   int         big_endian ) {
     128        3033 :   fd_bls12_381_g1aff_t a[1];
     129        3033 :   return !!fd_bls12_381_g1_frombytes( a, _a, big_endian );
     130        3033 : }
     131             : 
     132             : int
     133             : fd_bls12_381_g1_add_syscall( uchar       _r[ 96 ],
     134             :                              uchar const _a[ 96 ],
     135             :                              uchar const _b[ 96 ],
     136       30033 :                              int         big_endian ) {
     137             :   /* points a, b are unchecked per SIMD-0388 */
     138       30033 :   fd_bls12_381_g1aff_t a[1], b[1];
     139       30033 :   if( FD_UNLIKELY( fd_bls12_381_g1_frombytes_unchecked( a, _a, big_endian )==NULL ) ) {
     140           0 :     return -1;
     141           0 :   }
     142       30033 :   if( FD_UNLIKELY( fd_bls12_381_g1_frombytes_unchecked( b, _b, big_endian )==NULL ) ) {
     143           0 :     return -1;
     144           0 :   }
     145             : 
     146       30033 :   fd_bls12_381_g1_t r[1], p[1];
     147       30033 :   blst_p1_from_affine( p, a );
     148       30033 :   blst_p1_add_or_double_affine( r, p, b );
     149             : 
     150       30033 :   fd_bls12_381_g1_tobytes( _r, r, big_endian );
     151       30033 :   return 0;
     152       30033 : }
     153             : 
     154             : int
     155             : fd_bls12_381_g1_sub_syscall( uchar       _r[ 96 ],
     156             :                              uchar const _a[ 96 ],
     157             :                              uchar const _b[ 96 ],
     158       30030 :                              int         big_endian ) {
     159             :   /* points a, b are unchecked per SIMD-0388 */
     160       30030 :   fd_bls12_381_g1aff_t a[1], b[1];
     161       30030 :   if( FD_UNLIKELY( fd_bls12_381_g1_frombytes_unchecked( a, _a, big_endian )==NULL ) ) {
     162           0 :     return -1;
     163           0 :   }
     164       30030 :   if( FD_UNLIKELY( fd_bls12_381_g1_frombytes_unchecked( b, _b, big_endian )==NULL ) ) {
     165           0 :     return -1;
     166           0 :   }
     167             : 
     168       30030 :   fd_bls12_381_g1_t r[1], p[1];
     169       30030 :   blst_p1_from_affine( p, a );
     170       30030 :   blst_fp_cneg( &b->y, &b->y, 1 ); /* -b, it works also with b=0 */
     171       30030 :   blst_p1_add_or_double_affine( r, p, b );
     172             : 
     173       30030 :   fd_bls12_381_g1_tobytes( _r, r, big_endian );
     174       30030 :   return 0;
     175       30030 : }
     176             : 
     177             : int
     178             : fd_bls12_381_g1_mul_syscall( uchar       _r[ 96 ],
     179             :                              uchar const _n[ 32 ],
     180             :                              uchar const _a[ 96 ],
     181         330 :                              int         big_endian ) {
     182             :   /* point a, scalar n are validated per SIMD-0388 */
     183         330 :   fd_bls12_381_g1aff_t a[1];
     184         330 :   fd_bls12_381_scalar_t n[1];
     185         330 :   if( FD_UNLIKELY( fd_bls12_381_g1_frombytes( a, _a, big_endian )==NULL ) ) {
     186           0 :     return -1;
     187           0 :   }
     188         330 :   if( FD_UNLIKELY( fd_bls12_381_scalar_frombytes( n, _n, big_endian )==NULL ) ) {
     189           0 :     return -1;
     190           0 :   }
     191             : 
     192         330 :   fd_bls12_381_g1_t r[1], p[1];
     193         330 :   blst_p1_from_affine( p, a );
     194             :   /* https://github.com/filecoin-project/blstrs/blob/v0.7.1/src/g1.rs#L578-L580 */
     195         330 :   blst_p1_mult( r, p, n->b, 255 );
     196             : 
     197         330 :   fd_bls12_381_g1_tobytes( _r, r, big_endian );
     198         330 :   return 0;
     199         330 : }
     200             : 
     201             : /* G2 serde */
     202             : 
     203             : typedef blst_p2_affine fd_bls12_381_g2aff_t;
     204             : typedef blst_p2        fd_bls12_381_g2_t;
     205             : 
     206             : static inline void
     207             : fd_bls12_381_g2_bswap( uchar       out[ 96*2 ], /* out can be in */
     208      187383 :                        uchar const in [ 96*2 ] ) {
     209             :   /* copy into aligned memory */
     210      187383 :   ulong e[ 96*2/sizeof(ulong) ];
     211      187383 :   memcpy( e, in, 96*2 );
     212             : 
     213             :   /* bswap X, Y independently (96 bytes each) */
     214      187383 :   fd_ulong_n_bswap( e+00, 12 );
     215      187383 :   fd_ulong_n_bswap( e+12, 12 );
     216             : 
     217             :   /* copy to out */
     218      187383 :   memcpy( out, e, 96*2 );
     219      187383 : }
     220             : 
     221             : static inline uchar *
     222             : fd_bls12_381_g2_tobytes( uchar                     out[ 96*2 ],
     223             :                          fd_bls12_381_g2_t const * a,
     224       60390 :                          int                       big_endian ) {
     225       60390 :   blst_p2_serialize( out, a );
     226       60390 :   if( !big_endian ) {
     227       60345 :     fd_bls12_381_g2_bswap( out, out );
     228       60345 :   }
     229       60390 :   return out;
     230       60390 : }
     231             : 
     232             : static inline fd_bls12_381_g2aff_t *
     233             : fd_bls12_381_g2_frombytes_unchecked( fd_bls12_381_g2aff_t * r,
     234             :                                      uchar const            _in[ 96*2 ],
     235      124182 :                                      int                    big_endian ) {
     236      124182 :   ulong be[ 96*2/sizeof(ulong) ];
     237      124182 :   uchar const * in = _in;
     238      124182 :   if( !big_endian ) {
     239      124026 :     fd_bls12_381_g2_bswap( (uchar *)be, _in );
     240      124026 :     in = (uchar *)be;
     241      124026 :   }
     242             : 
     243             :   /* Reject the point if the compressed or parity flag is set.
     244             :      https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/bls12-381/src/encoding.rs#L103-L106 */
     245      124182 :   if( FD_UNLIKELY( in[ 0 ] & 0xA0 ) ) {
     246           3 :     return NULL;
     247           3 :   }
     248             : 
     249      124179 :   if( FD_UNLIKELY( blst_p2_deserialize( r, in )!=BLST_SUCCESS ) ) {
     250          18 :     return NULL;
     251          18 :   }
     252      124161 :   return r;
     253      124179 : }
     254             : 
     255             : static inline fd_bls12_381_g2aff_t *
     256             : fd_bls12_381_g2_frombytes( fd_bls12_381_g2aff_t * r,
     257             :                            uchar const            in[ 96*2 ],
     258        4062 :                            int                    big_endian ) {
     259        4062 :   if( FD_UNLIKELY( !fd_bls12_381_g2_frombytes_unchecked( r, in, big_endian ) ) ) {
     260          21 :     return NULL;
     261          21 :   }
     262        4041 :   if( FD_UNLIKELY( !blst_p2_affine_in_g2( r ) ) ) {
     263           6 :     return NULL;
     264           6 :   }
     265        4035 :   return r;
     266        4041 : }
     267             : 
     268             : /* G2 syscalls */
     269             : 
     270             : int
     271             : fd_bls12_381_g2_decompress_syscall( uchar       _r[ 96*2 ],
     272             :                                     uchar const _a[ 48*2 ],
     273        3036 :                                     int         big_endian ) {
     274             :   /* blst expects input in big endian. if little endian, bswap. */
     275        3036 :   ulong be[ 48*2/sizeof(ulong) ];
     276        3036 :   uchar const * in = _a;
     277        3036 :   if( !big_endian ) {
     278        3018 :     in = (uchar *)be;
     279        3018 :     memcpy( be, _a, 48*2 );
     280        3018 :     fd_ulong_n_bswap( be, 6*2 );
     281        3018 :   }
     282             : 
     283             :   /* decompress and serialize */
     284        3036 :   fd_bls12_381_g2aff_t r[1];
     285        3036 :   if( FD_UNLIKELY( blst_p2_uncompress( r, in )!=BLST_SUCCESS ) ) {
     286           6 :     return -1;
     287           6 :   }
     288        3030 :   if( FD_UNLIKELY( !blst_p2_affine_in_g2( r ) ) ) {
     289           6 :     return -1;
     290           6 :   }
     291        3024 :   blst_p2_affine_serialize( _r, r );
     292             : 
     293             :   /* blst output is big endian. if we want little endian, bswap. */
     294        3024 :   if( !big_endian ) {
     295        3012 :     fd_bls12_381_g2_bswap( _r, _r );
     296        3012 :   }
     297        3024 :   return 0;
     298        3030 : }
     299             : 
     300             : int
     301             : fd_bls12_381_g2_compress( uchar       _r[ 48*2 ],
     302             :                           uchar const _a[ 96*2 ],
     303          24 :                           int         big_endian ) {
     304          24 :   fd_bls12_381_g2aff_t a[1];
     305          24 :   if( FD_UNLIKELY( fd_bls12_381_g2_frombytes( a, _a, big_endian )==NULL ) ) {
     306          12 :     return -1;
     307          12 :   }
     308             : 
     309          12 :   blst_p2_affine_compress( _r, a );
     310             : 
     311             :   /* blst output is big endian. if we want little endian, bswap. */
     312          12 :   if( !big_endian ) {
     313           6 :     ulong le[ 48*2/sizeof(ulong) ];
     314           6 :     memcpy( le, _r, 48*2 );
     315           6 :     fd_ulong_n_bswap( le, 6*2 );
     316           6 :     memcpy( _r, le, 48*2 );
     317           6 :   }
     318          12 :   return 0;
     319          24 : }
     320             : 
     321             : int
     322             : fd_bls12_381_g2_validate_syscall( uchar const _a[ 96*2 ],
     323        3027 :                                   int         big_endian ) {
     324        3027 :   fd_bls12_381_g2aff_t a[1];
     325        3027 :   return !!fd_bls12_381_g2_frombytes( a, _a, big_endian );
     326        3027 : }
     327             : 
     328             : int
     329             : fd_bls12_381_g2_add_syscall( uchar       _r[ 96*2 ],
     330             :                              uchar const _a[ 96*2 ],
     331             :                              uchar const _b[ 96*2 ],
     332       30030 :                              int         big_endian ) {
     333             :   /* points a, b are unchecked per SIMD-0388 */
     334       30030 :   fd_bls12_381_g2aff_t a[1], b[1];
     335       30030 :   if( FD_UNLIKELY( fd_bls12_381_g2_frombytes_unchecked( a, _a, big_endian )==NULL ) ) {
     336           0 :     return -1;
     337           0 :   }
     338       30030 :   if( FD_UNLIKELY( fd_bls12_381_g2_frombytes_unchecked( b, _b, big_endian )==NULL ) ) {
     339           0 :     return -1;
     340           0 :   }
     341             : 
     342       30030 :   fd_bls12_381_g2_t r[1], p[1];
     343       30030 :   blst_p2_from_affine( p, a );
     344       30030 :   blst_p2_add_or_double_affine( r, p, b );
     345             : 
     346       30030 :   fd_bls12_381_g2_tobytes( _r, r, big_endian );
     347       30030 :   return 0;
     348       30030 : }
     349             : 
     350             : int
     351             : fd_bls12_381_g2_sub_syscall( uchar       _r[ 96*2 ],
     352             :                              uchar const _a[ 96*2 ],
     353             :                              uchar const _b[ 96*2 ],
     354       30030 :                              int         big_endian ) {
     355             :   /* points a, b are unchecked per SIMD-0388 */
     356       30030 :   fd_bls12_381_g2aff_t a[1], b[1];
     357       30030 :   if( FD_UNLIKELY( fd_bls12_381_g2_frombytes_unchecked( a, _a, big_endian )==NULL ) ) {
     358           0 :     return -1;
     359           0 :   }
     360       30030 :   if( FD_UNLIKELY( fd_bls12_381_g2_frombytes_unchecked( b, _b, big_endian )==NULL ) ) {
     361           0 :     return -1;
     362           0 :   }
     363             : 
     364       30030 :   fd_bls12_381_g2_t r[1], p[1];
     365       30030 :   blst_p2_from_affine( p, a );
     366       30030 :   blst_fp2_cneg( &b->y, &b->y, 1 ); /* -b, it works also with b=0 */
     367       30030 :   blst_p2_add_or_double_affine( r, p, b );
     368             : 
     369       30030 :   fd_bls12_381_g2_tobytes( _r, r, big_endian );
     370       30030 :   return 0;
     371       30030 : }
     372             : 
     373             : int
     374             : fd_bls12_381_g2_mul_syscall( uchar       _r[ 96*2 ],
     375             :                              uchar const _n[ 32 ],
     376             :                              uchar const _a[ 96*2 ],
     377         330 :                              int         big_endian ) {
     378             :   /* point a, scalar n are validated per SIMD-0388 */
     379         330 :   fd_bls12_381_g2aff_t a[1];
     380         330 :   fd_bls12_381_scalar_t n[1];
     381         330 :   if( FD_UNLIKELY( fd_bls12_381_g2_frombytes( a, _a, big_endian )==NULL ) ) {
     382           0 :     return -1;
     383           0 :   }
     384         330 :   if( FD_UNLIKELY( fd_bls12_381_scalar_frombytes( n, _n, big_endian )==NULL ) ) {
     385           0 :     return -1;
     386           0 :   }
     387             : 
     388         330 :   fd_bls12_381_g2_t r[1], p[1];
     389         330 :   blst_p2_from_affine( p, a );
     390             :   /* https://github.com/filecoin-project/blstrs/blob/v0.7.1/src/g2.rs#L545-L547 */
     391         330 :   blst_p2_mult( r, p, n->b, 255 );
     392             : 
     393         330 :   fd_bls12_381_g2_tobytes( _r, r, big_endian );
     394         330 :   return 0;
     395         330 : }
     396             : 
     397             : int
     398             : fd_bls12_381_pairing_syscall( uchar       _r[ 48*12 ],
     399             :                               uchar const _a[], /* 96*n */
     400             :                               uchar const _b[], /* 96*2*n */
     401             :                               ulong const _n,
     402         360 :                               int         big_endian ) {
     403             : 
     404         360 :   if( FD_UNLIKELY( _n>FD_BLS12_381_PAIRING_BATCH_SZ ) ) {
     405           0 :     return -1;
     406           0 :   }
     407             : 
     408         360 :   fd_bls12_381_g1aff_t a[ FD_BLS12_381_PAIRING_BATCH_SZ ];
     409         360 :   fd_bls12_381_g2aff_t b[ FD_BLS12_381_PAIRING_BATCH_SZ ];
     410         360 :   fd_bls12_381_g1aff_t const * aptr[ FD_BLS12_381_PAIRING_BATCH_SZ ];
     411         360 :   fd_bls12_381_g2aff_t const * bptr[ FD_BLS12_381_PAIRING_BATCH_SZ ];
     412             :   /* skip pairs where either side is the point at infinity.
     413             :      this is important because blst otherwise produces an invalid result. */
     414         360 :   ulong m = 0UL;
     415        1041 :   for( ulong j=0; j<_n; j++ ) {
     416         681 :     fd_bls12_381_g1aff_t * aj = &a[ m ];
     417         681 :     fd_bls12_381_g2aff_t * bj = &b[ m ];
     418         681 :     if( FD_UNLIKELY( fd_bls12_381_g1_frombytes( aj, _a+96*j, big_endian )==NULL ) ) {
     419           0 :       return -1;
     420           0 :     }
     421         681 :     if( FD_UNLIKELY( fd_bls12_381_g2_frombytes( bj, _b+96*2*j, big_endian )==NULL ) ) {
     422           0 :       return -1;
     423           0 :     }
     424         681 :     if( FD_UNLIKELY( blst_p1_affine_is_inf( aj ) || blst_p2_affine_is_inf( bj ) ) ) {
     425          24 :       continue;
     426          24 :     }
     427             :     /* blst wants an array of pointers (not necessarily a compact array) */
     428         657 :     aptr[ m ] = aj;
     429         657 :     bptr[ m ] = bj;
     430         657 :     m++;
     431         657 :   }
     432             : 
     433         360 :   blst_fp12 r[1];
     434         360 :   memcpy( r, blst_fp12_one(), sizeof(blst_fp12) );
     435             : 
     436         360 :   if( FD_LIKELY ( m>0 ) ) {
     437         333 :     blst_miller_loop_n( r, bptr, aptr, m );
     438         333 :     blst_final_exp( r, r );
     439         333 :   }
     440             : 
     441         360 :   if( big_endian ) {
     442         507 :     for( ulong j=0; j<12; j++ ) {
     443         468 :       blst_bendian_from_fp( _r+48*(12-1-j), &r[ 0 ].fp6[ j/6 ].fp2[ (j/2)%3 ].fp[ j%2 ] );
     444         468 :     }
     445         321 :   } else {
     446        4173 :     for( ulong j=0; j<12; j++ ) {
     447        3852 :       blst_lendian_from_fp( _r+48*j, &r[ 0 ].fp6[ j/6 ].fp2[ (j/2)%3 ].fp[ j%2 ] );
     448        3852 :     }
     449         321 :   }
     450             : 
     451         360 :   return 0;
     452         360 : }
     453             : 
     454             : /* Proof of possession */
     455             : 
     456         315 : #define FD_BLS_LITERAL(STR) ("" STR), (sizeof(STR)-1)
     457             : #define FD_BLS_SIG_DOMAIN_H2P "BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_POP_"
     458             : #define FD_BLS_SIG_DOMAIN_POP "BLS_POP_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_"
     459             : 
     460             : /* fd_bls12_381_core_verify verifies a BLS signature in the mathematical
     461             :    sense, i.e. computes a pairing to check that the signature is correct.
     462             :    This is the core computation both for "real world" signatures and proofs
     463             :    of possession. In both cases, the difference between the math paper and
     464             :    the RFC implementation is an additional domain separator that's used
     465             :    in computing the hash to G2.
     466             : 
     467             :    See also:
     468             :    https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-bls-signature-06#name-coreverify
     469             : 
     470             :    We use a1, a2 for points in G1, b1, b2 for points in G2.
     471             :    We have to check that e( pk, H(msg) ) == e( g1, sig ), or equivalently
     472             :    e( pk, H(msg) ) * e( -g1, sig ) == 1.
     473             : 
     474             :    Replacing the variables we get:
     475             :    - a1 <- public_key, input needs to be decompressed in G1
     476             :    - b1 <- msg, input needs to be hashed to G2
     477             :    - a2 <- -g1, the const generator of G1, negated
     478             :    - b2 <- signature, input needs to be decompressed in G2
     479             :    */
     480             : static inline int
     481             : fd_bls12_381_core_verify( uchar const  msg[], /* msg_sz */
     482             :                           ulong        msg_sz,
     483             :                           uchar const  signature[ 96 ],
     484             :                           uchar const  public_key[ 48 ],
     485             :                           char const * domain,
     486         315 :                           ulong        domain_len ) {
     487         315 :   fd_bls12_381_g1aff_t a1[1]; /* a2 is const, we don't need a var */
     488         315 :   fd_bls12_381_g2aff_t b1[1], b2[1];
     489             : 
     490             :   /* decompress public_key into a1 and check that it's a valid point in G1 */
     491         315 :   if( FD_UNLIKELY( blst_p1_uncompress( a1, public_key )!=BLST_SUCCESS ) ) {
     492           3 :     return -1;
     493           3 :   }
     494         312 :   if( FD_UNLIKELY( !blst_p1_affine_in_g1( a1 ) ) ) {
     495           0 :     return -1;
     496           0 :   }
     497             :   /* https://github.com/anza-xyz/solana-sdk/blob/b66abfddd564aef5b4b82cf4e76381e96f2459f0/bls-signatures/src/pubkey/verify.rs#L120 */
     498         312 :   if( FD_UNLIKELY( blst_p1_affine_is_inf( a1 ) ) ) {
     499           0 :     return -1;
     500           0 :   }
     501             : 
     502             :   /* hash msg into b1. the check that it's a valid point in G2 is implicit/guaranteed */
     503         312 :   fd_bls12_381_g2_t _b1[1];
     504         312 :   blst_hash_to_g2( _b1, msg, msg_sz, (uchar const *)domain, domain_len, NULL, 0UL );
     505         312 :   blst_p2_to_affine( b1, _b1 );
     506             : 
     507             :   /* decompress signature into b2 and check that it's a valid point in G2 */
     508         312 :   if( FD_UNLIKELY( blst_p2_uncompress( b2, signature )!=BLST_SUCCESS ) ) {
     509           3 :     return -1;
     510           3 :   }
     511         309 :   if( FD_UNLIKELY( !blst_p2_affine_in_g2( b2 ) ) ) {
     512           0 :     return -1;
     513           0 :   }
     514             : 
     515             :   /* prepare pairing input: blst needs 2 arrays of pointers, and the result
     516             :      needs to be initialized to 1. */
     517         309 :   fd_bls12_381_g1aff_t const * aptr[ 2 ] = { a1, &BLS12_381_NEG_G1 };
     518         309 :   fd_bls12_381_g2aff_t const * bptr[ 2 ] = { b1, b2 };
     519         309 :   blst_fp12 r[1];
     520         309 :   memcpy( r, blst_fp12_one(), sizeof(blst_fp12) );
     521             : 
     522             :   /* compute the actual pairing and check that it's 1 */
     523         309 :   blst_miller_loop_n( r, bptr, aptr, 2 );
     524         309 :   if( FD_LIKELY( blst_fp12_finalverify( r, blst_fp12_one() ) ) ) {
     525         306 :     return 0; /* success */
     526         306 :   }
     527           3 :   return -1;
     528         309 : }
     529             : 
     530             : int
     531             : fd_bls12_381_proof_of_possession_verify( uchar const msg[], /* msg_sz */
     532             :                                          ulong       msg_sz,
     533             :                                          uchar const proof[ static 96 ],
     534         321 :                                          uchar const public_key[ static 48 ] ) {
     535             :   /* Agave supports the case of empty msg, where the public key is used
     536             :      instead (i.e. the plain RFC proof of possession). But that's not really
     537             :      used anywhere, and probably shouldn't be used for security reasons.
     538             :      In order to avoid accidental future changes, we prefer to not implement
     539             :      the case msg_sz==0 and instead explicitly throw an error.
     540             :      Since the public key must be part of the message, we check that
     541             :      msg_sz >= public key size, again to avoid accidental mistakes. */
     542         321 :   if( FD_UNLIKELY( msg_sz<48 ) ) {
     543           6 :     return -1;
     544           6 :   }
     545             : 
     546         315 :   return fd_bls12_381_core_verify( msg, msg_sz, proof, public_key, FD_BLS_LITERAL( FD_BLS_SIG_DOMAIN_POP ) );
     547         321 : }

Generated by: LCOV version 1.14