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

Generated by: LCOV version 1.14