LCOV - code coverage report
Current view: top level - ballet/bls - fd_bls.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 84 118 71.2 %
Date: 2026-09-17 04:28:31 Functions: 8 12 66.7 %

          Line data    Source code
       1             : #include "fd_bls.h"
       2             : 
       3             : #include "fd_bls12_381.h"
       4             : #include "../../third_party/blst/bindings/blst.h"
       5             : 
       6             : void
       7             : fd_bls_sec_to_pub( fd_bls_sec_t const * sk,
       8        2754 :                    fd_bls_pub_t *       pk ) {
       9        2754 :   blst_sk_to_pk_in_g1( pk, sk );
      10        2754 : }
      11             : 
      12             : void
      13             : fd_bls_sec_sign( fd_bls_sec_t const * sk,
      14             :                  uchar const *        msg,
      15             :                  ulong                msg_sz,
      16        8736 :                  fd_bls_sig_t *       sig ) {
      17        8736 :   blst_p2 hash[1];
      18        8736 :   blst_hash_to_g2( hash, msg, msg_sz, (uchar const *)FD_BLS_DST, FD_BLS_DST_SZ, NULL, 0UL );
      19        8736 :   blst_sign_pk_in_g1( sig, hash, sk );
      20        8736 : }
      21             : 
      22             : void
      23             : fd_bls_sec_derive( fd_bls_sec_t * sk,
      24             :                    uchar const *  ikm,
      25          15 :                    ulong          ikm_sz ) {
      26          15 :   FD_TEST( ikm_sz>=32UL );
      27          15 :   blst_keygen( sk, ikm, ikm_sz, NULL, 0UL );
      28          15 : }
      29             : 
      30             : void
      31             : fd_bls_sig_ser( fd_bls_sig_t const * sig,
      32           0 :                 uchar                buf[ static FD_BLS_SIG_SZ ] ) {
      33           0 :   blst_p2_affine a[1];
      34           0 :   blst_p2_to_affine( a, sig );
      35           0 :   blst_p2_affine_serialize( buf, a );
      36           0 : }
      37             : 
      38             : int
      39             : fd_bls_sig_de( fd_bls_sig_t * sig,
      40           0 :                uchar const    buf[ static FD_BLS_SIG_SZ ] ) {
      41           0 :   blst_p2_affine a[1];
      42           0 :   if( FD_UNLIKELY( blst_p2_deserialize( a, buf )!=BLST_SUCCESS ) ) return -1;
      43           0 :   if( FD_UNLIKELY( !blst_p2_affine_in_g2( a ) ) )                 return -1;
      44           0 :   blst_p2_from_affine( sig, a );
      45           0 :   return 0;
      46           0 : }
      47             : 
      48             : static int
      49             : pub_from_bytes( blst_p1_affine * out,
      50             :                 uchar const *    in,
      51          12 :                 ulong            in_sz ) {
      52          12 :   BLST_ERROR err;
      53          12 :   switch( in_sz ) {
      54           6 :   case FD_BLS_PUB_COMPRESSED_SZ: err = blst_p1_uncompress ( out, in ); break;
      55           3 :   case FD_BLS_PUB_SZ:
      56           3 :     if( FD_UNLIKELY( in[0]&0xA0U ) ) return 0;
      57           3 :     err = blst_p1_deserialize( out, in );
      58           3 :     break;
      59           3 :   default: return 0;
      60          12 :   }
      61           9 :   return err==BLST_SUCCESS &&
      62           9 :          !blst_p1_affine_is_inf( out ) &&
      63           9 :          blst_p1_affine_in_g1( out );
      64          12 : }
      65             : 
      66             : int
      67             : fd_bls_pub_de( fd_bls_pub_t * pub,
      68             :                uchar const *  buf,
      69          12 :                ulong          buf_sz ) {
      70          12 :   blst_p1_affine a[1];
      71          12 :   if( FD_UNLIKELY( !pub_from_bytes( a, buf, buf_sz ) ) ) return -1;
      72           6 :   blst_p1_from_affine( pub, a );
      73           6 :   return 0;
      74          12 : }
      75             : 
      76             : fd_bls_agg_t *
      77             : fd_bls_agg_construct( fd_bls_agg_t *       agg,
      78             :                       fd_bls_pub_t const * pub,
      79             :                       fd_bls_sig_t const * sig,
      80           0 :                       fd_bls_set_t const * set ) {
      81           0 :   fd_bls_set_copy( agg->set, set );
      82           0 :   for( ulong rank = fd_bls_set_const_iter_init( set );
      83           0 :                    !fd_bls_set_const_iter_done( rank );
      84           0 :              rank = fd_bls_set_const_iter_next( set, rank ) ) {
      85           0 :     blst_p1_add_or_double( &agg->pub, &agg->pub, pub+rank );
      86           0 :     blst_p2_add_or_double( &agg->sig, &agg->sig, sig+rank );
      87           0 :   }
      88           0 :   return agg;
      89           0 : }
      90             : 
      91             : int
      92             : fd_bls_agg_verify( uchar const *        msg,
      93             :                    ulong                msg_sz,
      94             :                    fd_bls_pub_t const * pub,
      95        2058 :                    fd_bls_sig_t const * sig ) {
      96        2058 :   if( FD_UNLIKELY( blst_p1_is_inf( pub ) || blst_p2_is_inf( sig ) ) ) return 0; /* the miller loop is wrong on an infinity operand */
      97             : 
      98        2043 :   blst_p1_affine a[2];
      99        2043 :   blst_p2_affine b[2];
     100        2043 :   blst_p2        h[1];
     101        2043 :   blst_p1_to_affine( a, pub );
     102        2043 :   blst_hash_to_g2( h, msg, msg_sz, (uchar const *)FD_BLS_DST, FD_BLS_DST_SZ, NULL, 0UL );
     103        2043 :   blst_p2_to_affine( b, h );
     104        2043 :   a[1] = BLS12_381_NEG_G1;
     105        2043 :   blst_p2_to_affine( b+1, sig );
     106             : 
     107        2043 :   blst_p1_affine const * aptr[2] = { a, a+1 };
     108        2043 :   blst_p2_affine const * bptr[2] = { b, b+1 };
     109        2043 :   blst_fp12 r[1];
     110        2043 :   blst_miller_loop_n( r, bptr, aptr, 2UL );
     111        2043 :   return !!blst_fp12_finalverify( r, blst_fp12_one() );
     112        2058 : }
     113             : 
     114             : fd_bls_set_t *
     115             : fd_bls_agg_verify_linear( fd_bls_agg_t const * agg,
     116             :                           uchar const *        msg,
     117             :                           ulong                msg_sz,
     118             :                           fd_bls_pub_t const * pub,
     119             :                           fd_bls_sig_t const * sig,
     120          39 :                           fd_bls_set_t *       bad ) {
     121          39 :   fd_bls_set_null( bad );
     122          39 :   for( ulong rank = fd_bls_set_const_iter_init( agg->set );
     123          84 :                    !fd_bls_set_const_iter_done( rank );
     124          45 :              rank = fd_bls_set_const_iter_next( agg->set, rank ) ) {
     125          45 :     if( FD_UNLIKELY( !fd_bls_agg_verify( msg, msg_sz, pub+rank, sig+rank ) ) ) fd_bls_set_insert( bad, rank );
     126          45 :   }
     127          39 :   return bad;
     128          39 : }
     129             : 
     130             : fd_bls_set_t *
     131             : fd_bls_agg_verify_bisect( fd_bls_agg_t const * agg,
     132             :                           uchar const *        msg,
     133             :                           ulong                msg_sz,
     134             :                           fd_bls_pub_t const * pub,
     135             :                           fd_bls_sig_t const * sig,
     136          39 :                           fd_bls_set_t *       bad ) {
     137          39 :   fd_bls_set_null( bad );
     138          39 :   fd_bls_agg_t key = *agg;
     139          39 :   ulong        cnt = fd_bls_set_cnt( key.set );
     140         111 :   while( FD_LIKELY( cnt>1UL ) ) {
     141          75 :     fd_bls_agg_t lo = { 0 };
     142          75 :     fd_bls_agg_t hi; fd_bls_set_null( hi.set );
     143          75 :     ulong        mid = 0UL;
     144          75 :     for( ulong rank = fd_bls_set_const_iter_init( key.set );
     145         351 :                      !fd_bls_set_const_iter_done( rank );
     146         276 :                rank = fd_bls_set_const_iter_next( key.set, rank ) ) {
     147         276 :       if( FD_LIKELY( mid++<cnt/2UL ) ) { fd_bls_set_insert( lo.set, rank ); blst_p1_add_or_double( &lo.pub, &lo.pub, pub+rank ); blst_p2_add_or_double( &lo.sig, &lo.sig, sig+rank ); }
     148         153 :       else                             { fd_bls_set_insert( hi.set, rank ); }
     149         276 :     }
     150          75 :     hi.pub = lo.pub; blst_p1_cneg( &hi.pub, 1 ); blst_p1_add_or_double( &hi.pub, &hi.pub, &key.pub );
     151          75 :     hi.sig = lo.sig; blst_p2_cneg( &hi.sig, 1 ); blst_p2_add_or_double( &hi.sig, &hi.sig, &key.sig );
     152             : 
     153          75 :     int lo_ok = fd_bls_agg_verify( msg, msg_sz, &lo.pub, &lo.sig ); /* verify lo first, because agg is sorted by stake, so lo has higher-staked validators (which we assume are more likely to be honest) */
     154          75 :     if( FD_LIKELY( lo_ok ) ) key = hi; /* lo is good */
     155          15 :     else { /* lo is bad */
     156          15 :       int hi_ok = fd_bls_agg_verify( msg, msg_sz, &hi.pub, &hi.sig );
     157          15 :       if( FD_UNLIKELY( !hi_ok ) ) break; /* hi is also bad... have to linear scan */
     158          12 :       key = lo;
     159          12 :     }
     160          72 :     cnt = fd_bls_set_cnt( key.set );
     161          72 :   }
     162          39 :   return fd_bls_agg_verify_linear( &key, msg, msg_sz, pub, sig, bad );
     163          39 : }
     164             : 
     165             : int
     166             : fd_bls_agg_verify_subtract( fd_bls_agg_t *       agg,
     167             :                             uchar const *        msg,
     168             :                             ulong                msg_sz,
     169             :                             fd_bls_pub_t const * pub,
     170             :                             fd_bls_sig_t const * sig,
     171           0 :                             fd_bls_set_t *       bad ) {
     172           0 :   if( FD_LIKELY( fd_bls_agg_verify( msg, msg_sz, &agg->pub, &agg->sig ) ) ) { fd_bls_set_null( bad ); return FD_BLS_SUCCESS; }
     173           0 :   fd_bls_agg_verify_bisect( agg, msg, msg_sz, pub, sig, bad );
     174           0 :   fd_bls_agg_t sub = { 0 };
     175           0 :   fd_bls_agg_construct( &sub, pub, sig, bad );
     176           0 :   blst_p1_cneg( &sub.pub, 1 ); blst_p1_add_or_double( &agg->pub, &agg->pub, &sub.pub );
     177           0 :   blst_p2_cneg( &sub.sig, 1 ); blst_p2_add_or_double( &agg->sig, &agg->sig, &sub.sig );
     178           0 :   fd_bls_set_subtract( agg->set, agg->set, bad );
     179           0 :   if( FD_UNLIKELY( fd_bls_set_is_null( agg->set ) ) ) return FD_BLS_ERR_EMPTY;
     180           0 :   if( FD_UNLIKELY( blst_p1_is_inf( &agg->pub ) ) ) return FD_BLS_ERR_INFINITY;
     181           0 :   return FD_BLS_SUCCESS;
     182           0 : }

Generated by: LCOV version 1.14