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: 467 491 95.1 %
Date: 2026-10-22 18:10:43 Functions: 7 7 100.0 %

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

Generated by: LCOV version 1.14