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