Line data Source code
1 : #include "fd_vm_syscall.h"
2 :
3 : #include "../../../ballet/ed25519/fd_curve25519.h"
4 : #include "../../../ballet/ed25519/fd_ristretto255.h"
5 :
6 : int
7 : fd_vm_syscall_sol_curve_validate_point( /**/ void * _vm,
8 : /**/ ulong curve_id,
9 : /**/ ulong point_addr,
10 : FD_PARAM_UNUSED ulong r3,
11 : FD_PARAM_UNUSED ulong r4,
12 : FD_PARAM_UNUSED ulong r5,
13 0 : /**/ ulong * _ret ) {
14 : /* https://github.com/anza-xyz/agave/blob/v1.18.8/programs/bpf_loader/src/syscalls/mod.rs#L871 */
15 0 : fd_vm_t * vm = (fd_vm_t *)_vm;
16 0 : ulong ret = 1UL; /* by default return Ok(1) == error */
17 :
18 0 : uchar const * point = NULL;
19 0 : switch( curve_id ) {
20 :
21 0 : case FD_VM_SYSCALL_SOL_CURVE_CURVE25519_EDWARDS:
22 :
23 0 : FD_VM_CU_UPDATE( vm, FD_VM_CURVE25519_EDWARDS_VALIDATE_POINT_COST );
24 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 );
25 0 : ret = (ulong)!fd_ed25519_point_validate( point ); /* 0 if valid point, 1 if not */
26 0 : break;
27 :
28 0 : case FD_VM_SYSCALL_SOL_CURVE_CURVE25519_RISTRETTO:
29 :
30 0 : FD_VM_CU_UPDATE( vm, FD_VM_CURVE25519_RISTRETTO_VALIDATE_POINT_COST );
31 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 );
32 0 : ret = (ulong)!fd_ristretto255_point_validate( point ); /* 0 if valid point, 1 if not */
33 0 : break;
34 :
35 0 : default:
36 : /* https://github.com/anza-xyz/agave/blob/5b3390b99a6e7665439c623062c1a1dda2803524/programs/bpf_loader/src/syscalls/mod.rs#L919-L928 */
37 0 : if( FD_FEATURE_ACTIVE( vm->instr_ctx->txn_ctx->slot, vm->instr_ctx->txn_ctx->features, abort_on_invalid_curve ) ) {
38 0 : FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE );
39 0 : return FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE; /* SyscallError::InvalidAttribute */
40 0 : }
41 0 : }
42 :
43 0 : *_ret = ret;
44 0 : return FD_VM_SUCCESS;
45 0 : }
46 :
47 : int
48 : fd_vm_syscall_sol_curve_group_op( void * _vm,
49 : ulong curve_id,
50 : ulong group_op,
51 : ulong left_input_addr,
52 : ulong right_input_addr,
53 : ulong result_point_addr,
54 12 : ulong * _ret ) {
55 : /* https://github.com/anza-xyz/agave/blob/v1.18.8/programs/bpf_loader/src/syscalls/mod.rs#L928 */
56 12 : fd_vm_t * vm = (fd_vm_t *)_vm;
57 12 : ulong ret = 1UL; /* by default return Ok(1) == error */
58 :
59 : /* Note: we don't strictly follow the Rust implementation, but instead combine
60 : common code across switch cases. Similar to fd_vm_syscall_sol_alt_bn128_group_op. */
61 :
62 : /* MATCH_ID_OP allows us to unify 2 switch/case into 1.
63 : For better readability, we also temp define EDWARDS, RISTRETTO.
64 :
65 : The first time we check that both curve_id and group_op are valid
66 : with 2 nested switch/case. Using MATCH_ID_OP leads to undesidered
67 : edge cases. The second time, when we know that curve_id and group_op
68 : are correct, then we can use MATCH_ID_OP and a single switch/case. */
69 24 : #define MATCH_ID_OP(crv_id,grp_op) ((crv_id << 4) | grp_op)
70 12 : #define EDWARDS FD_VM_SYSCALL_SOL_CURVE_CURVE25519_EDWARDS
71 12 : #define RISTRETTO FD_VM_SYSCALL_SOL_CURVE_CURVE25519_RISTRETTO
72 :
73 12 : ulong cost = 0UL;
74 12 : switch( curve_id ) {
75 :
76 0 : case EDWARDS:
77 0 : switch( group_op ) {
78 :
79 0 : case FD_VM_SYSCALL_SOL_CURVE_ADD:
80 0 : cost = FD_VM_CURVE25519_EDWARDS_ADD_COST;
81 0 : break;
82 :
83 0 : case FD_VM_SYSCALL_SOL_CURVE_SUB:
84 0 : cost = FD_VM_CURVE25519_EDWARDS_SUBTRACT_COST;
85 0 : break;
86 :
87 0 : case FD_VM_SYSCALL_SOL_CURVE_MUL:
88 0 : cost = FD_VM_CURVE25519_EDWARDS_MULTIPLY_COST;
89 0 : break;
90 :
91 0 : default:
92 0 : goto invalid_error;
93 0 : }
94 0 : break;
95 :
96 12 : case RISTRETTO:
97 12 : switch( group_op ) {
98 :
99 6 : case FD_VM_SYSCALL_SOL_CURVE_ADD:
100 6 : cost = FD_VM_CURVE25519_RISTRETTO_ADD_COST;
101 6 : break;
102 :
103 3 : case FD_VM_SYSCALL_SOL_CURVE_SUB:
104 3 : cost = FD_VM_CURVE25519_RISTRETTO_SUBTRACT_COST;
105 3 : break;
106 :
107 3 : case FD_VM_SYSCALL_SOL_CURVE_MUL:
108 3 : cost = FD_VM_CURVE25519_RISTRETTO_MULTIPLY_COST;
109 3 : break;
110 :
111 0 : default:
112 0 : goto invalid_error;
113 12 : }
114 12 : break;
115 :
116 12 : default:
117 0 : goto invalid_error;
118 12 : }
119 :
120 : /* https://github.com/anza-xyz/agave/blob/v1.18.8/programs/bpf_loader/src/syscalls/mod.rs#L944-L947 */
121 24 : FD_VM_CU_UPDATE( vm, cost );
122 :
123 : /* https://github.com/anza-xyz/agave/blob/v1.18.8/programs/bpf_loader/src/syscalls/mod.rs#L949-L958 */
124 :
125 : /* Note: left_input_addr is a point for add, sub, BUT it's a scalar for mul.
126 : However, from a memory mapping perspective it's always 32 bytes, so we unify the code. */
127 36 : uchar const * inputL = FD_VM_MEM_HADDR_LD( vm, left_input_addr, FD_VM_ALIGN_RUST_POD_U8_ARRAY, 32UL );
128 36 : uchar const * inputR = FD_VM_MEM_HADDR_LD( vm, right_input_addr, FD_VM_ALIGN_RUST_POD_U8_ARRAY, FD_VM_SYSCALL_SOL_CURVE_CURVE25519_POINT_SZ );
129 :
130 12 : switch( MATCH_ID_OP( curve_id, group_op ) ) {
131 :
132 0 : case MATCH_ID_OP( EDWARDS, FD_VM_SYSCALL_SOL_CURVE_ADD ): {
133 0 : fd_ed25519_point_t p0[1], p1[1], r[1];
134 0 : if( FD_UNLIKELY( !fd_ed25519_point_frombytes( p0, inputL ) ) ) {
135 0 : goto soft_error;
136 0 : }
137 0 : if( FD_UNLIKELY( !fd_ed25519_point_frombytes( p1, inputR ) ) ) {
138 0 : goto soft_error;
139 0 : }
140 :
141 0 : 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 );
142 0 : fd_ed25519_point_add( r, p0, p1 );
143 0 : fd_ed25519_point_tobytes( result, r );
144 0 : ret = 0UL;
145 0 : break;
146 0 : }
147 :
148 0 : case MATCH_ID_OP( EDWARDS, FD_VM_SYSCALL_SOL_CURVE_SUB ): {
149 0 : fd_ed25519_point_t p0[1], p1[1], r[1];
150 0 : if( FD_UNLIKELY( !fd_ed25519_point_frombytes( p0, inputL ) ) ) {
151 0 : goto soft_error;
152 0 : }
153 0 : if( FD_UNLIKELY( !fd_ed25519_point_frombytes( p1, inputR ) ) ) {
154 0 : goto soft_error;
155 0 : }
156 :
157 0 : 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 );
158 0 : fd_ed25519_point_sub( r, p0, p1 );
159 0 : fd_ed25519_point_tobytes( result, r );
160 0 : ret = 0UL;
161 0 : break;
162 0 : }
163 :
164 0 : case MATCH_ID_OP( EDWARDS, FD_VM_SYSCALL_SOL_CURVE_MUL ): {
165 0 : fd_ed25519_point_t p[1], r[1];
166 0 : if( FD_UNLIKELY( !fd_curve25519_scalar_validate( inputL ) ) ) {
167 0 : goto soft_error;
168 0 : }
169 0 : if( FD_UNLIKELY( !fd_ed25519_point_frombytes( p, inputR ) ) ) {
170 0 : goto soft_error;
171 0 : }
172 :
173 0 : 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 );
174 0 : fd_ed25519_scalar_mul( r, inputL, p );
175 0 : fd_ed25519_point_tobytes( result, r );
176 0 : ret = 0UL;
177 0 : break;
178 0 : }
179 :
180 6 : case MATCH_ID_OP( RISTRETTO, FD_VM_SYSCALL_SOL_CURVE_ADD ): {
181 6 : fd_ristretto255_point_t p0[1], p1[1], r[1];
182 6 : if( FD_UNLIKELY( !fd_ristretto255_point_frombytes( p0, inputL ) ) ) {
183 0 : goto soft_error;
184 0 : }
185 6 : if( FD_UNLIKELY( !fd_ristretto255_point_frombytes( p1, inputR ) ) ) {
186 0 : goto soft_error;
187 0 : }
188 :
189 6 : 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 );
190 6 : fd_ristretto255_point_add( r, p0, p1 );
191 6 : fd_ristretto255_point_tobytes( result, r );
192 6 : ret = 0UL;
193 6 : break;
194 6 : }
195 :
196 3 : case MATCH_ID_OP( RISTRETTO, FD_VM_SYSCALL_SOL_CURVE_SUB ): {
197 3 : fd_ristretto255_point_t p0[1], p1[1], r[1];
198 3 : if( FD_UNLIKELY( !fd_ristretto255_point_frombytes( p0, inputL ) ) ) {
199 0 : goto soft_error;
200 0 : }
201 3 : if( FD_UNLIKELY( !fd_ristretto255_point_frombytes( p1, inputR ) ) ) {
202 0 : goto soft_error;
203 0 : }
204 :
205 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 );
206 3 : fd_ristretto255_point_sub( r, p0, p1 );
207 3 : fd_ristretto255_point_tobytes( result, r );
208 3 : ret = 0UL;
209 3 : break;
210 3 : }
211 :
212 3 : case MATCH_ID_OP( RISTRETTO, FD_VM_SYSCALL_SOL_CURVE_MUL ): {
213 3 : fd_ristretto255_point_t p[1], r[1];
214 3 : if( FD_UNLIKELY( !fd_curve25519_scalar_validate( inputL ) ) ) {
215 0 : goto soft_error;
216 0 : }
217 3 : if( FD_UNLIKELY( !fd_ristretto255_point_frombytes( p, inputR ) ) ) {
218 0 : goto soft_error;
219 0 : }
220 :
221 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 );
222 3 : fd_ristretto255_scalar_mul( r, inputL, p );
223 3 : fd_ristretto255_point_tobytes( result, r );
224 3 : ret = 0UL;
225 3 : break;
226 3 : }
227 :
228 0 : default:
229 : /* COV: this can never happen because of the previous switch */
230 0 : return FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE; /* SyscallError::InvalidAttribute */
231 36 : }
232 :
233 12 : soft_error:
234 12 : *_ret = ret;
235 12 : return FD_VM_SUCCESS;
236 0 : #undef MATCH_ID_OP
237 0 : #undef EDWARDS
238 0 : #undef RISTRETTO
239 :
240 0 : invalid_error:
241 : /* https://github.com/anza-xyz/agave/blob/5b3390b99a6e7665439c623062c1a1dda2803524/programs/bpf_loader/src/syscalls/mod.rs#L1135-L1156 */
242 0 : if( FD_FEATURE_ACTIVE( vm->instr_ctx->txn_ctx->slot, vm->instr_ctx->txn_ctx->features, abort_on_invalid_curve ) ) {
243 0 : FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE );
244 0 : return FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE; /* SyscallError::InvalidAttribute */
245 0 : }
246 0 : *_ret = 1UL;
247 0 : return FD_VM_SUCCESS;
248 0 : }
249 :
250 : /* multi_scalar_mul_edwards computes a MSM on curve25519.
251 :
252 : This function is equivalent to
253 : zk-token-sdk::edwards::multi_scalar_mul_edwards
254 :
255 : https://github.com/solana-labs/solana/blob/v1.17.7/zk-token-sdk/src/curve25519/edwards.rs#L116
256 :
257 : Specifically it takes as input byte arrays and takes care of scalars
258 : validation and points decompression. It then invokes ballet MSM
259 : function fd_ed25519_multi_scalar_mul. To avoid dynamic allocation,
260 : the full MSM is done in batches of FD_BALLET_CURVE25519_MSM_BATCH_SZ. */
261 :
262 : static fd_ed25519_point_t *
263 : multi_scalar_mul_edwards( fd_ed25519_point_t * r,
264 : uchar const * scalars,
265 : uchar const * points,
266 3 : ulong cnt ) {
267 : /* Validate all scalars first (fast) */
268 9 : for( ulong i=0UL; i<cnt; i++ ) {
269 6 : if( FD_UNLIKELY( !fd_curve25519_scalar_validate ( scalars + i*FD_VM_SYSCALL_SOL_CURVE_CURVE25519_SCALAR_SZ ) ) ) {
270 0 : return NULL;
271 0 : }
272 6 : }
273 :
274 : /* Static allocation of a batch of decompressed points */
275 3 : fd_ed25519_point_t tmp[1];
276 3 : fd_ed25519_point_t A[ FD_BALLET_CURVE25519_MSM_BATCH_SZ ];
277 :
278 3 : fd_ed25519_point_set_zero( r );
279 6 : for( ulong i=0UL; i<cnt; i+=FD_BALLET_CURVE25519_MSM_BATCH_SZ ) {
280 3 : ulong batch_cnt = fd_ulong_min( cnt-i, FD_BALLET_CURVE25519_MSM_BATCH_SZ );
281 :
282 : /* Decompress (and validate) points */
283 9 : for( ulong j=0UL; j<batch_cnt; j++ ) {
284 : //TODO: use fd_ed25519_point_frombytes_2x
285 6 : if( FD_UNLIKELY( !fd_ed25519_point_frombytes( &A[j], points + j*FD_VM_SYSCALL_SOL_CURVE_CURVE25519_POINT_SZ ) ) ) {
286 0 : return NULL;
287 0 : }
288 6 : }
289 :
290 3 : fd_ed25519_multi_scalar_mul( tmp, scalars, A, batch_cnt );
291 3 : fd_ed25519_point_add( r, r, tmp );
292 3 : points += FD_VM_SYSCALL_SOL_CURVE_CURVE25519_POINT_SZ *batch_cnt;
293 3 : scalars += FD_VM_SYSCALL_SOL_CURVE_CURVE25519_SCALAR_SZ*batch_cnt;
294 3 : }
295 :
296 3 : return r;
297 3 : }
298 :
299 : /* multi_scalar_mul_ristretto computes a MSM on ristretto255.
300 : See multi_scalar_mul_edwards for details. */
301 :
302 : static fd_ed25519_point_t *
303 : multi_scalar_mul_ristretto( fd_ristretto255_point_t * r,
304 : uchar const * scalars,
305 : uchar const * points,
306 3 : ulong cnt ) {
307 : /* Validate all scalars first (fast) */
308 9 : for( ulong i=0UL; i<cnt; i++ ) {
309 6 : if( FD_UNLIKELY( !fd_curve25519_scalar_validate ( scalars + i*FD_VM_SYSCALL_SOL_CURVE_CURVE25519_SCALAR_SZ ) ) ) {
310 0 : return NULL;
311 0 : }
312 6 : }
313 :
314 : /* Static allocation of a batch of decompressed points */
315 3 : fd_ristretto255_point_t tmp[1];
316 3 : fd_ristretto255_point_t A[ FD_BALLET_CURVE25519_MSM_BATCH_SZ ];
317 :
318 3 : fd_ristretto255_point_set_zero( r );
319 6 : for( ulong i=0UL; i<cnt; i+=FD_BALLET_CURVE25519_MSM_BATCH_SZ ) {
320 3 : ulong batch_cnt = fd_ulong_min( cnt-i, FD_BALLET_CURVE25519_MSM_BATCH_SZ );
321 :
322 : /* Decompress (and validate) points */
323 9 : for( ulong j=0UL; j<batch_cnt; j++ ) {
324 : //TODO: use fd_ristretto255_point_frombytes_2x
325 6 : if( FD_UNLIKELY( !fd_ristretto255_point_frombytes( &A[j], points + j*FD_VM_SYSCALL_SOL_CURVE_CURVE25519_POINT_SZ ) ) ) {
326 0 : return NULL;
327 0 : }
328 6 : }
329 :
330 3 : fd_ristretto255_multi_scalar_mul( tmp, scalars, A, batch_cnt );
331 3 : fd_ristretto255_point_add( r, r, tmp );
332 3 : points += FD_VM_SYSCALL_SOL_CURVE_CURVE25519_POINT_SZ *batch_cnt;
333 3 : scalars += FD_VM_SYSCALL_SOL_CURVE_CURVE25519_SCALAR_SZ*batch_cnt;
334 3 : }
335 :
336 3 : return r;
337 3 : }
338 :
339 : #undef BATCH_MAX
340 :
341 : int
342 : fd_vm_syscall_sol_curve_multiscalar_mul( void * _vm,
343 : ulong curve_id,
344 : ulong scalars_addr,
345 : ulong points_addr,
346 : ulong points_len,
347 : ulong result_point_addr,
348 15 : ulong * _ret ) {
349 : /* https://github.com/anza-xyz/agave/blob/v1.18.8/programs/bpf_loader/src/syscalls/mod.rs#L1129 */
350 15 : fd_vm_t * vm = (fd_vm_t *)_vm;
351 15 : ulong ret = 1UL; /* by default return Ok(1) == error */
352 :
353 : /* https://github.com/anza-xyz/agave/blob/v1.18.8/programs/bpf_loader/src/syscalls/mod.rs#L1143-L1151 */
354 15 : if( FD_UNLIKELY( points_len > 512 ) ) {
355 3 : FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_INVALID_LENGTH );
356 3 : return FD_VM_SYSCALL_ERR_INVALID_LENGTH; /* SyscallError::InvalidLength */
357 3 : }
358 :
359 : /* Note: we don't strictly follow the Rust implementation, but instead combine
360 : common code across switch cases. Similar to fd_vm_syscall_sol_alt_bn128_group_op. */
361 :
362 12 : ulong base_cost = 0UL;
363 12 : ulong incremental_cost = 0UL;
364 12 : switch( curve_id ) {
365 6 : case FD_VM_SYSCALL_SOL_CURVE_CURVE25519_EDWARDS:
366 6 : base_cost = FD_VM_CURVE25519_EDWARDS_MSM_BASE_COST;
367 6 : incremental_cost = FD_VM_CURVE25519_EDWARDS_MSM_INCREMENTAL_COST;
368 6 : break;
369 :
370 3 : case FD_VM_SYSCALL_SOL_CURVE_CURVE25519_RISTRETTO:
371 3 : base_cost = FD_VM_CURVE25519_RISTRETTO_MSM_BASE_COST;
372 3 : incremental_cost = FD_VM_CURVE25519_RISTRETTO_MSM_INCREMENTAL_COST;
373 3 : break;
374 :
375 3 : default:
376 : /* https://github.com/anza-xyz/agave/blob/5b3390b99a6e7665439c623062c1a1dda2803524/programs/bpf_loader/src/syscalls/mod.rs#L1262-L1271 */
377 3 : if( FD_FEATURE_ACTIVE( vm->instr_ctx->txn_ctx->slot, vm->instr_ctx->txn_ctx->features, abort_on_invalid_curve ) ) {
378 3 : FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE );
379 3 : return FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE; /* SyscallError::InvalidAttribute */
380 3 : }
381 0 : goto soft_error;
382 12 : }
383 :
384 : /* https://github.com/anza-xyz/agave/blob/v1.18.8/programs/bpf_loader/src/syscalls/mod.rs#L1155-L1164 */
385 9 : ulong cost = fd_ulong_sat_add(
386 9 : base_cost,
387 9 : fd_ulong_sat_mul(
388 9 : incremental_cost,
389 9 : fd_ulong_sat_sub( points_len, 1 )
390 9 : )
391 9 : );
392 9 : FD_VM_CU_UPDATE( vm, cost );
393 :
394 : /* Edge case points_len==0.
395 : Agave computes the MSM, that returns the point at infinity, and stores the result.
396 : This means that we have to mem map result, and then set the point at infinity,
397 : that is 0x0100..00 for Edwards and 0x00..00 for Ristretto. */
398 9 : if ( FD_UNLIKELY( points_len==0 ) ) {
399 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 );
400 0 : memset( result, 0, 32 );
401 0 : result[0] = curve_id==FD_VM_SYSCALL_SOL_CURVE_CURVE25519_EDWARDS ? 1 : 0;
402 0 : *_ret = 0;
403 0 : return FD_VM_SUCCESS;
404 3 : }
405 :
406 : /* https://github.com/anza-xyz/agave/blob/v1.18.8/programs/bpf_loader/src/syscalls/mod.rs#L1166-L1178 */
407 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 );
408 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 );
409 :
410 0 : switch( curve_id ) {
411 :
412 3 : case FD_VM_SYSCALL_SOL_CURVE_CURVE25519_EDWARDS: {
413 : /* https://github.com/anza-xyz/agave/blob/v1.18.8/programs/bpf_loader/src/syscalls/mod.rs#L1180-L1189 */
414 3 : fd_ed25519_point_t _r[1];
415 3 : fd_ed25519_point_t * r = multi_scalar_mul_edwards( _r, scalars, points, points_len );
416 :
417 3 : if( FD_LIKELY( r ) ) {
418 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 );
419 0 : fd_ed25519_point_tobytes( result, r );
420 3 : ret = 0UL;
421 3 : }
422 3 : break;
423 3 : }
424 :
425 3 : case FD_VM_SYSCALL_SOL_CURVE_CURVE25519_RISTRETTO: {
426 3 : fd_ristretto255_point_t _r[1];
427 3 : fd_ristretto255_point_t * r = multi_scalar_mul_ristretto( _r, scalars, points, points_len );
428 :
429 3 : if( FD_LIKELY( r ) ) {
430 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 );
431 0 : fd_ristretto255_point_tobytes( result, r );
432 3 : ret = 0UL;
433 3 : }
434 3 : break;
435 3 : }
436 :
437 3 : default:
438 : /* COV: this can never happen because of the previous switch */
439 0 : return FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE; /* SyscallError::InvalidAttribute */
440 18 : }
441 :
442 6 : soft_error:
443 6 : *_ret = ret;
444 6 : return FD_VM_SUCCESS;
445 18 : }
|