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: 259 499 51.9 %
Date: 2026-06-08 09:27:03 Functions: 6 7 85.7 %

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

Generated by: LCOV version 1.14