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

Generated by: LCOV version 1.14