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 : }
|