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 :
8 : /* Docs:
9 : https://docs.solana.com/developing/runtime-facilities/programs#ed25519-program
10 : https://docs.solana.com/developing/runtime-facilities/programs#secp256k1-program */
11 :
12 : /* There are 3 precompiles and 2 ways to serialize data.
13 : The most recent one seems are ed25519 and secp256r1 with 2 bytes per instruction,
14 : that works better with JS sdk even though it consumes a few bytes. */
15 : struct __attribute__((packed)) fd_precompile_sig_offsets {
16 : ushort sig_offset;
17 : ushort sig_instr_idx;
18 : ushort pubkey_offset;
19 : ushort pubkey_instr_idx;
20 : ushort msg_offset;
21 : ushort msg_data_sz;
22 : ushort msg_instr_idx;
23 : };
24 : typedef struct fd_precompile_sig_offsets fd_ed25519_signature_offsets_t;
25 : typedef struct fd_precompile_sig_offsets fd_secp256r1_signature_offsets_t;
26 :
27 : struct __attribute__((packed)) fd_precompile_one_byte_idx_sig_offsets {
28 : ushort sig_offset;
29 : uchar sig_instr_idx;
30 : ushort pubkey_offset;
31 : uchar pubkey_instr_idx;
32 : ushort msg_offset;
33 : ushort msg_data_sz;
34 : uchar msg_instr_idx;
35 : };
36 : typedef struct fd_precompile_one_byte_idx_sig_offsets fd_secp256k1_signature_offsets_t;
37 :
38 : /*
39 : Common
40 : */
41 :
42 6540 : #define SIGNATURE_SERIALIZED_SIZE (64UL)
43 8613 : #define SIGNATURE_OFFSETS_SERIALIZED_SIZE (14UL)
44 7206 : #define SIGNATURE_OFFSETS_START (2UL)
45 : #define DATA_START (SIGNATURE_OFFSETS_SERIALIZED_SIZE + SIGNATURE_OFFSETS_START)
46 :
47 : /*
48 : Custom
49 : */
50 :
51 4947 : #define ED25519_PUBKEY_SERIALIZED_SIZE (32UL)
52 :
53 0 : #define SECP256R1_PUBKEY_SERIALIZED_SIZE (33UL)
54 :
55 744 : #define SECP256K1_PUBKEY_SERIALIZED_SIZE (20UL)
56 1080 : #define SECP256K1_SIGNATURE_OFFSETS_SERIALIZED_SIZE (11UL)
57 567 : #define SECP256K1_SIGNATURE_OFFSETS_START (1UL)
58 : #define SECP256K1_DATA_START (SECP256K1_SIGNATURE_OFFSETS_SERIALIZED_SIZE + SECP256K1_SIGNATURE_OFFSETS_START)
59 :
60 : FD_STATIC_ASSERT( sizeof( fd_ed25519_signature_offsets_t )==SIGNATURE_OFFSETS_SERIALIZED_SIZE, fd_ballet );
61 : FD_STATIC_ASSERT( sizeof( fd_secp256k1_signature_offsets_t )==SECP256K1_SIGNATURE_OFFSETS_SERIALIZED_SIZE, fd_ballet );
62 :
63 : /*
64 : Common code
65 : */
66 :
67 : /* fd_precompile_get_instr_data fetches data across instructions.
68 : In Agave, the 2 precompiles have slightly different behavior:
69 : 1. Ed25519 has 16-bit instr index vs Secp256k1 has 8-bit
70 : 2. Ed25519 accepts instr index==0xFFFF as a special value to indicate
71 : the current instruction, Secp256k1 doesn't have this feature
72 : 3. Ed25519 always return InvalidDataOffsets, while Secp256k1 can
73 : return InvalidDataOffsets or InvalidSignature
74 : All these differences are completely useless, so we unify the logic.
75 : We handle the special case of index==0xFFFF as in Ed25519.
76 : We handle errors as in Secp256k1. */
77 : static inline int
78 : fd_precompile_get_instr_data( fd_exec_txn_ctx_t * txn_ctx,
79 : fd_txn_instr_t const * cur_instr,
80 : ushort index,
81 : ushort offset,
82 : ushort sz,
83 17160 : uchar const ** res ) {
84 17160 : uchar const * data;
85 17160 : ulong data_sz;
86 : /* The special value index==USHORT_MAX means current instruction.
87 : This feature has been introduced for ed25519, but not for secp256k1 where
88 : index is 1-byte only.
89 : So, fortunately, we can use the same function.
90 : https://github.com/anza-xyz/agave/blob/v1.18.12/sdk/src/ed25519_instruction.rs#L161-L163
91 : https://github.com/anza-xyz/agave/blob/v1.18.12/sdk/src/secp256k1_instruction.rs#L1018 */
92 17160 : if( index==USHORT_MAX ) {
93 :
94 : /* Use current instruction data */
95 12165 : data = fd_txn_get_instr_data( cur_instr, txn_ctx->_txn_raw->raw );
96 12165 : data_sz = cur_instr->data_sz;
97 :
98 12165 : } else {
99 :
100 4995 : fd_txn_t const * txn_descriptor = txn_ctx->txn_descriptor;
101 4995 : if( FD_UNLIKELY( index >= txn_descriptor->instr_cnt ) )
102 51 : return FD_EXECUTOR_PRECOMPILE_ERR_DATA_OFFSET;
103 :
104 4944 : fd_txn_instr_t const * instr = &txn_descriptor->instr[index];
105 4944 : data = fd_txn_get_instr_data( instr, txn_ctx->_txn_raw->raw );
106 4944 : data_sz = instr->data_sz;
107 :
108 4944 : }
109 :
110 17109 : if( FD_UNLIKELY( (ulong)offset+(ulong)sz > data_sz ) ) /* (offset+sz) in [0,2^17) */
111 114 : return FD_EXECUTOR_PRECOMPILE_ERR_SIGNATURE;
112 :
113 16995 : *res = data + offset;
114 16995 : return 0;
115 17109 : }
116 :
117 : /*
118 : Ed25519
119 : */
120 :
121 : int
122 : fd_precompile_ed25519_verify( fd_exec_txn_ctx_t * txn_ctx,
123 3687 : fd_txn_instr_t const * instr ) {
124 :
125 3687 : uchar const * data = fd_txn_get_instr_data( instr, txn_ctx->_txn_raw->raw );
126 3687 : ulong data_sz = instr->data_sz;
127 :
128 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/sdk/src/ed25519_instruction.rs#L90-L96
129 : note: this part is really silly and in fact in leaves out the edge case [0, 0].
130 :
131 : Our implementation does the following:
132 : 1. assert that there's enough data to deser 1+ fd_ed25519_sig_offsets
133 : (in particular, data[0] is accessible)
134 : - in the unlikely case, check for the Agave edge case
135 : 2. if data[0]==0 return
136 : 3. compute and check expected size */
137 3687 : if( FD_UNLIKELY( data_sz < DATA_START ) ) {
138 75 : if( FD_UNLIKELY( data_sz == 2 && data[0] == 0 ) ) {
139 48 : return FD_EXECUTOR_INSTR_SUCCESS;
140 48 : }
141 27 : txn_ctx->custom_err = FD_EXECUTOR_PRECOMPILE_ERR_INSTR_DATA_SIZE;
142 27 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
143 75 : }
144 :
145 3612 : ulong sig_cnt = data[0];
146 3612 : if( FD_UNLIKELY( sig_cnt==0 ) ) {
147 6 : txn_ctx->custom_err = FD_EXECUTOR_PRECOMPILE_ERR_INSTR_DATA_SIZE;
148 6 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
149 6 : }
150 :
151 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/sdk/src/ed25519_instruction.rs#L97-L103 */
152 3606 : ulong expected_data_size = sig_cnt * SIGNATURE_OFFSETS_SERIALIZED_SIZE + SIGNATURE_OFFSETS_START;
153 3606 : if( FD_UNLIKELY( data_sz < expected_data_size ) ) {
154 6 : txn_ctx->custom_err = FD_EXECUTOR_PRECOMPILE_ERR_INSTR_DATA_SIZE;
155 6 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
156 6 : }
157 :
158 3600 : ulong off = SIGNATURE_OFFSETS_START;
159 5502 : for( ulong i = 0; i < sig_cnt; ++i ) {
160 5007 : fd_ed25519_signature_offsets_t const * sigoffs = (const fd_ed25519_signature_offsets_t *) (data + off);
161 5007 : off += SIGNATURE_OFFSETS_SERIALIZED_SIZE;
162 :
163 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/sdk/src/ed25519_instruction.rs#L110-L112 */
164 : // ???
165 :
166 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/sdk/src/ed25519_instruction.rs#L114-L121 */
167 5007 : uchar const * sig = NULL;
168 5007 : int err = fd_precompile_get_instr_data( txn_ctx,
169 5007 : instr,
170 5007 : sigoffs->sig_instr_idx,
171 5007 : sigoffs->sig_offset,
172 5007 : SIGNATURE_SERIALIZED_SIZE,
173 5007 : &sig );
174 5007 : if( FD_UNLIKELY( err ) ) {
175 60 : txn_ctx->custom_err = (uint)err;
176 60 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
177 60 : }
178 :
179 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/sdk/src/ed25519_instruction.rs#L123-L124
180 : Note: we parse the signature as part of fd_ed25519_verify.
181 : Because of this, the return error code might be different from Agave in some edge cases. */
182 :
183 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/sdk/src/ed25519_instruction.rs#L126-L133 */
184 4947 : uchar const * pubkey = NULL;
185 4947 : err = fd_precompile_get_instr_data( txn_ctx,
186 4947 : instr,
187 4947 : sigoffs->pubkey_instr_idx,
188 4947 : sigoffs->pubkey_offset,
189 4947 : ED25519_PUBKEY_SERIALIZED_SIZE,
190 4947 : &pubkey );
191 4947 : if( FD_UNLIKELY( err ) ) {
192 9 : txn_ctx->custom_err = (uint)err;
193 9 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
194 9 : }
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 4938 : uchar const * msg = NULL;
202 4938 : ushort msg_sz = sigoffs->msg_data_sz;
203 4938 : err = fd_precompile_get_instr_data( txn_ctx,
204 4938 : instr,
205 4938 : sigoffs->msg_instr_idx,
206 4938 : sigoffs->msg_offset,
207 4938 : msg_sz,
208 4938 : &msg );
209 4938 : if( FD_UNLIKELY( err ) ) {
210 30 : txn_ctx->custom_err = (uint)err;
211 30 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
212 30 : }
213 :
214 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/sdk/src/ed25519_instruction.rs#L147-L149 */
215 4908 : fd_sha512_t sha[1];
216 4908 : if( FD_UNLIKELY( fd_ed25519_verify( msg, msg_sz, sig, pubkey, sha )!=FD_ED25519_SUCCESS ) ) {
217 3006 : txn_ctx->custom_err = FD_EXECUTOR_PRECOMPILE_ERR_SIGNATURE;
218 3006 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
219 3006 : }
220 4908 : }
221 :
222 495 : return FD_EXECUTOR_INSTR_SUCCESS;
223 3600 : }
224 :
225 : /*
226 : Secp256K1
227 : */
228 :
229 : int
230 : fd_precompile_secp256k1_verify( fd_exec_txn_ctx_t * txn_ctx,
231 393 : fd_txn_instr_t const * instr ) {
232 :
233 393 : uchar const * data = fd_txn_get_instr_data( instr, txn_ctx->_txn_raw->raw );
234 393 : ulong data_sz = 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 393 : if( FD_UNLIKELY( data_sz < SECP256K1_DATA_START ) ) {
239 93 : if( FD_UNLIKELY( data_sz == 1 && data[0] == 0 ) ) {
240 66 : return FD_EXECUTOR_INSTR_SUCCESS;
241 66 : }
242 27 : txn_ctx->custom_err = FD_EXECUTOR_PRECOMPILE_ERR_INSTR_DATA_SIZE;
243 27 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
244 93 : }
245 :
246 : /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/sdk/src/secp256k1_instruction.rs#L938-L947 */
247 300 : ulong sig_cnt = data[0];
248 300 : if( FD_UNLIKELY( sig_cnt==0 && data_sz>1 ) ) {
249 9 : txn_ctx->custom_err = FD_EXECUTOR_PRECOMPILE_ERR_INSTR_DATA_SIZE;
250 9 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
251 9 : }
252 :
253 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/sdk/src/secp256k1_instruction.rs#L948-L953 */
254 291 : ulong expected_data_size = sig_cnt * SECP256K1_SIGNATURE_OFFSETS_SERIALIZED_SIZE + SECP256K1_SIGNATURE_OFFSETS_START;
255 291 : if( FD_UNLIKELY( data_sz < expected_data_size ) ) {
256 15 : txn_ctx->custom_err = FD_EXECUTOR_PRECOMPILE_ERR_INSTR_DATA_SIZE;
257 15 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
258 15 : }
259 :
260 276 : ulong off = SECP256K1_SIGNATURE_OFFSETS_START;
261 801 : for( ulong i = 0; i < sig_cnt; ++i ) {
262 789 : fd_secp256k1_signature_offsets_t const * sigoffs = (const fd_secp256k1_signature_offsets_t *) (data + off);
263 789 : 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 789 : uchar const * sig = NULL;
272 789 : int err = fd_precompile_get_instr_data( txn_ctx,
273 789 : instr,
274 789 : sigoffs->sig_instr_idx,
275 789 : sigoffs->sig_offset,
276 789 : SIGNATURE_SERIALIZED_SIZE + 1, /* extra byte is recovery id */
277 789 : &sig );
278 789 : if( FD_UNLIKELY( err ) ) {
279 45 : txn_ctx->custom_err = (uint)err;
280 45 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
281 45 : }
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 744 : 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 744 : uchar const * eth_address = NULL;
290 744 : err = fd_precompile_get_instr_data( txn_ctx,
291 744 : instr,
292 744 : sigoffs->pubkey_instr_idx,
293 744 : sigoffs->pubkey_offset,
294 744 : SECP256K1_PUBKEY_SERIALIZED_SIZE,
295 744 : ð_address );
296 744 : if( FD_UNLIKELY( err ) ) {
297 9 : txn_ctx->custom_err = (uint)err;
298 9 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
299 9 : }
300 :
301 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/sdk/src/secp256k1_instruction.rs#L991-L997 */
302 735 : uchar const * msg = NULL;
303 735 : ushort msg_sz = sigoffs->msg_data_sz;
304 735 : err = fd_precompile_get_instr_data( txn_ctx,
305 735 : instr,
306 735 : sigoffs->msg_instr_idx,
307 735 : sigoffs->msg_offset,
308 735 : msg_sz,
309 735 : &msg );
310 735 : if( FD_UNLIKELY( err ) ) {
311 12 : txn_ctx->custom_err = (uint)err;
312 12 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
313 12 : }
314 :
315 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/sdk/src/secp256k1_instruction.rs#L999-L1001 */
316 723 : uchar msg_hash[ FD_KECCAK256_HASH_SZ ];
317 723 : fd_keccak256_hash( msg, msg_sz, msg_hash );
318 :
319 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/sdk/src/secp256k1_instruction.rs#L1003-L1008 */
320 723 : uchar pubkey[64];
321 723 : if ( FD_UNLIKELY( fd_secp256k1_recover( pubkey, msg_hash, sig, recovery_id ) == NULL ) ) {
322 75 : txn_ctx->custom_err = FD_EXECUTOR_PRECOMPILE_ERR_SIGNATURE;
323 75 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
324 75 : }
325 :
326 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/sdk/src/secp256k1_instruction.rs#L1009-L1013 */
327 648 : uchar pubkey_hash[ FD_KECCAK256_HASH_SZ ];
328 648 : fd_keccak256_hash( pubkey, 64, pubkey_hash );
329 :
330 648 : if( FD_UNLIKELY( memcmp( eth_address, pubkey_hash+(FD_KECCAK256_HASH_SZ-SECP256K1_PUBKEY_SERIALIZED_SIZE), SECP256K1_PUBKEY_SERIALIZED_SIZE ) ) ) {
331 123 : txn_ctx->custom_err = FD_EXECUTOR_PRECOMPILE_ERR_SIGNATURE;
332 123 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
333 123 : }
334 648 : }
335 :
336 12 : return FD_EXECUTOR_INSTR_SUCCESS;
337 276 : }
338 :
339 : /*
340 : Secp256r1
341 : */
342 :
343 : #ifdef FD_HAS_S2NBIGNUM
344 : int
345 : fd_precompile_secp256r1_verify( fd_exec_txn_ctx_t * txn_ctx,
346 0 : fd_txn_instr_t const * instr ) {
347 :
348 0 : uchar const * data = fd_txn_get_instr_data( instr, txn_ctx->_txn_raw->raw );
349 0 : ulong data_sz = instr->data_sz;
350 :
351 : /* ... */
352 0 : if( FD_UNLIKELY( data_sz < DATA_START ) ) {
353 0 : if( FD_UNLIKELY( data_sz == 2 && data[0] == 0 ) ) {
354 0 : return FD_EXECUTOR_INSTR_SUCCESS;
355 0 : }
356 0 : txn_ctx->custom_err = FD_EXECUTOR_PRECOMPILE_ERR_INSTR_DATA_SIZE;
357 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
358 0 : }
359 :
360 0 : ulong sig_cnt = data[0];
361 0 : if( FD_UNLIKELY( sig_cnt==0 ) ) {
362 0 : txn_ctx->custom_err = FD_EXECUTOR_PRECOMPILE_ERR_INSTR_DATA_SIZE;
363 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
364 0 : }
365 :
366 : /* ... */
367 0 : ulong expected_data_size = sig_cnt * SIGNATURE_OFFSETS_SERIALIZED_SIZE + SIGNATURE_OFFSETS_START;
368 0 : if( FD_UNLIKELY( data_sz < expected_data_size ) ) {
369 0 : txn_ctx->custom_err = FD_EXECUTOR_PRECOMPILE_ERR_INSTR_DATA_SIZE;
370 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
371 0 : }
372 :
373 0 : ulong off = SIGNATURE_OFFSETS_START;
374 0 : for( ulong i = 0; i < sig_cnt; ++i ) {
375 0 : fd_secp256r1_signature_offsets_t const * sigoffs = (const fd_secp256r1_signature_offsets_t *) (data + off);
376 0 : off += SIGNATURE_OFFSETS_SERIALIZED_SIZE;
377 :
378 : /* ... */
379 0 : uchar const * sig = NULL;
380 0 : int err = fd_precompile_get_instr_data( txn_ctx,
381 0 : instr,
382 0 : sigoffs->sig_instr_idx,
383 0 : sigoffs->sig_offset,
384 0 : SIGNATURE_SERIALIZED_SIZE,
385 0 : &sig );
386 0 : if( FD_UNLIKELY( err ) ) {
387 0 : txn_ctx->custom_err = (uint)err;
388 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
389 0 : }
390 :
391 : /* ... */
392 0 : uchar const * pubkey = NULL;
393 0 : err = fd_precompile_get_instr_data( txn_ctx,
394 0 : instr,
395 0 : sigoffs->pubkey_instr_idx,
396 0 : sigoffs->pubkey_offset,
397 0 : SECP256R1_PUBKEY_SERIALIZED_SIZE,
398 0 : &pubkey );
399 0 : if( FD_UNLIKELY( err ) ) {
400 0 : txn_ctx->custom_err = (uint)err;
401 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
402 0 : }
403 :
404 : /* ... */
405 0 : uchar const * msg = NULL;
406 0 : ushort msg_sz = sigoffs->msg_data_sz;
407 0 : err = fd_precompile_get_instr_data( txn_ctx,
408 0 : instr,
409 0 : sigoffs->msg_instr_idx,
410 0 : sigoffs->msg_offset,
411 0 : msg_sz,
412 0 : &msg );
413 0 : if( FD_UNLIKELY( err ) ) {
414 0 : txn_ctx->custom_err = (uint)err;
415 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
416 0 : }
417 :
418 : /* ... */
419 0 : fd_sha256_t sha[1];
420 0 : if( FD_UNLIKELY( fd_secp256r1_verify( msg, msg_sz, sig, pubkey, sha )!=FD_SECP256R1_SUCCESS ) ) {
421 0 : txn_ctx->custom_err = FD_EXECUTOR_PRECOMPILE_ERR_SIGNATURE;
422 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
423 0 : }
424 0 : }
425 :
426 0 : return FD_EXECUTOR_INSTR_SUCCESS;
427 0 : }
428 : #else
429 : int
430 : fd_precompile_secp256r1_verify( FD_PARAM_UNUSED fd_exec_txn_ctx_t * txn_ctx,
431 : FD_PARAM_UNUSED fd_txn_instr_t const * instr ) {
432 : return FD_EXECUTOR_INSTR_ERR_FATAL;
433 : }
434 : #endif
|