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: 235 264 89.0 %
Date: 2026-03-19 18:19:27 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             : #include "../../runtime/fd_bank.h"
       7             : 
       8             : int
       9             : fd_vm_syscall_sol_alt_bn128_group_op( void *  _vm,
      10             :                                       ulong   group_op,
      11             :                                       ulong   input_addr,
      12             :                                       ulong   input_sz,
      13             :                                       ulong   result_addr,
      14             :                                       FD_PARAM_UNUSED ulong r5,
      15        2300 :                                       ulong * _ret ) {
      16             :   /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1509 */
      17        2300 :   fd_vm_t * vm  = (fd_vm_t *)_vm;
      18        2300 :   ulong     ret = 1UL; /* by default return Ok(1) == error */
      19             : 
      20             :   /* G1/pairing little endian syscalls are under feature gate alt_bn128_little_endian.
      21             :      To clean up the feature gate after activation, just remove this block
      22             :      (the rest of the function will behave correctly). */
      23        2300 :   {
      24        2300 :     if( FD_UNLIKELY(
      25        2300 :       !FD_FEATURE_ACTIVE_BANK( vm->instr_ctx->bank, alt_bn128_little_endian )
      26        2300 :       && ( group_op==FD_VM_SYSCALL_SOL_ALT_BN128_G1_ADD_LE
      27        2300 :         || group_op==FD_VM_SYSCALL_SOL_ALT_BN128_G1_MUL_LE
      28        2300 :         || group_op==FD_VM_SYSCALL_SOL_ALT_BN128_PAIRING_LE )
      29        2300 :     ) ) {
      30           0 :       FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE );
      31           0 :       return FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE; /* SyscallError::InvalidAttribute */
      32           0 :     }
      33        2300 :   }
      34             : 
      35             :   /* G2 syscalls are under feature gate enable_alt_bn128_g2_syscalls.
      36             :      To clean up the feature gate after activation, just remove this block
      37             :      (the rest of the function will behave correctly). */
      38        2300 :   {
      39        2300 :     if( FD_UNLIKELY(
      40        2300 :       !FD_FEATURE_ACTIVE_BANK( vm->instr_ctx->bank, enable_alt_bn128_g2_syscalls )
      41        2300 :       && ( group_op==FD_VM_SYSCALL_SOL_ALT_BN128_G2_ADD_BE
      42        2300 :         || group_op==FD_VM_SYSCALL_SOL_ALT_BN128_G2_ADD_LE
      43        2300 :         || group_op==FD_VM_SYSCALL_SOL_ALT_BN128_G2_MUL_BE
      44        2300 :         || group_op==FD_VM_SYSCALL_SOL_ALT_BN128_G2_MUL_LE )
      45        2300 :     ) ) {
      46           1 :       FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE );
      47           1 :       return FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE; /* SyscallError::InvalidAttribute */
      48           1 :     }
      49        2300 :   }
      50             : 
      51             :   /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1520-L1549 */
      52        2299 :   ulong cost = 0UL;
      53        2299 :   ulong output_sz = 0UL;
      54        2299 :   switch( group_op ) {
      55             : 
      56          26 :   case FD_VM_SYSCALL_SOL_ALT_BN128_G1_ADD_BE:
      57          26 :   case FD_VM_SYSCALL_SOL_ALT_BN128_G1_ADD_LE:
      58          26 :     output_sz = FD_VM_SYSCALL_SOL_ALT_BN128_G1_SZ;
      59          26 :     cost = FD_VM_ALT_BN128_G1_ADDITION_COST;
      60          26 :     break;
      61             : 
      62        1780 :   case FD_VM_SYSCALL_SOL_ALT_BN128_G1_MUL_BE:
      63        1780 :   case FD_VM_SYSCALL_SOL_ALT_BN128_G1_MUL_LE:
      64        1780 :     output_sz = FD_VM_SYSCALL_SOL_ALT_BN128_G1_SZ;
      65        1780 :     cost = FD_VM_ALT_BN128_G1_MULTIPLICATION_COST;
      66        1780 :     break;
      67             : 
      68           0 :   case FD_VM_SYSCALL_SOL_ALT_BN128_G2_ADD_BE:
      69           0 :   case FD_VM_SYSCALL_SOL_ALT_BN128_G2_ADD_LE:
      70           0 :     output_sz = FD_VM_SYSCALL_SOL_ALT_BN128_G2_SZ;
      71           0 :     cost = FD_VM_ALT_BN128_G2_ADDITION_COST;
      72           0 :     break;
      73             : 
      74           0 :   case FD_VM_SYSCALL_SOL_ALT_BN128_G2_MUL_BE:
      75           0 :   case FD_VM_SYSCALL_SOL_ALT_BN128_G2_MUL_LE:
      76           0 :     output_sz = FD_VM_SYSCALL_SOL_ALT_BN128_G2_SZ;
      77           0 :     cost = FD_VM_ALT_BN128_G2_MULTIPLICATION_COST;
      78           0 :     break;
      79             : 
      80         491 :   case FD_VM_SYSCALL_SOL_ALT_BN128_PAIRING_BE:
      81         491 :   case FD_VM_SYSCALL_SOL_ALT_BN128_PAIRING_LE:
      82         491 :     output_sz = FD_VM_SYSCALL_SOL_ALT_BN128_PAIRING_OUTPUT_SZ;
      83         491 :     ulong elements_len = input_sz / FD_VM_SYSCALL_SOL_ALT_BN128_PAIRING_INPUT_EL_SZ;
      84         491 :     cost = FD_VM_ALT_BN128_PAIRING_ONE_PAIR_COST_FIRST
      85         491 :       + FD_VM_SHA256_BASE_COST
      86         491 :       + FD_VM_SYSCALL_SOL_ALT_BN128_PAIRING_OUTPUT_SZ;
      87         491 :     cost = fd_ulong_sat_add( cost,
      88         491 :       fd_ulong_sat_mul( FD_VM_ALT_BN128_PAIRING_ONE_PAIR_COST_OTHER,
      89         491 :         fd_ulong_sat_sub( elements_len, 1 ) ) );
      90         491 :     cost = fd_ulong_sat_add( cost, input_sz );
      91         491 :     break;
      92             : 
      93           1 :   default:
      94           1 :     FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE );
      95           1 :     return FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE; /* SyscallError::InvalidAttribute */
      96        2299 :   }
      97             : 
      98             :   /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1551 */
      99             : 
     100        4579 :   FD_VM_CU_UPDATE( vm, cost );
     101             : 
     102        2280 :   uchar * call_result = FD_VM_HADDR_QUERY_U8_SLICE( vm, result_addr, output_sz );
     103        4553 :   uchar const * input = FD_VM_MEM_SLICE_HADDR_LD( vm, input_addr,  FD_VM_ALIGN_RUST_U8, input_sz );
     104             : 
     105        2275 :   int big_endian = ( group_op & FD_VM_SYSCALL_SOL_ALT_BN128_LITTLE_ENDIAN_FLAG ) ? 0 : 1;
     106             : 
     107             :   /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1567-L1598
     108             :      Note: this implementation is post SIMD-0129, we only support the simplified error codes. */
     109        4553 :   switch( group_op ) {
     110             : 
     111          21 :   case FD_VM_SYSCALL_SOL_ALT_BN128_G1_ADD_BE:
     112          21 :   case FD_VM_SYSCALL_SOL_ALT_BN128_G1_ADD_LE:
     113             :     /* Compute add */
     114          21 :     if( FD_LIKELY( fd_bn254_g1_add_syscall( call_result, input, input_sz, big_endian )==0 ) ) {
     115          13 :       ret = 0UL; /* success */
     116          13 :     }
     117          21 :     break;
     118             : 
     119        1777 :   case FD_VM_SYSCALL_SOL_ALT_BN128_G1_MUL_BE:
     120        1777 :   case FD_VM_SYSCALL_SOL_ALT_BN128_G1_MUL_LE:
     121             :     /* Compute scalar mul */
     122        1777 :     if( FD_LIKELY( fd_bn254_g1_scalar_mul_syscall( call_result, input, input_sz, big_endian )==0 ) ) {
     123         466 :       ret = 0UL; /* success */
     124         466 :     }
     125        1777 :     break;
     126             : 
     127           0 :   case FD_VM_SYSCALL_SOL_ALT_BN128_G2_ADD_BE:
     128           0 :   case FD_VM_SYSCALL_SOL_ALT_BN128_G2_ADD_LE:
     129             :     /* Compute add */
     130           0 :     if( FD_LIKELY( fd_bn254_g2_add_syscall( call_result, input, input_sz, big_endian )==0 ) ) {
     131           0 :       ret = 0UL; /* success */
     132           0 :     }
     133           0 :     break;
     134             : 
     135           0 :   case FD_VM_SYSCALL_SOL_ALT_BN128_G2_MUL_BE:
     136           0 :   case FD_VM_SYSCALL_SOL_ALT_BN128_G2_MUL_LE:
     137             :     /* Compute scalar mul */
     138           0 :     if( FD_LIKELY( fd_bn254_g2_scalar_mul_syscall( call_result, input, input_sz, big_endian )==0 ) ) {
     139           0 :       ret = 0UL; /* success */
     140           0 :     }
     141           0 :     break;
     142             : 
     143         478 :   case FD_VM_SYSCALL_SOL_ALT_BN128_PAIRING_BE:
     144         478 :   case FD_VM_SYSCALL_SOL_ALT_BN128_PAIRING_LE:
     145             :     /* Compute pairing with length check based on feature gate.
     146             :        https://github.com/anza-xyz/solana-sdk/blob/bn254%40v3.1.2/bn254/src/pairing.rs#L76-L82 */
     147         478 :     if( FD_LIKELY( fd_bn254_pairing_is_one_syscall( call_result, input, input_sz, big_endian,
     148         478 :                                                     FD_FEATURE_ACTIVE_BANK( vm->instr_ctx->bank, fix_alt_bn128_pairing_length_check ) )==0 ) ) {
     149          91 :       ret = 0UL; /* success */
     150          91 :     }
     151         478 :     break;
     152        4553 :   }
     153             : 
     154        2280 :   *_ret = ret;
     155        2280 :   return FD_VM_SUCCESS; /* Ok(SUCCESS) or Ok(ERROR) */
     156        4553 : }
     157             : 
     158             : int
     159             : fd_vm_syscall_sol_alt_bn128_compression( void *  _vm,
     160             :                                          ulong   op,
     161             :                                          ulong   input_addr,
     162             :                                          ulong   input_sz,
     163             :                                          ulong   result_addr,
     164             :                                          FD_PARAM_UNUSED ulong r5,
     165         961 :                                          ulong * _ret ) {
     166             :   /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1776 */
     167         961 :   fd_vm_t * vm  = (fd_vm_t *)_vm;
     168         961 :   ulong     ret = 1UL; /* by default return Ok(1) == error */
     169             : 
     170             :   /* G1/G2 little endian syscalls are under feature gate alt_bn128_little_endian.
     171             :      To clean up the feature gate after activation, just remove this block
     172             :      (the rest of the function will behave correctly). */
     173         961 :   {
     174         961 :     if( FD_UNLIKELY(
     175         961 :       !FD_FEATURE_ACTIVE_BANK( vm->instr_ctx->bank, alt_bn128_little_endian )
     176         961 :       && ( op==FD_VM_SYSCALL_SOL_ALT_BN128_G1_COMPRESS_LE
     177         961 :         || op==FD_VM_SYSCALL_SOL_ALT_BN128_G2_COMPRESS_LE
     178         961 :         || op==FD_VM_SYSCALL_SOL_ALT_BN128_G1_DECOMPRESS_LE
     179         961 :         || op==FD_VM_SYSCALL_SOL_ALT_BN128_G2_DECOMPRESS_LE )
     180         961 :     ) ) {
     181           0 :       FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE );
     182           0 :       return FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE; /* SyscallError::InvalidAttribute */
     183           0 :     }
     184         961 :   }
     185             : 
     186             :   /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1791-L1811 */
     187         961 :   ulong cost = 0UL;
     188         961 :   ulong output_sz = 0UL;
     189         961 :   switch( op ) {
     190             : 
     191         210 :   case FD_VM_SYSCALL_SOL_ALT_BN128_G1_COMPRESS_BE:
     192         210 :   case FD_VM_SYSCALL_SOL_ALT_BN128_G1_COMPRESS_LE:
     193         210 :     output_sz = FD_VM_SYSCALL_SOL_ALT_BN128_G1_COMPRESSED_SZ;
     194         210 :     cost = FD_VM_ALT_BN128_G1_COMPRESS;
     195         210 :     break;
     196             : 
     197         204 :   case FD_VM_SYSCALL_SOL_ALT_BN128_G1_DECOMPRESS_BE:
     198         204 :   case FD_VM_SYSCALL_SOL_ALT_BN128_G1_DECOMPRESS_LE:
     199         204 :     output_sz = FD_VM_SYSCALL_SOL_ALT_BN128_G1_SZ;
     200         204 :     cost = FD_VM_ALT_BN128_G1_DECOMPRESS;
     201         204 :     break;
     202             : 
     203         272 :   case FD_VM_SYSCALL_SOL_ALT_BN128_G2_COMPRESS_BE:
     204         272 :   case FD_VM_SYSCALL_SOL_ALT_BN128_G2_COMPRESS_LE:
     205         272 :     output_sz = FD_VM_SYSCALL_SOL_ALT_BN128_G2_COMPRESSED_SZ;
     206         272 :     cost = FD_VM_ALT_BN128_G2_COMPRESS;
     207         272 :     break;
     208             : 
     209         270 :   case FD_VM_SYSCALL_SOL_ALT_BN128_G2_DECOMPRESS_BE:
     210         270 :   case FD_VM_SYSCALL_SOL_ALT_BN128_G2_DECOMPRESS_LE:
     211         270 :     output_sz = FD_VM_SYSCALL_SOL_ALT_BN128_G2_SZ;
     212         270 :     cost = FD_VM_ALT_BN128_G2_DECOMPRESS;
     213         270 :     break;
     214             : 
     215           3 :   default:
     216           3 :     FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE );
     217           3 :     return FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE; /* SyscallError::InvalidAttribute */
     218         961 :   }
     219         956 :   cost = fd_ulong_sat_add( cost, FD_VM_SYSCALL_BASE_COST );
     220             : 
     221             :   /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1813 */
     222             : 
     223         956 :   FD_VM_CU_UPDATE( vm, cost );
     224             : 
     225             :   /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1815-L1827 */
     226             : 
     227         947 :   uchar * call_result = FD_VM_HADDR_QUERY_U8_SLICE( vm, result_addr, output_sz );
     228        1890 :   void const * input  = FD_VM_MEM_SLICE_HADDR_LD( vm, input_addr,  FD_VM_ALIGN_RUST_U8, input_sz );
     229             : 
     230         943 :   int big_endian = ( op & FD_VM_SYSCALL_SOL_ALT_BN128_LITTLE_ENDIAN_FLAG ) ? 0 : 1;
     231             : 
     232             :   /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1829-L1891
     233             :      Note: this implementation is post SIMD-0129, we only support the simplified error codes. */
     234        1890 :   switch( op ) {
     235             : 
     236         207 :   case FD_VM_SYSCALL_SOL_ALT_BN128_G1_COMPRESS_BE:
     237         207 :   case FD_VM_SYSCALL_SOL_ALT_BN128_G1_COMPRESS_LE:
     238         207 :     if( FD_UNLIKELY( input_sz!=FD_VM_SYSCALL_SOL_ALT_BN128_G1_SZ ) ) {
     239           3 :       goto soft_error;
     240           3 :     }
     241         204 :     if( FD_LIKELY( fd_bn254_g1_compress( call_result, fd_type_pun_const(input), big_endian ) ) ) {
     242          66 :       ret = 0UL; /* success */
     243          66 :     }
     244         204 :     break;
     245             : 
     246         201 :   case FD_VM_SYSCALL_SOL_ALT_BN128_G1_DECOMPRESS_BE:
     247         201 :   case FD_VM_SYSCALL_SOL_ALT_BN128_G1_DECOMPRESS_LE:
     248         201 :     if( FD_UNLIKELY( input_sz!=FD_VM_SYSCALL_SOL_ALT_BN128_G1_COMPRESSED_SZ ) ) {
     249           3 :       goto soft_error;
     250           3 :     }
     251         198 :     if( FD_LIKELY( fd_bn254_g1_decompress( call_result, fd_type_pun_const(input), big_endian ) ) ) {
     252         138 :       ret = 0UL; /* success */
     253         138 :     }
     254         198 :     break;
     255             : 
     256         268 :   case FD_VM_SYSCALL_SOL_ALT_BN128_G2_COMPRESS_BE:
     257         268 :   case FD_VM_SYSCALL_SOL_ALT_BN128_G2_COMPRESS_LE:
     258         268 :     if( FD_UNLIKELY( input_sz!=FD_VM_SYSCALL_SOL_ALT_BN128_G2_SZ ) ) {
     259           7 :       goto soft_error;
     260           7 :     }
     261         261 :     if( FD_LIKELY( fd_bn254_g2_compress( call_result, fd_type_pun_const(input), big_endian ) ) ) {
     262          38 :       ret = 0UL; /* success */
     263          38 :     }
     264         261 :     break;
     265             : 
     266         268 :   case FD_VM_SYSCALL_SOL_ALT_BN128_G2_DECOMPRESS_BE:
     267         268 :   case FD_VM_SYSCALL_SOL_ALT_BN128_G2_DECOMPRESS_LE:
     268         268 :     if( FD_UNLIKELY( input_sz!=FD_VM_SYSCALL_SOL_ALT_BN128_G2_COMPRESSED_SZ ) ) {
     269           2 :       goto soft_error;
     270           2 :     }
     271         266 :     if( FD_LIKELY( fd_bn254_g2_decompress( call_result, fd_type_pun_const(input), big_endian ) ) ) {
     272         138 :       ret = 0UL; /* success */
     273         138 :     }
     274         266 :     break;
     275        1890 :   }
     276             : 
     277         942 : soft_error:
     278         942 :   *_ret = ret;
     279         942 :   return FD_VM_SUCCESS; /* Ok(SUCCESS) or Ok(ERROR) */
     280        1890 : }
     281             : 
     282             : int
     283             : fd_vm_syscall_sol_poseidon( void *  _vm,
     284             :                             ulong   params,
     285             :                             ulong   endianness,
     286             :                             ulong   vals_addr,
     287             :                             ulong   vals_len,
     288             :                             ulong   result_addr,
     289          75 :                             ulong * _ret ) {
     290             :   /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1678 */
     291          75 :   fd_vm_t * vm  = (fd_vm_t *)_vm;
     292          75 :   ulong     ret = 1UL; /* by default return Ok(1) == error */
     293             : 
     294             :   /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1688 */
     295             : 
     296          75 :   if( FD_UNLIKELY( params!=0UL ) ) {
     297           1 :     FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_POSEIDON_INVALID_PARAMS );
     298           1 :     return FD_VM_SYSCALL_ERR_POSEIDON_INVALID_PARAMS; /* PoseidonSyscallError::InvalidParameters */
     299           1 :   }
     300             : 
     301             :   /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1689 */
     302             : 
     303          74 :   if( FD_UNLIKELY(
     304          74 :        endianness!=0UL /* Big endian */
     305          74 :     && endianness!=1UL /* Little endian */
     306          74 :   ) ) {
     307           1 :     FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_POSEIDON_INVALID_ENDIANNESS );
     308           1 :     return FD_VM_SYSCALL_ERR_POSEIDON_INVALID_ENDIANNESS; /* PoseidonSyscallError::InvalidEndianness */
     309           1 :   }
     310             : 
     311             :   /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1691-L1698 */
     312             : 
     313          73 :   if( FD_UNLIKELY( vals_len > FD_VM_SYSCALL_SOL_POSEIDON_MAX_VALS ) ) {
     314             :     /* Max msg_sz = 47 - 3 + 20 = 64 < 127 => we can use printf */
     315           2 :     fd_log_collector_printf_dangerous_max_127( vm->instr_ctx,
     316           2 :       "Poseidon hashing %lu sequences is not supported", vals_len );
     317           2 :     FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_INVALID_LENGTH );
     318           2 :     return FD_VM_SYSCALL_ERR_INVALID_LENGTH; /* SyscallError::InvalidLength */
     319           2 :   }
     320             : 
     321             :   /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1700-L1707
     322             :      poseidon_cost(): https://github.com/solana-labs/solana/blob/v1.18.12/program-runtime/src/compute_budget.rs#L211 */
     323             : 
     324             :   /* vals_len^2 * A + C */
     325          71 :   ulong cost = fd_ulong_sat_add(
     326          71 :     fd_ulong_sat_mul(
     327          71 :       fd_ulong_sat_mul( vals_len, vals_len ),
     328          71 :       FD_VM_POSEIDON_COST_COEFFICIENT_A
     329          71 :     ),
     330          71 :     FD_VM_POSEIDON_COST_COEFFICIENT_C
     331          71 :   );
     332             : 
     333             :   /* The following can never happen, left as comment for completeness.
     334             :      if( FD_UNLIKELY( cost == ULONG_MAX ) ) {
     335             :        fd_vm_log_append_printf( vm, "Overflow while calculating the compute cost" );
     336             :        return FD_VM_SYSCALL_ERR_ARITHMETIC_OVERFLOW; // SyscallError::ArithmeticOverflow
     337             :      }
     338             :   */
     339             : 
     340             :   /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1708 */
     341             : 
     342          71 :   FD_VM_CU_UPDATE( vm, cost );
     343             : 
     344             :   /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1710-L1715 */
     345             : 
     346          61 :   uchar * hash_result = FD_VM_HADDR_QUERY_U8_SLICE( vm, result_addr, 32UL );
     347             : 
     348             :   /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1716-L1732 */
     349             : 
     350             :   /* Agave allocates a vector of translated slices (that can return a fatal
     351             :      error), and then computes Poseidon, returning a soft error in case of
     352             :      issues (e.g. invalid input).
     353             : 
     354             :      We must be careful in returning the correct fatal vs soft error.
     355             : 
     356             :      The special case of vals_len==0 returns Ok(1), so for simplicity
     357             :      we capture it explicitly. */
     358             : 
     359          61 :   if( FD_UNLIKELY( !vals_len ) ) {
     360           3 :     goto soft_error;
     361           3 :   }
     362             : 
     363             :   /* First loop to memory map. This can return a fatal error. */
     364         170 :   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) );
     365           0 :   void const * inputs_haddr[ FD_VM_SYSCALL_SOL_POSEIDON_MAX_VALS ];
     366         302 :   for( ulong i=0UL; i<vals_len; i++ ) {
     367         498 :     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 );
     368         498 :   }
     369             : 
     370             :   /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1734-L1750
     371             :      Note: this implementation is post SIMD-0129, we only support the simplified error codes. */
     372             : 
     373             :   /* Second loop to computed Poseidon. This can return a soft error. */
     374          50 :   int big_endian = endianness==0;
     375          50 :   int enforce_padding = FD_FEATURE_ACTIVE_BANK( vm->instr_ctx->bank, poseidon_enforce_padding );
     376          50 :   fd_poseidon_t pos[1];
     377          50 :   fd_poseidon_init( pos, big_endian );
     378             : 
     379         288 :   for( ulong i=0UL; i<vals_len; i++ ) {
     380         242 :     if( FD_UNLIKELY( fd_poseidon_append( pos, inputs_haddr[ i ], input_vec_haddr[i].len, enforce_padding )==NULL ) ) {
     381           4 :       goto soft_error;
     382           4 :     }
     383         242 :   }
     384             : 
     385          46 :   ret = !fd_poseidon_fini( pos, hash_result );
     386             : 
     387          53 : soft_error:
     388          53 :   *_ret = ret;
     389          53 :   return FD_VM_SUCCESS; /* Ok(1) == error */
     390          46 : }
     391             : 
     392             : #if FD_HAS_S2NBIGNUM
     393             : 
     394             : int
     395             : fd_vm_syscall_sol_secp256k1_recover( /**/            void *  _vm,
     396             :                                      /**/            ulong   hash_vaddr,
     397             :                                      /**/            ulong   recovery_id_val,
     398             :                                      /**/            ulong   signature_vaddr,
     399             :                                      /**/            ulong   result_vaddr,
     400             :                                      FD_PARAM_UNUSED ulong   r5,
     401         122 :                                      /**/            ulong * _ret ) {
     402             :   /* https://github.com/anza-xyz/agave/blob/v1.18.8/programs/bpf_loader/src/syscalls/mod.rs#L810 */
     403         122 :   fd_vm_t * vm = (fd_vm_t *)_vm;
     404             : 
     405             :   /* https://github.com/anza-xyz/agave/blob/v1.18.8/programs/bpf_loader/src/syscalls/mod.rs#L820-L821 */
     406             : 
     407         122 :   FD_VM_CU_UPDATE( vm, FD_VM_SECP256K1_RECOVER_COST );
     408             : 
     409             :   /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L957-L968 */
     410             : 
     411         102 :   uchar * pubkey_result = FD_VM_HADDR_QUERY_U8_SLICE( vm, result_vaddr, 64UL );
     412         300 :   uchar const * hash = FD_VM_MEM_HADDR_LD( vm, hash_vaddr,      FD_VM_ALIGN_RUST_U8, 32UL );
     413         291 :   uchar const * sig  = FD_VM_MEM_HADDR_LD( vm, signature_vaddr, FD_VM_ALIGN_RUST_U8, 64UL );
     414             : 
     415             :   /* CRITICAL */
     416             : 
     417             :   /* https://github.com/anza-xyz/agave/blob/v1.18.8/programs/bpf_loader/src/syscalls/mod.rs#L842-L853 */
     418             : 
     419             :   /* Secp256k1RecoverError::InvalidHash
     420             :      This can never happen, as `libsecp256k1::Message::parse_slice(hash)`
     421             :      only checks that hash is 32-byte long, and that's by construction.
     422             :      https://github.com/paritytech/libsecp256k1/blob/v0.6.0/src/lib.rs#L657-L665
     423             : 
     424             :      if( FD_UNLIKELY( 0 ) ) {
     425             :        *_ret = 1UL; // Secp256k1RecoverError::InvalidHash
     426             :        return FD_VM_SUCCESS;
     427             :      }
     428             :    */
     429             : 
     430             :   /* Secp256k1RecoverError::InvalidRecoveryId
     431             :      Agave code has 2 checks: the first is a cast from u64 to u8.
     432             :      The second is `libsecp256k1::RecoveryId::parse(adjusted_recover_id_val)` that
     433             :      checks if `adjusted_recover_id_val < 4`.
     434             :      https://github.com/paritytech/libsecp256k1/blob/v0.6.0/src/lib.rs#L674-L680
     435             :   */
     436             : 
     437          96 :   if( FD_UNLIKELY( recovery_id_val >= 4UL ) ) {
     438           2 :     *_ret = 2UL; /* Secp256k1RecoverError::InvalidRecoveryId */
     439           2 :     return FD_VM_SUCCESS;
     440           2 :   }
     441             : 
     442             :   /* Secp256k1RecoverError::InvalidSignature
     443             :      We omit this check, as this is done as part of fd_secp256k1_recover() below,
     444             :      and the return code is the same.
     445             : 
     446             :      In more details, this checks that the signature is valid, i.e. if the
     447             :      signature is represented as two scalars (r, s), it checks that both r
     448             :      and s are canonical scalars.
     449             : 
     450             :      Note the `?` at the end of this line:
     451             :      https://github.com/paritytech/libsecp256k1/blob/v0.6.0/src/lib.rs#L535
     452             :      And following the code, `scalar::check_overflow` is checks that the scalar is valid:
     453             :      https://github.com/paritytech/libsecp256k1/blob/master/core/src/scalar.rs#L70-L87 */
     454             : 
     455             :   /* https://github.com/anza-xyz/agave/blob/v1.18.8/programs/bpf_loader/src/syscalls/mod.rs#L855-L860 */
     456             : 
     457          94 :   uchar secp256k1_pubkey[64];
     458          94 :   if( FD_UNLIKELY( !fd_secp256k1_recover( secp256k1_pubkey, hash, sig, (int)recovery_id_val ) ) ) {
     459           2 :     *_ret = 3UL; /* Secp256k1RecoverError::InvalidSignature */
     460           2 :     return FD_VM_SUCCESS;
     461           2 :   }
     462             : 
     463          92 :   memcpy( pubkey_result, secp256k1_pubkey, 64UL );
     464             : 
     465          92 :   *_ret = 0UL;
     466          92 :   return FD_VM_SUCCESS;
     467          94 : }
     468             : 
     469             : #endif /* FD_HAS_S2NBIGNUM */

Generated by: LCOV version 1.14