LCOV - code coverage report
Current view: top level - ballet/bls - fd_bls12_381.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 257 299 86.0 %
Date: 2026-03-31 06:22:16 Functions: 22 22 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      187380 :                        uchar const in [ 96 ] ) {
      34             :   /* copy into aligned memory */
      35      187380 :   ulong e[ 96/sizeof(ulong) ];
      36      187380 :   memcpy( e, in, 96 );
      37             : 
      38             :   /* bswap X, Y independently (48 bytes each) */
      39      187380 :   fd_ulong_n_bswap( e+0, 6 );
      40      187380 :   fd_ulong_n_bswap( e+6, 6 );
      41             : 
      42             :   /* copy to out */
      43      187380 :   memcpy( out, e, 96 );
      44      187380 : }
      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      124137 :                                      int                    big_endian ) {
      61      124137 :   ulong be[ 96/sizeof(ulong) ];
      62      124137 :   uchar const * in = _in;
      63      124137 :   if( !big_endian ) {
      64      124020 :     fd_bls12_381_g1_bswap( (uchar *)be, _in );
      65      124020 :     in = (uchar *)be;
      66      124020 :   }
      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      124137 :   if( FD_UNLIKELY( in[ 0 ] & 0xA0 ) ) {
      71           3 :     return NULL;
      72           3 :   }
      73             : 
      74      124134 :   if( FD_UNLIKELY( blst_p1_deserialize( r, in )!=BLST_SUCCESS ) ) {
      75          12 :     return NULL;
      76          12 :   }
      77      124122 :   return r;
      78      124134 : }
      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        4011 :                            int                    big_endian ) {
      84        4011 :   if( FD_UNLIKELY( !fd_bls12_381_g1_frombytes_unchecked( r, in, big_endian ) ) ) {
      85          15 :     return NULL;
      86          15 :   }
      87        3996 :   if( FD_UNLIKELY( !blst_p1_affine_in_g1( r ) ) ) {
      88           0 :     return NULL;
      89           0 :   }
      90        3996 :   return r;
      91        3996 : }
      92             : 
      93             : /* G1 syscalls */
      94             : 
      95             : int
      96             : fd_bls12_381_g1_decompress_syscall( uchar       _r[ 96 ],
      97             :                                     uchar const _a[ 48 ],
      98        3033 :                                     int         big_endian ) {
      99             :   /* blst expects input in big endian. if little endian, bswap. */
     100        3033 :   ulong be[ 48/sizeof(ulong) ];
     101        3033 :   uchar const * in = _a;
     102        3033 :   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        3033 :   fd_bls12_381_g1aff_t r[1];
     110        3033 :   if( FD_UNLIKELY( blst_p1_uncompress( r, in )!=BLST_SUCCESS ) ) {
     111           6 :     return -1;
     112           6 :   }
     113        3027 :   if( FD_UNLIKELY( !blst_p1_affine_in_g1( r ) ) ) {
     114           6 :     return -1;
     115           6 :   }
     116        3021 :   blst_p1_affine_serialize( _r, r );
     117             : 
     118             :   /* blst output is big endian. if we want little endian, bswap. */
     119        3021 :   if( !big_endian ) {
     120        3012 :     fd_bls12_381_g1_bswap( _r, _r );
     121        3012 :   }
     122        3021 :   return 0;
     123        3027 : }
     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      187368 :                        uchar const in [ 96*2 ] ) {
     209             :   /* copy into aligned memory */
     210      187368 :   ulong e[ 96*2/sizeof(ulong) ];
     211      187368 :   memcpy( e, in, 96*2 );
     212             : 
     213             :   /* bswap X, Y independently (96 bytes each) */
     214      187368 :   fd_ulong_n_bswap( e+00, 12 );
     215      187368 :   fd_ulong_n_bswap( e+12, 12 );
     216             : 
     217             :   /* copy to out */
     218      187368 :   memcpy( out, e, 96*2 );
     219      187368 : }
     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      124125 :                                      int                    big_endian ) {
     236      124125 :   ulong be[ 96*2/sizeof(ulong) ];
     237      124125 :   uchar const * in = _in;
     238      124125 :   if( !big_endian ) {
     239      124011 :     fd_bls12_381_g2_bswap( (uchar *)be, _in );
     240      124011 :     in = (uchar *)be;
     241      124011 :   }
     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      124125 :   if( FD_UNLIKELY( in[ 0 ] & 0xA0 ) ) {
     246           3 :     return NULL;
     247           3 :   }
     248             : 
     249      124122 :   if( FD_UNLIKELY( blst_p2_deserialize( r, in )!=BLST_SUCCESS ) ) {
     250          12 :     return NULL;
     251          12 :   }
     252      124110 :   return r;
     253      124122 : }
     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        4005 :                            int                    big_endian ) {
     259        4005 :   if( FD_UNLIKELY( !fd_bls12_381_g2_frombytes_unchecked( r, in, big_endian ) ) ) {
     260          15 :     return NULL;
     261          15 :   }
     262        3990 :   if( FD_UNLIKELY( !blst_p2_affine_in_g2( r ) ) ) {
     263           0 :     return NULL;
     264           0 :   }
     265        3990 :   return r;
     266        3990 : }
     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        3033 :                                     int         big_endian ) {
     274             :   /* blst expects input in big endian. if little endian, bswap. */
     275        3033 :   ulong be[ 48*2/sizeof(ulong) ];
     276        3033 :   uchar const * in = _a;
     277        3033 :   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        3033 :   fd_bls12_381_g2aff_t r[1];
     285        3033 :   if( FD_UNLIKELY( blst_p2_uncompress( r, in )!=BLST_SUCCESS ) ) {
     286           6 :     return -1;
     287           6 :   }
     288        3027 :   if( FD_UNLIKELY( !blst_p2_affine_in_g2( r ) ) ) {
     289           6 :     return -1;
     290           6 :   }
     291        3021 :   blst_p2_affine_serialize( _r, r );
     292             : 
     293             :   /* blst output is big endian. if we want little endian, bswap. */
     294        3021 :   if( !big_endian ) {
     295        3012 :     fd_bls12_381_g2_bswap( _r, _r );
     296        3012 :   }
     297        3021 :   return 0;
     298        3027 : }
     299             : 
     300             : int
     301             : fd_bls12_381_g2_validate_syscall( uchar const _a[ 96*2 ],
     302        3027 :                                   int         big_endian ) {
     303        3027 :   fd_bls12_381_g2aff_t a[1];
     304        3027 :   return !!fd_bls12_381_g2_frombytes( a, _a, big_endian );
     305        3027 : }
     306             : 
     307             : int
     308             : fd_bls12_381_g2_add_syscall( uchar       _r[ 96*2 ],
     309             :                              uchar const _a[ 96*2 ],
     310             :                              uchar const _b[ 96*2 ],
     311       30030 :                              int         big_endian ) {
     312             :   /* points a, b are unchecked per SIMD-0388 */
     313       30030 :   fd_bls12_381_g2aff_t a[1], b[1];
     314       30030 :   if( FD_UNLIKELY( fd_bls12_381_g2_frombytes_unchecked( a, _a, big_endian )==NULL ) ) {
     315           0 :     return -1;
     316           0 :   }
     317       30030 :   if( FD_UNLIKELY( fd_bls12_381_g2_frombytes_unchecked( b, _b, big_endian )==NULL ) ) {
     318           0 :     return -1;
     319           0 :   }
     320             : 
     321       30030 :   fd_bls12_381_g2_t r[1], p[1];
     322       30030 :   blst_p2_from_affine( p, a );
     323       30030 :   blst_p2_add_or_double_affine( r, p, b );
     324             : 
     325       30030 :   fd_bls12_381_g2_tobytes( _r, r, big_endian );
     326       30030 :   return 0;
     327       30030 : }
     328             : 
     329             : int
     330             : fd_bls12_381_g2_sub_syscall( uchar       _r[ 96*2 ],
     331             :                              uchar const _a[ 96*2 ],
     332             :                              uchar const _b[ 96*2 ],
     333       30030 :                              int         big_endian ) {
     334             :   /* points a, b are unchecked per SIMD-0388 */
     335       30030 :   fd_bls12_381_g2aff_t a[1], b[1];
     336       30030 :   if( FD_UNLIKELY( fd_bls12_381_g2_frombytes_unchecked( a, _a, big_endian )==NULL ) ) {
     337           0 :     return -1;
     338           0 :   }
     339       30030 :   if( FD_UNLIKELY( fd_bls12_381_g2_frombytes_unchecked( b, _b, big_endian )==NULL ) ) {
     340           0 :     return -1;
     341           0 :   }
     342             : 
     343       30030 :   fd_bls12_381_g2_t r[1], p[1];
     344       30030 :   blst_p2_from_affine( p, a );
     345       30030 :   blst_fp2_cneg( &b->y, &b->y, 1 ); /* -b, it works also with b=0 */
     346       30030 :   blst_p2_add_or_double_affine( r, p, b );
     347             : 
     348       30030 :   fd_bls12_381_g2_tobytes( _r, r, big_endian );
     349       30030 :   return 0;
     350       30030 : }
     351             : 
     352             : int
     353             : fd_bls12_381_g2_mul_syscall( uchar       _r[ 96*2 ],
     354             :                              uchar const _n[ 32 ],
     355             :                              uchar const _a[ 96*2 ],
     356         330 :                              int         big_endian ) {
     357             :   /* point a, scalar n are validated per SIMD-0388 */
     358         330 :   fd_bls12_381_g2aff_t a[1];
     359         330 :   fd_bls12_381_scalar_t n[1];
     360         330 :   if( FD_UNLIKELY( fd_bls12_381_g2_frombytes( a, _a, big_endian )==NULL ) ) {
     361           0 :     return -1;
     362           0 :   }
     363         330 :   if( FD_UNLIKELY( fd_bls12_381_scalar_frombytes( n, _n, big_endian )==NULL ) ) {
     364           0 :     return -1;
     365           0 :   }
     366             : 
     367         330 :   fd_bls12_381_g2_t r[1], p[1];
     368         330 :   blst_p2_from_affine( p, a );
     369             :   /* https://github.com/filecoin-project/blstrs/blob/v0.7.1/src/g2.rs#L545-L547 */
     370         330 :   blst_p2_mult( r, p, n->b, 255 );
     371             : 
     372         330 :   fd_bls12_381_g2_tobytes( _r, r, big_endian );
     373         330 :   return 0;
     374         330 : }
     375             : 
     376             : int
     377             : fd_bls12_381_pairing_syscall( uchar       _r[ 48*12 ],
     378             :                               uchar const _a[], /* 96*n */
     379             :                               uchar const _b[], /* 96*2*n */
     380             :                               ulong const _n,
     381         330 :                               int         big_endian ) {
     382             : 
     383         330 :   if( FD_UNLIKELY( _n>FD_BLS12_381_PAIRING_BATCH_SZ ) ) {
     384           0 :     return -1;
     385           0 :   }
     386             : 
     387         330 :   fd_bls12_381_g1aff_t a[ FD_BLS12_381_PAIRING_BATCH_SZ ];
     388         330 :   fd_bls12_381_g2aff_t b[ FD_BLS12_381_PAIRING_BATCH_SZ ];
     389         330 :   fd_bls12_381_g1aff_t const * aptr[ FD_BLS12_381_PAIRING_BATCH_SZ ];
     390         330 :   fd_bls12_381_g2aff_t const * bptr[ FD_BLS12_381_PAIRING_BATCH_SZ ];
     391         978 :   for( ulong j=0; j<_n; j++ ) {
     392         648 :     if( FD_UNLIKELY( fd_bls12_381_g1_frombytes( &a[ j ], _a+96*j, big_endian )==NULL ) ) {
     393           0 :       return -1;
     394           0 :     }
     395         648 :     if( FD_UNLIKELY( fd_bls12_381_g2_frombytes( &b[ j ], _b+96*2*j, big_endian )==NULL ) ) {
     396           0 :       return -1;
     397           0 :     }
     398             :     /* blst wants an array of pointers (not necessarily a compact array) */
     399         648 :     aptr[ j ] = &a[ j ];
     400         648 :     bptr[ j ] = &b[ j ];
     401         648 :   }
     402             : 
     403         330 :   blst_fp12 r[1];
     404         330 :   memcpy( r, blst_fp12_one(), sizeof(blst_fp12) );
     405             : 
     406         330 :   if( FD_LIKELY ( _n>0 ) ) {
     407         324 :     blst_miller_loop_n( r, bptr, aptr, _n );
     408         324 :     blst_final_exp( r, r );
     409         324 :   }
     410             : 
     411         330 :   if( big_endian ) {
     412         195 :     for( ulong j=0; j<12; j++ ) {
     413         180 :       blst_bendian_from_fp( _r+48*(12-1-j), &r[ 0 ].fp6[ j/6 ].fp2[ (j/2)%3 ].fp[ j%2 ] );
     414         180 :     }
     415         315 :   } else {
     416        4095 :     for( ulong j=0; j<12; j++ ) {
     417        3780 :       blst_lendian_from_fp( _r+48*j, &r[ 0 ].fp6[ j/6 ].fp2[ (j/2)%3 ].fp[ j%2 ] );
     418        3780 :     }
     419         315 :   }
     420             : 
     421         330 :   return 0;
     422         330 : }
     423             : 
     424             : /* Proof of possession */
     425             : 
     426             : #define FD_BLS_SIG_DOMAIN_NUL "BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_"
     427         315 : #define FD_BLS_SIG_DOMAIN_POP "BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_"
     428         312 : #define FD_BLS_SIG_DOMAIN_SZ  (43UL)
     429             : 
     430             : /* fd_bls12_381_core_verify verifies a BLS signature in the mathematical
     431             :    sense, i.e. computes a pairing to check that the signature is correct.
     432             :    This is the core computation both for "real world" signatures and proofs
     433             :    of possession. In both cases, the difference between the math paper and
     434             :    the RFC implementation is an additional domain separator that's used
     435             :    in computing the hash to G2.
     436             : 
     437             :    See also:
     438             :    https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-bls-signature-06#name-coreverify
     439             : 
     440             :    We use a1, a2 for points in G1, b1, b2 for points in G2.
     441             :    We have to check that e( pk, H(msg) ) == e( g1, sig ), or equivalently
     442             :    e( pk, H(msg) ) * e( -g1, sig ) == 1.
     443             : 
     444             :    Replacing the variables we get:
     445             :    - a1 <- public_key, input needs to be decompressed in G1
     446             :    - b1 <- msg, input needs to be hashed to G2
     447             :    - a2 <- -g1, the const generator of G1, negated
     448             :    - b2 <- signature, input needs to be decompressed in G2
     449             :    */
     450             : static inline int
     451             : fd_bls12_381_core_verify( uchar const  msg[], /* msg_sz */
     452             :                           ulong        msg_sz,
     453             :                           uchar const  signature[ 96 ],
     454             :                           uchar const  public_key[ 48 ],
     455         315 :                           char const * domain ) {
     456         315 :   fd_bls12_381_g1aff_t a1[1]; /* a2 is const, we don't need a var */
     457         315 :   fd_bls12_381_g2aff_t b1[1], b2[1];
     458             : 
     459             :   /* decompress public_key into a1 and check that it's a valid point in G1 */
     460         315 :   if( FD_UNLIKELY( blst_p1_uncompress( a1, public_key )!=BLST_SUCCESS ) ) {
     461           3 :     return -1;
     462           3 :   }
     463         312 :   if( FD_UNLIKELY( !blst_p1_affine_in_g1( a1 ) ) ) {
     464           0 :     return -1;
     465           0 :   }
     466             :   /* https://github.com/anza-xyz/solana-sdk/blob/b66abfddd564aef5b4b82cf4e76381e96f2459f0/bls-signatures/src/pubkey/verify.rs#L120 */
     467         312 :   if( FD_UNLIKELY( blst_p1_affine_is_inf( a1 ) ) ) {
     468           0 :     return -1;
     469           0 :   }
     470             : 
     471             :   /* hash msg into b1. the check that it's a valid point in G2 is implicit/guaranteed */
     472         312 :   fd_bls12_381_g2_t _b1[1];
     473         312 :   blst_hash_to_g2( _b1, msg, msg_sz, (uchar const *)domain, FD_BLS_SIG_DOMAIN_SZ, NULL, 0UL );
     474         312 :   blst_p2_to_affine( b1, _b1 );
     475             : 
     476             :   /* decompress signature into b2 and check that it's a valid point in G2 */
     477         312 :   if( FD_UNLIKELY( blst_p2_uncompress( b2, signature )!=BLST_SUCCESS ) ) {
     478           3 :     return -1;
     479           3 :   }
     480         309 :   if( FD_UNLIKELY( !blst_p2_affine_in_g2( b2 ) ) ) {
     481           0 :     return -1;
     482           0 :   }
     483             : 
     484             :   /* prepare pairing input: blst needs 2 arrays of pointers, and the result
     485             :      needs to be initialized to 1. */
     486         309 :   fd_bls12_381_g1aff_t const * aptr[ 2 ] = { a1, &BLS12_381_NEG_G1 };
     487         309 :   fd_bls12_381_g2aff_t const * bptr[ 2 ] = { b1, b2 };
     488         309 :   blst_fp12 r[1];
     489         309 :   memcpy( r, blst_fp12_one(), sizeof(blst_fp12) );
     490             : 
     491             :   /* compute the actual pairing and check that it's 1 */
     492         309 :   blst_miller_loop_n( r, bptr, aptr, 2 );
     493         309 :   if( FD_LIKELY( blst_fp12_finalverify( r, blst_fp12_one() ) ) ) {
     494         306 :     return 0; /* success */
     495         306 :   }
     496           3 :   return -1;
     497         309 : }
     498             : 
     499             : int
     500             : fd_bls12_381_proof_of_possession_verify( uchar const msg[], /* msg_sz */
     501             :                                          ulong       msg_sz,
     502             :                                          uchar const proof[ 96 ],
     503         321 :                                          uchar const public_key[ 48 ] ) {
     504             :   /* Agave supports the case of empty msg, where the public key is used
     505             :      instead (i.e. the plain RFC proof of possession). But that's not really
     506             :      used anywhere, and probably shouldn't be used for security reasons.
     507             :      In order to avoid accidental future changes, we prefer to not implement
     508             :      the case msg_sz==0 and instead explicitly throw an error.
     509             :      Since the public key must be part of the message, we check that
     510             :      msg_sz >= public key size, again to avoid accidental mistakes. */
     511         321 :   if( FD_UNLIKELY( msg_sz<48 ) ) {
     512           6 :     return -1;
     513           6 :   }
     514             : 
     515         315 :   return fd_bls12_381_core_verify( msg, msg_sz, proof, public_key, FD_BLS_SIG_DOMAIN_POP );
     516         321 : }

Generated by: LCOV version 1.14