LCOV - code coverage report
Current view: top level - flamenco/vm/syscall - fd_vm_syscall_crypto.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 191 194 98.5 %
Date: 2024-11-13 11:58:15 Functions: 4 4 100.0 %

          Line data    Source code
       1             : #include "fd_vm_syscall.h"
       2             : 
       3             : #include "../../../ballet/bn254/fd_bn254.h"
       4             : #include "../../../ballet/bn254/fd_poseidon.h"
       5             : #include "../../../ballet/secp256k1/fd_secp256k1.h"
       6             : 
       7             : int
       8             : fd_vm_syscall_sol_alt_bn128_group_op( void *  _vm,
       9             :                                       ulong   group_op,
      10             :                                       ulong   input_addr,
      11             :                                       ulong   input_sz,
      12             :                                       ulong   result_addr,
      13             :                                       FD_PARAM_UNUSED ulong r5,
      14        6873 :                                       ulong * _ret ) {
      15             :   /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1509 */
      16        6873 :   fd_vm_t * vm  = (fd_vm_t *)_vm;
      17        6873 :   ulong     ret = 1UL; /* by default return Ok(1) == error */
      18             : 
      19             :   /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1520-L1549 */
      20        6873 :   ulong cost = 0UL;
      21        6873 :   ulong output_sz = 0UL;
      22        6873 :   switch( group_op ) {
      23             : 
      24          54 :   case FD_VM_SYSCALL_SOL_ALT_BN128_ADD:
      25          54 :     output_sz = FD_VM_SYSCALL_SOL_ALT_BN128_G1_SZ;
      26          54 :     cost = FD_VM_ALT_BN128_ADDITION_COST;
      27          54 :     break;
      28             : 
      29        5376 :   case FD_VM_SYSCALL_SOL_ALT_BN128_MUL:
      30        5376 :     output_sz = FD_VM_SYSCALL_SOL_ALT_BN128_G1_SZ;
      31        5376 :     cost = FD_VM_ALT_BN128_MULTIPLICATION_COST;
      32        5376 :     break;
      33             : 
      34        1437 :   case FD_VM_SYSCALL_SOL_ALT_BN128_PAIRING:
      35        1437 :     output_sz = FD_VM_SYSCALL_SOL_ALT_BN128_PAIRING_OUTPUT_SZ;
      36        1437 :     ulong elements_len = input_sz / FD_VM_SYSCALL_SOL_ALT_BN128_PAIRING_INPUT_EL_SZ;
      37        1437 :     cost = FD_VM_ALT_BN128_PAIRING_ONE_PAIR_COST_FIRST
      38        1437 :       + FD_VM_SHA256_BASE_COST
      39        1437 :       + FD_VM_SYSCALL_SOL_ALT_BN128_PAIRING_OUTPUT_SZ;
      40        1437 :     cost = fd_ulong_sat_add( cost,
      41        1437 :       fd_ulong_sat_mul( FD_VM_ALT_BN128_PAIRING_ONE_PAIR_COST_OTHER,
      42        1437 :         fd_ulong_sat_sub( elements_len, 1 ) ) );
      43        1437 :     cost = fd_ulong_sat_add( cost, input_sz );
      44        1437 :     break;
      45             : 
      46           6 :   default:
      47           6 :     FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_ERR_SYSCALL_INVALID_ATTRIBUTE );
      48           6 :     return FD_VM_ERR_INVAL; /* SyscallError::InvalidAttribute */
      49        6873 :   }
      50             : 
      51             :   /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1551 */
      52             : 
      53       13725 :   FD_VM_CU_UPDATE( vm, cost );
      54             : 
      55             :   /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1553-L1565 */
      56             : 
      57       13707 :   uchar const * input = FD_VM_MEM_SLICE_HADDR_LD( vm, input_addr,  FD_VM_ALIGN_RUST_U8, input_sz );
      58       13689 :   uchar * call_result = FD_VM_MEM_SLICE_HADDR_ST( vm, result_addr, FD_VM_ALIGN_RUST_U8, output_sz );
      59             : 
      60             :   /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1567-L1598
      61             :      Note: this implementation is post SIMD-0129, we only support the simplified error codes. */
      62           0 :   switch( group_op ) {
      63             : 
      64          45 :   case FD_VM_SYSCALL_SOL_ALT_BN128_ADD:
      65             :     /* Compute add */
      66          45 :     if( FD_LIKELY( fd_bn254_g1_add_syscall( call_result, input, input_sz )==0 ) ) {
      67          36 :       ret = 0UL; /* success */
      68          36 :     }
      69          45 :     break;
      70             : 
      71        5367 :   case FD_VM_SYSCALL_SOL_ALT_BN128_MUL:
      72             :     /* Compute scalar mul */
      73        5367 :     if( FD_LIKELY( fd_bn254_g1_scalar_mul_syscall( call_result, input, input_sz )==0 ) ) {
      74        1392 :       ret = 0UL; /* success */
      75        1392 :     }
      76        5367 :     break;
      77             : 
      78        1428 :   case FD_VM_SYSCALL_SOL_ALT_BN128_PAIRING:
      79             :     /* Compute pairing */
      80        1428 :     if( FD_LIKELY( fd_bn254_pairing_is_one_syscall( call_result, input, input_sz )==0 ) ) {
      81         264 :       ret = 0UL; /* success */
      82         264 :     }
      83        1428 :     break;
      84       13689 :   }
      85             : 
      86        6840 :   *_ret = ret;
      87        6840 :   return FD_VM_SUCCESS; /* Ok(SUCCESS) or Ok(ERROR) */
      88       13689 : }
      89             : 
      90             : int
      91             : fd_vm_syscall_sol_alt_bn128_compression( void *  _vm,
      92             :                                          ulong   op,
      93             :                                          ulong   input_addr,
      94             :                                          ulong   input_sz,
      95             :                                          ulong   result_addr,
      96             :                                          FD_PARAM_UNUSED ulong r5,
      97        2811 :                                          ulong * _ret ) {
      98             :   /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1776 */
      99        2811 :   fd_vm_t * vm  = (fd_vm_t *)_vm;
     100        2811 :   ulong     ret = 1UL; /* by default return Ok(1) == error */
     101             : 
     102             :   /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1791-L1811 */
     103        2811 :   ulong cost = 0UL;
     104        2811 :   ulong output_sz = 0UL;
     105        2811 :   switch( op ) {
     106             : 
     107         606 :   case FD_VM_SYSCALL_SOL_ALT_BN128_G1_COMPRESS:
     108         606 :     output_sz = FD_VM_SYSCALL_SOL_ALT_BN128_G1_COMPRESSED_SZ;
     109         606 :     cost = FD_VM_ALT_BN128_G1_COMPRESS;
     110         606 :     break;
     111             : 
     112         606 :   case FD_VM_SYSCALL_SOL_ALT_BN128_G1_DECOMPRESS:
     113         606 :     output_sz = FD_VM_SYSCALL_SOL_ALT_BN128_G1_SZ;
     114         606 :     cost = FD_VM_ALT_BN128_G1_DECOMPRESS;
     115         606 :     break;
     116             : 
     117         798 :   case FD_VM_SYSCALL_SOL_ALT_BN128_G2_COMPRESS:
     118         798 :     output_sz = FD_VM_SYSCALL_SOL_ALT_BN128_G2_COMPRESSED_SZ;
     119         798 :     cost = FD_VM_ALT_BN128_G2_COMPRESS;
     120         798 :     break;
     121             : 
     122         798 :   case FD_VM_SYSCALL_SOL_ALT_BN128_G2_DECOMPRESS:
     123         798 :     output_sz = FD_VM_SYSCALL_SOL_ALT_BN128_G2_SZ;
     124         798 :     cost = FD_VM_ALT_BN128_G2_DECOMPRESS;
     125         798 :     break;
     126             : 
     127           3 :   default:
     128           3 :     FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_ERR_SYSCALL_INVALID_ATTRIBUTE );
     129           3 :     return FD_VM_ERR_INVAL; /* SyscallError::InvalidAttribute */
     130        2811 :   }
     131        2808 :   cost = fd_ulong_sat_add( cost, FD_VM_SYSCALL_BASE_COST );
     132             : 
     133             :   /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1813 */
     134             : 
     135        2808 :   FD_VM_CU_UPDATE( vm, cost );
     136             : 
     137             :   /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1815-L1827 */
     138             : 
     139        5580 :   void const * input       = FD_VM_MEM_SLICE_HADDR_LD( vm, input_addr,  FD_VM_ALIGN_RUST_U8, input_sz  );
     140        5556 :   void *       call_result = FD_VM_MEM_SLICE_HADDR_ST( vm, result_addr, FD_VM_ALIGN_RUST_U8, output_sz );
     141             : 
     142             :   /* input and call_result may alias.  Therefore, buffer via out_buf */
     143           0 :   uchar out_buf[128];
     144             : 
     145             :   /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1829-L1891
     146             :      Note: this implementation is post SIMD-0129, we only support the simplified error codes. */
     147        5556 :   switch( op ) {
     148             : 
     149         597 :   case FD_VM_SYSCALL_SOL_ALT_BN128_G1_COMPRESS:
     150         597 :     if( FD_UNLIKELY( input_sz!=FD_VM_SYSCALL_SOL_ALT_BN128_G1_SZ ) ) {
     151           3 :       goto soft_error;
     152           3 :     }
     153         594 :     if( FD_LIKELY( fd_bn254_g1_compress( out_buf, fd_type_pun_const(input) ) ) ) {
     154         186 :       fd_memcpy( call_result, out_buf, FD_VM_SYSCALL_SOL_ALT_BN128_G1_COMPRESSED_SZ );
     155         186 :       ret = 0UL; /* success */
     156         186 :     }
     157         594 :     break;
     158             : 
     159         597 :   case FD_VM_SYSCALL_SOL_ALT_BN128_G1_DECOMPRESS:
     160         597 :     if( FD_UNLIKELY( input_sz!=FD_VM_SYSCALL_SOL_ALT_BN128_G1_COMPRESSED_SZ ) ) {
     161           3 :       goto soft_error;
     162           3 :     }
     163         594 :     if( FD_LIKELY( fd_bn254_g1_decompress( out_buf, fd_type_pun_const(input) ) ) ) {
     164         414 :       fd_memcpy( call_result, out_buf, FD_VM_SYSCALL_SOL_ALT_BN128_G1_SZ );
     165         414 :       ret = 0UL; /* success */
     166         414 :     }
     167         594 :     break;
     168             : 
     169         789 :   case FD_VM_SYSCALL_SOL_ALT_BN128_G2_COMPRESS:
     170         789 :     if( FD_UNLIKELY( input_sz!=FD_VM_SYSCALL_SOL_ALT_BN128_G2_SZ ) ) {
     171           3 :       goto soft_error;
     172           3 :     }
     173         786 :     if( FD_LIKELY( fd_bn254_g2_compress( out_buf, fd_type_pun_const(input) ) ) ) {
     174         114 :       fd_memcpy( call_result, out_buf, FD_VM_SYSCALL_SOL_ALT_BN128_G2_COMPRESSED_SZ );
     175         114 :       ret = 0UL; /* success */
     176         114 :     }
     177         786 :     break;
     178             : 
     179         789 :   case FD_VM_SYSCALL_SOL_ALT_BN128_G2_DECOMPRESS:
     180         789 :     if( FD_UNLIKELY( input_sz!=FD_VM_SYSCALL_SOL_ALT_BN128_G2_COMPRESSED_SZ ) ) {
     181           3 :       goto soft_error;
     182           3 :     }
     183         786 :     if( FD_LIKELY( fd_bn254_g2_decompress( out_buf, fd_type_pun_const(input) ) ) ) {
     184         402 :       fd_memcpy( call_result, out_buf, FD_VM_SYSCALL_SOL_ALT_BN128_G2_SZ );
     185         402 :       ret = 0UL; /* success */
     186         402 :     }
     187         786 :     break;
     188        5556 :   }
     189             : 
     190        2772 : soft_error:
     191        2772 :   *_ret = ret;
     192        2772 :   return FD_VM_SUCCESS; /* Ok(SUCCESS) or Ok(ERROR) */
     193        5556 : }
     194             : 
     195             : int
     196             : fd_vm_syscall_sol_poseidon( void *  _vm,
     197             :                             ulong   params,
     198             :                             ulong   endianness,
     199             :                             ulong   vals_addr,
     200             :                             ulong   vals_len,
     201             :                             ulong   result_addr,
     202         126 :                             ulong * _ret ) {
     203             :   /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1678 */
     204         126 :   fd_vm_t * vm  = (fd_vm_t *)_vm;
     205         126 :   ulong     ret = 1UL; /* by default return Ok(1) == error */
     206             : 
     207             :   /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1688 */
     208             : 
     209         126 :   if( FD_UNLIKELY( params!=0UL ) ) {
     210           3 :     FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_ERR_SYSCALL_POSEIDON_INVALID_PARAMS );
     211           3 :     return FD_VM_ERR_INVAL; /* PoseidonSyscallError::InvalidParameters */
     212           3 :   }
     213             : 
     214             :   /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1689 */
     215             : 
     216         123 :   if( FD_UNLIKELY(
     217         123 :        endianness!=0UL /* Big endian */
     218         123 :     && endianness!=1UL /* Little endian */
     219         123 :   ) ) {
     220           3 :     FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_ERR_SYSCALL_POSEIDON_INVALID_ENDIANNESS );
     221           3 :     return FD_VM_ERR_INVAL; /* PoseidonSyscallError::InvalidEndianness */
     222           3 :   }
     223             : 
     224             :   /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1691-L1698 */
     225             : 
     226         120 :   if( FD_UNLIKELY( vals_len > FD_VM_SYSCALL_SOL_POSEIDON_MAX_VALS ) ) {
     227             :     /* Max msg_sz = 47 - 3 + 20 = 64 < 127 => we can use printf */
     228           6 :     fd_log_collector_printf_dangerous_max_127( vm->instr_ctx,
     229           6 :       "Poseidon hashing %lu sequences is not supported", vals_len );
     230           6 :     FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_ERR_SYSCALL_INVALID_LENGTH );
     231           6 :     return FD_VM_ERR_INVAL; /* SyscallError::InvalidLength */
     232           6 :   }
     233             : 
     234             :   /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1700-L1707
     235             :      poseidon_cost(): https://github.com/solana-labs/solana/blob/v1.18.12/program-runtime/src/compute_budget.rs#L211 */
     236             : 
     237             :   /* vals_len^2 * A + C */
     238         114 :   ulong cost = fd_ulong_sat_add(
     239         114 :     fd_ulong_sat_mul(
     240         114 :       fd_ulong_sat_mul( vals_len, vals_len ),
     241         114 :       FD_VM_POSEIDON_COST_COEFFICIENT_A
     242         114 :     ),
     243         114 :     FD_VM_POSEIDON_COST_COEFFICIENT_C
     244         114 :   );
     245             : 
     246             :   /* The following can never happen, left as comment for completeness.
     247             :      if( FD_UNLIKELY( cost == ULONG_MAX ) ) {
     248             :        fd_vm_log_append_printf( vm, "Overflow while calculating the compute cost" );
     249             :        return FD_VM_ERR_INVAL; // SyscallError::ArithmeticOverflow
     250             :      }
     251             :   */
     252             : 
     253             :   /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1708 */
     254             : 
     255         114 :   FD_VM_CU_UPDATE( vm, cost );
     256             : 
     257             :   /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1710-L1715 */
     258             : 
     259         279 :   void * hash_result = FD_VM_MEM_HADDR_ST( vm, result_addr, FD_VM_ALIGN_RUST_U8, 32UL );
     260             : 
     261             :   /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1716-L1732 */
     262             : 
     263             :   /* Agave allocates a vector of translated slices (that can return a fatal
     264             :      error), and then computes Poseidon, returning a soft error in case of
     265             :      issues (e.g. invalid input).
     266             : 
     267             :      We must be careful in returning the correct fatal vs soft error.
     268             : 
     269             :      The special case of vals_len==0 returns Ok(1), so for simplicity
     270             :      we capture it explicitly. */
     271             : 
     272          90 :   if( FD_UNLIKELY( !vals_len ) ) {
     273           3 :     goto soft_error;
     274           3 :   }
     275             : 
     276             :   /* First loop to memory map. This can return a fatal error. */
     277         249 :   fd_vm_vec_t const * input_vec_haddr = (fd_vm_vec_t const *)FD_VM_MEM_HADDR_LD( vm, vals_addr, FD_VM_VEC_ALIGN, vals_len*sizeof(fd_vm_vec_t) );
     278           0 :   void const * inputs_haddr[ FD_VM_SYSCALL_SOL_POSEIDON_MAX_VALS ];
     279         393 :   for( ulong i=0UL; i<vals_len; i++ ) {
     280         630 :     inputs_haddr[i] = FD_VM_MEM_SLICE_HADDR_LD( vm, input_vec_haddr[i].addr, FD_VM_ALIGN_RUST_U8, input_vec_haddr[i].len );
     281         630 :   }
     282             : 
     283             :   /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1734-L1750
     284             :      Note: this implementation is post SIMD-0129, we only support the simplified error codes. */
     285             : 
     286             :   /* Second loop to computed Poseidon. This can return a soft error. */
     287          75 :   int big_endian = endianness==0;
     288          75 :   fd_poseidon_t pos[1];
     289          75 :   fd_poseidon_init( pos, big_endian );
     290             : 
     291         363 :   for( ulong i=0UL; i<vals_len; i++ ) {
     292         300 :     if( FD_UNLIKELY( fd_poseidon_append( pos, inputs_haddr[ i ], input_vec_haddr[i].len )==NULL ) ) {
     293          12 :       goto soft_error;
     294          12 :     }
     295         300 :   }
     296             : 
     297          63 :   ret = !fd_poseidon_fini( pos, hash_result );
     298             : 
     299          78 : soft_error:
     300          78 :   *_ret = ret;
     301          78 :   return FD_VM_SUCCESS; /* Ok(1) == error */
     302          63 : }
     303             : 
     304             : int
     305             : fd_vm_syscall_sol_secp256k1_recover( /**/            void *  _vm,
     306             :                                      /**/            ulong   hash_vaddr,
     307             :                                      /**/            ulong   recovery_id_val,
     308             :                                      /**/            ulong   signature_vaddr,
     309             :                                      /**/            ulong   result_vaddr,
     310             :                                      FD_PARAM_UNUSED ulong   r5,
     311          51 :                                      /**/            ulong * _ret ) {
     312             :   /* https://github.com/anza-xyz/agave/blob/v1.18.8/programs/bpf_loader/src/syscalls/mod.rs#L810 */
     313          51 :   fd_vm_t * vm = (fd_vm_t *)_vm;
     314             : 
     315             :   /* https://github.com/anza-xyz/agave/blob/v1.18.8/programs/bpf_loader/src/syscalls/mod.rs#L820-L821 */
     316             : 
     317          51 :   FD_VM_CU_UPDATE( vm, FD_VM_SECP256K1_RECOVER_COST );
     318             : 
     319             :   /* https://github.com/anza-xyz/agave/blob/v1.18.8/programs/bpf_loader/src/syscalls/mod.rs#L823-L840 */
     320             : 
     321         126 :   uchar const * hash    = FD_VM_MEM_HADDR_LD( vm, hash_vaddr,      FD_VM_ALIGN_RUST_U8, 32UL );
     322          99 :   uchar const * sig     = FD_VM_MEM_HADDR_LD( vm, signature_vaddr, FD_VM_ALIGN_RUST_U8, 64UL );
     323          72 :   uchar * pubkey_result = FD_VM_MEM_HADDR_ST( vm, result_vaddr,    FD_VM_ALIGN_RUST_U8, 64UL );
     324             : 
     325             :   /* CRITICAL */
     326             : 
     327             :   /* https://github.com/anza-xyz/agave/blob/v1.18.8/programs/bpf_loader/src/syscalls/mod.rs#L842-L853 */
     328             : 
     329             :   /* Secp256k1RecoverError::InvalidHash
     330             :      This can never happen, as `libsecp256k1::Message::parse_slice(hash)`
     331             :      only checks that hash is 32-byte long, and that's by construction.
     332             :      https://github.com/paritytech/libsecp256k1/blob/v0.6.0/src/lib.rs#L657-L665
     333             : 
     334             :      if( FD_UNLIKELY( 0 ) ) {
     335             :        *_ret = 1UL; // Secp256k1RecoverError::InvalidHash
     336             :        return FD_VM_SUCCESS;
     337             :      }
     338             :    */
     339             : 
     340             :   /* Secp256k1RecoverError::InvalidRecoveryId
     341             :      Agave code has 2 checks: the first is a cast from u64 to u8.
     342             :      The second is `libsecp256k1::RecoveryId::parse(adjusted_recover_id_val)` that
     343             :      checks if `adjusted_recover_id_val < 4`.
     344             :      https://github.com/paritytech/libsecp256k1/blob/v0.6.0/src/lib.rs#L674-L680
     345             :   */
     346             : 
     347          21 :   if( FD_UNLIKELY( recovery_id_val >= 4UL ) ) {
     348           6 :     *_ret = 2UL; /* Secp256k1RecoverError::InvalidRecoveryId */
     349           6 :     return FD_VM_SUCCESS;
     350           6 :   }
     351             : 
     352             :   /* Secp256k1RecoverError::InvalidSignature
     353             :      We omit this check, as this is done as part of fd_secp256k1_recover() below,
     354             :      and the return code is the same.
     355             : 
     356             :      In more details, this checks that the signature is valid, i.e. if the
     357             :      signature is represented as two scalars (r, s), it checks that both r
     358             :      and s are canonical scalars.
     359             : 
     360             :      Note the `?` at the end of this line:
     361             :      https://github.com/paritytech/libsecp256k1/blob/v0.6.0/src/lib.rs#L535
     362             :      And following the code, `scalar::check_overflow` is checks that the scalar is valid:
     363             :      https://github.com/paritytech/libsecp256k1/blob/master/core/src/scalar.rs#L70-L87 */
     364             : 
     365             :   /* https://github.com/anza-xyz/agave/blob/v1.18.8/programs/bpf_loader/src/syscalls/mod.rs#L855-L860 */
     366             : 
     367          15 :   uchar secp256k1_pubkey[64];
     368          15 :   if( FD_UNLIKELY( !fd_secp256k1_recover( secp256k1_pubkey, hash, sig, (int)recovery_id_val ) ) ) {
     369           6 :     *_ret = 3UL; /* Secp256k1RecoverError::InvalidSignature */
     370           6 :     return FD_VM_SUCCESS;
     371           6 :   }
     372             : 
     373           9 :   memcpy( pubkey_result, secp256k1_pubkey, 64UL );
     374             : 
     375           9 :   *_ret = 0UL;
     376           9 :   return FD_VM_SUCCESS;
     377          15 : }

Generated by: LCOV version 1.14