LCOV - code coverage report
Current view: top level - flamenco/runtime/program - fd_precompiles.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 11 238 4.6 %
Date: 2026-03-21 05:43:32 Functions: 2 6 33.3 %

          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 :                                         &eth_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 */

Generated by: LCOV version 1.14