Line data Source code
1 : #ifndef HEADER_fd_src_choreo_votor_test_fd_cert_builder_h
2 : #define HEADER_fd_src_choreo_votor_test_fd_cert_builder_h
3 :
4 : /* Certificates are built incrementally in fd_votor_pool.c as votes
5 : arrive. These rebuild one from a complete vote list, which tests
6 : need to get a cert in isolation; they are not part of the fd_cert
7 : API. */
8 :
9 : #include "fd_cert.h"
10 : #include "fd_epoch_info.h"
11 : #include "fd_vote.h"
12 :
13 : static inline void
14 : bls_key_from_sec( uchar out[ FD_BLS_PUB_COMPRESSED_SZ ],
15 0 : fd_bls_sec_t const * sec ) {
16 0 : fd_bls_pub_t pub[1];
17 0 : fd_bls_sec_to_pub( sec, pub );
18 0 : fd_bls_pub_compress( pub, out );
19 0 : }
20 :
21 : /* epoch_info_build fills epoch_info from an already ranked validator
22 : list. Production ranks in the votor tile (handle_epoch). */
23 :
24 : static inline void
25 : epoch_info_build( fd_epoch_info_t * epoch_info,
26 : fd_validator_info_t const * validators,
27 0 : ulong validator_cnt ) {
28 0 : epoch_info->total_stake = 0UL;
29 0 : for( ulong i=0UL; i<validator_cnt; i++ ) {
30 0 : FD_TEST( validators[i].id==i );
31 0 : epoch_info->validators[i] = validators[i];
32 0 : FD_TEST( !fd_bls_pub_de( &epoch_info->pubkeys[i], validators[i].bls_key, FD_BLS_PUB_COMPRESSED_SZ ) );
33 0 : epoch_info->total_stake += validators[i].stake;
34 0 : }
35 0 : epoch_info->validator_cnt = validator_cnt;
36 0 : }
37 :
38 : static uchar const test_bls_public_key[ FD_BLS_PUB_COMPRESSED_SZ ] = {0};
39 :
40 : /* A valid affine G2 point outside the prime-order subgroup. */
41 : static inline void
42 0 : test_bls_torsion( fd_bls_sig_t * out ) {
43 0 : static uchar const bytes[ FD_BLS_SIG_SZ ] = {
44 0 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
45 0 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
46 0 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
47 0 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
48 0 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
49 0 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
50 0 : 0x17, 0x2e, 0x93, 0xdb, 0x76, 0x4a, 0x84, 0x00, 0xa7, 0xd5, 0x07, 0x1b, 0x6b, 0x6f, 0x5d, 0xe0,
51 0 : 0xda, 0x2f, 0x0f, 0x4a, 0x06, 0x31, 0x19, 0xab, 0xca, 0x01, 0x40, 0x06, 0xb7, 0xc4, 0x0a, 0x2c,
52 0 : 0xfe, 0x29, 0x1a, 0x19, 0x24, 0xe6, 0x5d, 0xb0, 0xd6, 0xd0, 0xfc, 0xfb, 0xf3, 0xbf, 0x3d, 0x5c,
53 0 : 0x18, 0xc6, 0xb8, 0x64, 0xae, 0x17, 0xdc, 0x9d, 0xa6, 0x42, 0x03, 0xff, 0xef, 0xb9, 0x66, 0x30,
54 0 : 0x64, 0x25, 0xa7, 0xbc, 0x6a, 0xeb, 0x7c, 0x75, 0x24, 0x74, 0x38, 0x37, 0x27, 0x16, 0x28, 0x4a,
55 0 : 0x41, 0x73, 0x83, 0x04, 0x20, 0xcd, 0x47, 0x6b, 0xa1, 0xa3, 0x65, 0xb9, 0x5b, 0xfc, 0xec, 0x38
56 0 : };
57 0 : FD_TEST( !fd_bls_sig_de_unchecked( out, bytes ) );
58 0 : FD_TEST( !fd_bls_sig_validate( out ) );
59 0 : }
60 :
61 : /* sec_sign_fn is the fd_bls_sign_fn of a test that holds the secret
62 : key in memory; ctx points to the fd_bls_sec_t. */
63 :
64 : static inline void
65 : sec_sign_fn( void * ctx,
66 : fd_bls_sig_t * sig,
67 : uchar const * public_key,
68 : uchar const * msg,
69 0 : ulong msg_sz ) {
70 0 : (void)public_key;
71 0 : fd_bls_sec_sign( (fd_bls_sec_t const *)ctx, msg, msg_sz, sig );
72 0 : }
73 :
74 : static inline void
75 : agg_add( fd_bls_agg_t * agg,
76 : ulong rank,
77 0 : fd_bls_sig_t const * sig ) {
78 0 : fd_bls_set_insert( agg->set, rank );
79 0 : fd_bls_sig_add( &agg->sig, &agg->sig, sig );
80 0 : }
81 :
82 : static inline int
83 0 : agg_is_identity( fd_bls_agg_t const * agg ) {
84 0 : return !!fd_bls_sig_is_inf( &agg->sig );
85 0 : }
86 :
87 : static inline fd_cert_t
88 : cert_build_final( fd_vote_final_t const * votes, ulong vote_cnt, fd_epoch_info_t const * epoch_info );
89 : static inline fd_cert_t
90 : cert_build_fast_final( fd_vote_notar_t const * votes, ulong vote_cnt, fd_epoch_info_t const * epoch_info );
91 : static inline fd_cert_t
92 : cert_build_notar( fd_vote_notar_t const * votes, ulong vote_cnt, fd_epoch_info_t const * epoch_info );
93 : static inline fd_cert_t
94 : cert_build_notar_fallback( fd_vote_notar_t const * votes, ulong vote_cnt, fd_vote_notar_fallback_t const * fallback_votes, ulong fallback_vote_cnt, fd_epoch_info_t const * epoch_info );
95 : static inline fd_cert_t
96 : cert_build_skip( fd_vote_skip_t const * votes, ulong vote_cnt, fd_vote_skip_fallback_t const * fallback_votes, ulong fallback_vote_cnt, fd_epoch_info_t const * epoch_info );
97 :
98 : static inline fd_cert_t
99 : cert_build_final( fd_vote_final_t const * votes,
100 : ulong vote_cnt,
101 0 : fd_epoch_info_t const * epoch_info ) {
102 0 : fd_validator_info_t const * validators = fd_epoch_info_validators( epoch_info );
103 0 : FD_TEST( vote_cnt>0UL );
104 0 : ulong slot = votes[0].slot;
105 0 : ulong stake = 0UL;
106 0 : for( ulong i=0UL; i<vote_cnt; i++ ) {
107 0 : FD_TEST( votes[i].slot==slot );
108 0 : stake += validators[ votes[i].rank ].stake;
109 0 : }
110 0 : fd_cert_final_t cert;
111 0 : cert.slot = slot; cert.stake = stake; cert.shred_version = votes[0].shred_version;
112 0 : memset( &cert.agg, 0, sizeof(fd_bls_agg_t) );
113 0 : for( ulong i=0UL; i<vote_cnt; i++ ) agg_add( &cert.agg, votes[i].rank, &votes[i].sig );
114 0 : return (fd_cert_t){ .kind = FD_CERT_KIND_FINAL, .final = cert };
115 0 : }
116 :
117 : static inline fd_cert_t
118 : cert_build_fast_final( fd_vote_notar_t const * votes,
119 : ulong vote_cnt,
120 0 : fd_epoch_info_t const * epoch_info ) {
121 0 : fd_cert_notar_t notar = cert_build_notar( votes, vote_cnt, epoch_info ).notar;
122 0 : fd_cert_fast_final_t cert;
123 0 : cert.slot = notar.slot; cert.stake = notar.stake; cert.agg = notar.agg; cert.shred_version = notar.shred_version;
124 0 : memcpy( &cert.block_hash, ¬ar.block_hash, sizeof(fd_block_hash_t) );
125 0 : return (fd_cert_t){ .kind = FD_CERT_KIND_FAST_FINAL, .fast_final = cert };
126 0 : }
127 :
128 : static inline fd_cert_t
129 : cert_build_notar( fd_vote_notar_t const * votes,
130 : ulong vote_cnt,
131 0 : fd_epoch_info_t const * epoch_info ) {
132 0 : fd_validator_info_t const * validators = fd_epoch_info_validators( epoch_info );
133 0 : FD_TEST( vote_cnt>0UL );
134 0 : ulong slot = votes[0].slot;
135 0 : ulong stake = 0UL;
136 0 : fd_block_hash_t block_hash;
137 0 : memcpy( &block_hash, &votes[0].block_hash, sizeof(fd_block_hash_t) );
138 0 : for( ulong i=0UL; i<vote_cnt; i++ ) {
139 0 : FD_TEST( votes[i].slot==slot );
140 0 : FD_TEST( !memcmp( &votes[i].block_hash, &block_hash, sizeof(fd_block_hash_t) ) );
141 0 : stake += validators[ votes[i].rank ].stake;
142 0 : }
143 0 : fd_cert_notar_t cert;
144 0 : cert.slot = slot; cert.stake = stake; cert.shred_version = votes[0].shred_version;
145 0 : memcpy( &cert.block_hash, &block_hash, sizeof(fd_block_hash_t) );
146 0 : memset( &cert.agg, 0, sizeof(fd_bls_agg_t) );
147 0 : for( ulong i=0UL; i<vote_cnt; i++ ) agg_add( &cert.agg, votes[i].rank, &votes[i].sig );
148 0 : return (fd_cert_t){ .kind = FD_CERT_KIND_NOTAR, .notar = cert };
149 0 : }
150 :
151 : static inline fd_cert_t
152 : cert_build_notar_fallback( fd_vote_notar_t const * votes,
153 : ulong vote_cnt,
154 : fd_vote_notar_fallback_t const * fallback_votes,
155 : ulong fallback_vote_cnt,
156 0 : fd_epoch_info_t const * epoch_info ) {
157 0 : fd_validator_info_t const * validators = fd_epoch_info_validators( epoch_info );
158 0 : FD_TEST( vote_cnt>0UL || fallback_vote_cnt>0UL );
159 0 : ulong slot;
160 0 : fd_block_hash_t block_hash;
161 0 : if( vote_cnt>0UL ) { slot = votes[0].slot; memcpy( &block_hash, &votes[0].block_hash, sizeof(fd_block_hash_t) ); }
162 0 : else { slot = fallback_votes[0].slot; memcpy( &block_hash, &fallback_votes[0].block_hash, sizeof(fd_block_hash_t) ); }
163 :
164 0 : ulong stake = 0UL;
165 0 : for( ulong i=0UL; i<vote_cnt; i++ ) {
166 0 : FD_TEST( votes[i].slot==slot );
167 0 : FD_TEST( !memcmp( &votes[i].block_hash, &block_hash, sizeof(fd_block_hash_t) ) );
168 0 : stake += validators[ votes[i].rank ].stake;
169 0 : }
170 0 : ulong stake_fallback = 0UL;
171 0 : for( ulong i=0UL; i<fallback_vote_cnt; i++ ) {
172 0 : FD_TEST( fallback_votes[i].slot==slot );
173 0 : FD_TEST( !memcmp( &fallback_votes[i].block_hash, &block_hash, sizeof(fd_block_hash_t) ) );
174 0 : stake_fallback += validators[ fallback_votes[i].rank ].stake;
175 0 : }
176 :
177 0 : fd_cert_notar_fallback_t cert;
178 0 : cert.slot = slot; cert.shred_version = vote_cnt>0UL ? votes[0].shred_version : fallback_votes[0].shred_version;
179 0 : memcpy( &cert.block_hash, &block_hash, sizeof(fd_block_hash_t) );
180 0 : memset( &cert.agg_notar, 0, sizeof(fd_bls_agg_t) );
181 0 : for( ulong i=0UL; i<vote_cnt; i++ ) agg_add( &cert.agg_notar, votes[i].rank, &votes[i].sig );
182 0 : if( FD_UNLIKELY( agg_is_identity( &cert.agg_notar ) ) ) {
183 0 : memset( &cert.agg_notar, 0, sizeof(fd_bls_agg_t) );
184 0 : stake = 0UL;
185 0 : }
186 0 : memset( &cert.agg_notar_fallback, 0, sizeof(fd_bls_agg_t) );
187 0 : for( ulong i=0UL; i<fallback_vote_cnt; i++ ) agg_add( &cert.agg_notar_fallback, fallback_votes[i].rank, &fallback_votes[i].sig );
188 0 : if( FD_UNLIKELY( agg_is_identity( &cert.agg_notar_fallback ) ) ) {
189 0 : memset( &cert.agg_notar_fallback, 0, sizeof(fd_bls_agg_t) );
190 0 : stake_fallback = 0UL;
191 0 : }
192 0 : cert.stake = stake + stake_fallback;
193 0 : return (fd_cert_t){ .kind = FD_CERT_KIND_NOTAR_FALLBACK, .notar_fallback = cert };
194 0 : }
195 :
196 : static inline fd_cert_t
197 : cert_build_skip( fd_vote_skip_t const * votes,
198 : ulong vote_cnt,
199 : fd_vote_skip_fallback_t const * fallback_votes,
200 : ulong fallback_vote_cnt,
201 0 : fd_epoch_info_t const * epoch_info ) {
202 0 : fd_validator_info_t const * validators = fd_epoch_info_validators( epoch_info );
203 0 : FD_TEST( vote_cnt>0UL || fallback_vote_cnt>0UL );
204 0 : ulong slot = vote_cnt>0UL ? votes[0].slot : fallback_votes[0].slot;
205 :
206 0 : ulong stake = 0UL;
207 0 : for( ulong i=0UL; i<vote_cnt; i++ ) {
208 0 : FD_TEST( votes[i].slot==slot );
209 0 : stake += validators[ votes[i].rank ].stake;
210 0 : }
211 0 : ulong stake_fallback = 0UL;
212 0 : for( ulong i=0UL; i<fallback_vote_cnt; i++ ) {
213 0 : FD_TEST( fallback_votes[i].slot==slot );
214 0 : stake_fallback += validators[ fallback_votes[i].rank ].stake;
215 0 : }
216 :
217 0 : fd_cert_skip_t cert;
218 0 : cert.slot = slot; cert.shred_version = vote_cnt>0UL ? votes[0].shred_version : fallback_votes[0].shred_version;
219 0 : memset( &cert.agg_skip, 0, sizeof(fd_bls_agg_t) );
220 0 : for( ulong i=0UL; i<vote_cnt; i++ ) agg_add( &cert.agg_skip, votes[i].rank, &votes[i].sig );
221 0 : if( FD_UNLIKELY( agg_is_identity( &cert.agg_skip ) ) ) {
222 0 : memset( &cert.agg_skip, 0, sizeof(fd_bls_agg_t) );
223 0 : stake = 0UL;
224 0 : }
225 0 : memset( &cert.agg_skip_fallback, 0, sizeof(fd_bls_agg_t) );
226 0 : for( ulong i=0UL; i<fallback_vote_cnt; i++ ) agg_add( &cert.agg_skip_fallback, fallback_votes[i].rank, &fallback_votes[i].sig );
227 0 : if( FD_UNLIKELY( agg_is_identity( &cert.agg_skip_fallback ) ) ) {
228 0 : memset( &cert.agg_skip_fallback, 0, sizeof(fd_bls_agg_t) );
229 0 : stake_fallback = 0UL;
230 0 : }
231 0 : cert.stake = stake + stake_fallback;
232 0 : return (fd_cert_t){ .kind = FD_CERT_KIND_SKIP, .skip = cert };
233 0 : }
234 :
235 : #endif
|