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