Line data Source code
1 : #include "fd_precompiles.h"
2 : #include "../fd_executor_err.h"
3 : #include "../../../ballet/keccak256/fd_keccak256.h"
4 : #include "../../../ballet/ed25519/fd_ed25519.h"
5 : #include "../../../ballet/secp256k1/fd_secp256k1.h"
6 : #include "../../../ballet/secp256r1/fd_secp256r1.h"
7 : #include "../fd_system_ids.h"
8 : #include "../fd_system_ids_pp.h"
9 :
10 : /* Docs:
11 : https://docs.solana.com/developing/runtime-facilities/programs#ed25519-program
12 : https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program */
13 :
14 : /* There are 3 precompiles and 2 ways to serialize data.
15 : The most recent one seems are ed25519 and secp256r1 with 2 bytes per instruction,
16 : that works better with JS sdk even though it consumes a few bytes. */
17 : struct __attribute__((packed)) fd_precompile_sig_offsets {
18 : ushort sig_offset;
19 : ushort sig_instr_idx;
20 : ushort pubkey_offset;
21 : ushort pubkey_instr_idx;
22 : ushort msg_offset;
23 : ushort msg_data_sz;
24 : ushort msg_instr_idx;
25 : };
26 : typedef struct fd_precompile_sig_offsets fd_ed25519_signature_offsets_t;
27 : typedef struct fd_precompile_sig_offsets fd_secp256r1_signature_offsets_t;
28 :
29 : struct __attribute__((packed)) fd_precompile_one_byte_idx_sig_offsets {
30 : ushort sig_offset;
31 : uchar sig_instr_idx;
32 : ushort pubkey_offset;
33 : uchar pubkey_instr_idx;
34 : ushort msg_offset;
35 : ushort msg_data_sz;
36 : uchar msg_instr_idx;
37 : };
38 : typedef struct fd_precompile_one_byte_idx_sig_offsets fd_secp256k1_signature_offsets_t;
39 :
40 : /*
41 : Common
42 : */
43 :
44 0 : #define SIGNATURE_SERIALIZED_SIZE (64UL)
45 0 : #define SIGNATURE_OFFSETS_SERIALIZED_SIZE (14UL)
46 0 : #define SIGNATURE_OFFSETS_START (2UL)
47 : #define DATA_START (SIGNATURE_OFFSETS_SERIALIZED_SIZE + SIGNATURE_OFFSETS_START)
48 :
49 : /*
50 : Custom
51 : */
52 :
53 0 : #define ED25519_PUBKEY_SERIALIZED_SIZE (32UL)
54 :
55 0 : #define SECP256R1_PUBKEY_SERIALIZED_SIZE (33UL)
56 :
57 0 : #define SECP256K1_PUBKEY_SERIALIZED_SIZE (20UL)
58 0 : #define SECP256K1_SIGNATURE_OFFSETS_SERIALIZED_SIZE (11UL)
59 0 : #define SECP256K1_SIGNATURE_OFFSETS_START (1UL)
60 : #define SECP256K1_DATA_START (SECP256K1_SIGNATURE_OFFSETS_SERIALIZED_SIZE + SECP256K1_SIGNATURE_OFFSETS_START)
61 :
62 : FD_STATIC_ASSERT( sizeof( fd_ed25519_signature_offsets_t )==SIGNATURE_OFFSETS_SERIALIZED_SIZE, fd_ballet );
63 : FD_STATIC_ASSERT( sizeof( fd_secp256k1_signature_offsets_t )==SECP256K1_SIGNATURE_OFFSETS_SERIALIZED_SIZE, fd_ballet );
64 :
65 : /*
66 : Common code
67 : */
68 :
69 : /* fd_precompile_get_instr_data fetches data across instructions.
70 : In Agave, the 2 precompiles have slightly different behavior:
71 : 1. Ed25519 has 16-bit instr index vs Secp256k1 has 8-bit
72 : 2. Ed25519 accepts instr index==0xFFFF as a special value to indicate
73 : the current instruction, Secp256k1 doesn't have this feature
74 : 3. Ed25519 always return InvalidDataOffsets, while Secp256k1 can
75 : return InvalidDataOffsets or InvalidSignature
76 : All these differences are completely useless, so we unify the logic.
77 : We handle the special case of index==0xFFFF as in Ed25519.
78 : We handle errors as in Secp256k1. */
79 : static inline int
80 : fd_precompile_get_instr_data( fd_exec_instr_ctx_t * ctx,
81 : ushort index,
82 : ushort offset,
83 : ushort sz,
84 0 : uchar const ** res ) {
85 0 : uchar const * data;
86 0 : ulong data_sz;
87 : /* The special value index==USHORT_MAX means current instruction.
88 : This feature has been introduced for ed25519, but not for secp256k1 where
89 : index is 1-byte only.
90 : So, fortunately, we can use the same function.
91 : https://github.com/anza-xyz/agave/blob/v1.18.12/sdk/src/ed25519_instruction.rs#L161-L163
92 : https://github.com/anza-xyz/agave/blob/v1.18.12/sdk/src/secp256k1_instruction.rs#L1018 */
93 0 : if( index==USHORT_MAX ) {
94 :
95 : /* Use current instruction data */
96 0 : data = ctx->instr->data;
97 0 : data_sz = ctx->instr->data_sz;
98 :
99 0 : } else {
100 :
101 0 : if( FD_UNLIKELY( index>=TXN( ctx->txn_in->txn )->instr_cnt ) )
102 0 : return FD_EXECUTOR_PRECOMPILE_ERR_DATA_OFFSET;
103 :
104 0 : fd_txn_t const * txn = TXN( ctx->txn_in->txn );
105 0 : uchar const * payload = ctx->txn_in->txn->payload;
106 0 : fd_txn_instr_t const * instr = &txn->instr[ index ];
107 :
108 0 : data = fd_txn_get_instr_data( instr, payload );
109 0 : data_sz = instr->data_sz;
110 :
111 0 : }
112 :
113 0 : if( FD_UNLIKELY( (ulong)offset+(ulong)sz > data_sz ) ) /* (offset+sz) in [0,2^17) */
114 0 : return FD_EXECUTOR_PRECOMPILE_ERR_SIGNATURE;
115 :
116 0 : *res = data + offset;
117 0 : return 0;
118 0 : }
119 :
120 : /*
121 : Ed25519
122 : */
123 :
124 : int
125 0 : fd_precompile_ed25519_verify( fd_exec_instr_ctx_t * ctx ) {
126 :
127 0 : uchar const * data = ctx->instr->data;
128 0 : ulong data_sz = ctx->instr->data_sz;
129 :
130 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/sdk/src/ed25519_instruction.rs#L90-L96
131 : note: this part is really silly and in fact in leaves out the edge case [0, 0].
132 :
133 : Our implementation does the following:
134 : 1. assert that there's enough data to deser 1+ fd_ed25519_sig_offsets
135 : (in particular, data[0] is accessible)
136 : - in the unlikely case, check for the Agave edge case
137 : 2. if data[0]==0 return
138 : 3. compute and check expected size */
139 0 : if( FD_UNLIKELY( data_sz < DATA_START ) ) {
140 0 : if( FD_UNLIKELY( data_sz == 2 && data[0] == 0 ) ) {
141 0 : return FD_EXECUTOR_INSTR_SUCCESS;
142 0 : }
143 0 : ctx->txn_out->err.custom_err = FD_EXECUTOR_PRECOMPILE_ERR_INSTR_DATA_SIZE;
144 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
145 0 : }
146 :
147 0 : ulong sig_cnt = data[0];
148 0 : if( FD_UNLIKELY( sig_cnt==0 ) ) {
149 0 : ctx->txn_out->err.custom_err = FD_EXECUTOR_PRECOMPILE_ERR_INSTR_DATA_SIZE;
150 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
151 0 : }
152 :
153 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/sdk/src/ed25519_instruction.rs#L97-L103 */
154 0 : ulong expected_data_size = sig_cnt * SIGNATURE_OFFSETS_SERIALIZED_SIZE + SIGNATURE_OFFSETS_START;
155 0 : if( FD_UNLIKELY( data_sz < expected_data_size ) ) {
156 0 : ctx->txn_out->err.custom_err = FD_EXECUTOR_PRECOMPILE_ERR_INSTR_DATA_SIZE;
157 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
158 0 : }
159 :
160 0 : ulong off = SIGNATURE_OFFSETS_START;
161 0 : for( ulong i = 0; i < sig_cnt; ++i ) {
162 0 : fd_ed25519_signature_offsets_t const * sigoffs = (const fd_ed25519_signature_offsets_t *) (data + off);
163 0 : off += SIGNATURE_OFFSETS_SERIALIZED_SIZE;
164 :
165 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/sdk/src/ed25519_instruction.rs#L110-L112 */
166 : // ???
167 :
168 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/sdk/src/ed25519_instruction.rs#L114-L121 */
169 0 : uchar const * sig = NULL;
170 0 : int err = fd_precompile_get_instr_data( ctx,
171 0 : sigoffs->sig_instr_idx,
172 0 : sigoffs->sig_offset,
173 0 : SIGNATURE_SERIALIZED_SIZE,
174 0 : &sig );
175 0 : if( FD_UNLIKELY( err ) ) {
176 0 : ctx->txn_out->err.custom_err = (uint)err;
177 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
178 0 : }
179 :
180 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/sdk/src/ed25519_instruction.rs#L123-L124
181 : Note: we parse the signature as part of fd_ed25519_verify.
182 : Because of this, the return error code might be different from Agave in some edge cases. */
183 :
184 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/sdk/src/ed25519_instruction.rs#L126-L133 */
185 0 : uchar const * pubkey = NULL;
186 0 : err = fd_precompile_get_instr_data( ctx,
187 0 : sigoffs->pubkey_instr_idx,
188 0 : sigoffs->pubkey_offset,
189 0 : ED25519_PUBKEY_SERIALIZED_SIZE,
190 0 : &pubkey );
191 0 : if( FD_UNLIKELY( err ) ) {
192 0 : ctx->txn_out->err.custom_err = (uint)err;
193 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
194 0 : }
195 :
196 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/sdk/src/ed25519_instruction.rs#L135-L136
197 : Note: we parse the public key as part of fd_ed25519_verify.
198 : Because of this, the return error code might be different from Agave in some edge cases. */
199 :
200 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/sdk/src/ed25519_instruction.rs#L138-L145 */
201 0 : uchar const * msg = NULL;
202 0 : ushort msg_sz = sigoffs->msg_data_sz;
203 0 : err = fd_precompile_get_instr_data( ctx,
204 0 : sigoffs->msg_instr_idx,
205 0 : sigoffs->msg_offset,
206 0 : msg_sz,
207 0 : &msg );
208 0 : if( FD_UNLIKELY( err ) ) {
209 0 : ctx->txn_out->err.custom_err = (uint)err;
210 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
211 0 : }
212 :
213 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/sdk/src/ed25519_instruction.rs#L147-L149 */
214 0 : fd_sha512_t sha[1];
215 0 : if( FD_UNLIKELY( fd_ed25519_verify( msg, msg_sz, sig, pubkey, sha )!=FD_ED25519_SUCCESS ) ) {
216 0 : ctx->txn_out->err.custom_err = FD_EXECUTOR_PRECOMPILE_ERR_SIGNATURE;
217 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
218 0 : }
219 0 : }
220 :
221 0 : return FD_EXECUTOR_INSTR_SUCCESS;
222 0 : }
223 :
224 : #if FD_HAS_S2NBIGNUM
225 :
226 : /*
227 : Secp256K1
228 : */
229 :
230 : int
231 0 : fd_precompile_secp256k1_verify( fd_exec_instr_ctx_t * ctx ) {
232 :
233 0 : uchar const * data = ctx->instr->data;
234 0 : ulong data_sz = ctx->instr->data_sz;
235 :
236 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/sdk/src/secp256k1_instruction.rs#L934-L947
237 : see comment in ed25519, here the special case is [0] instead of [0, 0] */
238 0 : if( FD_UNLIKELY( data_sz < SECP256K1_DATA_START ) ) {
239 0 : if( FD_UNLIKELY( data_sz == 1 && data[0] == 0 ) ) {
240 0 : return FD_EXECUTOR_INSTR_SUCCESS;
241 0 : }
242 0 : ctx->txn_out->err.custom_err = FD_EXECUTOR_PRECOMPILE_ERR_INSTR_DATA_SIZE;
243 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
244 0 : }
245 :
246 : /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/sdk/src/secp256k1_instruction.rs#L938-L947 */
247 0 : ulong sig_cnt = data[0];
248 0 : if( FD_UNLIKELY( sig_cnt==0 && data_sz>1 ) ) {
249 0 : ctx->txn_out->err.custom_err = FD_EXECUTOR_PRECOMPILE_ERR_INSTR_DATA_SIZE;
250 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
251 0 : }
252 :
253 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/sdk/src/secp256k1_instruction.rs#L948-L953 */
254 0 : ulong expected_data_size = sig_cnt * SECP256K1_SIGNATURE_OFFSETS_SERIALIZED_SIZE + SECP256K1_SIGNATURE_OFFSETS_START;
255 0 : if( FD_UNLIKELY( data_sz < expected_data_size ) ) {
256 0 : ctx->txn_out->err.custom_err = FD_EXECUTOR_PRECOMPILE_ERR_INSTR_DATA_SIZE;
257 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
258 0 : }
259 :
260 0 : ulong off = SECP256K1_SIGNATURE_OFFSETS_START;
261 0 : for( ulong i = 0; i < sig_cnt; ++i ) {
262 0 : fd_secp256k1_signature_offsets_t const * sigoffs = (const fd_secp256k1_signature_offsets_t *) (data + off);
263 0 : off += SECP256K1_SIGNATURE_OFFSETS_SERIALIZED_SIZE;
264 :
265 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/sdk/src/secp256k1_instruction.rs#L960-L961 */
266 : // ???
267 :
268 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/sdk/src/secp256k1_instruction.rs#L963-L973
269 : Note: for whatever reason, Agave returns InvalidInstructionDataSize instead of InvalidDataOffsets.
270 : We just return the err as is. */
271 0 : uchar const * sig = NULL;
272 0 : int err = fd_precompile_get_instr_data( ctx,
273 0 : sigoffs->sig_instr_idx,
274 0 : sigoffs->sig_offset,
275 0 : SIGNATURE_SERIALIZED_SIZE + 1, /* extra byte is recovery id */
276 0 : &sig );
277 0 : if( FD_UNLIKELY( err ) ) {
278 0 : ctx->txn_out->err.custom_err = (uint)err;
279 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
280 0 : }
281 :
282 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/sdk/src/secp256k1_instruction.rs#L975-L981
283 : Note: we parse the signature and recovery id as part of fd_secp256k1_recover.
284 : Because of this, the return error code might be different from Agave in some edge cases. */
285 0 : int recovery_id = (int)sig[SIGNATURE_SERIALIZED_SIZE]; /* extra byte is recovery id */
286 :
287 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/sdk/src/secp256k1_instruction.rs#L983-L989 */
288 0 : uchar const * eth_address = NULL;
289 0 : err = fd_precompile_get_instr_data( ctx,
290 0 : sigoffs->pubkey_instr_idx,
291 0 : sigoffs->pubkey_offset,
292 0 : SECP256K1_PUBKEY_SERIALIZED_SIZE,
293 0 : ð_address );
294 0 : if( FD_UNLIKELY( err ) ) {
295 0 : ctx->txn_out->err.custom_err = (uint)err;
296 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
297 0 : }
298 :
299 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/sdk/src/secp256k1_instruction.rs#L991-L997 */
300 0 : uchar const * msg = NULL;
301 0 : ushort msg_sz = sigoffs->msg_data_sz;
302 0 : err = fd_precompile_get_instr_data( ctx,
303 0 : sigoffs->msg_instr_idx,
304 0 : sigoffs->msg_offset,
305 0 : msg_sz,
306 0 : &msg );
307 0 : if( FD_UNLIKELY( err ) ) {
308 0 : ctx->txn_out->err.custom_err = (uint)err;
309 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
310 0 : }
311 :
312 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/sdk/src/secp256k1_instruction.rs#L999-L1001 */
313 0 : uchar msg_hash[ FD_KECCAK256_HASH_SZ ];
314 0 : fd_keccak256_hash( msg, msg_sz, msg_hash );
315 :
316 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/sdk/src/secp256k1_instruction.rs#L1003-L1008 */
317 0 : uchar pubkey[64];
318 0 : if ( FD_UNLIKELY( fd_secp256k1_recover( pubkey, msg_hash, sig, recovery_id ) == NULL ) ) {
319 0 : ctx->txn_out->err.custom_err = FD_EXECUTOR_PRECOMPILE_ERR_SIGNATURE;
320 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
321 0 : }
322 :
323 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/sdk/src/secp256k1_instruction.rs#L1009-L1013 */
324 0 : uchar pubkey_hash[ FD_KECCAK256_HASH_SZ ];
325 0 : fd_keccak256_hash( pubkey, 64, pubkey_hash );
326 :
327 0 : if( FD_UNLIKELY( memcmp( eth_address, pubkey_hash+(FD_KECCAK256_HASH_SZ-SECP256K1_PUBKEY_SERIALIZED_SIZE), SECP256K1_PUBKEY_SERIALIZED_SIZE ) ) ) {
328 0 : ctx->txn_out->err.custom_err = FD_EXECUTOR_PRECOMPILE_ERR_SIGNATURE;
329 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
330 0 : }
331 0 : }
332 :
333 0 : return FD_EXECUTOR_INSTR_SUCCESS;
334 0 : }
335 :
336 : /*
337 : Secp256r1
338 : */
339 :
340 : int
341 0 : fd_precompile_secp256r1_verify( fd_exec_instr_ctx_t * ctx ) {
342 0 : uchar const * data = ctx->instr->data;
343 0 : ulong data_sz = ctx->instr->data_sz;
344 :
345 : /* ... */
346 0 : if( FD_UNLIKELY( data_sz < DATA_START ) ) {
347 0 : ctx->txn_out->err.custom_err = FD_EXECUTOR_PRECOMPILE_ERR_INSTR_DATA_SIZE;
348 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
349 0 : }
350 :
351 0 : ulong sig_cnt = data[0];
352 0 : if( FD_UNLIKELY( sig_cnt==0UL ) ) {
353 0 : ctx->txn_out->err.custom_err = FD_EXECUTOR_PRECOMPILE_ERR_INSTR_DATA_SIZE;
354 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
355 0 : }
356 :
357 : /* https://github.com/anza-xyz/agave/blob/v2.3.1/precompiles/src/secp256r1.rs#L30 */
358 0 : if( FD_UNLIKELY( sig_cnt>8UL ) ) {
359 0 : ctx->txn_out->err.custom_err = FD_EXECUTOR_PRECOMPILE_ERR_INSTR_DATA_SIZE;
360 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
361 0 : }
362 :
363 : /* ... */
364 0 : ulong expected_data_size = sig_cnt * SIGNATURE_OFFSETS_SERIALIZED_SIZE + SIGNATURE_OFFSETS_START;
365 0 : if( FD_UNLIKELY( data_sz < expected_data_size ) ) {
366 0 : ctx->txn_out->err.custom_err = FD_EXECUTOR_PRECOMPILE_ERR_INSTR_DATA_SIZE;
367 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
368 0 : }
369 :
370 0 : ulong off = SIGNATURE_OFFSETS_START;
371 0 : for( ulong i = 0; i < sig_cnt; ++i ) {
372 0 : fd_secp256r1_signature_offsets_t const * sigoffs = (const fd_secp256r1_signature_offsets_t *) (data + off);
373 0 : off += SIGNATURE_OFFSETS_SERIALIZED_SIZE;
374 :
375 : /* ... */
376 0 : uchar const * sig = NULL;
377 0 : int err = fd_precompile_get_instr_data( ctx,
378 0 : sigoffs->sig_instr_idx,
379 0 : sigoffs->sig_offset,
380 0 : SIGNATURE_SERIALIZED_SIZE,
381 0 : &sig );
382 0 : if( FD_UNLIKELY( err ) ) {
383 0 : ctx->txn_out->err.custom_err = (uint)err;
384 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
385 0 : }
386 :
387 : /* ... */
388 0 : uchar const * pubkey = NULL;
389 0 : err = fd_precompile_get_instr_data( ctx,
390 0 : sigoffs->pubkey_instr_idx,
391 0 : sigoffs->pubkey_offset,
392 0 : SECP256R1_PUBKEY_SERIALIZED_SIZE,
393 0 : &pubkey );
394 0 : if( FD_UNLIKELY( err ) ) {
395 0 : ctx->txn_out->err.custom_err = (uint)err;
396 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
397 0 : }
398 :
399 : /* ... */
400 0 : uchar const * msg = NULL;
401 0 : ushort msg_sz = sigoffs->msg_data_sz;
402 0 : err = fd_precompile_get_instr_data( ctx,
403 0 : sigoffs->msg_instr_idx,
404 0 : sigoffs->msg_offset,
405 0 : msg_sz,
406 0 : &msg );
407 0 : if( FD_UNLIKELY( err ) ) {
408 0 : ctx->txn_out->err.custom_err = (uint)err;
409 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
410 0 : }
411 :
412 : /* ... */
413 0 : fd_sha256_t sha[1];
414 0 : if( FD_UNLIKELY( fd_secp256r1_verify( msg, msg_sz, sig, pubkey, sha )!=FD_SECP256R1_SUCCESS ) ) {
415 0 : ctx->txn_out->err.custom_err = FD_EXECUTOR_PRECOMPILE_ERR_SIGNATURE;
416 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
417 0 : }
418 0 : }
419 :
420 0 : return FD_EXECUTOR_INSTR_SUCCESS;
421 0 : }
422 :
423 : static const fd_precompile_program_t precompiles[] = {
424 : { &fd_solana_secp256r1_program_id, NO_ENABLE_FEATURE_ID, fd_precompile_secp256r1_verify },
425 : { &fd_solana_keccak_secp_256k_program_id, NO_ENABLE_FEATURE_ID, fd_precompile_secp256k1_verify },
426 : { &fd_solana_ed25519_sig_verify_program_id, NO_ENABLE_FEATURE_ID, fd_precompile_ed25519_verify },
427 : {0}
428 : };
429 :
430 : fd_precompile_program_t const *
431 9 : fd_precompiles( void ) {
432 9 : return precompiles;
433 9 : }
434 :
435 : #define MAP_PERFECT_NAME fd_native_precompile_program_fn_lookup_tbl
436 : #define MAP_PERFECT_LG_TBL_SZ 2
437 : #define MAP_PERFECT_T fd_native_prog_info_t
438 126 : #define MAP_PERFECT_HASH_C 63546U
439 : #define MAP_PERFECT_KEY key.uc
440 : #define MAP_PERFECT_KEY_T fd_pubkey_t const *
441 : #define MAP_PERFECT_ZERO_KEY (0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0)
442 : #define MAP_PERFECT_COMPLEX_KEY 1
443 126 : #define MAP_PERFECT_KEYS_EQUAL(k1,k2) (!memcmp( (k1), (k2), 32UL ))
444 :
445 126 : #define PERFECT_HASH( u ) (((MAP_PERFECT_HASH_C*(u))>>30)&0x3U)
446 :
447 : #define MAP_PERFECT_HASH_PP( a00,a01,a02,a03,a04,a05,a06,a07,a08,a09,a10,a11,a12,a13,a14,a15, \
448 : a16,a17,a18,a19,a20,a21,a22,a23,a24,a25,a26,a27,a28,a29,a30,a31) \
449 : PERFECT_HASH( (a00 | (a01<<8)) )
450 126 : #define MAP_PERFECT_HASH_R( ptr ) PERFECT_HASH( fd_uint_load_2( (uchar const *)ptr ) )
451 :
452 : #define MAP_PERFECT_0 ( ED25519_SV_PROG_ID ), .fn = fd_precompile_ed25519_verify
453 : #define MAP_PERFECT_1 ( KECCAK_SECP_PROG_ID ), .fn = fd_precompile_secp256k1_verify
454 : #define MAP_PERFECT_2 ( SECP256R1_PROG_ID ), .fn = fd_precompile_secp256r1_verify
455 :
456 : #include "../../../util/tmpl/fd_map_perfect.c"
457 : #undef PERFECT_HASH
458 :
459 : fd_exec_instr_fn_t
460 126 : fd_executor_lookup_native_precompile_program( fd_pubkey_t const * pubkey ) {
461 126 : const fd_native_prog_info_t null_function = {0};
462 126 : return fd_native_precompile_program_fn_lookup_tbl_query( pubkey, &null_function )->fn;
463 126 : }
464 :
465 : #else /* !FD_HAS_S2NBIGNUM */
466 :
467 : fd_precompile_program_t const *
468 : fd_precompiles( void ) {
469 : FD_LOG_ERR(( "This build does not include s2n-bignum, which is required to run a validator.\n"
470 : "To install s2n-bignum, re-run ./deps.sh, make distclean, and make -j" ));
471 : return NULL;
472 : }
473 :
474 : fd_exec_instr_fn_t
475 : fd_executor_lookup_native_precompile_program( fd_pubkey_t const * pubkey ) {
476 : (void)pubkey;
477 : FD_LOG_ERR(( "This build does not include s2n-bignum, which is required to run a validator.\n"
478 : "To install s2n-bignum, re-run ./deps.sh, make distclean, and make -j" ));
479 : return NULL;
480 : }
481 :
482 : #endif /* FD_HAS_S2NBIGNUM */
|