Line data Source code
1 : #include "fd_vm_syscall.h"
2 :
3 : #include "../../../ballet/bn254/fd_bn254.h"
4 : #include "../../../ballet/bn254/fd_poseidon.h"
5 : #include "../../../ballet/secp256k1/fd_secp256k1.h"
6 : #include "../../runtime/fd_bank.h"
7 :
8 : int
9 : fd_vm_syscall_sol_alt_bn128_group_op( void * _vm,
10 : ulong group_op,
11 : ulong input_addr,
12 : ulong input_sz,
13 : ulong result_addr,
14 2621 : FD_PARAM_UNUSED ulong r5 ) {
15 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1509 */
16 2621 : fd_vm_t * vm = (fd_vm_t *)_vm;
17 2621 : ulong ret = 1UL; /* by default return Ok(1) == error */
18 :
19 : /* G1/pairing little endian syscalls are under feature gate alt_bn128_little_endian.
20 : To clean up the feature gate after activation, just remove this block
21 : (the rest of the function will behave correctly). */
22 2621 : {
23 2621 : if( FD_UNLIKELY(
24 2621 : !FD_FEATURE_ACTIVE_BANK( vm->instr_ctx->bank, alt_bn128_little_endian )
25 2621 : && ( group_op==FD_VM_SYSCALL_SOL_ALT_BN128_G1_ADD_LE
26 2621 : || group_op==FD_VM_SYSCALL_SOL_ALT_BN128_G1_MUL_LE
27 2621 : || group_op==FD_VM_SYSCALL_SOL_ALT_BN128_PAIRING_LE )
28 2621 : ) ) {
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 2621 : }
33 :
34 : /* G2 syscalls are under feature gate enable_alt_bn128_g2_syscalls.
35 : To clean up the feature gate after activation, just remove this block
36 : (the rest of the function will behave correctly). */
37 2621 : {
38 2621 : if( FD_UNLIKELY(
39 2621 : !FD_FEATURE_ACTIVE_BANK( vm->instr_ctx->bank, enable_alt_bn128_g2_syscalls )
40 2621 : && ( group_op==FD_VM_SYSCALL_SOL_ALT_BN128_G2_ADD_BE
41 2621 : || group_op==FD_VM_SYSCALL_SOL_ALT_BN128_G2_ADD_LE
42 2621 : || group_op==FD_VM_SYSCALL_SOL_ALT_BN128_G2_MUL_BE
43 2621 : || group_op==FD_VM_SYSCALL_SOL_ALT_BN128_G2_MUL_LE )
44 2621 : ) ) {
45 0 : FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE );
46 0 : return FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE; /* SyscallError::InvalidAttribute */
47 0 : }
48 2621 : }
49 :
50 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1520-L1549 */
51 2621 : ulong cost = 0UL;
52 2621 : ulong output_sz = 0UL;
53 2621 : switch( group_op ) {
54 :
55 63 : case FD_VM_SYSCALL_SOL_ALT_BN128_G1_ADD_BE:
56 95 : case FD_VM_SYSCALL_SOL_ALT_BN128_G1_ADD_LE:
57 95 : output_sz = FD_VM_SYSCALL_SOL_ALT_BN128_G1_SZ;
58 95 : cost = FD_VM_ALT_BN128_G1_ADDITION_COST;
59 95 : break;
60 :
61 1813 : case FD_VM_SYSCALL_SOL_ALT_BN128_G1_MUL_BE:
62 1848 : case FD_VM_SYSCALL_SOL_ALT_BN128_G1_MUL_LE:
63 1848 : output_sz = FD_VM_SYSCALL_SOL_ALT_BN128_G1_SZ;
64 1848 : cost = FD_VM_ALT_BN128_G1_MULTIPLICATION_COST;
65 1848 : break;
66 :
67 32 : case FD_VM_SYSCALL_SOL_ALT_BN128_G2_ADD_BE:
68 64 : case FD_VM_SYSCALL_SOL_ALT_BN128_G2_ADD_LE:
69 64 : output_sz = FD_VM_SYSCALL_SOL_ALT_BN128_G2_SZ;
70 64 : cost = FD_VM_ALT_BN128_G2_ADDITION_COST;
71 64 : break;
72 :
73 24 : case FD_VM_SYSCALL_SOL_ALT_BN128_G2_MUL_BE:
74 53 : case FD_VM_SYSCALL_SOL_ALT_BN128_G2_MUL_LE:
75 53 : output_sz = FD_VM_SYSCALL_SOL_ALT_BN128_G2_SZ;
76 53 : cost = FD_VM_ALT_BN128_G2_MULTIPLICATION_COST;
77 53 : break;
78 :
79 528 : case FD_VM_SYSCALL_SOL_ALT_BN128_PAIRING_BE:
80 559 : case FD_VM_SYSCALL_SOL_ALT_BN128_PAIRING_LE:
81 559 : output_sz = FD_VM_SYSCALL_SOL_ALT_BN128_PAIRING_OUTPUT_SZ;
82 559 : ulong elements_len = input_sz / FD_VM_SYSCALL_SOL_ALT_BN128_PAIRING_INPUT_EL_SZ;
83 559 : cost = FD_VM_ALT_BN128_PAIRING_ONE_PAIR_COST_FIRST
84 559 : + FD_VM_SHA256_BASE_COST
85 559 : + FD_VM_SYSCALL_SOL_ALT_BN128_PAIRING_OUTPUT_SZ;
86 559 : cost = fd_ulong_sat_add( cost,
87 559 : fd_ulong_sat_mul( FD_VM_ALT_BN128_PAIRING_ONE_PAIR_COST_OTHER,
88 559 : fd_ulong_sat_sub( elements_len, 1 ) ) );
89 559 : cost = fd_ulong_sat_add( cost, input_sz );
90 559 : break;
91 :
92 2 : default:
93 2 : FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE );
94 2 : return FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE; /* SyscallError::InvalidAttribute */
95 2621 : }
96 :
97 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1551 */
98 :
99 5224 : FD_VM_CU_UPDATE( vm, cost );
100 :
101 2599 : uchar * call_result = FD_VM_HADDR_QUERY_U8_SLICE( vm, result_addr, output_sz );
102 5195 : uchar const * input = FD_VM_MEM_SLICE_HADDR_LD( vm, input_addr, FD_VM_ALIGN_RUST_U8, input_sz );
103 :
104 2596 : int big_endian = ( group_op & FD_VM_SYSCALL_SOL_ALT_BN128_LITTLE_ENDIAN_FLAG ) ? 0 : 1;
105 :
106 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1567-L1598
107 : Note: this implementation is post SIMD-0129, we only support the simplified error codes. */
108 5195 : switch( group_op ) {
109 :
110 60 : case FD_VM_SYSCALL_SOL_ALT_BN128_G1_ADD_BE:
111 92 : case FD_VM_SYSCALL_SOL_ALT_BN128_G1_ADD_LE:
112 : /* Compute add */
113 92 : if( FD_LIKELY( fd_bn254_g1_add_syscall( call_result, input, input_sz, big_endian )==0 ) ) {
114 57 : ret = 0UL; /* success */
115 57 : }
116 92 : break;
117 :
118 1819 : case FD_VM_SYSCALL_SOL_ALT_BN128_G1_MUL_BE:
119 1853 : case FD_VM_SYSCALL_SOL_ALT_BN128_G1_MUL_LE:
120 : /* Compute scalar mul */
121 1853 : if( FD_LIKELY( fd_bn254_g1_scalar_mul_syscall( call_result, input, input_sz, big_endian )==0 ) ) {
122 514 : ret = 0UL; /* success */
123 514 : }
124 1853 : break;
125 :
126 30 : case FD_VM_SYSCALL_SOL_ALT_BN128_G2_ADD_BE:
127 61 : case FD_VM_SYSCALL_SOL_ALT_BN128_G2_ADD_LE:
128 : /* Compute add */
129 61 : if( FD_LIKELY( fd_bn254_g2_add_syscall( call_result, input, input_sz, big_endian )==0 ) ) {
130 27 : ret = 0UL; /* success */
131 27 : }
132 61 : break;
133 :
134 24 : case FD_VM_SYSCALL_SOL_ALT_BN128_G2_MUL_BE:
135 52 : case FD_VM_SYSCALL_SOL_ALT_BN128_G2_MUL_LE:
136 : /* Compute scalar mul */
137 52 : if( FD_LIKELY( fd_bn254_g2_scalar_mul_syscall( call_result, input, input_sz, big_endian )==0 ) ) {
138 30 : ret = 0UL; /* success */
139 30 : }
140 52 : break;
141 :
142 520 : case FD_VM_SYSCALL_SOL_ALT_BN128_PAIRING_BE:
143 549 : case FD_VM_SYSCALL_SOL_ALT_BN128_PAIRING_LE:
144 : /* Compute pairing, always checking that input length is a multiple of 192.
145 : https://github.com/anza-xyz/solana-sdk/blob/bn254%40v3.1.2/bn254/src/pairing.rs#L76-L82 */
146 549 : if( FD_LIKELY( fd_bn254_pairing_is_one_syscall( call_result, input, input_sz, big_endian )==0 ) ) {
147 132 : ret = 0UL; /* success */
148 132 : }
149 549 : break;
150 5195 : }
151 :
152 2614 : vm->reg[0] = ret;
153 2614 : return FD_VM_SUCCESS; /* Ok(SUCCESS) or Ok(ERROR) */
154 5195 : }
155 :
156 : int
157 : fd_vm_syscall_sol_alt_bn128_compression( void * _vm,
158 : ulong op,
159 : ulong input_addr,
160 : ulong input_sz,
161 : ulong result_addr,
162 1218 : FD_PARAM_UNUSED ulong r5 ) {
163 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1776 */
164 1218 : fd_vm_t * vm = (fd_vm_t *)_vm;
165 1218 : ulong ret = 1UL; /* by default return Ok(1) == error */
166 :
167 : /* G1/G2 little endian syscalls are under feature gate alt_bn128_little_endian.
168 : To clean up the feature gate after activation, just remove this block
169 : (the rest of the function will behave correctly). */
170 1218 : {
171 1218 : if( FD_UNLIKELY(
172 1218 : !FD_FEATURE_ACTIVE_BANK( vm->instr_ctx->bank, alt_bn128_little_endian )
173 1218 : && ( op==FD_VM_SYSCALL_SOL_ALT_BN128_G1_COMPRESS_LE
174 1218 : || op==FD_VM_SYSCALL_SOL_ALT_BN128_G2_COMPRESS_LE
175 1218 : || op==FD_VM_SYSCALL_SOL_ALT_BN128_G1_DECOMPRESS_LE
176 1218 : || op==FD_VM_SYSCALL_SOL_ALT_BN128_G2_DECOMPRESS_LE )
177 1218 : ) ) {
178 0 : FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE );
179 0 : return FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE; /* SyscallError::InvalidAttribute */
180 0 : }
181 1218 : }
182 :
183 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1791-L1811 */
184 1218 : ulong cost = 0UL;
185 1218 : ulong output_sz = 0UL;
186 1218 : switch( op ) {
187 :
188 240 : case FD_VM_SYSCALL_SOL_ALT_BN128_G1_COMPRESS_BE:
189 275 : case FD_VM_SYSCALL_SOL_ALT_BN128_G1_COMPRESS_LE:
190 275 : output_sz = FD_VM_SYSCALL_SOL_ALT_BN128_G1_COMPRESSED_SZ;
191 275 : cost = FD_VM_ALT_BN128_G1_COMPRESS;
192 275 : break;
193 :
194 238 : case FD_VM_SYSCALL_SOL_ALT_BN128_G1_DECOMPRESS_BE:
195 270 : case FD_VM_SYSCALL_SOL_ALT_BN128_G1_DECOMPRESS_LE:
196 270 : output_sz = FD_VM_SYSCALL_SOL_ALT_BN128_G1_SZ;
197 270 : cost = FD_VM_ALT_BN128_G1_DECOMPRESS;
198 270 : break;
199 :
200 296 : case FD_VM_SYSCALL_SOL_ALT_BN128_G2_COMPRESS_BE:
201 332 : case FD_VM_SYSCALL_SOL_ALT_BN128_G2_COMPRESS_LE:
202 332 : output_sz = FD_VM_SYSCALL_SOL_ALT_BN128_G2_COMPRESSED_SZ;
203 332 : cost = FD_VM_ALT_BN128_G2_COMPRESS;
204 332 : break;
205 :
206 308 : case FD_VM_SYSCALL_SOL_ALT_BN128_G2_DECOMPRESS_BE:
207 337 : case FD_VM_SYSCALL_SOL_ALT_BN128_G2_DECOMPRESS_LE:
208 337 : output_sz = FD_VM_SYSCALL_SOL_ALT_BN128_G2_SZ;
209 337 : cost = FD_VM_ALT_BN128_G2_DECOMPRESS;
210 337 : break;
211 :
212 5 : default:
213 5 : FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE );
214 5 : return FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE; /* SyscallError::InvalidAttribute */
215 1218 : }
216 1212 : cost = fd_ulong_sat_add( cost, FD_VM_SYSCALL_BASE_COST );
217 :
218 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1813 */
219 :
220 1212 : FD_VM_CU_UPDATE( vm, cost );
221 :
222 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1815-L1827 */
223 :
224 1194 : uchar * call_result = FD_VM_HADDR_QUERY_U8_SLICE( vm, result_addr, output_sz );
225 2384 : void const * input = FD_VM_MEM_SLICE_HADDR_LD( vm, input_addr, FD_VM_ALIGN_RUST_U8, input_sz );
226 :
227 1190 : int big_endian = ( op & FD_VM_SYSCALL_SOL_ALT_BN128_LITTLE_ENDIAN_FLAG ) ? 0 : 1;
228 :
229 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1829-L1891
230 : Note: this implementation is post SIMD-0129, we only support the simplified error codes. */
231 2384 : switch( op ) {
232 :
233 235 : case FD_VM_SYSCALL_SOL_ALT_BN128_G1_COMPRESS_BE:
234 269 : case FD_VM_SYSCALL_SOL_ALT_BN128_G1_COMPRESS_LE:
235 269 : if( FD_UNLIKELY( input_sz!=FD_VM_SYSCALL_SOL_ALT_BN128_G1_SZ ) ) {
236 5 : goto soft_error;
237 5 : }
238 264 : if( FD_LIKELY( fd_bn254_g1_compress( call_result, fd_type_pun_const(input), big_endian ) ) ) {
239 101 : ret = 0UL; /* success */
240 101 : }
241 264 : break;
242 :
243 235 : case FD_VM_SYSCALL_SOL_ALT_BN128_G1_DECOMPRESS_BE:
244 267 : case FD_VM_SYSCALL_SOL_ALT_BN128_G1_DECOMPRESS_LE:
245 267 : if( FD_UNLIKELY( input_sz!=FD_VM_SYSCALL_SOL_ALT_BN128_G1_COMPRESSED_SZ ) ) {
246 2 : goto soft_error;
247 2 : }
248 265 : if( FD_LIKELY( fd_bn254_g1_decompress( call_result, fd_type_pun_const(input), big_endian ) ) ) {
249 182 : ret = 0UL; /* success */
250 182 : }
251 265 : break;
252 :
253 294 : case FD_VM_SYSCALL_SOL_ALT_BN128_G2_COMPRESS_BE:
254 328 : case FD_VM_SYSCALL_SOL_ALT_BN128_G2_COMPRESS_LE:
255 328 : if( FD_UNLIKELY( input_sz!=FD_VM_SYSCALL_SOL_ALT_BN128_G2_SZ ) ) {
256 6 : goto soft_error;
257 6 : }
258 322 : if( FD_LIKELY( fd_bn254_g2_compress( call_result, fd_type_pun_const(input), big_endian ) ) ) {
259 70 : ret = 0UL; /* success */
260 70 : }
261 322 : break;
262 :
263 305 : case FD_VM_SYSCALL_SOL_ALT_BN128_G2_DECOMPRESS_BE:
264 332 : case FD_VM_SYSCALL_SOL_ALT_BN128_G2_DECOMPRESS_LE:
265 332 : if( FD_UNLIKELY( input_sz!=FD_VM_SYSCALL_SOL_ALT_BN128_G2_COMPRESSED_SZ ) ) {
266 3 : goto soft_error;
267 3 : }
268 329 : if( FD_LIKELY( fd_bn254_g2_decompress( call_result, fd_type_pun_const(input), big_endian ) ) ) {
269 171 : ret = 0UL; /* success */
270 171 : }
271 329 : break;
272 2384 : }
273 :
274 1197 : soft_error:
275 1197 : vm->reg[0] = ret;
276 1197 : return FD_VM_SUCCESS; /* Ok(SUCCESS) or Ok(ERROR) */
277 2384 : }
278 :
279 : int
280 : fd_vm_syscall_sol_poseidon( void * _vm,
281 : ulong params,
282 : ulong endianness,
283 : ulong vals_addr,
284 : ulong vals_len,
285 289 : ulong result_addr ) {
286 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1678 */
287 289 : fd_vm_t * vm = (fd_vm_t *)_vm;
288 289 : ulong ret = 1UL; /* by default return Ok(1) == error */
289 :
290 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1688 */
291 :
292 289 : if( FD_UNLIKELY( params!=0UL ) ) {
293 2 : FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_POSEIDON_INVALID_PARAMS );
294 2 : return FD_VM_SYSCALL_ERR_POSEIDON_INVALID_PARAMS; /* PoseidonSyscallError::InvalidParameters */
295 2 : }
296 :
297 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1689 */
298 :
299 287 : if( FD_UNLIKELY(
300 287 : endianness!=0UL /* Big endian */
301 287 : && endianness!=1UL /* Little endian */
302 287 : ) ) {
303 3 : FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_POSEIDON_INVALID_ENDIANNESS );
304 3 : return FD_VM_SYSCALL_ERR_POSEIDON_INVALID_ENDIANNESS; /* PoseidonSyscallError::InvalidEndianness */
305 3 : }
306 :
307 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1691-L1698 */
308 :
309 284 : if( FD_UNLIKELY( vals_len > FD_VM_SYSCALL_SOL_POSEIDON_MAX_VALS ) ) {
310 : /* Max msg_sz = 47 - 3 + 20 = 64 < 127 => we can use printf */
311 3 : fd_log_collector_printf_dangerous_max_127( vm->instr_ctx,
312 3 : "Poseidon hashing %lu sequences is not supported", vals_len );
313 3 : FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_INVALID_LENGTH );
314 3 : return FD_VM_SYSCALL_ERR_INVALID_LENGTH; /* SyscallError::InvalidLength */
315 3 : }
316 :
317 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1700-L1707
318 : poseidon_cost(): https://github.com/solana-labs/solana/blob/v1.18.12/program-runtime/src/compute_budget.rs#L211 */
319 :
320 : /* vals_len^2 * A + C */
321 281 : ulong cost = fd_ulong_sat_add(
322 281 : fd_ulong_sat_mul(
323 281 : fd_ulong_sat_mul( vals_len, vals_len ),
324 281 : FD_VM_POSEIDON_COST_COEFFICIENT_A
325 281 : ),
326 281 : FD_VM_POSEIDON_COST_COEFFICIENT_C
327 281 : );
328 :
329 : /* The following can never happen, left as comment for completeness.
330 : if( FD_UNLIKELY( cost == ULONG_MAX ) ) {
331 : fd_vm_log_append_printf( vm, "Overflow while calculating the compute cost" );
332 : return FD_VM_SYSCALL_ERR_ARITHMETIC_OVERFLOW; // SyscallError::ArithmeticOverflow
333 : }
334 : */
335 :
336 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1708 */
337 :
338 281 : FD_VM_CU_UPDATE( vm, cost );
339 :
340 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1710-L1715 */
341 :
342 259 : uchar * hash_result = FD_VM_HADDR_QUERY_U8_SLICE( vm, result_addr, 32UL );
343 :
344 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1716-L1732 */
345 :
346 : /* Agave allocates a vector of translated slices (that can return a fatal
347 : error), and then computes Poseidon, returning a soft error in case of
348 : issues (e.g. invalid input).
349 :
350 : We must be careful in returning the correct fatal vs soft error.
351 :
352 : The special case of vals_len==0 returns Ok(1), so for simplicity
353 : we capture it explicitly. */
354 :
355 259 : if( FD_UNLIKELY( !vals_len ) ) {
356 17 : goto soft_error;
357 17 : }
358 :
359 : /* First loop to memory map. This can return a fatal error. */
360 718 : fd_vm_vec_t const * input_vec_haddr = (fd_vm_vec_t const *)FD_VM_MEM_HADDR_LD( vm, vals_addr, FD_VM_VEC_ALIGN, vals_len*sizeof(fd_vm_vec_t) );
361 0 : void const * inputs_haddr[ FD_VM_SYSCALL_SOL_POSEIDON_MAX_VALS ];
362 1567 : for( ulong i=0UL; i<vals_len; i++ ) {
363 2668 : inputs_haddr[i] = FD_VM_MEM_SLICE_HADDR_LD( vm, input_vec_haddr[i].addr, FD_VM_ALIGN_RUST_U8, input_vec_haddr[i].len );
364 2668 : }
365 :
366 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1734-L1750
367 : Note: this implementation is post SIMD-0129, we only support the simplified error codes. */
368 :
369 : /* Second loop to computed Poseidon. This can return a soft error. */
370 228 : int big_endian = endianness==0;
371 228 : fd_poseidon_t pos[1];
372 228 : fd_poseidon_init( pos, big_endian );
373 :
374 1066 : for( ulong i=0UL; i<vals_len; i++ ) {
375 949 : if( FD_UNLIKELY( fd_poseidon_append( pos, inputs_haddr[ i ], input_vec_haddr[i].len )==NULL ) ) {
376 111 : goto soft_error;
377 111 : }
378 949 : }
379 :
380 117 : ret = !fd_poseidon_fini( pos, hash_result );
381 :
382 246 : soft_error:
383 246 : vm->reg[0] = ret;
384 246 : return FD_VM_SUCCESS; /* Ok(1) == error */
385 117 : }
386 :
387 : int
388 : fd_vm_syscall_sol_secp256k1_recover( /**/ void * _vm,
389 : /**/ ulong hash_vaddr,
390 : /**/ ulong recovery_id_val,
391 : /**/ ulong signature_vaddr,
392 : /**/ ulong result_vaddr,
393 302 : FD_PARAM_UNUSED ulong r5 ) {
394 : /* https://github.com/anza-xyz/agave/blob/v1.18.8/programs/bpf_loader/src/syscalls/mod.rs#L810 */
395 302 : fd_vm_t * vm = (fd_vm_t *)_vm;
396 :
397 : /* https://github.com/anza-xyz/agave/blob/v1.18.8/programs/bpf_loader/src/syscalls/mod.rs#L820-L821 */
398 :
399 302 : FD_VM_CU_UPDATE( vm, FD_VM_SECP256K1_RECOVER_COST );
400 :
401 : /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L957-L968 */
402 :
403 271 : uchar * pubkey_result = FD_VM_HADDR_QUERY_U8_SLICE( vm, result_vaddr, 64UL );
404 807 : uchar const * hash = FD_VM_MEM_HADDR_LD( vm, hash_vaddr, FD_VM_ALIGN_RUST_U8, 32UL );
405 790 : uchar const * sig = FD_VM_MEM_HADDR_LD( vm, signature_vaddr, FD_VM_ALIGN_RUST_U8, 64UL );
406 :
407 : /* CRITICAL */
408 :
409 : /* https://github.com/anza-xyz/agave/blob/v1.18.8/programs/bpf_loader/src/syscalls/mod.rs#L842-L853 */
410 :
411 : /* Secp256k1RecoverError::InvalidHash
412 : This can never happen, as `libsecp256k1::Message::parse_slice(hash)`
413 : only checks that hash is 32-byte long, and that's by construction.
414 : https://github.com/paritytech/libsecp256k1/blob/v0.6.0/src/lib.rs#L657-L665
415 :
416 : if( FD_UNLIKELY( 0 ) ) {
417 : vm->reg[0] = 1UL; // Secp256k1RecoverError::InvalidHash
418 : return FD_VM_SUCCESS;
419 : }
420 : */
421 :
422 : /* Secp256k1RecoverError::InvalidRecoveryId
423 : Agave code has 2 checks: the first is a cast from u64 to u8.
424 : The second is `libsecp256k1::RecoveryId::parse(adjusted_recover_id_val)` that
425 : checks if `adjusted_recover_id_val < 4`.
426 : https://github.com/paritytech/libsecp256k1/blob/v0.6.0/src/lib.rs#L674-L680
427 : */
428 :
429 261 : if( FD_UNLIKELY( recovery_id_val >= 4UL ) ) {
430 8 : vm->reg[0] = 2UL; /* Secp256k1RecoverError::InvalidRecoveryId */
431 8 : return FD_VM_SUCCESS;
432 8 : }
433 :
434 : /* Secp256k1RecoverError::InvalidSignature
435 : We omit this check, as this is done as part of fd_secp256k1_recover() below,
436 : and the return code is the same.
437 :
438 : In more details, this checks that the signature is valid, i.e. if the
439 : signature is represented as two scalars (r, s), it checks that both r
440 : and s are canonical scalars.
441 :
442 : Note the `?` at the end of this line:
443 : https://github.com/paritytech/libsecp256k1/blob/v0.6.0/src/lib.rs#L535
444 : And following the code, `scalar::check_overflow` is checks that the scalar is valid:
445 : https://github.com/paritytech/libsecp256k1/blob/master/core/src/scalar.rs#L70-L87 */
446 :
447 : /* https://github.com/anza-xyz/agave/blob/v1.18.8/programs/bpf_loader/src/syscalls/mod.rs#L855-L860 */
448 :
449 253 : uchar secp256k1_pubkey[64];
450 253 : if( FD_UNLIKELY( !fd_secp256k1_recover( secp256k1_pubkey, hash, sig, (int)recovery_id_val ) ) ) {
451 82 : vm->reg[0] = 3UL; /* Secp256k1RecoverError::InvalidSignature */
452 82 : return FD_VM_SUCCESS;
453 82 : }
454 :
455 171 : memcpy( pubkey_result, secp256k1_pubkey, 64UL );
456 :
457 171 : vm->reg[0] = 0UL;
458 171 : return FD_VM_SUCCESS;
459 253 : }
460 :
|