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