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