Line data Source code
1 : #include "ag_cert.h"
2 :
3 : #include "ag_vote_serde.h" /* ag_vote_signing_ser */
4 :
5 : static int
6 : is_signer( ag_cert_t const * self,
7 4284 : ulong rank ) {
8 4284 : switch( self->kind ) {
9 531 : case AG_CERT_KIND_FINAL: return fd_bls_set_test( self->final.agg.set, rank );
10 1455 : case AG_CERT_KIND_FAST_FINAL: return fd_bls_set_test( self->fast_final.agg.set, rank );
11 795 : case AG_CERT_KIND_NOTAR: return fd_bls_set_test( self->notar.agg.set, rank );
12 801 : case AG_CERT_KIND_NOTAR_FALLBACK: return fd_bls_set_test( self->notar_fallback.agg_notar.set, rank ) || fd_bls_set_test( self->notar_fallback.agg_notar_fallback.set, rank );
13 702 : case AG_CERT_KIND_SKIP: return fd_bls_set_test( self->skip.agg_skip.set, rank ) || fd_bls_set_test( self->skip.agg_skip_fallback.set, rank );
14 0 : default: FD_LOG_CRIT(( "unreachable" ));
15 4284 : }
16 4284 : }
17 :
18 : /* each validator is counted once even if in both partitions */
19 :
20 : static int
21 : check_threshold( ag_cert_t const * self,
22 273 : ag_epoch_info_t const * epoch_info ) {
23 273 : ag_validator_info_t const * validators = ag_epoch_info_validators( epoch_info );
24 273 : ulong stake = 0UL;
25 4557 : for( ulong i=0UL; i<epoch_info->validator_cnt; i++ ) if( FD_LIKELY( is_signer( self, validators[i].id ) ) ) stake += validators[i].stake;
26 273 : return fd_int_if( self->kind==AG_CERT_KIND_FAST_FINAL,
27 273 : ag_epoch_info_is_strong_quorum( epoch_info, stake ),
28 273 : ag_epoch_info_is_quorum ( epoch_info, stake ) );
29 273 : }
30 :
31 : /* TODO sum all the pubkeys on advance_epoch and subtract instead? */
32 :
33 : static int
34 : pub_sum( fd_bls_pub_t * pub,
35 : fd_bls_set_t const * set,
36 339 : ag_epoch_info_t const * epoch_info ) {
37 339 : memset( pub, 0, sizeof(fd_bls_pub_t) ); /* zero is the point at infinity */
38 4059 : for( ulong rank=fd_bls_set_const_iter_init( set ); !fd_bls_set_const_iter_done( rank ); rank=fd_bls_set_const_iter_next( set, rank ) ) {
39 3723 : if( FD_UNLIKELY( rank>=epoch_info->validator_cnt ) ) return -1;
40 3720 : blst_p1_add_or_double( pub, pub, epoch_info->pubkeys+rank );
41 3720 : }
42 336 : return 0;
43 339 : }
44 :
45 : static int
46 : pair_verify( fd_bls_pub_t const * pub,
47 : uchar const * msg,
48 : ulong msg_sz,
49 : fd_bls_pub_t const * pub_fb,
50 : uchar const * msg_fb,
51 : ulong msg_fb_sz,
52 54 : fd_bls_sig_t const * sig ) {
53 54 : if( FD_UNLIKELY( blst_p1_is_inf( pub ) || blst_p1_is_inf( pub_fb ) || blst_p2_is_inf( sig ) ) ) return 0; /* the miller loop is wrong on an infinity operand */
54 :
55 54 : blst_p1_affine a[3];
56 54 : blst_p2_affine b[3];
57 54 : blst_p2 h[1];
58 54 : blst_p1_to_affine( a, pub );
59 54 : blst_hash_to_g2( h, msg, msg_sz, (uchar const *)FD_BLS_DST, FD_BLS_DST_SZ, NULL, 0UL );
60 54 : blst_p2_to_affine( b, h );
61 54 : blst_p1_to_affine( a+1, pub_fb );
62 54 : blst_hash_to_g2( h, msg_fb, msg_fb_sz, (uchar const *)FD_BLS_DST, FD_BLS_DST_SZ, NULL, 0UL );
63 54 : blst_p2_to_affine( b+1, h );
64 54 : a[2] = BLS12_381_NEG_G1;
65 54 : blst_p2_to_affine( b+2, sig );
66 :
67 54 : blst_p1_affine const * aptr[3] = { a, a+1, a+2 };
68 54 : blst_p2_affine const * bptr[3] = { b, b+1, b+2 };
69 54 : blst_fp12 r[1];
70 54 : blst_miller_loop_n( r, bptr, aptr, 3UL );
71 54 : return !!blst_fp12_finalverify( r, blst_fp12_one() );
72 54 : }
73 :
74 : static int
75 : check_sig_one( fd_bls_agg_t const * agg,
76 : uint kind,
77 : ulong slot,
78 : uchar const * block_hash,
79 : ag_epoch_info_t const * epoch_info,
80 171 : ushort shred_version ) {
81 171 : fd_bls_pub_t pub[1];
82 171 : if( FD_UNLIKELY( pub_sum( pub, agg->set, epoch_info ) ) ) return 0;
83 168 : uchar buf[ AG_VOTE_SIGNING_SER_MAX ];
84 168 : ulong sz = ag_vote_signing_ser( kind, slot, block_hash, shred_version, buf );
85 168 : return fd_bls_agg_verify( buf, sz, pub, &agg->sig );
86 171 : }
87 :
88 : static int
89 : check_sig_pair( fd_bls_agg_t const * agg,
90 : uint kind,
91 : fd_bls_agg_t const * agg_fb,
92 : uint kind_fb,
93 : ulong slot,
94 : uchar const * block_hash,
95 : ag_epoch_info_t const * epoch_info,
96 84 : ushort shred_version ) {
97 84 : fd_bls_pub_t pub[1], pub_fb[1];
98 84 : if( FD_UNLIKELY( pub_sum( pub, agg->set, epoch_info ) || pub_sum( pub_fb, agg_fb->set, epoch_info ) ) ) return 0;
99 84 : fd_bls_sig_t sig[1];
100 84 : blst_p2_add_or_double( sig, &agg->sig, &agg_fb->sig );
101 84 : uchar buf [ AG_VOTE_SIGNING_SER_MAX ]; ulong sz = ag_vote_signing_ser( kind, slot, block_hash, shred_version, buf );
102 84 : uchar buf_fb[ AG_VOTE_SIGNING_SER_MAX ]; ulong sz_fb = ag_vote_signing_ser( kind_fb, slot, block_hash, shred_version, buf_fb );
103 84 : if( FD_LIKELY ( fd_bls_set_is_null( agg_fb->set ) ) ) return fd_bls_agg_verify( buf, sz, pub, sig ); /* one partition is the common case */
104 63 : if( FD_UNLIKELY( fd_bls_set_is_null( agg->set ) ) ) return fd_bls_agg_verify( buf_fb, sz_fb, pub_fb, sig );
105 54 : return pair_verify( pub, buf, sz, pub_fb, buf_fb, sz_fb, sig );
106 63 : }
107 :
108 : static int
109 : check_sig( ag_cert_t const * self,
110 255 : ag_epoch_info_t const * epoch_info ) {
111 255 : switch( self->kind ) {
112 21 : case AG_CERT_KIND_FINAL: return check_sig_one( &self->final.agg, AG_VOTE_KIND_FINAL, self->final.slot, NULL, epoch_info, self->final.shred_version );
113 105 : case AG_CERT_KIND_FAST_FINAL: return check_sig_one( &self->fast_final.agg, AG_VOTE_KIND_NOTAR, self->fast_final.slot, self->fast_final.block_hash, epoch_info, self->fast_final.shred_version );
114 45 : case AG_CERT_KIND_NOTAR: return check_sig_one( &self->notar.agg, AG_VOTE_KIND_NOTAR, self->notar.slot, self->notar.block_hash, epoch_info, self->notar.shred_version );
115 45 : case AG_CERT_KIND_NOTAR_FALLBACK: {
116 45 : ag_cert_notar_fallback_t const * nf = &self->notar_fallback;
117 45 : return check_sig_pair( &nf->agg_notar, AG_VOTE_KIND_NOTAR, &nf->agg_notar_fallback, AG_VOTE_KIND_NOTAR_FALLBACK, nf->slot, nf->block_hash, epoch_info, nf->shred_version );
118 0 : }
119 39 : case AG_CERT_KIND_SKIP: {
120 39 : ag_cert_skip_t const * skip = &self->skip;
121 39 : return check_sig_pair( &skip->agg_skip, AG_VOTE_KIND_SKIP, &skip->agg_skip_fallback, AG_VOTE_KIND_SKIP_FALLBACK, skip->slot, NULL, epoch_info, skip->shred_version );
122 0 : }
123 0 : default:
124 0 : FD_LOG_CRIT(( "unreachable" ));
125 255 : }
126 255 : }
127 :
128 : int
129 : ag_cert_verify( ag_cert_t const * self,
130 273 : ag_epoch_info_t const * epoch_info ) {
131 273 : return check_threshold( self, epoch_info ) && check_sig( self, epoch_info );
132 273 : }
133 :
134 : char *
135 : ag_cert_to_cstr( ag_cert_t const * self,
136 3 : char cstr[ static AG_CERT_CSTR_MAX ] ) {
137 3 : static char const * kind_cstr[] = { "Final", "FastFinal", "Notar", "NotarFallback", "Skip" };
138 3 : fd_bls_agg_t const * aggs[2] = { NULL, NULL };
139 3 : ulong stake;
140 3 : switch( self->kind ) {
141 0 : case AG_CERT_KIND_FINAL: aggs[0] = &self->final.agg; stake = self->final.stake; break;
142 0 : case AG_CERT_KIND_FAST_FINAL: aggs[0] = &self->fast_final.agg; stake = self->fast_final.stake; break;
143 0 : case AG_CERT_KIND_NOTAR: aggs[0] = &self->notar.agg; stake = self->notar.stake; break;
144 3 : case AG_CERT_KIND_NOTAR_FALLBACK: aggs[0] = &self->notar_fallback.agg_notar; aggs[1] = &self->notar_fallback.agg_notar_fallback; stake = self->notar_fallback.stake; break;
145 0 : case AG_CERT_KIND_SKIP: aggs[0] = &self->skip.agg_skip; aggs[1] = &self->skip.agg_skip_fallback; stake = self->skip.stake; break;
146 0 : default: FD_LOG_CRIT(( "unreachable" ));
147 3 : }
148 3 : uchar const * block_hash = ag_cert_block_hash( self );
149 3 : char * p = cstr;
150 3 : p = fd_cstr_append_printf( p, "%s { slot: %lu", kind_cstr[ self->kind ], ag_cert_slot( self ) );
151 3 : if( FD_LIKELY( block_hash ) ) p = fd_cstr_append_printf( p, ", hash: %02x%02x%02x...", block_hash[0], block_hash[1], block_hash[2] );
152 3 : p = fd_cstr_append_printf( p, ", sig: %lu", fd_bls_set_cnt( aggs[0]->set ) );
153 3 : if( FD_LIKELY( aggs[1] ) ) p = fd_cstr_append_printf( p, ", sig_fallback: %lu", fd_bls_set_cnt( aggs[1]->set ) );
154 3 : p = fd_cstr_append_printf( p, ", stake: %lu }", stake );
155 3 : *p = '\0';
156 3 : return cstr;
157 3 : }
|