LCOV - code coverage report
Current view: top level - ballet/bls - fd_bls12_381.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 296 0.0 %
Date: 2026-03-19 18:19:27 Functions: 0 22 0.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           0 :                                int                     big_endian ) {
      14             :   /* https://github.com/filecoin-project/blstrs/blob/v0.7.1/src/scalar.rs#L551-L569 */
      15           0 :   if( big_endian ) {
      16           0 :     blst_scalar_from_bendian( n, in );
      17           0 :   } else {
      18           0 :     blst_scalar_from_lendian( n, in );
      19           0 :   }
      20           0 :   if( FD_UNLIKELY( !blst_scalar_fr_check( n ) ) ) {
      21           0 :     return NULL;
      22           0 :   }
      23           0 :   return n;
      24           0 : }
      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           0 :                        uchar const in [ 96 ] ) {
      34             :   /* copy into aligned memory */
      35           0 :   ulong e[ 96/sizeof(ulong) ];
      36           0 :   memcpy( e, in, 96 );
      37             : 
      38             :   /* bswap X, Y independently (48 bytes each) */
      39           0 :   fd_ulong_n_bswap( e+0, 6 );
      40           0 :   fd_ulong_n_bswap( e+6, 6 );
      41             : 
      42             :   /* copy to out */
      43           0 :   memcpy( out, e, 96 );
      44           0 : }
      45             : 
      46             : static inline uchar *
      47             : fd_bls12_381_g1_tobytes( uchar                     out[ 96 ],
      48             :                          fd_bls12_381_g1_t const * a,
      49           0 :                          int                       big_endian ) {
      50           0 :   blst_p1_serialize( out, a );
      51           0 :   if( !big_endian ) {
      52           0 :     fd_bls12_381_g1_bswap( out, out );
      53           0 :   }
      54           0 :   return out;
      55           0 : }
      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           0 :                                      int                    big_endian ) {
      61           0 :   ulong be[ 96/sizeof(ulong) ];
      62           0 :   uchar const * in = _in;
      63           0 :   if( !big_endian ) {
      64           0 :     fd_bls12_381_g1_bswap( (uchar *)be, _in );
      65           0 :     in = (uchar *)be;
      66           0 :   }
      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           0 :   if( FD_UNLIKELY( in[ 0 ] & 0xA0 ) ) {
      71           0 :     return NULL;
      72           0 :   }
      73             : 
      74           0 :   if( FD_UNLIKELY( blst_p1_deserialize( r, in )!=BLST_SUCCESS ) ) {
      75           0 :     return NULL;
      76           0 :   }
      77           0 :   return r;
      78           0 : }
      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           0 :                            int                    big_endian ) {
      84           0 :   if( FD_UNLIKELY( !fd_bls12_381_g1_frombytes_unchecked( r, in, big_endian ) ) ) {
      85           0 :     return NULL;
      86           0 :   }
      87           0 :   if( FD_UNLIKELY( !blst_p1_affine_in_g1( r ) ) ) {
      88           0 :     return NULL;
      89           0 :   }
      90           0 :   return r;
      91           0 : }
      92             : 
      93             : /* G1 syscalls */
      94             : 
      95             : int
      96             : fd_bls12_381_g1_decompress_syscall( uchar       _r[ 96 ],
      97             :                                     uchar const _a[ 48 ],
      98           0 :                                     int         big_endian ) {
      99             :   /* blst expects input in big endian. if little endian, bswap. */
     100           0 :   ulong be[ 48/sizeof(ulong) ];
     101           0 :   uchar const * in = _a;
     102           0 :   if( !big_endian ) {
     103           0 :     in = (uchar *)be;
     104           0 :     memcpy( be, _a, 48 );
     105           0 :     fd_ulong_n_bswap( be, 6 );
     106           0 :   }
     107             : 
     108             :   /* decompress and serialize */
     109           0 :   fd_bls12_381_g1aff_t r[1];
     110           0 :   if( FD_UNLIKELY( blst_p1_uncompress( r, in )!=BLST_SUCCESS ) ) {
     111           0 :     return -1;
     112           0 :   }
     113           0 :   if( FD_UNLIKELY( !blst_p1_affine_in_g1( r ) ) ) {
     114           0 :     return -1;
     115           0 :   }
     116           0 :   blst_p1_affine_serialize( _r, r );
     117             : 
     118             :   /* blst output is big endian. if we want little endian, bswap. */
     119           0 :   if( !big_endian ) {
     120           0 :     fd_bls12_381_g1_bswap( _r, _r );
     121           0 :   }
     122           0 :   return 0;
     123           0 : }
     124             : 
     125             : int
     126             : fd_bls12_381_g1_validate_syscall( uchar const _a[ 96 ],
     127           0 :                                   int         big_endian ) {
     128           0 :   fd_bls12_381_g1aff_t a[1];
     129           0 :   return !!fd_bls12_381_g1_frombytes( a, _a, big_endian );
     130           0 : }
     131             : 
     132             : int
     133             : fd_bls12_381_g1_add_syscall( uchar       _r[ 96 ],
     134             :                              uchar const _a[ 96 ],
     135             :                              uchar const _b[ 96 ],
     136           0 :                              int         big_endian ) {
     137             :   /* points a, b are unchecked per SIMD-0388 */
     138           0 :   fd_bls12_381_g1aff_t a[1], b[1];
     139           0 :   if( FD_UNLIKELY( fd_bls12_381_g1_frombytes_unchecked( a, _a, big_endian )==NULL ) ) {
     140           0 :     return -1;
     141           0 :   }
     142           0 :   if( FD_UNLIKELY( fd_bls12_381_g1_frombytes_unchecked( b, _b, big_endian )==NULL ) ) {
     143           0 :     return -1;
     144           0 :   }
     145             : 
     146           0 :   fd_bls12_381_g1_t r[1], p[1];
     147           0 :   blst_p1_from_affine( p, a );
     148           0 :   blst_p1_add_or_double_affine( r, p, b );
     149             : 
     150           0 :   fd_bls12_381_g1_tobytes( _r, r, big_endian );
     151           0 :   return 0;
     152           0 : }
     153             : 
     154             : int
     155             : fd_bls12_381_g1_sub_syscall( uchar       _r[ 96 ],
     156             :                              uchar const _a[ 96 ],
     157             :                              uchar const _b[ 96 ],
     158           0 :                              int         big_endian ) {
     159             :   /* points a, b are unchecked per SIMD-0388 */
     160           0 :   fd_bls12_381_g1aff_t a[1], b[1];
     161           0 :   if( FD_UNLIKELY( fd_bls12_381_g1_frombytes_unchecked( a, _a, big_endian )==NULL ) ) {
     162           0 :     return -1;
     163           0 :   }
     164           0 :   if( FD_UNLIKELY( fd_bls12_381_g1_frombytes_unchecked( b, _b, big_endian )==NULL ) ) {
     165           0 :     return -1;
     166           0 :   }
     167             : 
     168           0 :   fd_bls12_381_g1_t r[1], p[1];
     169           0 :   blst_p1_from_affine( p, a );
     170           0 :   blst_fp_cneg( &b->y, &b->y, 1 ); /* -b, it works also with b=0 */
     171           0 :   blst_p1_add_or_double_affine( r, p, b );
     172             : 
     173           0 :   fd_bls12_381_g1_tobytes( _r, r, big_endian );
     174           0 :   return 0;
     175           0 : }
     176             : 
     177             : int
     178             : fd_bls12_381_g1_mul_syscall( uchar       _r[ 96 ],
     179             :                              uchar const _n[ 32 ],
     180             :                              uchar const _a[ 96 ],
     181           0 :                              int         big_endian ) {
     182             :   /* point a, scalar n are validated per SIMD-0388 */
     183           0 :   fd_bls12_381_g1aff_t a[1];
     184           0 :   fd_bls12_381_scalar_t n[1];
     185           0 :   if( FD_UNLIKELY( fd_bls12_381_g1_frombytes( a, _a, big_endian )==NULL ) ) {
     186           0 :     return -1;
     187           0 :   }
     188           0 :   if( FD_UNLIKELY( fd_bls12_381_scalar_frombytes( n, _n, big_endian )==NULL ) ) {
     189           0 :     return -1;
     190           0 :   }
     191             : 
     192           0 :   fd_bls12_381_g1_t r[1], p[1];
     193           0 :   blst_p1_from_affine( p, a );
     194             :   /* https://github.com/filecoin-project/blstrs/blob/v0.7.1/src/g1.rs#L578-L580 */
     195           0 :   blst_p1_mult( r, p, n->b, 255 );
     196             : 
     197           0 :   fd_bls12_381_g1_tobytes( _r, r, big_endian );
     198           0 :   return 0;
     199           0 : }
     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           0 :                        uchar const in [ 96*2 ] ) {
     209             :   /* copy into aligned memory */
     210           0 :   ulong e[ 96*2/sizeof(ulong) ];
     211           0 :   memcpy( e, in, 96*2 );
     212             : 
     213             :   /* bswap X, Y independently (96 bytes each) */
     214           0 :   fd_ulong_n_bswap( e+00, 12 );
     215           0 :   fd_ulong_n_bswap( e+12, 12 );
     216             : 
     217             :   /* copy to out */
     218           0 :   memcpy( out, e, 96*2 );
     219           0 : }
     220             : 
     221             : static inline uchar *
     222             : fd_bls12_381_g2_tobytes( uchar                     out[ 96*2 ],
     223             :                          fd_bls12_381_g2_t const * a,
     224           0 :                          int                       big_endian ) {
     225           0 :   blst_p2_serialize( out, a );
     226           0 :   if( !big_endian ) {
     227           0 :     fd_bls12_381_g2_bswap( out, out );
     228           0 :   }
     229           0 :   return out;
     230           0 : }
     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           0 :                                      int                    big_endian ) {
     236           0 :   ulong be[ 96*2/sizeof(ulong) ];
     237           0 :   uchar const * in = _in;
     238           0 :   if( !big_endian ) {
     239           0 :     fd_bls12_381_g2_bswap( (uchar *)be, _in );
     240           0 :     in = (uchar *)be;
     241           0 :   }
     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           0 :   if( FD_UNLIKELY( in[ 0 ] & 0xA0 ) ) {
     246           0 :     return NULL;
     247           0 :   }
     248             : 
     249           0 :   if( FD_UNLIKELY( blst_p2_deserialize( r, in )!=BLST_SUCCESS ) ) {
     250           0 :     return NULL;
     251           0 :   }
     252           0 :   return r;
     253           0 : }
     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           0 :                            int                    big_endian ) {
     259           0 :   if( FD_UNLIKELY( !fd_bls12_381_g2_frombytes_unchecked( r, in, big_endian ) ) ) {
     260           0 :     return NULL;
     261           0 :   }
     262           0 :   if( FD_UNLIKELY( !blst_p2_affine_in_g2( r ) ) ) {
     263           0 :     return NULL;
     264           0 :   }
     265           0 :   return r;
     266           0 : }
     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           0 :                                     int         big_endian ) {
     274             :   /* blst expects input in big endian. if little endian, bswap. */
     275           0 :   ulong be[ 48*2/sizeof(ulong) ];
     276           0 :   uchar const * in = _a;
     277           0 :   if( !big_endian ) {
     278           0 :     in = (uchar *)be;
     279           0 :     memcpy( be, _a, 48*2 );
     280           0 :     fd_ulong_n_bswap( be, 6*2 );
     281           0 :   }
     282             : 
     283             :   /* decompress and serialize */
     284           0 :   fd_bls12_381_g2aff_t r[1];
     285           0 :   if( FD_UNLIKELY( blst_p2_uncompress( r, in )!=BLST_SUCCESS ) ) {
     286           0 :     return -1;
     287           0 :   }
     288           0 :   if( FD_UNLIKELY( !blst_p2_affine_in_g2( r ) ) ) {
     289           0 :     return -1;
     290           0 :   }
     291           0 :   blst_p2_affine_serialize( _r, r );
     292             : 
     293             :   /* blst output is big endian. if we want little endian, bswap. */
     294           0 :   if( !big_endian ) {
     295           0 :     fd_bls12_381_g2_bswap( _r, _r );
     296           0 :   }
     297           0 :   return 0;
     298           0 : }
     299             : 
     300             : int
     301             : fd_bls12_381_g2_validate_syscall( uchar const _a[ 96*2 ],
     302           0 :                                   int         big_endian ) {
     303           0 :   fd_bls12_381_g2aff_t a[1];
     304           0 :   return !!fd_bls12_381_g2_frombytes( a, _a, big_endian );
     305           0 : }
     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           0 :                              int         big_endian ) {
     312             :   /* points a, b are unchecked per SIMD-0388 */
     313           0 :   fd_bls12_381_g2aff_t a[1], b[1];
     314           0 :   if( FD_UNLIKELY( fd_bls12_381_g2_frombytes_unchecked( a, _a, big_endian )==NULL ) ) {
     315           0 :     return -1;
     316           0 :   }
     317           0 :   if( FD_UNLIKELY( fd_bls12_381_g2_frombytes_unchecked( b, _b, big_endian )==NULL ) ) {
     318           0 :     return -1;
     319           0 :   }
     320             : 
     321           0 :   fd_bls12_381_g2_t r[1], p[1];
     322           0 :   blst_p2_from_affine( p, a );
     323           0 :   blst_p2_add_or_double_affine( r, p, b );
     324             : 
     325           0 :   fd_bls12_381_g2_tobytes( _r, r, big_endian );
     326           0 :   return 0;
     327           0 : }
     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           0 :                              int         big_endian ) {
     334             :   /* points a, b are unchecked per SIMD-0388 */
     335           0 :   fd_bls12_381_g2aff_t a[1], b[1];
     336           0 :   if( FD_UNLIKELY( fd_bls12_381_g2_frombytes_unchecked( a, _a, big_endian )==NULL ) ) {
     337           0 :     return -1;
     338           0 :   }
     339           0 :   if( FD_UNLIKELY( fd_bls12_381_g2_frombytes_unchecked( b, _b, big_endian )==NULL ) ) {
     340           0 :     return -1;
     341           0 :   }
     342             : 
     343           0 :   fd_bls12_381_g2_t r[1], p[1];
     344           0 :   blst_p2_from_affine( p, a );
     345           0 :   blst_fp2_cneg( &b->y, &b->y, 1 ); /* -b, it works also with b=0 */
     346           0 :   blst_p2_add_or_double_affine( r, p, b );
     347             : 
     348           0 :   fd_bls12_381_g2_tobytes( _r, r, big_endian );
     349           0 :   return 0;
     350           0 : }
     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           0 :                              int         big_endian ) {
     357             :   /* point a, scalar n are validated per SIMD-0388 */
     358           0 :   fd_bls12_381_g2aff_t a[1];
     359           0 :   fd_bls12_381_scalar_t n[1];
     360           0 :   if( FD_UNLIKELY( fd_bls12_381_g2_frombytes( a, _a, big_endian )==NULL ) ) {
     361           0 :     return -1;
     362           0 :   }
     363           0 :   if( FD_UNLIKELY( fd_bls12_381_scalar_frombytes( n, _n, big_endian )==NULL ) ) {
     364           0 :     return -1;
     365           0 :   }
     366             : 
     367           0 :   fd_bls12_381_g2_t r[1], p[1];
     368           0 :   blst_p2_from_affine( p, a );
     369             :   /* https://github.com/filecoin-project/blstrs/blob/v0.7.1/src/g2.rs#L545-L547 */
     370           0 :   blst_p2_mult( r, p, n->b, 255 );
     371             : 
     372           0 :   fd_bls12_381_g2_tobytes( _r, r, big_endian );
     373           0 :   return 0;
     374           0 : }
     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           0 :                               int         big_endian ) {
     382             : 
     383           0 :   if( FD_UNLIKELY( _n>FD_BLS12_381_PAIRING_BATCH_SZ ) ) {
     384           0 :     return -1;
     385           0 :   }
     386             : 
     387           0 :   fd_bls12_381_g1aff_t a[ FD_BLS12_381_PAIRING_BATCH_SZ ];
     388           0 :   fd_bls12_381_g2aff_t b[ FD_BLS12_381_PAIRING_BATCH_SZ ];
     389           0 :   fd_bls12_381_g1aff_t const * aptr[ FD_BLS12_381_PAIRING_BATCH_SZ ];
     390           0 :   fd_bls12_381_g2aff_t const * bptr[ FD_BLS12_381_PAIRING_BATCH_SZ ];
     391           0 :   for( ulong j=0; j<_n; j++ ) {
     392           0 :     if( FD_UNLIKELY( fd_bls12_381_g1_frombytes( &a[ j ], _a+96*j, big_endian )==NULL ) ) {
     393           0 :       return -1;
     394           0 :     }
     395           0 :     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           0 :     aptr[ j ] = &a[ j ];
     400           0 :     bptr[ j ] = &b[ j ];
     401           0 :   }
     402             : 
     403           0 :   blst_fp12 r[1];
     404           0 :   memcpy( r, blst_fp12_one(), sizeof(blst_fp12) );
     405             : 
     406           0 :   if( FD_LIKELY ( _n>0 ) ) {
     407           0 :     blst_miller_loop_n( r, bptr, aptr, _n );
     408           0 :     blst_final_exp( r, r );
     409           0 :   }
     410             : 
     411           0 :   if( big_endian ) {
     412           0 :     for( ulong j=0; j<12; j++ ) {
     413           0 :       blst_bendian_from_fp( _r+48*(12-1-j), &r[ 0 ].fp6[ j/6 ].fp2[ (j/2)%3 ].fp[ j%2 ] );
     414           0 :     }
     415           0 :   } else {
     416           0 :     for( ulong j=0; j<12; j++ ) {
     417           0 :       blst_lendian_from_fp( _r+48*j, &r[ 0 ].fp6[ j/6 ].fp2[ (j/2)%3 ].fp[ j%2 ] );
     418           0 :     }
     419           0 :   }
     420             : 
     421           0 :   return 0;
     422           0 : }
     423             : 
     424             : /* Proof of possession */
     425             : 
     426             : #define FD_BLS_SIG_DOMAIN_NUL "BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_"
     427           0 : #define FD_BLS_SIG_DOMAIN_POP "BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_"
     428           0 : #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           0 :                           char const * domain ) {
     456           0 :   fd_bls12_381_g1aff_t a1[1]; /* a2 is const, we don't need a var */
     457           0 :   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           0 :   if( FD_UNLIKELY( blst_p1_uncompress( a1, public_key )!=BLST_SUCCESS ) ) {
     461           0 :     return -1;
     462           0 :   }
     463           0 :   if( FD_UNLIKELY( !blst_p1_affine_in_g1( a1 ) ) ) {
     464           0 :     return -1;
     465           0 :   }
     466             : 
     467             :   /* hash msg into b1. the check that it's a valid point in G2 is implicit/guaranteed */
     468           0 :   fd_bls12_381_g2_t _b1[1];
     469           0 :   blst_hash_to_g2( _b1, msg, msg_sz, (uchar const *)domain, FD_BLS_SIG_DOMAIN_SZ, NULL, 0UL );
     470           0 :   blst_p2_to_affine( b1, _b1 );
     471             : 
     472             :   /* decompress signature into b2 and check that it's a valid point in G2 */
     473           0 :   if( FD_UNLIKELY( blst_p2_uncompress( b2, signature )!=BLST_SUCCESS ) ) {
     474           0 :     return -1;
     475           0 :   }
     476           0 :   if( FD_UNLIKELY( !blst_p2_affine_in_g2( b2 ) ) ) {
     477           0 :     return -1;
     478           0 :   }
     479             : 
     480             :   /* prepare pairing input: blst needs 2 arrays of pointers, and the result
     481             :      needs to be initialized to 1. */
     482           0 :   fd_bls12_381_g1aff_t const * aptr[ 2 ] = { a1, &BLS12_381_NEG_G1 };
     483           0 :   fd_bls12_381_g2aff_t const * bptr[ 2 ] = { b1, b2 };
     484           0 :   blst_fp12 r[1];
     485           0 :   memcpy( r, blst_fp12_one(), sizeof(blst_fp12) );
     486             : 
     487             :   /* compute the actual pairing and check that it's 1 */
     488           0 :   blst_miller_loop_n( r, bptr, aptr, 2 );
     489           0 :   if( FD_LIKELY( blst_fp12_finalverify( r, blst_fp12_one() ) ) ) {
     490           0 :     return 0; /* success */
     491           0 :   }
     492           0 :   return -1;
     493           0 : }
     494             : 
     495             : int
     496             : fd_bls12_381_proof_of_possession_verify( uchar const msg[], /* msg_sz */
     497             :                                          ulong       msg_sz,
     498             :                                          uchar const proof[ 96 ],
     499           0 :                                          uchar const public_key[ 48 ] ) {
     500             :   /* Agave supports the case of empty msg, where the public key is used
     501             :      instead (i.e. the plain RFC proof of possession). But that's not really
     502             :      used anywhere, and probably shouldn't be used for security reasons.
     503             :      In order to avoid accidental future changes, we prefer to not implement
     504             :      the case msg_sz==0 and instead explicitly throw an error.
     505             :      Since the public key must be part of the message, we check that
     506             :      msg_sz >= public key size, again to avoid accidental mistakes. */
     507           0 :   if( FD_UNLIKELY( msg_sz<48 ) ) {
     508           0 :     return -1;
     509           0 :   }
     510             : 
     511           0 :   return fd_bls12_381_core_verify( msg, msg_sz, proof, public_key, FD_BLS_SIG_DOMAIN_POP );
     512           0 : }

Generated by: LCOV version 1.14