LCOV - code coverage report
Current view: top level - flamenco/runtime/program - fd_precompiles.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 220 241 91.3 %
Date: 2026-03-19 18:19:27 Functions: 6 6 100.0 %

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

Generated by: LCOV version 1.14