LCOV - code coverage report
Current view: top level - ballet/bls - fd_bls.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 187 0.0 %
Date: 2026-10-22 18:10:43 Functions: 0 20 0.0 %

          Line data    Source code
       1             : #include "fd_bls.h"
       2             : 
       3             : #include "../../third_party/blst/bindings/blst.h"
       4             : 
       5             : void
       6             : fd_bls_sec_to_pub( fd_bls_sec_t const * sk,
       7           0 :                    fd_bls_pub_t *       pk ) {
       8           0 :   blst_p1 p[1];
       9           0 :   blst_sk_to_pk_in_g1( p, sk );
      10           0 :   blst_p1_to_affine( pk, p );
      11           0 : }
      12             : 
      13             : void
      14             : fd_bls_sec_sign( fd_bls_sec_t const * sk,
      15             :                  uchar const *        msg,
      16             :                  ulong                msg_sz,
      17           0 :                  fd_bls_sig_t *       sig ) {
      18           0 :   blst_p2 hash[1];
      19           0 :   blst_p2 p[1];
      20           0 :   blst_hash_to_g2( hash, msg, msg_sz, (uchar const *)FD_BLS_DST, FD_BLS_DST_SZ, NULL, 0UL );
      21           0 :   blst_sign_pk_in_g1( p, hash, sk );
      22           0 :   blst_p2_to_affine( sig, p );
      23           0 : }
      24             : 
      25             : void
      26             : fd_bls_sec_derive( fd_bls_sec_t * sk,
      27             :                    uchar const *  ikm,
      28           0 :                    ulong          ikm_sz ) {
      29           0 :   FD_TEST( ikm_sz>=32UL );
      30           0 :   blst_keygen( sk, ikm, ikm_sz, NULL, 0UL );
      31           0 : }
      32             : 
      33             : void
      34             : fd_bls_sig_ser( fd_bls_sig_t const * sig,
      35           0 :                 uchar                buf[ static FD_BLS_SIG_SZ ] ) {
      36           0 :   blst_p2_affine_serialize( buf, sig );
      37           0 : }
      38             : 
      39             : int
      40             : fd_bls_sig_de( fd_bls_sig_t * sig,
      41           0 :                uchar const    buf[ static FD_BLS_SIG_SZ ] ) {
      42           0 :   if( FD_UNLIKELY( blst_p2_deserialize( sig, buf )!=BLST_SUCCESS ) ) return -1;
      43           0 :   if( FD_UNLIKELY( !blst_p2_affine_in_g2( sig ) ) )                  return -1;
      44           0 :   return 0;
      45           0 : }
      46             : 
      47             : static int
      48             : pub_from_bytes( blst_p1_affine * out,
      49             :                 uchar const *    in,
      50           0 :                 ulong            in_sz ) {
      51           0 :   BLST_ERROR err;
      52           0 :   switch( in_sz ) {
      53           0 :   case FD_BLS_PUB_COMPRESSED_SZ: err = blst_p1_uncompress ( out, in ); break;
      54           0 :   case FD_BLS_PUB_SZ:
      55           0 :     if( FD_UNLIKELY( in[0]&0xA0U ) ) return 0;
      56           0 :     err = blst_p1_deserialize( out, in );
      57           0 :     break;
      58           0 :   default: return 0;
      59           0 :   }
      60           0 :   return err==BLST_SUCCESS &&
      61           0 :          !blst_p1_affine_is_inf( out ) &&
      62           0 :          blst_p1_affine_in_g1( out );
      63           0 : }
      64             : 
      65             : int
      66             : fd_bls_pub_de( fd_bls_pub_t * pub,
      67             :                uchar const *  buf,
      68           0 :                ulong          buf_sz ) {
      69           0 :   return pub_from_bytes( pub, buf, buf_sz ) ? 0 : -1;
      70           0 : }
      71             : 
      72             : fd_bls_agg_t *
      73           0 : fd_bls_agg_null( fd_bls_agg_t * agg ) {
      74           0 :   fd_memset( &agg->pub, 0, sizeof(blst_p1) );
      75           0 :   fd_memset( &agg->sig, 0, sizeof(blst_p2) );
      76           0 :   fd_bls_set_null( agg->set );
      77           0 :   return agg;
      78           0 : }
      79             : 
      80             : fd_bls_agg_t *
      81             : fd_bls_agg_construct( fd_bls_agg_t *       agg,
      82             :                       fd_bls_pub_t const * pub,
      83             :                       fd_bls_sig_t const * sig,
      84           0 :                       fd_bls_set_t const * set ) {
      85           0 :   fd_bls_set_copy( agg->set, set );
      86             : 
      87             :   /* one batched addition per curve: a field inversion per batch in
      88             :      place of one per signer */
      89           0 :   fd_bls_pub_t const * pub_ptr[ FD_BLS_SET_MAX ];
      90           0 :   fd_bls_sig_t const * sig_ptr[ FD_BLS_SET_MAX ];
      91           0 :   ulong                cnt = 0UL;
      92           0 :   for( ulong rank = fd_bls_set_const_iter_init( set );
      93           0 :                    !fd_bls_set_const_iter_done( rank );
      94           0 :              rank = fd_bls_set_const_iter_next( set, rank ) ) {
      95           0 :     pub_ptr[ cnt ] = pub+rank;
      96           0 :     sig_ptr[ cnt ] = sig+rank;
      97           0 :     cnt++;
      98           0 :   }
      99           0 :   blst_p1s_add( &agg->pub, pub_ptr, cnt );
     100           0 :   blst_p2s_add( &agg->sig, sig_ptr, cnt );
     101           0 :   return agg;
     102           0 : }
     103             : 
     104             : blst_p1 *
     105             : fd_bls_pub_sum( blst_p1 *            pub,
     106             :                 fd_bls_pub_t const * key,
     107             :                 ulong                key_cnt,
     108             :                 fd_bls_set_t const * set,
     109           0 :                 blst_p1 const *      full ) {
     110           0 :   fd_memset( pub, 0, sizeof(blst_p1) ); /* point at infinity */
     111             : 
     112           0 :   if( FD_LIKELY( !full || 2UL*fd_bls_set_cnt( set )<=key_cnt ) ) {
     113           0 :     for( ulong rank=0UL; rank<key_cnt; rank++ ) {
     114           0 :       if( fd_bls_set_test( set, rank ) ) blst_p1_add_or_double_affine( pub, pub, key+rank );
     115           0 :     }
     116           0 :     return pub;
     117           0 :   }
     118             : 
     119             :   /* full minus the keys not in set */
     120           0 :   for( ulong rank=0UL; rank<key_cnt; rank++ ) {
     121           0 :     if( !fd_bls_set_test( set, rank ) ) blst_p1_add_or_double_affine( pub, pub, key+rank );
     122           0 :   }
     123           0 :   blst_p1_cneg( pub, 1 );
     124           0 :   blst_p1_add_or_double( pub, full, pub );
     125           0 :   return pub;
     126           0 : }
     127             : 
     128             : 
     129             : void
     130             : fd_bls_hash_msg( uchar const *    msg,
     131             :                  ulong            msg_sz,
     132           0 :                  blst_p2_affine * h ) {
     133           0 :   blst_p2 p[1];
     134           0 :   blst_hash_to_g2( p, msg, msg_sz, (uchar const *)FD_BLS_DST, FD_BLS_DST_SZ, NULL, 0UL );
     135           0 :   blst_p2_to_affine( h, p );
     136           0 : }
     137             : 
     138             : /* agg_pairing computes gt = e(pub,h) / e(G1,sig), which is the identity iff
     139             :    sig is a valid signature on h under pub. */
     140             : 
     141             : static blst_fp12 *
     142             : agg_pairing( blst_fp12 *            gt,
     143             :              blst_p2_affine const * h,
     144             :              blst_p1 const *        pub,
     145           0 :              blst_p2 const *        sig ) {
     146           0 :   blst_p1_affine         a[2];
     147           0 :   blst_p2_affine         b[2];
     148           0 :   blst_p1_affine const * aptr[2];
     149           0 :   blst_p2_affine const * bptr[2];
     150           0 :   ulong                  n = 0UL;
     151           0 :   if( FD_LIKELY( !blst_p1_is_inf( pub ) && !blst_p2_affine_is_inf( h ) ) ) { blst_p1_to_affine( a+n, pub ); b[n] = *h;                     aptr[n] = a+n; bptr[n] = b+n; n++; }
     152           0 :   if( FD_LIKELY( !blst_p2_is_inf( sig )                                ) ) { a[n] = BLS12_381_NEG_G1;       blst_p2_to_affine( b+n, sig ); aptr[n] = a+n; bptr[n] = b+n; n++; }
     153           0 :   if( FD_UNLIKELY( !n ) ) { *gt = *blst_fp12_one(); return gt; }
     154           0 :   blst_miller_loop_n( gt, bptr, aptr, n );
     155           0 :   blst_final_exp( gt, gt );
     156           0 :   return gt;
     157           0 : }
     158             : 
     159             : int
     160             : fd_bls_agg_verify_hashed( blst_p2_affine const * h,
     161             :                           blst_p1 const *        pub,
     162           0 :                           blst_p2 const *        sig ) {
     163           0 :   if( FD_UNLIKELY( blst_p2_affine_is_inf( h ) || blst_p1_is_inf( pub ) || blst_p2_is_inf( sig ) ) ) return 0;
     164           0 :   blst_fp12 gt[1];
     165           0 :   return !!blst_fp12_is_one( agg_pairing( gt, h, pub, sig ) );
     166           0 : }
     167             : 
     168             : int
     169             : fd_bls_agg_verify( uchar const *   msg,
     170             :                    ulong           msg_sz,
     171             :                    blst_p1 const * pub,
     172           0 :                    blst_p2 const * sig ) {
     173           0 :   if( FD_UNLIKELY( blst_p1_is_inf( pub ) || blst_p2_is_inf( sig ) ) ) return 0;
     174           0 :   blst_p2_affine h[1];
     175           0 :   fd_bls_hash_msg( msg, msg_sz, h );
     176           0 :   return fd_bls_agg_verify_hashed( h, pub, sig );
     177           0 : }
     178             : 
     179             : static fd_bls_set_t *
     180             : verify_linear_hashed( fd_bls_agg_t const *   agg,
     181             :                       blst_p2_affine const * h,
     182             :                       fd_bls_pub_t const *   pub,
     183             :                       fd_bls_sig_t const *   sig,
     184           0 :                       fd_bls_set_t *         bad ) {
     185           0 :   fd_bls_set_null( bad );
     186           0 :   for( ulong rank = fd_bls_set_const_iter_init( agg->set );
     187           0 :                    !fd_bls_set_const_iter_done( rank );
     188           0 :              rank = fd_bls_set_const_iter_next( agg->set, rank ) ) {
     189           0 :     blst_p1 p; blst_p1_from_affine( &p, pub+rank );
     190           0 :     blst_p2 s; blst_p2_from_affine( &s, sig+rank );
     191           0 :     if( FD_UNLIKELY( !fd_bls_agg_verify_hashed( h, &p, &s ) ) ) fd_bls_set_insert( bad, rank );
     192           0 :   }
     193           0 :   return bad;
     194           0 : }
     195             : 
     196             : /* verify_bisect_rec descends the contiguous run ranks[ lo, hi ) of
     197             :    the signer list.  pub and sig are the signers' keys and signatures
     198             :    gathered into signer-list (not rank) order.  The caller
     199             :    guarantees gt!=1, i.e. the run contains a bad signer.  p, s and gt
     200             :    are consumed by the descent, which lets both halves be derived
     201             :    without copying the parent: the hi run's sums are p-lp and its gt
     202             :    is conj( lgt*conj(gt) ) = conj(lgt)*gt. */
     203             : 
     204             : #define BISECT_DEPTH_MAX (11UL)
     205             : FD_STATIC_ASSERT( FD_BLS_SET_MAX<=(1UL<<BISECT_DEPTH_MAX), bisect_depth );
     206             : 
     207             : static void
     208             : verify_bisect_rec( blst_p2_affine const * h,
     209             :                    fd_bls_pub_t const *   pub,
     210             :                    fd_bls_sig_t const *   sig,
     211             :                    ushort const *         ranks,
     212             :                    ushort                 lo,
     213             :                    ushort                 hi,
     214             :                    blst_p1 *              p,
     215             :                    blst_p2 *              s,
     216             :                    blst_fp12 *            gt,
     217           0 :                    fd_bls_set_t *         bad ) {
     218           0 :   if( hi-lo==1 ) { fd_bls_set_insert( bad, ranks[ lo ] ); return; }
     219             : 
     220           0 :   ushort mid = (ushort)( lo + ( (ulong)hi-(ulong)lo )/2UL );
     221             : 
     222             :   /* Sum the lo half's pub and sig points in one batch each. */
     223           0 :   fd_bls_pub_t const * pub_sum[2] = { pub+lo, NULL };
     224           0 :   fd_bls_sig_t const * sig_sum[2] = { sig+lo, NULL };
     225           0 :   blst_p1 lp[1]; blst_p2 ls[1];
     226           0 :   blst_p1s_add( lp, pub_sum, (size_t)( (ulong)mid-(ulong)lo ) );
     227           0 :   blst_p2s_add( ls, sig_sum, (size_t)( (ulong)mid-(ulong)lo ) );
     228             : 
     229           0 :   blst_p1_cneg( p, 1 );
     230           0 :   blst_p2_cneg( s, 1 );
     231           0 :   blst_p1 hp[1]; blst_p2 hs[1];
     232           0 :   blst_p1_add_or_double( hp, lp, p ); blst_p1_cneg( hp, 1 ); /* hp = p-lp */
     233           0 :   blst_p2_add_or_double( hs, ls, s ); blst_p2_cneg( hs, 1 ); /* hs = s-ls */
     234             : 
     235           0 :   blst_fp12 lgt[1];
     236           0 :   agg_pairing( lgt, h, lp, ls );
     237           0 :   blst_fp12_conjugate( gt );
     238           0 :   blst_fp12 hgt[1];
     239           0 :   blst_fp12_mul( hgt, lgt, gt );
     240           0 :   blst_fp12_conjugate( hgt ); /* hgt = conj(lgt)*gt */
     241             : 
     242           0 :   if( FD_LIKELY( !blst_fp12_is_one( lgt ) ) ) verify_bisect_rec( h, pub, sig, ranks, lo, mid, lp, ls, lgt, bad );
     243           0 :   if( FD_LIKELY( !blst_fp12_is_one( hgt ) ) ) verify_bisect_rec( h, pub, sig, ranks, mid, hi, hp, hs, hgt, bad );
     244           0 : }
     245             : 
     246             : static fd_bls_set_t *
     247             : verify_bisect_hashed( fd_bls_agg_t const *   agg,
     248             :                       blst_p2_affine const * h,
     249             :                       fd_bls_pub_t const *   pub,
     250             :                       fd_bls_sig_t const *   sig,
     251           0 :                       fd_bls_set_t *         bad ) {
     252           0 :   fd_bls_set_null( bad );
     253           0 :   if( FD_UNLIKELY( fd_bls_set_is_null( agg->set ) ) ) return bad;
     254             : 
     255             :   /* a valid aggregate, the common case */
     256           0 :   blst_p1   p[1]; p[ 0 ] = agg->pub; /* consumed by the descent */
     257           0 :   blst_p2   s[1]; s[ 0 ] = agg->sig;
     258           0 :   blst_fp12 gt[1];
     259           0 :   agg_pairing( gt, h, &agg->pub, &agg->sig );
     260           0 :   if( FD_LIKELY( blst_fp12_is_one( gt ) ) ) return bad;
     261             : 
     262             :   /* gather the signers into a contiguous run so each half of the
     263             :      descent is a linear range */
     264           0 :   ushort       ranks  [ FD_BLS_SET_MAX ];
     265           0 :   fd_bls_pub_t pub_run[ FD_BLS_SET_MAX ];
     266           0 :   fd_bls_sig_t sig_run[ FD_BLS_SET_MAX ];
     267           0 :   ulong        cnt = 0UL;
     268           0 :   for( ulong rank = fd_bls_set_const_iter_init( agg->set );
     269           0 :                    !fd_bls_set_const_iter_done( rank );
     270           0 :              rank = fd_bls_set_const_iter_next( agg->set, rank ) ) {
     271           0 :     ranks  [ cnt ] = (ushort)rank;
     272           0 :     pub_run[ cnt ] = pub[ rank ];
     273           0 :     sig_run[ cnt ] = sig[ rank ];
     274           0 :     cnt++;
     275           0 :   }
     276           0 :   verify_bisect_rec( h, pub_run, sig_run, ranks, 0, (ushort)cnt, p, s, gt, bad );
     277           0 :   return bad;
     278           0 : }
     279             : 
     280             : fd_bls_set_t *
     281             : fd_bls_agg_verify_linear( fd_bls_agg_t const * agg,
     282             :                           uchar const *        msg,
     283             :                           ulong                msg_sz,
     284             :                           fd_bls_pub_t const * pub,
     285             :                           fd_bls_sig_t const * sig,
     286           0 :                           fd_bls_set_t *       bad ) {
     287           0 :   blst_p2_affine h[1];
     288           0 :   fd_bls_hash_msg( msg, msg_sz, h );
     289           0 :   return verify_linear_hashed( agg, h, pub, sig, bad );
     290           0 : }
     291             : 
     292             : fd_bls_set_t *
     293             : fd_bls_agg_verify_bisect( fd_bls_agg_t const * agg,
     294             :                           uchar const *        msg,
     295             :                           ulong                msg_sz,
     296             :                           fd_bls_pub_t const * pub,
     297             :                           fd_bls_sig_t const * sig,
     298           0 :                           fd_bls_set_t *       bad ) {
     299           0 :   blst_p2_affine h[1];
     300           0 :   fd_bls_hash_msg( msg, msg_sz, h );
     301           0 :   return verify_bisect_hashed( agg, h, pub, sig, bad );
     302           0 : }
     303             : 
     304             : int
     305             : fd_bls_agg_verify_subtract( fd_bls_agg_t *       agg,
     306             :                             uchar const *        msg,
     307             :                             ulong                msg_sz,
     308             :                             fd_bls_pub_t const * pub,
     309             :                             fd_bls_sig_t const * sig,
     310           0 :                             fd_bls_set_t *       bad ) {
     311           0 :   blst_p2_affine h[1];
     312           0 :   fd_bls_hash_msg( msg, msg_sz, h );
     313           0 :   verify_bisect_hashed( agg, h, pub, sig, bad );
     314           0 :   if( FD_UNLIKELY( !fd_bls_set_is_null( bad ) ) ) {
     315           0 :     fd_bls_agg_t sub = { 0 };
     316           0 :     fd_bls_agg_construct( &sub, pub, sig, bad );
     317           0 :     blst_p1_cneg( &sub.pub, 1 ); blst_p1_add_or_double( &agg->pub, &agg->pub, &sub.pub );
     318           0 :     blst_p2_cneg( &sub.sig, 1 ); blst_p2_add_or_double( &agg->sig, &agg->sig, &sub.sig );
     319           0 :     fd_bls_set_subtract( agg->set, agg->set, bad );
     320           0 :   }
     321             :   /* an aggregate whose keys cancel to infinity carries no stake even
     322             :      when every signer is individually valid */
     323           0 :   if( FD_UNLIKELY( blst_p1_is_inf( &agg->pub ) ) ) return -1;
     324           0 :   return 0;
     325           0 : }

Generated by: LCOV version 1.14