LCOV - code coverage report
Current view: top level - flamenco/vm/syscall - fd_vm_syscall_curve.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 483 600 80.5 %
Date: 2026-11-11 12:40:43 Functions: 7 7 100.0 %

          Line data    Source code
       1             : #include "fd_vm_syscall.h"
       2             : #include "../../../ballet/ed25519/fd_curve25519.h"
       3             : #include "../../../ballet/ed25519/fd_ristretto255.h"
       4             : #include "../../../ballet/bls/fd_bls12_381.h"
       5             : #include "../../../ballet/secp256r1/fd_secp256r1.h"
       6             : 
       7             : int
       8             : fd_vm_syscall_sol_curve_validate_point( /**/            void *  _vm,
       9             :                                         /**/            ulong   curve_id,
      10             :                                         /**/            ulong   point_addr,
      11             :                                         FD_PARAM_UNUSED ulong   r3,
      12             :                                         FD_PARAM_UNUSED ulong   r4,
      13         505 :                                         FD_PARAM_UNUSED ulong   r5 ) {
      14             :   /* https://github.com/anza-xyz/agave/blob/v1.18.8/programs/bpf_loader/src/syscalls/mod.rs#L871 */
      15         505 :   fd_vm_t * vm = (fd_vm_t *)_vm;
      16         505 :   ulong     ret = 1UL; /* by default return Ok(1) == error */
      17             : 
      18             :   /* secp256r1 syscalls are under feature gate secp256r1_syscall_enabled.
      19             :      To clean up the feature gate after activation, just remove this block
      20             :      (the rest of the function will behave correctly). */
      21         505 :   {
      22         505 :     if( FD_UNLIKELY(
      23         505 :       !FD_FEATURE_ACTIVE_BANK( vm->instr_ctx->bank, secp256r1_syscall_enabled )
      24         505 :       && ( curve_id==FD_VM_SYSCALL_SOL_CURVE_SECP256R1_BE
      25         505 :         || curve_id==FD_VM_SYSCALL_SOL_CURVE_SECP256R1_LE )
      26         505 :     ) ) {
      27           0 :       FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE );
      28           0 :       return FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE; /* SyscallError::InvalidAttribute */
      29           0 :     }
      30         505 :   }
      31             : 
      32         505 :   uchar const * point = NULL;
      33         505 :   switch( curve_id ) {
      34             : 
      35         152 :   case FD_VM_SYSCALL_SOL_CURVE_CURVE25519_EDWARDS:
      36             : 
      37         152 :     FD_VM_CU_UPDATE( vm, FD_VM_CURVE_EDWARDS_VALIDATE_POINT_COST );
      38         151 :     point = FD_VM_MEM_HADDR_LD( vm, point_addr, FD_VM_ALIGN_RUST_POD_U8_ARRAY, FD_VM_SYSCALL_SOL_CURVE_CURVE25519_POINT_SZ );
      39           0 :     ret = (ulong)!fd_ed25519_point_validate( point ); /* 0 if valid point, 1 if not */
      40         150 :     break;
      41             : 
      42         148 :   case FD_VM_SYSCALL_SOL_CURVE_CURVE25519_RISTRETTO:
      43             : 
      44         148 :     FD_VM_CU_UPDATE( vm, FD_VM_CURVE_RISTRETTO_VALIDATE_POINT_COST );
      45         147 :     point = FD_VM_MEM_HADDR_LD( vm, point_addr, FD_VM_ALIGN_RUST_POD_U8_ARRAY, FD_VM_SYSCALL_SOL_CURVE_CURVE25519_POINT_SZ );
      46           0 :     ret = (ulong)!fd_ristretto255_point_validate( point ); /* 0 if valid point, 1 if not */
      47         146 :     break;
      48             : 
      49          47 :   case FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G1_BE:
      50         103 :   case FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G1_LE: {
      51             : 
      52         103 :     int big_endian = ( curve_id & 0x80 ) ? 1 : 0;
      53         103 :     FD_VM_CU_UPDATE( vm, FD_VM_CURVE_BLS12_381_G1_VALIDATE_COST );
      54         103 :     point = FD_VM_MEM_HADDR_LD( vm, point_addr, FD_VM_ALIGN_RUST_POD_U8_ARRAY, FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G1_POINT_SZ );
      55           0 :     ret = (ulong)!fd_bls12_381_g1_validate_syscall( point, big_endian ); /* 0 if valid point, 1 if not */
      56         103 :   } break;
      57             : 
      58          43 :   case FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G2_BE:
      59          99 :   case FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G2_LE: {
      60             : 
      61          99 :     int big_endian = ( curve_id & 0x80 ) ? 1 : 0;
      62          99 :     FD_VM_CU_UPDATE( vm, FD_VM_CURVE_BLS12_381_G2_VALIDATE_COST );
      63          99 :     point = FD_VM_MEM_HADDR_LD( vm, point_addr, FD_VM_ALIGN_RUST_POD_U8_ARRAY, FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G2_POINT_SZ );
      64           0 :     ret = (ulong)!fd_bls12_381_g2_validate_syscall( point, big_endian ); /* 0 if valid point, 1 if not */
      65          99 :   } break;
      66             : 
      67           0 :   case FD_VM_SYSCALL_SOL_CURVE_SECP256R1_BE:
      68           0 :   case FD_VM_SYSCALL_SOL_CURVE_SECP256R1_LE: {
      69             : 
      70           0 :     int big_endian = ( curve_id & 0x80 ) ? 1 : 0;
      71           0 :     FD_VM_CU_UPDATE( vm, FD_VM_CURVE_SECP256R1_VALIDATE_COST );
      72           0 :     point = FD_VM_MEM_HADDR_LD( vm, point_addr, FD_VM_ALIGN_RUST_POD_U8_ARRAY, FD_VM_SYSCALL_SOL_CURVE_SECP256R1_POINT_SZ );
      73           0 :     ret = (ulong)!fd_secp256r1_validate_syscall( point, big_endian ); /* 0 if valid point, 1 if not */
      74           0 :   } break;
      75             : 
      76           3 :   default:
      77             :     /* https://github.com/anza-xyz/agave/blob/5b3390b99a6e7665439c623062c1a1dda2803524/programs/bpf_loader/src/syscalls/mod.rs#L919-L928 */
      78           3 :     FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE );
      79           3 :     return FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE; /* SyscallError::InvalidAttribute */
      80         505 :   }
      81             : 
      82         498 :   vm->reg[0] = ret;
      83         498 :   return FD_VM_SUCCESS;
      84         505 : }
      85             : 
      86             : int
      87             : fd_vm_syscall_sol_curve_group_op( void *  _vm,
      88             :                                   ulong   curve_id,
      89             :                                   ulong   group_op,
      90             :                                   ulong   left_input_addr,
      91             :                                   ulong   right_input_addr,
      92         647 :                                   ulong   result_point_addr ) {
      93             :   /* https://github.com/anza-xyz/agave/blob/v1.18.8/programs/bpf_loader/src/syscalls/mod.rs#L928 */
      94         647 :   fd_vm_t * vm = (fd_vm_t *)_vm;
      95         647 :   ulong     ret = 1UL; /* by default return Ok(1) == error */
      96             : 
      97             :   /* secp256r1 syscalls are under feature gate secp256r1_syscall_enabled.
      98             :      To clean up the feature gate after activation, just remove this block
      99             :      (the rest of the function will behave correctly). */
     100         647 :   {
     101         647 :     if( FD_UNLIKELY(
     102         647 :       !FD_FEATURE_ACTIVE_BANK( vm->instr_ctx->bank, secp256r1_syscall_enabled )
     103         647 :       && ( curve_id==FD_VM_SYSCALL_SOL_CURVE_SECP256R1_BE
     104         647 :         || curve_id==FD_VM_SYSCALL_SOL_CURVE_SECP256R1_LE )
     105         647 :     ) ) {
     106           0 :       FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE );
     107           0 :       return FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE; /* SyscallError::InvalidAttribute */
     108           0 :     }
     109         647 :   }
     110             : 
     111             :   /* Note: we don't strictly follow the Rust implementation, but instead combine
     112             :      common code across switch cases. Similar to fd_vm_syscall_sol_alt_bn128_group_op. */
     113             : 
     114             : /* MATCH_ID_OP allows us to unify 2 switch/case into 1.
     115             :    For better readability, we also temp define EDWARDS, RISTRETTO.
     116             : 
     117             :    The first time we check that both curve_id and group_op are valid
     118             :    with 2 nested switch/case. Using MATCH_ID_OP leads to undesidered
     119             :    edge cases. The second time, when we know that curve_id and group_op
     120             :    are correct, then we can use MATCH_ID_OP and a single switch/case. */
     121        1354 : #define MATCH_ID_OP(crv_id,grp_op) ((crv_id << 4) | grp_op)
     122         647 : #define EDWARDS   FD_VM_SYSCALL_SOL_CURVE_CURVE25519_EDWARDS
     123         647 : #define RISTRETTO FD_VM_SYSCALL_SOL_CURVE_CURVE25519_RISTRETTO
     124         647 : #define BLS_G1_BE FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G1_BE
     125         647 : #define BLS_G1_LE FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G1_LE
     126         647 : #define BLS_G2_BE FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G2_BE
     127         647 : #define BLS_G2_LE FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G2_LE
     128         647 : #define P256_BE   FD_VM_SYSCALL_SOL_CURVE_SECP256R1_BE
     129         647 : #define P256_LE   FD_VM_SYSCALL_SOL_CURVE_SECP256R1_LE
     130             : 
     131         647 :   ulong cost = 0UL;
     132         647 :   ulong inputL_sz = 32UL;
     133         647 :   ulong inputR_sz = 32UL;
     134         647 :   switch( curve_id ) {
     135             : 
     136         202 :   case EDWARDS:
     137         202 :     switch( group_op ) {
     138             : 
     139          61 :     case FD_VM_SYSCALL_SOL_CURVE_ADD:
     140          61 :       cost = FD_VM_CURVE_EDWARDS_ADD_COST;
     141          61 :       break;
     142             : 
     143          53 :     case FD_VM_SYSCALL_SOL_CURVE_SUB:
     144          53 :       cost = FD_VM_CURVE_EDWARDS_SUBTRACT_COST;
     145          53 :       break;
     146             : 
     147          87 :     case FD_VM_SYSCALL_SOL_CURVE_MUL:
     148          87 :       cost = FD_VM_CURVE_EDWARDS_MULTIPLY_COST;
     149          87 :       break;
     150             : 
     151           2 :     default:
     152           2 :       goto invalid_error;
     153         202 :     }
     154         200 :     break;
     155             : 
     156         200 :   case RISTRETTO:
     157         170 :     switch( group_op ) {
     158             : 
     159          48 :     case FD_VM_SYSCALL_SOL_CURVE_ADD:
     160          48 :       cost = FD_VM_CURVE_RISTRETTO_ADD_COST;
     161          48 :       break;
     162             : 
     163          54 :     case FD_VM_SYSCALL_SOL_CURVE_SUB:
     164          54 :       cost = FD_VM_CURVE_RISTRETTO_SUBTRACT_COST;
     165          54 :       break;
     166             : 
     167          66 :     case FD_VM_SYSCALL_SOL_CURVE_MUL:
     168          66 :       cost = FD_VM_CURVE_RISTRETTO_MULTIPLY_COST;
     169          66 :       break;
     170             : 
     171           2 :     default:
     172           2 :       goto invalid_error;
     173         170 :     }
     174         168 :     break;
     175             : 
     176             :   /* BLS12-381 G1 */
     177         168 :   case BLS_G1_BE:
     178         138 :   case BLS_G1_LE:
     179         138 :     switch( group_op ) {
     180             : 
     181          41 :     case FD_VM_SYSCALL_SOL_CURVE_ADD:
     182          41 :       cost = FD_VM_CURVE_BLS12_381_G1_ADD_COST;
     183          41 :       inputL_sz = FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G1_POINT_SZ;
     184          41 :       inputR_sz = FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G1_POINT_SZ;
     185          41 :       break;
     186             : 
     187          49 :     case FD_VM_SYSCALL_SOL_CURVE_SUB:
     188          49 :       cost = FD_VM_CURVE_BLS12_381_G1_SUB_COST;
     189          49 :       inputL_sz = FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G1_POINT_SZ;
     190          49 :       inputR_sz = FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G1_POINT_SZ;
     191          49 :       break;
     192             : 
     193          47 :     case FD_VM_SYSCALL_SOL_CURVE_MUL:
     194          47 :       cost = FD_VM_CURVE_BLS12_381_G1_MUL_COST;
     195             :       /* inputL_sz = 32UL // scalar */
     196          47 :       inputR_sz = FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G1_POINT_SZ;
     197          47 :       break;
     198             : 
     199           1 :     default:
     200           1 :       goto invalid_error;
     201         138 :     }
     202         137 :     break;
     203             : 
     204             :   /* BLS12-381 G2 */
     205         137 :   case BLS_G2_BE:
     206         134 :   case BLS_G2_LE:
     207         134 :     switch( group_op ) {
     208             : 
     209          44 :     case FD_VM_SYSCALL_SOL_CURVE_ADD:
     210          44 :       cost = FD_VM_CURVE_BLS12_381_G2_ADD_COST;
     211          44 :       inputL_sz = FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G2_POINT_SZ;
     212          44 :       inputR_sz = FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G2_POINT_SZ;
     213          44 :       break;
     214             : 
     215          41 :     case FD_VM_SYSCALL_SOL_CURVE_SUB:
     216          41 :       cost = FD_VM_CURVE_BLS12_381_G2_SUB_COST;
     217          41 :       inputL_sz = FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G2_POINT_SZ;
     218          41 :       inputR_sz = FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G2_POINT_SZ;
     219          41 :       break;
     220             : 
     221          48 :     case FD_VM_SYSCALL_SOL_CURVE_MUL:
     222          48 :       cost = FD_VM_CURVE_BLS12_381_G2_MUL_COST;
     223             :       /* inputL_sz = 32UL // scalar */
     224          48 :       inputR_sz = FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G2_POINT_SZ;
     225          48 :       break;
     226             : 
     227           1 :     default:
     228           1 :       goto invalid_error;
     229         134 :     }
     230         133 :     break;
     231             : 
     232             :   /* secp256r1 */
     233         133 :   case P256_BE:
     234           0 :   case P256_LE:
     235           0 :     switch( group_op ) {
     236             : 
     237           0 :     case FD_VM_SYSCALL_SOL_CURVE_ADD:
     238           0 :       cost = FD_VM_CURVE_SECP256R1_ADD_COST;
     239           0 :       inputL_sz = FD_VM_SYSCALL_SOL_CURVE_SECP256R1_POINT_SZ;
     240           0 :       inputR_sz = FD_VM_SYSCALL_SOL_CURVE_SECP256R1_POINT_SZ;
     241           0 :       break;
     242             : 
     243           0 :     case FD_VM_SYSCALL_SOL_CURVE_SUB:
     244           0 :       cost = FD_VM_CURVE_SECP256R1_SUB_COST;
     245           0 :       inputL_sz = FD_VM_SYSCALL_SOL_CURVE_SECP256R1_POINT_SZ;
     246           0 :       inputR_sz = FD_VM_SYSCALL_SOL_CURVE_SECP256R1_POINT_SZ;
     247           0 :       break;
     248             : 
     249           0 :     case FD_VM_SYSCALL_SOL_CURVE_MUL:
     250           0 :       cost = FD_VM_CURVE_SECP256R1_MUL_COST;
     251             :       /* inputL_sz = 32UL // scalar */
     252           0 :       inputR_sz = FD_VM_SYSCALL_SOL_CURVE_SECP256R1_POINT_SZ;
     253           0 :       break;
     254             : 
     255           0 :     default:
     256           0 :       goto invalid_error;
     257           0 :     }
     258           0 :     break;
     259             : 
     260           3 :   default:
     261           3 :     goto invalid_error;
     262         647 :   }
     263             : 
     264             :   /* https://github.com/anza-xyz/agave/blob/v1.18.8/programs/bpf_loader/src/syscalls/mod.rs#L944-L947 */
     265        1270 :   FD_VM_CU_UPDATE( vm, cost );
     266             : 
     267             :   /* https://github.com/anza-xyz/agave/blob/v1.18.8/programs/bpf_loader/src/syscalls/mod.rs#L949-L958 */
     268             : 
     269             :   /* Note: left_input_addr is a point for add, sub, BUT it's a scalar for mul. */
     270        1884 :   uchar const * inputL = FD_VM_MEM_HADDR_LD( vm, left_input_addr,  FD_VM_ALIGN_RUST_POD_U8_ARRAY, inputL_sz );
     271        1850 :   uchar const * inputR = FD_VM_MEM_HADDR_LD( vm, right_input_addr, FD_VM_ALIGN_RUST_POD_U8_ARRAY, inputR_sz );
     272             : 
     273         612 :   int big_endian = ( curve_id & 0x80 ) ? 1 : 0;
     274             : 
     275        1850 :   switch( MATCH_ID_OP( curve_id, group_op ) ) {
     276             : 
     277          58 :   case MATCH_ID_OP( EDWARDS, FD_VM_SYSCALL_SOL_CURVE_ADD ): {
     278          58 :     fd_ed25519_point_t p0[1], p1[1], r[1];
     279          58 :     if( FD_UNLIKELY( !fd_ed25519_point_frombytes( p0, inputL ) ) ) {
     280           7 :       goto soft_error;
     281           7 :     }
     282          51 :     if( FD_UNLIKELY( !fd_ed25519_point_frombytes( p1, inputR ) ) ) {
     283           2 :       goto soft_error;
     284           2 :     }
     285             : 
     286          49 :     uchar * result = FD_VM_HADDR_QUERY_U8_ARRAY( vm, result_point_addr, FD_VM_SYSCALL_SOL_CURVE_CURVE25519_POINT_SZ );
     287          46 :     fd_ed25519_point_add( r, p0, p1 );
     288          46 :     fd_ed25519_point_tobytes( result, r );
     289          46 :     ret = 0UL;
     290          46 :     break;
     291          49 :   }
     292             : 
     293          50 :   case MATCH_ID_OP( EDWARDS, FD_VM_SYSCALL_SOL_CURVE_SUB ): {
     294          50 :     fd_ed25519_point_t p0[1], p1[1], r[1];
     295          50 :     if( FD_UNLIKELY( !fd_ed25519_point_frombytes( p0, inputL ) ) ) {
     296           4 :       goto soft_error;
     297           4 :     }
     298          46 :     if( FD_UNLIKELY( !fd_ed25519_point_frombytes( p1, inputR ) ) ) {
     299           3 :       goto soft_error;
     300           3 :     }
     301             : 
     302          43 :     uchar * result = FD_VM_HADDR_QUERY_U8_ARRAY( vm, result_point_addr, FD_VM_SYSCALL_SOL_CURVE_CURVE25519_POINT_SZ );
     303          35 :     fd_ed25519_point_sub( r, p0, p1 );
     304          35 :     fd_ed25519_point_tobytes( result, r );
     305          35 :     ret = 0UL;
     306          35 :     break;
     307          43 :   }
     308             : 
     309          84 :   case MATCH_ID_OP( EDWARDS, FD_VM_SYSCALL_SOL_CURVE_MUL ): {
     310          84 :     fd_ed25519_point_t p[1], r[1];
     311          84 :     if( FD_UNLIKELY( !fd_curve25519_scalar_validate( inputL ) ) ) {
     312          13 :       goto soft_error;
     313          13 :     }
     314          71 :     if( FD_UNLIKELY( !fd_ed25519_point_frombytes( p, inputR ) ) ) {
     315           2 :       goto soft_error;
     316           2 :     }
     317             : 
     318          69 :     uchar * result = FD_VM_HADDR_QUERY_U8_ARRAY( vm, result_point_addr, FD_VM_SYSCALL_SOL_CURVE_CURVE25519_POINT_SZ );
     319          62 :     fd_ed25519_scalar_mul( r, inputL, p );
     320          62 :     fd_ed25519_point_tobytes( result, r );
     321          62 :     ret = 0UL;
     322          62 :     break;
     323          69 :   }
     324             : 
     325          45 :   case MATCH_ID_OP( RISTRETTO, FD_VM_SYSCALL_SOL_CURVE_ADD ): {
     326          45 :     fd_ristretto255_point_t p0[1], p1[1], r[1];
     327          45 :     if( FD_UNLIKELY( !fd_ristretto255_point_frombytes( p0, inputL ) ) ) {
     328           3 :       goto soft_error;
     329           3 :     }
     330          42 :     if( FD_UNLIKELY( !fd_ristretto255_point_frombytes( p1, inputR ) ) ) {
     331           1 :       goto soft_error;
     332           1 :     }
     333             : 
     334          41 :     uchar * result = FD_VM_HADDR_QUERY_U8_ARRAY( vm, result_point_addr, FD_VM_SYSCALL_SOL_CURVE_CURVE25519_POINT_SZ );
     335          35 :     fd_ristretto255_point_add( r, p0, p1 );
     336          35 :     fd_ristretto255_point_tobytes( result, r );
     337          35 :     ret = 0UL;
     338          35 :     break;
     339          41 :   }
     340             : 
     341          51 :   case MATCH_ID_OP( RISTRETTO, FD_VM_SYSCALL_SOL_CURVE_SUB ): {
     342          51 :     fd_ristretto255_point_t p0[1], p1[1], r[1];
     343          51 :     if( FD_UNLIKELY( !fd_ristretto255_point_frombytes( p0, inputL ) ) ) {
     344           4 :       goto soft_error;
     345           4 :     }
     346          47 :     if( FD_UNLIKELY( !fd_ristretto255_point_frombytes( p1, inputR ) ) ) {
     347           1 :       goto soft_error;
     348           1 :     }
     349             : 
     350          46 :     uchar * result = FD_VM_HADDR_QUERY_U8_ARRAY( vm, result_point_addr, FD_VM_SYSCALL_SOL_CURVE_CURVE25519_POINT_SZ );
     351          41 :     fd_ristretto255_point_sub( r, p0, p1 );
     352          41 :     fd_ristretto255_point_tobytes( result, r );
     353          41 :     ret = 0UL;
     354          41 :     break;
     355          46 :   }
     356             : 
     357          62 :   case MATCH_ID_OP( RISTRETTO, FD_VM_SYSCALL_SOL_CURVE_MUL ): {
     358          62 :     fd_ristretto255_point_t p[1], r[1];
     359          62 :     if( FD_UNLIKELY( !fd_curve25519_scalar_validate( inputL ) ) ) {
     360           8 :       goto soft_error;
     361           8 :     }
     362          54 :     if( FD_UNLIKELY( !fd_ristretto255_point_frombytes( p, inputR ) ) ) {
     363          10 :       goto soft_error;
     364          10 :     }
     365             : 
     366          44 :     uchar * result = FD_VM_HADDR_QUERY_U8_ARRAY( vm, result_point_addr, FD_VM_SYSCALL_SOL_CURVE_CURVE25519_POINT_SZ );
     367          41 :     fd_ristretto255_scalar_mul( r, inputL, p );
     368          41 :     fd_ristretto255_point_tobytes( result, r );
     369          41 :     ret = 0UL;
     370          41 :     break;
     371          44 :   }
     372             : 
     373             :   /* BLS12-381 G1 */
     374             : 
     375             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/syscalls/src/lib.rs#L1453 */
     376          17 :   case MATCH_ID_OP( BLS_G1_BE, FD_VM_SYSCALL_SOL_CURVE_ADD ):
     377          40 :   case MATCH_ID_OP( BLS_G1_LE, FD_VM_SYSCALL_SOL_CURVE_ADD ): {
     378          40 :     uchar _result[ FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G1_POINT_SZ ];
     379             :     /* Compute add */
     380          40 :     if( FD_LIKELY( fd_bls12_381_g1_add_syscall( _result, inputL, inputR, big_endian )==0 ) ) {
     381             :       /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/syscalls/src/lib.rs#L1474 */
     382          30 :       uchar * result = FD_VM_HADDR_QUERY_U8_ARRAY( vm, result_point_addr, FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G1_POINT_SZ );
     383          29 :       memcpy( result, _result, FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G1_POINT_SZ );
     384          29 :       ret = 0UL; /* success */
     385          29 :     }
     386          39 :     break;
     387          40 :   }
     388             : 
     389             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/syscalls/src/lib.rs#L1485 */
     390          39 :   case MATCH_ID_OP( BLS_G1_BE, FD_VM_SYSCALL_SOL_CURVE_SUB ):
     391          48 :   case MATCH_ID_OP( BLS_G1_LE, FD_VM_SYSCALL_SOL_CURVE_SUB ): {
     392          48 :     uchar _result[ FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G1_POINT_SZ ];
     393             :     /* Compute sub */
     394          48 :     if( FD_LIKELY( fd_bls12_381_g1_sub_syscall( _result, inputL, inputR, big_endian )==0 ) ) {
     395          32 :       uchar * result = FD_VM_HADDR_QUERY_U8_ARRAY( vm, result_point_addr, FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G1_POINT_SZ );
     396          32 :       memcpy( result, _result, FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G1_POINT_SZ );
     397          32 :       ret = 0UL; /* success */
     398          32 :     }
     399          48 :     break;
     400          48 :   }
     401             : 
     402             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/syscalls/src/lib.rs#L1519 */
     403          48 :   case MATCH_ID_OP( BLS_G1_BE, FD_VM_SYSCALL_SOL_CURVE_MUL ):
     404          46 :   case MATCH_ID_OP( BLS_G1_LE, FD_VM_SYSCALL_SOL_CURVE_MUL ): {
     405          46 :     uchar _result[ FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G1_POINT_SZ ];
     406             :     /* Compute mul */
     407          46 :     if( FD_LIKELY( fd_bls12_381_g1_mul_syscall( _result, inputL, inputR, big_endian )==0 ) ) {
     408          32 :       uchar * result = FD_VM_HADDR_QUERY_U8_ARRAY( vm, result_point_addr, FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G1_POINT_SZ );
     409          30 :       memcpy( result, _result, FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G1_POINT_SZ );
     410          30 :       ret = 0UL; /* success */
     411          30 :     }
     412          44 :     break;
     413          46 :   }
     414             : 
     415             :   /* BLS12-381 G2 */
     416             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/syscalls/src/lib.rs#L1566 */
     417          44 :   case MATCH_ID_OP( BLS_G2_BE, FD_VM_SYSCALL_SOL_CURVE_ADD ):
     418          43 :   case MATCH_ID_OP( BLS_G2_LE, FD_VM_SYSCALL_SOL_CURVE_ADD ): {
     419          43 :     uchar _result[ FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G2_POINT_SZ ];
     420             :     /* Compute add */
     421          43 :     if( FD_LIKELY( fd_bls12_381_g2_add_syscall( _result, inputL, inputR, big_endian )==0 ) ) {
     422          29 :       uchar * result = FD_VM_HADDR_QUERY_U8_ARRAY( vm, result_point_addr, FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G2_POINT_SZ );
     423          28 :       memcpy( result, _result, FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G2_POINT_SZ );
     424          28 :       ret = 0UL; /* success */
     425          28 :     }
     426          42 :     break;
     427          43 :   }
     428             : 
     429             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/syscalls/src/lib.rs#L1598 */
     430          42 :   case MATCH_ID_OP( BLS_G2_BE, FD_VM_SYSCALL_SOL_CURVE_SUB ):
     431          40 :   case MATCH_ID_OP( BLS_G2_LE, FD_VM_SYSCALL_SOL_CURVE_SUB ): {
     432          40 :     uchar _result[ FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G2_POINT_SZ ];
     433             :     /* Compute sub */
     434          40 :     if( FD_LIKELY( fd_bls12_381_g2_sub_syscall( _result, inputL, inputR, big_endian )==0 ) ) {
     435          34 :       uchar * result = FD_VM_HADDR_QUERY_U8_ARRAY( vm, result_point_addr, FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G2_POINT_SZ );
     436          34 :       memcpy( result, _result, FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G2_POINT_SZ );
     437          34 :       ret = 0UL; /* success */
     438          34 :     }
     439          40 :     break;
     440          40 :   }
     441             : 
     442             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/syscalls/src/lib.rs#L1632 */
     443          40 :   case MATCH_ID_OP( BLS_G2_BE, FD_VM_SYSCALL_SOL_CURVE_MUL ):
     444          45 :   case MATCH_ID_OP( BLS_G2_LE, FD_VM_SYSCALL_SOL_CURVE_MUL ): {
     445          45 :     uchar _result[ FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G2_POINT_SZ ];
     446             :     /* Compute mul */
     447          45 :     if( FD_LIKELY( fd_bls12_381_g2_mul_syscall( _result, inputL, inputR, big_endian )==0 ) ) {
     448          33 :       uchar * result = FD_VM_HADDR_QUERY_U8_ARRAY( vm, result_point_addr, FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G2_POINT_SZ );
     449          30 :       memcpy( result, _result, FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G2_POINT_SZ );
     450          30 :       ret = 0UL; /* success */
     451          30 :     }
     452          42 :     break;
     453          45 :   }
     454             : 
     455             :   /* secp256r1 */
     456          42 :   case MATCH_ID_OP( P256_BE, FD_VM_SYSCALL_SOL_CURVE_ADD ):
     457           0 :   case MATCH_ID_OP( P256_LE, FD_VM_SYSCALL_SOL_CURVE_ADD ): {
     458           0 :     uchar _result[ FD_VM_SYSCALL_SOL_CURVE_SECP256R1_POINT_SZ ];
     459             :     /* Compute add */
     460           0 :     if( FD_LIKELY( fd_secp256r1_add_syscall( _result, inputL, inputR, big_endian )==0 ) ) {
     461           0 :       uchar * result = FD_VM_HADDR_QUERY_U8_ARRAY( vm, result_point_addr, FD_VM_SYSCALL_SOL_CURVE_SECP256R1_POINT_SZ );
     462           0 :       memcpy( result, _result, FD_VM_SYSCALL_SOL_CURVE_SECP256R1_POINT_SZ );
     463           0 :       ret = 0UL; /* success */
     464           0 :     }
     465           0 :     break;
     466           0 :   }
     467             : 
     468           0 :   case MATCH_ID_OP( P256_BE, FD_VM_SYSCALL_SOL_CURVE_SUB ):
     469           0 :   case MATCH_ID_OP( P256_LE, FD_VM_SYSCALL_SOL_CURVE_SUB ): {
     470           0 :     uchar _result[ FD_VM_SYSCALL_SOL_CURVE_SECP256R1_POINT_SZ ];
     471             :     /* Compute sub */
     472           0 :     if( FD_LIKELY( fd_secp256r1_sub_syscall( _result, inputL, inputR, big_endian )==0 ) ) {
     473           0 :       uchar * result = FD_VM_HADDR_QUERY_U8_ARRAY( vm, result_point_addr, FD_VM_SYSCALL_SOL_CURVE_SECP256R1_POINT_SZ );
     474           0 :       memcpy( result, _result, FD_VM_SYSCALL_SOL_CURVE_SECP256R1_POINT_SZ );
     475           0 :       ret = 0UL; /* success */
     476           0 :     }
     477           0 :     break;
     478           0 :   }
     479             : 
     480           0 :   case MATCH_ID_OP( P256_BE, FD_VM_SYSCALL_SOL_CURVE_MUL ):
     481           0 :   case MATCH_ID_OP( P256_LE, FD_VM_SYSCALL_SOL_CURVE_MUL ): {
     482           0 :     uchar _result[ FD_VM_SYSCALL_SOL_CURVE_SECP256R1_POINT_SZ ];
     483             :     /* Compute mul */
     484           0 :     if( FD_LIKELY( fd_secp256r1_mul_syscall( _result, inputL, inputR, big_endian )==0 ) ) {
     485           0 :       uchar * result = FD_VM_HADDR_QUERY_U8_ARRAY( vm, result_point_addr, FD_VM_SYSCALL_SOL_CURVE_SECP256R1_POINT_SZ );
     486           0 :       memcpy( result, _result, FD_VM_SYSCALL_SOL_CURVE_SECP256R1_POINT_SZ );
     487           0 :       ret = 0UL; /* success */
     488           0 :     }
     489           0 :     break;
     490           0 :   }
     491             : 
     492           0 :   default:
     493             :     /* COV: this can never happen because of the previous switch */
     494           0 :     return FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE; /* SyscallError::InvalidAttribute */
     495        1850 :   }
     496             : 
     497         574 : soft_error:
     498         574 :   vm->reg[0] = ret;
     499         574 :   return FD_VM_SUCCESS;
     500           0 : #undef MATCH_ID_OP
     501           0 : #undef EDWARDS
     502           0 : #undef RISTRETTO
     503           0 : #undef BLS_G1_BE
     504           0 : #undef BLS_G1_LE
     505           0 : #undef BLS_G2_BE
     506           0 : #undef BLS_G2_LE
     507           0 : #undef P256_BE
     508           0 : #undef P256_LE
     509             : 
     510           9 : invalid_error:
     511             :   /* https://github.com/anza-xyz/agave/blob/5b3390b99a6e7665439c623062c1a1dda2803524/programs/bpf_loader/src/syscalls/mod.rs#L1135-L1156 */
     512           9 :   FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE );
     513           9 :   return FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE; /* SyscallError::InvalidAttribute */
     514        1850 : }
     515             : 
     516             : /* multi_scalar_mul_edwards computes a MSM on curve25519.
     517             : 
     518             :    This function is equivalent to
     519             :    zk-token-sdk::edwards::multi_scalar_mul_edwards
     520             : 
     521             :    https://github.com/solana-labs/solana/blob/v1.17.7/zk-token-sdk/src/curve25519/edwards.rs#L116
     522             : 
     523             :    Specifically it takes as input byte arrays and takes care of scalars
     524             :    validation and points decompression.  It then invokes ballet MSM
     525             :    function fd_ed25519_multi_scalar_mul.  To avoid dynamic allocation,
     526             :    the full MSM is done in batches of FD_BALLET_CURVE25519_MSM_BATCH_SZ. */
     527             : 
     528             : static fd_ed25519_point_t *
     529             : multi_scalar_mul_edwards( fd_ed25519_point_t * r,
     530             :                           uchar const *        scalars,
     531             :                           uchar const *        points,
     532         203 :                           ulong                cnt ) {
     533             :   /* Validate all scalars first (fast) */
     534         878 :   for( ulong i=0UL; i<cnt; i++ ) {
     535         722 :     if( FD_UNLIKELY( !fd_curve25519_scalar_validate ( scalars + i*FD_VM_SYSCALL_SOL_CURVE_CURVE25519_SCALAR_SZ ) ) ) {
     536          47 :       return NULL;
     537          47 :     }
     538         722 :   }
     539             : 
     540             :   /* Static allocation of a batch of decompressed points */
     541         156 :   fd_ed25519_point_t tmp[1];
     542         156 :   fd_ed25519_point_t A[ FD_BALLET_CURVE25519_MSM_BATCH_SZ ];
     543             : 
     544         156 :   fd_ed25519_point_set_zero( r );
     545         311 :   for( ulong i=0UL; i<cnt; i+=FD_BALLET_CURVE25519_MSM_BATCH_SZ ) {
     546         156 :     ulong batch_cnt = fd_ulong_min( cnt-i, FD_BALLET_CURVE25519_MSM_BATCH_SZ );
     547             : 
     548             :     /* Decompress (and validate) points */
     549         826 :     for( ulong j=0UL; j<batch_cnt; j++ ) {
     550             :       //TODO: use fd_ed25519_point_frombytes_2x
     551         671 :       if( FD_UNLIKELY( !fd_ed25519_point_frombytes( &A[j], points + j*FD_VM_SYSCALL_SOL_CURVE_CURVE25519_POINT_SZ ) ) ) {
     552           1 :         return NULL;
     553           1 :       }
     554         671 :     }
     555             : 
     556         155 :     fd_ed25519_multi_scalar_mul( tmp, scalars, A, batch_cnt );
     557         155 :     fd_ed25519_point_add( r, r, tmp );
     558         155 :     points  += FD_VM_SYSCALL_SOL_CURVE_CURVE25519_POINT_SZ *batch_cnt;
     559         155 :     scalars += FD_VM_SYSCALL_SOL_CURVE_CURVE25519_SCALAR_SZ*batch_cnt;
     560         155 :   }
     561             : 
     562         155 :   return r;
     563         156 : }
     564             : 
     565             : /* multi_scalar_mul_ristretto computes a MSM on ristretto255.
     566             :    See multi_scalar_mul_edwards for details. */
     567             : 
     568             : static fd_ristretto255_point_t *
     569             : multi_scalar_mul_ristretto( fd_ristretto255_point_t * r,
     570             :                             uchar const *             scalars,
     571             :                             uchar const *             points,
     572         215 :                             ulong                     cnt ) {
     573             :   /* Validate all scalars first (fast) */
     574         878 :   for( ulong i=0UL; i<cnt; i++ ) {
     575         712 :     if( FD_UNLIKELY( !fd_curve25519_scalar_validate ( scalars + i*FD_VM_SYSCALL_SOL_CURVE_CURVE25519_SCALAR_SZ ) ) ) {
     576          49 :       return NULL;
     577          49 :     }
     578         712 :   }
     579             : 
     580             :   /* Static allocation of a batch of decompressed points */
     581         166 :   fd_ristretto255_point_t tmp[1];
     582         166 :   fd_ristretto255_point_t A[ FD_BALLET_CURVE25519_MSM_BATCH_SZ ];
     583             : 
     584         166 :   fd_ristretto255_point_set_zero( r );
     585         327 :   for( ulong i=0UL; i<cnt; i+=FD_BALLET_CURVE25519_MSM_BATCH_SZ ) {
     586         165 :     ulong batch_cnt = fd_ulong_min( cnt-i, FD_BALLET_CURVE25519_MSM_BATCH_SZ );
     587             : 
     588             :     /* Decompress (and validate) points */
     589         821 :     for( ulong j=0UL; j<batch_cnt; j++ ) {
     590             :       //TODO: use fd_ristretto255_point_frombytes_2x
     591         660 :       if( FD_UNLIKELY( !fd_ristretto255_point_frombytes( &A[j], points + j*FD_VM_SYSCALL_SOL_CURVE_CURVE25519_POINT_SZ ) ) ) {
     592           4 :         return NULL;
     593           4 :       }
     594         660 :     }
     595             : 
     596         161 :     fd_ristretto255_multi_scalar_mul( tmp, scalars, A, batch_cnt );
     597         161 :     fd_ristretto255_point_add( r, r, tmp );
     598         161 :     points  += FD_VM_SYSCALL_SOL_CURVE_CURVE25519_POINT_SZ *batch_cnt;
     599         161 :     scalars += FD_VM_SYSCALL_SOL_CURVE_CURVE25519_SCALAR_SZ*batch_cnt;
     600         161 :   }
     601             : 
     602         162 :   return r;
     603         166 : }
     604             : 
     605             : #undef BATCH_MAX
     606             : 
     607             : int
     608             : fd_vm_syscall_sol_curve_multiscalar_mul( void *  _vm,
     609             :                                          ulong   curve_id,
     610             :                                          ulong   scalars_addr,
     611             :                                          ulong   points_addr,
     612             :                                          ulong   points_len,
     613         463 :                                          ulong   result_point_addr ) {
     614             :   /* https://github.com/anza-xyz/agave/blob/v1.18.8/programs/bpf_loader/src/syscalls/mod.rs#L1129 */
     615         463 :   fd_vm_t * vm = (fd_vm_t *)_vm;
     616         463 :   ulong     ret = 1UL; /* by default return Ok(1) == error */
     617             : 
     618             :   /* https://github.com/anza-xyz/agave/blob/v1.18.8/programs/bpf_loader/src/syscalls/mod.rs#L1143-L1151 */
     619         463 :   if( FD_UNLIKELY( points_len > 512 ) ) {
     620           2 :     FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_INVALID_LENGTH );
     621           2 :     return FD_VM_SYSCALL_ERR_INVALID_LENGTH; /* SyscallError::InvalidLength */
     622           2 :   }
     623             : 
     624             :   /* secp256r1 syscalls are under feature gate secp256r1_syscall_enabled.
     625             :      To clean up the feature gate after activation, just remove this block
     626             :      (the rest of the function will behave correctly). */
     627         461 :   {
     628         461 :     if( FD_UNLIKELY(
     629         461 :       !FD_FEATURE_ACTIVE_BANK( vm->instr_ctx->bank, secp256r1_syscall_enabled )
     630         461 :       && ( curve_id==FD_VM_SYSCALL_SOL_CURVE_SECP256R1_BE
     631         461 :         || curve_id==FD_VM_SYSCALL_SOL_CURVE_SECP256R1_LE )
     632         461 :     ) ) {
     633           0 :       FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE );
     634           0 :       return FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE; /* SyscallError::InvalidAttribute */
     635           0 :     }
     636         461 :   }
     637             : 
     638             :   /* Note: we don't strictly follow the Rust implementation, but instead combine
     639             :      common code across switch cases. Similar to fd_vm_syscall_sol_alt_bn128_group_op. */
     640             : 
     641         461 :   ulong base_cost = 0UL;
     642         461 :   ulong incremental_cost = 0UL;
     643         461 :   ulong scalar_sz = FD_VM_SYSCALL_SOL_CURVE_CURVE25519_SCALAR_SZ;
     644         461 :   ulong point_sz = FD_VM_SYSCALL_SOL_CURVE_CURVE25519_POINT_SZ;
     645         461 :   switch( curve_id ) {
     646         224 :   case FD_VM_SYSCALL_SOL_CURVE_CURVE25519_EDWARDS:
     647         224 :     base_cost = FD_VM_CURVE_EDWARDS_MSM_BASE_COST;
     648         224 :     incremental_cost = FD_VM_CURVE_EDWARDS_MSM_INCREMENTAL_COST;
     649         224 :     break;
     650             : 
     651         235 :   case FD_VM_SYSCALL_SOL_CURVE_CURVE25519_RISTRETTO:
     652         235 :     base_cost = FD_VM_CURVE_RISTRETTO_MSM_BASE_COST;
     653         235 :     incremental_cost = FD_VM_CURVE_RISTRETTO_MSM_INCREMENTAL_COST;
     654         235 :     break;
     655             : 
     656           0 :   case FD_VM_SYSCALL_SOL_CURVE_SECP256R1_BE:
     657           0 :   case FD_VM_SYSCALL_SOL_CURVE_SECP256R1_LE:
     658           0 :     base_cost = FD_VM_CURVE_SECP256R1_MSM_BASE_COST;
     659           0 :     incremental_cost = FD_VM_CURVE_SECP256R1_MSM_INCREMENTAL_COST;
     660           0 :     scalar_sz = FD_VM_SYSCALL_SOL_CURVE_SECP256R1_SCALAR_SZ;
     661           0 :     point_sz = FD_VM_SYSCALL_SOL_CURVE_SECP256R1_POINT_SZ;
     662           0 :     break;
     663             : 
     664           2 :   default:
     665             :     /* https://github.com/anza-xyz/agave/blob/5b3390b99a6e7665439c623062c1a1dda2803524/programs/bpf_loader/src/syscalls/mod.rs#L1262-L1271 */
     666           2 :     FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE );
     667           2 :     return FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE; /* SyscallError::InvalidAttribute */
     668         461 :   }
     669             : 
     670             :   /* https://github.com/anza-xyz/agave/blob/v1.18.8/programs/bpf_loader/src/syscalls/mod.rs#L1155-L1164 */
     671         459 :   ulong cost = fd_ulong_sat_add(
     672         459 :     base_cost,
     673         459 :     fd_ulong_sat_mul(
     674         459 :       incremental_cost,
     675         459 :       fd_ulong_sat_sub( points_len, 1 )
     676         459 :     )
     677         459 :   );
     678         459 :   FD_VM_CU_UPDATE( vm, cost );
     679             : 
     680             :   /* Edge case points_len==0.
     681             :      Agave computes the MSM, that returns the point at infinity, and stores the result.
     682             :      This means that we have to mem map result, and then set the point at infinity,
     683             :      that is 0x0100..00 for Edwards and 0x00..00 for Ristretto and secp256r1. */
     684         455 :   if ( FD_UNLIKELY( points_len==0 ) ) {
     685          33 :     uchar * result = FD_VM_MEM_HADDR_ST( vm, result_point_addr, FD_VM_ALIGN_RUST_POD_U8_ARRAY, point_sz );
     686           0 :     memset( result, 0, point_sz );
     687          30 :     result[0] = curve_id==FD_VM_SYSCALL_SOL_CURVE_CURVE25519_EDWARDS ? 1 : 0;
     688          30 :     vm->reg[0] = 0UL;
     689          30 :     return FD_VM_SUCCESS;
     690          33 :   }
     691             : 
     692             :   /* https://github.com/anza-xyz/agave/blob/v1.18.8/programs/bpf_loader/src/syscalls/mod.rs#L1166-L1178 */
     693        1262 :   uchar const * scalars = FD_VM_MEM_HADDR_LD( vm, scalars_addr, FD_VM_ALIGN_RUST_POD_U8_ARRAY, points_len*scalar_sz );
     694        1256 :   uchar const * points  = FD_VM_MEM_HADDR_LD( vm, points_addr,  FD_VM_ALIGN_RUST_POD_U8_ARRAY, points_len*point_sz );
     695             : 
     696           0 :   switch( curve_id ) {
     697             : 
     698         203 :   case FD_VM_SYSCALL_SOL_CURVE_CURVE25519_EDWARDS: {
     699             :     /* https://github.com/anza-xyz/agave/blob/v1.18.8/programs/bpf_loader/src/syscalls/mod.rs#L1180-L1189 */
     700         203 :     fd_ed25519_point_t _r[1];
     701         203 :     fd_ed25519_point_t * r = multi_scalar_mul_edwards( _r, scalars, points, points_len );
     702             : 
     703         203 :     if( FD_LIKELY( r ) ) {
     704         155 :       uchar * result = FD_VM_HADDR_QUERY_U8_ARRAY( vm, result_point_addr, FD_VM_SYSCALL_SOL_CURVE_CURVE25519_POINT_SZ );
     705         141 :       fd_ed25519_point_tobytes( result, r );
     706         141 :       ret = 0UL;
     707         141 :     }
     708         189 :     break;
     709         203 :   }
     710             : 
     711         215 :   case FD_VM_SYSCALL_SOL_CURVE_CURVE25519_RISTRETTO: {
     712         215 :     fd_ristretto255_point_t _r[1];
     713         215 :     fd_ristretto255_point_t * r = multi_scalar_mul_ristretto( _r, scalars, points, points_len );
     714             : 
     715         215 :     if( FD_LIKELY( r ) ) {
     716         162 :       uchar * result = FD_VM_HADDR_QUERY_U8_ARRAY( vm, result_point_addr, FD_VM_SYSCALL_SOL_CURVE_CURVE25519_POINT_SZ );
     717         154 :       fd_ristretto255_point_tobytes( result, r );
     718         154 :       ret = 0UL;
     719         154 :     }
     720         207 :     break;
     721         215 :   }
     722             : 
     723         207 :   case FD_VM_SYSCALL_SOL_CURVE_SECP256R1_BE:
     724           0 :   case FD_VM_SYSCALL_SOL_CURVE_SECP256R1_LE: {
     725           0 :     int big_endian = ( curve_id & 0x80 ) ? 1 : 0;
     726           0 :     uchar _result[ FD_VM_SYSCALL_SOL_CURVE_SECP256R1_POINT_SZ ];
     727           0 :     if( FD_LIKELY( fd_secp256r1_msm_syscall( _result, scalars, points, points_len, big_endian )==0 ) ) {
     728           0 :       uchar * result = FD_VM_HADDR_QUERY_U8_ARRAY( vm, result_point_addr, FD_VM_SYSCALL_SOL_CURVE_SECP256R1_POINT_SZ );
     729           0 :       memcpy( result, _result, FD_VM_SYSCALL_SOL_CURVE_SECP256R1_POINT_SZ );
     730           0 :       ret = 0UL; /* success */
     731           0 :     }
     732           0 :     break;
     733           0 :   }
     734             : 
     735           0 :   default:
     736             :     /* COV: this can never happen because of the previous switch */
     737           0 :     return FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE; /* SyscallError::InvalidAttribute */
     738        1256 :   }
     739             : 
     740         396 :   vm->reg[0] = ret;
     741         396 :   return FD_VM_SUCCESS;
     742        1256 : }
     743             : 
     744             : int
     745             : fd_vm_syscall_sol_curve_decompress( /**/            void *  _vm,
     746             :                                     /**/            ulong   curve_id,
     747             :                                     /**/            ulong   point_addr,
     748             :                                     /**/            ulong   result_addr,
     749             :                                     FD_PARAM_UNUSED ulong   r4,
     750         159 :                                     FD_PARAM_UNUSED ulong   r5 ) {
     751             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/syscalls/src/lib.rs#L1118 */
     752         159 :   fd_vm_t * vm = (fd_vm_t *)_vm;
     753         159 :   ulong     ret = 1UL; /* by default return Ok(1) == error */
     754             : 
     755             :   /* secp256r1 syscalls are under feature gate secp256r1_syscall_enabled.
     756             :      To clean up the feature gate after activation, just remove this block
     757             :      (the rest of the function will behave correctly). */
     758         159 :   {
     759         159 :     if( FD_UNLIKELY(
     760         159 :       !FD_FEATURE_ACTIVE_BANK( vm->instr_ctx->bank, secp256r1_syscall_enabled )
     761         159 :       && ( curve_id==FD_VM_SYSCALL_SOL_CURVE_SECP256R1_BE
     762         159 :         || curve_id==FD_VM_SYSCALL_SOL_CURVE_SECP256R1_LE )
     763         159 :     ) ) {
     764           0 :       FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE );
     765           0 :       return FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE; /* SyscallError::InvalidAttribute */
     766           0 :     }
     767         159 :   }
     768             : 
     769         159 :   int big_endian = ( curve_id & 0x80 ) ? 1 : 0;
     770             : 
     771         159 :   uchar const * point = NULL;
     772         159 :   switch( curve_id ) {
     773             : 
     774             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/syscalls/src/lib.rs#L1137 */
     775          30 :   case FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G1_BE:
     776          72 :   case FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G1_LE: {
     777          72 :     FD_VM_CU_UPDATE( vm, FD_VM_CURVE_BLS12_381_G1_DECOMPRESS_COST );
     778         216 :     point = FD_VM_MEM_HADDR_LD( vm, point_addr, FD_VM_ALIGN_RUST_POD_U8_ARRAY, FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G1_COMPRESSED_SZ );
     779           0 :     uchar _result[ FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G1_POINT_SZ ];
     780         216 :     if( FD_LIKELY( fd_bls12_381_g1_decompress_syscall( _result, point, big_endian )==0 ) ) {
     781             :       /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/syscalls/src/lib.rs#L1160 */
     782          66 :       uchar * result = FD_VM_HADDR_QUERY_U8_ARRAY( vm, result_addr, FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G1_POINT_SZ );
     783          63 :       memcpy( result, _result, FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G1_POINT_SZ );
     784          63 :       ret = 0UL; /* success */
     785          63 :     }
     786         216 :   } break;
     787             : 
     788             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/syscalls/src/lib.rs#L1171 */
     789          69 :   case FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G2_BE:
     790          86 :   case FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G2_LE: {
     791          86 :     FD_VM_CU_UPDATE( vm, FD_VM_CURVE_BLS12_381_G2_DECOMPRESS_COST );
     792         258 :     point = FD_VM_MEM_HADDR_LD( vm, point_addr, FD_VM_ALIGN_RUST_POD_U8_ARRAY, FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G2_COMPRESSED_SZ );
     793           0 :     uchar _result[ FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G2_POINT_SZ ];
     794         258 :     if( FD_LIKELY( fd_bls12_381_g2_decompress_syscall( _result, point, big_endian )==0 ) ) {
     795          74 :       uchar * result = FD_VM_HADDR_QUERY_U8_ARRAY( vm, result_addr, FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G2_POINT_SZ );
     796          67 :       memcpy( result, _result, FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G2_POINT_SZ );
     797          67 :       ret = 0UL; /* success */
     798          67 :     }
     799         258 :   } break;
     800             : 
     801          79 :   case FD_VM_SYSCALL_SOL_CURVE_SECP256R1_BE:
     802           0 :   case FD_VM_SYSCALL_SOL_CURVE_SECP256R1_LE: {
     803           0 :     FD_VM_CU_UPDATE( vm, FD_VM_CURVE_SECP256R1_DECOMPRESS_COST );
     804           0 :     point = FD_VM_MEM_HADDR_LD( vm, point_addr, FD_VM_ALIGN_RUST_POD_U8_ARRAY, FD_VM_SYSCALL_SOL_CURVE_SECP256R1_COMPRESSED_SZ );
     805           0 :     uchar _result[ FD_VM_SYSCALL_SOL_CURVE_SECP256R1_POINT_SZ ];
     806           0 :     if( FD_LIKELY( fd_secp256r1_decompress_syscall( _result, point, big_endian )==0 ) ) {
     807           0 :       uchar * result = FD_VM_HADDR_QUERY_U8_ARRAY( vm, result_addr, FD_VM_SYSCALL_SOL_CURVE_SECP256R1_POINT_SZ );
     808           0 :       memcpy( result, _result, FD_VM_SYSCALL_SOL_CURVE_SECP256R1_POINT_SZ );
     809           0 :       ret = 0UL; /* success */
     810           0 :     }
     811           0 :   } break;
     812             : 
     813           1 :   default:
     814           1 :     FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE );
     815           1 :     return FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE; /* SyscallError::InvalidAttribute */
     816         159 :   }
     817             : 
     818         148 :   vm->reg[0] = ret;
     819         148 :   return FD_VM_SUCCESS;
     820         159 : }
     821             : 
     822             : int
     823             : fd_vm_syscall_sol_curve_pairing_map( /**/            void *  _vm,
     824             :                                      /**/            ulong   curve_id,
     825             :                                      /**/            ulong   num_pairs,
     826             :                                      /**/            ulong   g1_points_addr,
     827             :                                      /**/            ulong   g2_points_addr,
     828         139 :                                      /**/            ulong   result_addr ) {
     829             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/syscalls/src/lib.rs#L1804 */
     830         139 :   fd_vm_t * vm = (fd_vm_t *)_vm;
     831         139 :   ulong     ret = 1UL; /* by default return Ok(1) == error */
     832             : 
     833         139 :   int big_endian = ( curve_id & 0x80 ) ? 1 : 0;
     834             : 
     835         139 :   switch( curve_id ) {
     836             : 
     837             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/syscalls/src/lib.rs#L1823 */
     838          65 :   case FD_VM_SYSCALL_SOL_CURVE_BLS12_381_BE:
     839         138 :   case FD_VM_SYSCALL_SOL_CURVE_BLS12_381_LE: {
     840             : 
     841         138 :     ulong cost = fd_ulong_sat_add( FD_VM_CURVE_BLS12_381_PAIRING_BASE_COST,
     842         138 :       fd_ulong_sat_mul( FD_VM_CURVE_BLS12_381_PAIRING_INCR_COST,
     843         138 :         fd_ulong_sat_sub( num_pairs, 1 ) ) );
     844         138 :     FD_VM_CU_UPDATE( vm, cost );
     845             : 
     846         137 :     ulong total_g1_sz = fd_ulong_sat_mul( FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G1_POINT_SZ, num_pairs );
     847         274 :     uchar const * g1_points = FD_VM_MEM_SLICE_HADDR_LD( vm, g1_points_addr, FD_VM_ALIGN_RUST_POD_U8_ARRAY, total_g1_sz );
     848             : 
     849         137 :     ulong total_g2_sz = fd_ulong_sat_mul( FD_VM_SYSCALL_SOL_CURVE_BLS12_381_G2_POINT_SZ, num_pairs );
     850         274 :     uchar const * g2_points = FD_VM_MEM_SLICE_HADDR_LD( vm, g2_points_addr, FD_VM_ALIGN_RUST_POD_U8_ARRAY, total_g2_sz );
     851             : 
     852           0 :     uchar _result[ FD_VM_SYSCALL_SOL_CURVE_BLS12_381_GT_ELE_SZ ];
     853         271 :     if( FD_LIKELY( fd_bls12_381_pairing_syscall( _result, g1_points, g2_points, num_pairs, big_endian )==0 ) ) {
     854             :       /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/syscalls/src/lib.rs#L1860 */
     855         112 :       uchar * result = FD_VM_HADDR_QUERY_U8_ARRAY( vm, result_addr, FD_VM_SYSCALL_SOL_CURVE_BLS12_381_GT_ELE_SZ );
     856          90 :       memcpy( result, _result, FD_VM_SYSCALL_SOL_CURVE_BLS12_381_GT_ELE_SZ );
     857          90 :       ret = 0UL; /* success */
     858          90 :     }
     859         271 :   } break;
     860             : 
     861         112 :   default:
     862           1 :     FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE );
     863           1 :     return FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE; /* SyscallError::InvalidAttribute */
     864         139 :   }
     865             : 
     866         112 :   vm->reg[0] = ret;
     867         112 :   return FD_VM_SUCCESS;
     868         139 : }

Generated by: LCOV version 1.14