Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
instruction.cpp
Go to the documentation of this file.
2
3#include <optional>
4#include <random>
5#include <vector>
6
20
21namespace {
22
23// Maximum operand values based on instruction operand size
24constexpr uint32_t MAX_8BIT_OPERAND = 255;
25constexpr uint32_t MAX_16BIT_OPERAND = 65535;
26
27// Helper to generate a SET instruction for a given tag at a given address
29{
30 switch (tag) {
31 // We use set 16 for u1 and u8 because using set_8 will limit the address range to 255.
33 return SET_16_Instruction{ .value_tag = tag, .result_address = addr, .value = static_cast<uint8_t>(rng() & 1) };
35 return SET_16_Instruction{ .value_tag = tag, .result_address = addr, .value = generate_random_uint8(rng) };
37 return SET_16_Instruction{ .value_tag = tag, .result_address = addr, .value = generate_random_uint16(rng) };
39 return SET_32_Instruction{ .value_tag = tag, .result_address = addr, .value = generate_random_uint32(rng) };
41 return SET_64_Instruction{ .value_tag = tag, .result_address = addr, .value = generate_random_uint64(rng) };
44 .result_address = addr,
45 .value_low = generate_random_uint64(rng),
46 .value_high = generate_random_uint64(rng) };
48 default:
49 return SET_FF_Instruction{ .value_tag = tag, .result_address = addr, .value = generate_random_field(rng) };
50 }
51}
52
53uint8_t generate_envvar_type(std::mt19937_64& rng)
54{
55 bool valid_type = std::uniform_int_distribution<int>(0, 9)(rng) != 0;
56
57 if (valid_type) {
58 // 0 -> ADDRESS, 1 -> SENDER, 2 -> TRANSACTIONFEE, 3 -> CHAINID, 4 -> VERSION, 5 -> BLOCKNUMBER, 6 -> TIMESTAMP,
59 // 7 -> MINFEEPERDAGAS, 8 -> MINFEEPERL2GAS, 9 -> ISSTATICCALL, 10 -> L2GASLEFT, 11 -> DAGASLEFT
61 } else {
62 return generate_random_uint8(rng);
63 }
64}
65
66std::optional<MemoryTag> get_param_ref_tag(const ParamRef& param)
67{
68 return std::visit(overloaded{ [](const VariableRef& var) -> std::optional<MemoryTag> { return var.tag.value; },
69 [](const AddressRef&) -> std::optional<MemoryTag> { return std::nullopt; } },
70 param);
71}
72
73void sanitize_address_ref(AddressRef& address_ref, uint32_t base_offset, uint32_t max_operand_value)
74{
75
76 // For Direct mode, constrain address to fit in the operand
77 if (address_ref.mode == AddressingMode::Direct) {
78 address_ref.address = address_ref.address % (max_operand_value + 1);
79 }
80 // For Relative mode, we can reach from base_pointer to base_pointer + max_operand_value
81 if (address_ref.mode == AddressingMode::Relative) {
82 address_ref.address = base_offset + (address_ref.address % (max_operand_value + 1));
83 }
84}
85
86uint32_t generate_address(std::mt19937_64& rng)
87{
88 if (std::uniform_int_distribution<int>(0, 19)(rng) == 0) { // 5% chance to generate the highest address
90 }
91 return generate_random_uint32(rng);
92}
93
94} // namespace
95
96namespace bb::avm2::fuzzer {
97
99{
101 // forgive me
102 switch (option) {
104 return generate_alu_with_matching_tags<ADD_8_Instruction>(rng, MAX_8BIT_OPERAND);
106 return generate_alu_with_matching_tags<SUB_8_Instruction>(rng, MAX_8BIT_OPERAND);
108 return generate_alu_with_matching_tags<MUL_8_Instruction>(rng, MAX_8BIT_OPERAND);
110 return generate_alu_with_matching_tags_not_ff<DIV_8_Instruction>(rng, MAX_8BIT_OPERAND);
112 return generate_fdiv_instruction(rng, MAX_8BIT_OPERAND);
115 .b_address = generate_variable_ref(rng),
116 .result_address = generate_address_ref(rng, MAX_8BIT_OPERAND) } };
119 .b_address = generate_variable_ref(rng),
120 .result_address = generate_address_ref(rng, MAX_8BIT_OPERAND) } };
123 .b_address = generate_variable_ref(rng),
124 .result_address = generate_address_ref(rng, MAX_8BIT_OPERAND) } };
126 return generate_alu_with_matching_tags_not_ff<AND_8_Instruction>(rng, MAX_8BIT_OPERAND);
128 return generate_alu_with_matching_tags_not_ff<OR_8_Instruction>(rng, MAX_8BIT_OPERAND);
130 return generate_alu_with_matching_tags_not_ff<XOR_8_Instruction>(rng, MAX_8BIT_OPERAND);
133 .result_address = generate_address_ref(rng, MAX_8BIT_OPERAND) } };
136 .b_address = generate_variable_ref(rng),
137 .result_address = generate_address_ref(rng, MAX_8BIT_OPERAND) } };
138
141 .b_address = generate_variable_ref(rng),
142 .result_address = generate_address_ref(rng, MAX_8BIT_OPERAND) } };
145 .result_address = generate_address_ref(rng, MAX_8BIT_OPERAND),
146 .value = generate_random_uint8(rng) } };
149 .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
150 .value = generate_random_uint16(rng) } };
153 .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
154 .value = generate_random_uint32(rng) } };
157 .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
158 .value = generate_random_uint64(rng) } };
161 .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
162 .value_low = generate_random_uint64(rng),
163 .value_high = generate_random_uint64(rng) } };
166 .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
167 .value = generate_random_field(rng) } };
170 .src_address = generate_variable_ref(rng),
171 .result_address = generate_address_ref(rng, MAX_8BIT_OPERAND) } };
174 .src_address = generate_variable_ref(rng),
175 .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
177 return generate_alu_with_matching_tags<ADD_16_Instruction>(rng, MAX_16BIT_OPERAND);
179 return generate_alu_with_matching_tags<SUB_16_Instruction>(rng, MAX_16BIT_OPERAND);
181 return generate_alu_with_matching_tags<MUL_16_Instruction>(rng, MAX_16BIT_OPERAND);
183 return generate_alu_with_matching_tags_not_ff<DIV_16_Instruction>(rng, MAX_16BIT_OPERAND);
186 .b_address = generate_variable_ref(rng),
187 .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
190 .b_address = generate_variable_ref(rng),
191 .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
194 .b_address = generate_variable_ref(rng),
195 .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
198 .b_address = generate_variable_ref(rng),
199 .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
201 return generate_alu_with_matching_tags_not_ff<AND_16_Instruction>(rng, MAX_16BIT_OPERAND);
203 return generate_alu_with_matching_tags_not_ff<OR_16_Instruction>(rng, MAX_16BIT_OPERAND);
205 return generate_alu_with_matching_tags_not_ff<XOR_16_Instruction>(rng, MAX_16BIT_OPERAND);
208 .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
211 .b_address = generate_variable_ref(rng),
212 .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
215 .b_address = generate_variable_ref(rng),
216 .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
219 .result_address = generate_address_ref(rng, MAX_8BIT_OPERAND),
220 .target_tag =
224 .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
225 .target_tag =
229 .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
230 .slot = generate_random_field(rng) } };
232 return generate_sload_instruction(rng);
234 return { GETENVVAR_Instruction{ .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
235 .type = generate_envvar_type(rng) } };
240 .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
243 .leaf_index_address = generate_variable_ref(rng),
244 .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
246 return { EMITNOTEHASH_Instruction{ .note_hash_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
247 .note_hash = generate_random_field(rng) } };
257 return generate_call_instruction(rng);
265 return { SUCCESSCOPY_Instruction{ .dst_address = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
267 return generate_ecadd_instruction(rng);
269 return { POSEIDON2PERM_Instruction{ .src_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
270 .dst_address = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
279 .message_offset = generate_variable_ref(rng),
280 .fields_offset = generate_variable_ref(rng),
281 .fields_size_offset = generate_variable_ref(rng),
282 .message_size = generate_random_uint16(rng) } } };
283 }
284}
285
287{
288 std::visit(
290 [&rng, this](ADD_8_Instruction& instr) { mutate_binary_instruction_8(instr, rng); },
291 [&rng, this](SUB_8_Instruction& instr) { mutate_binary_instruction_8(instr, rng); },
292 [&rng, this](MUL_8_Instruction& instr) { mutate_binary_instruction_8(instr, rng); },
293 [&rng, this](DIV_8_Instruction& instr) { mutate_binary_instruction_8(instr, rng); },
294 [&rng, this](EQ_8_Instruction& instr) { mutate_binary_instruction_8(instr, rng); },
295 [&rng, this](LT_8_Instruction& instr) { mutate_binary_instruction_8(instr, rng); },
296 [&rng, this](LTE_8_Instruction& instr) { mutate_binary_instruction_8(instr, rng); },
297 [&rng, this](AND_8_Instruction& instr) { mutate_binary_instruction_8(instr, rng); },
298 [&rng, this](OR_8_Instruction& instr) { mutate_binary_instruction_8(instr, rng); },
299 [&rng, this](XOR_8_Instruction& instr) { mutate_binary_instruction_8(instr, rng); },
300 [&rng, this](SHL_8_Instruction& instr) { mutate_binary_instruction_8(instr, rng); },
301 [&rng, this](SHR_8_Instruction& instr) { mutate_binary_instruction_8(instr, rng); },
302 [&rng, this](SET_8_Instruction& instr) { mutate_set_8_instruction(instr, rng); },
303 [&rng, this](SET_16_Instruction& instr) { mutate_set_16_instruction(instr, rng); },
304 [&rng, this](SET_32_Instruction& instr) { mutate_set_32_instruction(instr, rng); },
305 [&rng, this](SET_64_Instruction& instr) { mutate_set_64_instruction(instr, rng); },
306 [&rng, this](SET_128_Instruction& instr) { mutate_set_128_instruction(instr, rng); },
307 [&rng, this](SET_FF_Instruction& instr) { mutate_set_ff_instruction(instr, rng); },
308 [&rng, this](MOV_8_Instruction& instr) { mutate_mov_8_instruction(instr, rng); },
309 [&rng, this](MOV_16_Instruction& instr) { mutate_mov_16_instruction(instr, rng); },
310 [&rng, this](FDIV_8_Instruction& instr) { mutate_binary_instruction_8(instr, rng); },
311 [&rng, this](NOT_8_Instruction& instr) { mutate_not_8_instruction(instr, rng); },
312 [&rng, this](ADD_16_Instruction& instr) { mutate_binary_instruction_16(instr, rng); },
313 [&rng, this](SUB_16_Instruction& instr) { mutate_binary_instruction_16(instr, rng); },
314 [&rng, this](MUL_16_Instruction& instr) { mutate_binary_instruction_16(instr, rng); },
315 [&rng, this](DIV_16_Instruction& instr) { mutate_binary_instruction_16(instr, rng); },
316 [&rng, this](FDIV_16_Instruction& instr) { mutate_binary_instruction_16(instr, rng); },
317 [&rng, this](EQ_16_Instruction& instr) { mutate_binary_instruction_16(instr, rng); },
318 [&rng, this](LT_16_Instruction& instr) { mutate_binary_instruction_16(instr, rng); },
319 [&rng, this](LTE_16_Instruction& instr) { mutate_binary_instruction_16(instr, rng); },
320 [&rng, this](AND_16_Instruction& instr) { mutate_binary_instruction_16(instr, rng); },
321 [&rng, this](OR_16_Instruction& instr) { mutate_binary_instruction_16(instr, rng); },
322 [&rng, this](XOR_16_Instruction& instr) { mutate_binary_instruction_16(instr, rng); },
323 [&rng, this](NOT_16_Instruction& instr) { mutate_not_16_instruction(instr, rng); },
324 [&rng, this](SHL_16_Instruction& instr) { mutate_binary_instruction_16(instr, rng); },
325 [&rng, this](SHR_16_Instruction& instr) { mutate_binary_instruction_16(instr, rng); },
326 [&rng, this](CAST_8_Instruction& instr) { mutate_cast_8_instruction(instr, rng); },
327 [&rng, this](CAST_16_Instruction& instr) { mutate_cast_16_instruction(instr, rng); },
328 [&rng, this](SSTORE_Instruction& instr) { mutate_sstore_instruction(instr, rng); },
329 [&rng, this](SLOAD_Instruction& instr) { mutate_sload_instruction(instr, rng); },
330 [&rng, this](GETENVVAR_Instruction& instr) { mutate_getenvvar_instruction(instr, rng); },
331 [&rng, this](EMITNULLIFIER_Instruction& instr) { mutate_emit_nullifier_instruction(instr, rng); },
332 [&rng, this](NULLIFIEREXISTS_Instruction& instr) { mutate_nullifier_exists_instruction(instr, rng); },
333 [&rng, this](L1TOL2MSGEXISTS_Instruction& instr) { mutate_l1tol2msgexists_instruction(instr, rng); },
334 [&rng, this](EMITNOTEHASH_Instruction& instr) { mutate_emit_note_hash_instruction(instr, rng); },
335 [&rng, this](NOTEHASHEXISTS_Instruction& instr) { mutate_note_hash_exists_instruction(instr, rng); },
336 [&rng, this](CALLDATACOPY_Instruction& instr) { mutate_calldatacopy_instruction(instr, rng); },
337 [&rng, this](SENDL2TOL1MSG_Instruction& instr) { mutate_sendl2tol1msg_instruction(instr, rng); },
338 [&rng, this](EMITPUBLICLOG_Instruction& instr) { mutate_emitpubliclog_instruction(instr, rng); },
339 [&rng, this](CALL_Instruction& instr) { mutate_call_instruction(instr, rng); },
340 [&rng, this](RETURNDATASIZE_Instruction& instr) { mutate_returndatasize_instruction(instr, rng); },
341 [&rng, this](RETURNDATACOPY_Instruction& instr) { mutate_returndatacopy_instruction(instr, rng); },
342 [&rng, this](GETCONTRACTINSTANCE_Instruction& instr) {
344 },
345 [&rng, this](SUCCESSCOPY_Instruction& instr) { mutate_successcopy_instruction(instr, rng); },
346 [&rng, this](ECADD_Instruction& instr) { mutate_ecadd_instruction(instr, rng); },
347 [&rng, this](POSEIDON2PERM_Instruction& instr) { mutate_poseidon2perm_instruction(instr, rng); },
348 [&rng, this](KECCAKF1600_Instruction& instr) { mutate_keccakf1600_instruction(instr, rng); },
349 [&rng, this](SHA256COMPRESSION_Instruction& instr) { mutate_sha256compression_instruction(instr, rng); },
350 [&rng, this](TORADIXBE_Instruction& instr) { mutate_toradixbe_instruction(instr, rng); },
351 [&rng, this](DEBUGLOG_Instruction& instr) { mutate_debuglog_instruction(instr, rng); },
352 [](auto&) { throw std::runtime_error("Unknown instruction"); } },
354}
355
360
362{
363 AddressRef address_ref = AddressRef{ .address = generate_address(rng),
364 .pointer_address_seed = generate_random_uint16(rng),
365 .mode = generate_addressing_mode(rng) };
366 sanitize_address_ref(address_ref, base_offset, max_operand_value);
367 return address_ref;
368}
369
371{
373 switch (option) {
376 break;
379 break;
382 break;
383 }
384 sanitize_address_ref(address, base_offset, max_operand_value);
385}
386
395
398 std::mt19937_64& rng,
399 std::optional<MemoryTag> default_tag)
400{
402 switch (option) {
404 if (default_tag.has_value()) {
405 mutate_or_default_tag(variable.tag.value, rng, default_tag.value());
406 } else {
408 }
409 break;
412 break;
415 break;
417 variable.mode = generate_addressing_mode(rng);
418 break;
419 }
420}
421
423{
424 // 80% chance to use backfill (4 out of 5) to increase success rate
425 bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
426
427 if (!use_backfill) {
428 // Random mode: use existing memory values (may fail if not valid points on curve)
430 .p1_y = generate_variable_ref(rng),
431 .p2_x = generate_variable_ref(rng),
432 .p2_y = generate_variable_ref(rng),
433 .result = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
434 }
435
436 // Backfill mode: generate valid points on the Grumpkin curve and SET them
437 // 4 SET instructions (2 points * 4 fields each) + 1 ECADD = 5 instructions
438 std::vector<FuzzInstruction> instructions;
439 instructions.reserve(5);
440
441 // Generate a valid point via scalar multiplication of the generator (always on curve)
442 auto generate_point = [&rng]() {
444 return bb::avm2::EmbeddedCurvePoint::one() * scalar;
445 };
446
447 // Generate SET instructions to backfill a point at the given addresses
448 auto backfill_point = [&instructions](
449 const bb::avm2::EmbeddedCurvePoint& point, AddressRef x_addr, AddressRef y_addr) {
450 instructions.push_back(
451 SET_FF_Instruction{ .value_tag = bb::avm2::MemoryTag::FF, .result_address = x_addr, .value = point.x() });
452 instructions.push_back(
453 SET_FF_Instruction{ .value_tag = bb::avm2::MemoryTag::FF, .result_address = y_addr, .value = point.y() });
454 };
455
456 auto p1 = generate_point();
457 auto p2 = generate_point();
458
459 // Generate addresses (SET_FF uses 16-bit, SET_8 uses 8-bit operands)
460 AddressRef p1_x_addr = generate_address_ref(rng, MAX_16BIT_OPERAND);
461 AddressRef p1_y_addr = generate_address_ref(rng, MAX_16BIT_OPERAND);
462 AddressRef p2_x_addr = generate_address_ref(rng, MAX_16BIT_OPERAND);
463 AddressRef p2_y_addr = generate_address_ref(rng, MAX_16BIT_OPERAND);
464
465 backfill_point(p1, p1_x_addr, p1_y_addr);
466 backfill_point(p2, p2_x_addr, p2_y_addr);
467
468 instructions.push_back(ECADD_Instruction{ .p1_x = p1_x_addr,
469 .p1_y = p1_y_addr,
470 .p2_x = p2_x_addr,
471 .p2_y = p2_y_addr,
472 .result = generate_address_ref(rng, MAX_16BIT_OPERAND) });
473
474 return instructions;
475}
476
477// Generate binary ALU instruction with optional backfill for matching tagged operands
478template <typename InstructionType>
480 uint32_t max_operand)
481{
482 // 80% chance to use backfill (4 out of 5) to increase success rate
483 bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
484
485 if (!use_backfill) {
486 return { InstructionType{ .a_address = generate_variable_ref(rng),
487 .b_address = generate_variable_ref(rng),
488 .result_address = generate_address_ref(rng, max_operand) } };
489 }
490
492 AddressRef a_addr = generate_address_ref(rng, max_operand);
493 AddressRef b_addr = generate_address_ref(rng, max_operand);
494
495 std::vector<FuzzInstruction> instructions;
496 instructions.push_back(generate_set_for_tag(tag, a_addr, rng));
497 instructions.push_back(generate_set_for_tag(tag, b_addr, rng));
498 instructions.push_back(InstructionType{
499 .a_address = a_addr, .b_address = b_addr, .result_address = generate_address_ref(rng, max_operand) });
500 return instructions;
501}
502
503// Generate binary ALU instruction with optional backfill for matching non-FF tagged operands
504// Used for bitwise operations (AND, OR, XOR) and integer DIV which don't support FF
505template <typename InstructionType>
507 uint32_t max_operand)
508{
509 // 80% chance to use backfill (4 out of 5) to increase success rate
510 bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
511
512 if (!use_backfill) {
513 return { InstructionType{ .a_address = generate_variable_ref(rng),
514 .b_address = generate_variable_ref(rng),
515 .result_address = generate_address_ref(rng, max_operand) } };
516 }
517
518 // Pick a random non-FF tag (U1, U8, U16, U32, U64, U128)
519 static constexpr std::array<bb::avm2::MemoryTag, 6> int_tags = {
522 };
523 auto tag = int_tags[std::uniform_int_distribution<size_t>(0, int_tags.size() - 1)(rng)];
524
525 AddressRef a_addr = generate_address_ref(rng, max_operand);
526 AddressRef b_addr = generate_address_ref(rng, max_operand);
527
528 std::vector<FuzzInstruction> instructions;
529 instructions.push_back(generate_set_for_tag(tag, a_addr, rng));
530 instructions.push_back(generate_set_for_tag(tag, b_addr, rng));
531 instructions.push_back(InstructionType{
532 .a_address = a_addr, .b_address = b_addr, .result_address = generate_address_ref(rng, max_operand) });
533 return instructions;
534}
535
536std::vector<FuzzInstruction> InstructionMutator::generate_fdiv_instruction(std::mt19937_64& rng, uint32_t max_operand)
537{
538 // 80% chance to use backfill (4 out of 5) to increase success rate
539 bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
540
541 if (!use_backfill) {
542 // Random mode: use existing memory values
544 .b_address = generate_variable_ref(rng),
545 .result_address = generate_address_ref(rng, max_operand) } };
546 }
547
548 // Backfill mode: generate two non-zero FF values
549 std::vector<FuzzInstruction> instructions;
550 instructions.reserve(3);
551
552 // Generate non-zero field values (avoid division by zero)
553 auto generate_nonzero_field = [&rng]() {
555 do {
557 } while (value.is_zero());
558 return value;
559 };
560
561 AddressRef a_addr = generate_address_ref(rng, max_operand);
562 AddressRef b_addr = generate_address_ref(rng, max_operand);
563
564 // SET the dividend (a)
565 instructions.push_back(SET_FF_Instruction{
566 .value_tag = bb::avm2::MemoryTag::FF, .result_address = a_addr, .value = generate_nonzero_field() });
567
568 // SET the divisor (b) - must be non-zero
569 instructions.push_back(SET_FF_Instruction{
570 .value_tag = bb::avm2::MemoryTag::FF, .result_address = b_addr, .value = generate_nonzero_field() });
571
572 // FDIV instruction
573 instructions.push_back(FDIV_8_Instruction{
574 .a_address = a_addr, .b_address = b_addr, .result_address = generate_address_ref(rng, max_operand) });
575
576 return instructions;
577}
578
580{
581 // 80% chance to use backfill (4 out of 5) to increase success rate
582 bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
583 if (!use_backfill) {
584 // Random mode
586 .dst_address = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
587 }
588 // Backfill mode
589 std::vector<FuzzInstruction> instructions;
590
591 // Keccak needs to backfill 25 U64 values, these need be contiguous in memory
592 AddressRef src_address = generate_address_ref(rng, MAX_16BIT_OPERAND - 24);
593 for (size_t i = 0; i < 25; i++) {
594 AddressRef item_address = src_address;
595 item_address.address += static_cast<uint32_t>(i);
596 instructions.push_back(SET_64_Instruction{ .value_tag = bb::avm2::MemoryTag::U64,
597 .result_address = item_address,
598 .value = generate_random_uint64(rng) });
599 }
600 instructions.push_back(KECCAKF1600_Instruction{ .src_address = src_address,
601 .dst_address = generate_address_ref(rng, MAX_16BIT_OPERAND) });
602 return instructions;
603}
604
606{
607 // 80% chance to use backfill (4 out of 5) to increase success rate
608 bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
609 if (!use_backfill) {
610 // Random mode
612 .input_address = generate_variable_ref(rng),
613 .dst_address = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
614 }
615 // Backfill mode
616 // SHA256 compression needs 8 U32 values for state and 16 U32 values for input (contiguous)
617 std::vector<FuzzInstruction> instructions;
618 instructions.reserve(8 + 16 + 1);
619
620 // Generate state address (8 contiguous U32 values)
621 AddressRef state_address = generate_address_ref(rng, MAX_16BIT_OPERAND - 7);
622
623 for (size_t i = 0; i < 8; i++) {
624 AddressRef item_address = state_address;
625 item_address.address += static_cast<uint32_t>(i);
626 instructions.push_back(SET_32_Instruction{ .value_tag = bb::avm2::MemoryTag::U32,
627 .result_address = item_address,
628 .value = generate_random_uint32(rng) });
629 }
630
631 // Generate input address (16 contiguous U32 values)
632 AddressRef input_address = generate_address_ref(rng, MAX_16BIT_OPERAND - 15);
633
634 for (size_t i = 0; i < 16; i++) {
635 AddressRef item_address = input_address;
636 item_address.address += static_cast<uint32_t>(i);
637 instructions.push_back(SET_32_Instruction{ .value_tag = bb::avm2::MemoryTag::U32,
638 .result_address = item_address,
639 .value = generate_random_uint32(rng) });
640 }
641
642 instructions.push_back(
644 .input_address = input_address,
645 .dst_address = generate_address_ref(rng, MAX_16BIT_OPERAND) });
646 return instructions;
647}
648
650{
651 // 80% chance to use backfill (4 out of 5) to increase success rate
652 bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
653 if (!use_backfill) {
654 // Random mode
656 .radix_address = generate_variable_ref(rng),
657 .num_limbs_address = generate_variable_ref(rng),
658 .output_bits_address = generate_variable_ref(rng),
659 .dst_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
660 .is_output_bits = std::uniform_int_distribution<int>(0, 1)(rng) == 0 } };
661 }
662 // Backfill mode: set up proper typed values
663 // value: FF, radix: U32, num_limbs: U32, output_bits: U1
664 std::vector<FuzzInstruction> instructions;
665 instructions.reserve(5);
666
667 AddressRef value_addr = generate_address_ref(rng, MAX_16BIT_OPERAND);
668 AddressRef radix_addr = generate_address_ref(rng, MAX_16BIT_OPERAND);
669 AddressRef num_limbs_addr = generate_address_ref(rng, MAX_16BIT_OPERAND);
670 AddressRef output_bits_addr = generate_address_ref(rng, MAX_8BIT_OPERAND);
671
672 // SET the radix (U32) - pick radix between 2 and 256
673 uint32_t radix = std::uniform_int_distribution<uint32_t>(2, 256)(rng);
674 instructions.push_back(
675 SET_32_Instruction{ .value_tag = bb::avm2::MemoryTag::U32, .result_address = radix_addr, .value = radix });
676
677 // SET the output_bits (U1)
678 bool is_output_bits = radix == 2;
679 instructions.push_back(SET_8_Instruction{ .value_tag = bb::avm2::MemoryTag::U1,
680 .result_address = output_bits_addr,
681 .value = static_cast<uint8_t>(is_output_bits ? 1 : 0) });
682
683 // Generate value with num_limbs digits
684 uint32_t num_limbs = std::uniform_int_distribution<uint32_t>(0, 256)(rng);
686 bb::avm2::FF exponent = 1;
687 for (uint32_t i = 0; i < num_limbs; i++) {
688 uint32_t digit = std::uniform_int_distribution<uint32_t>(0, radix - 1)(rng);
689 value += bb::avm2::FF(digit) * exponent;
690 exponent *= radix;
691 }
692
693 // 20% chance to truncate - reduce the number of limbs we request or increment the value if we have 0 limbs
694 if (std::uniform_int_distribution<int>(0, 4)(rng) == 0) {
695 if (num_limbs > 0) {
696 num_limbs--;
697 } else {
698 value++;
699 }
700 }
701
702 // SET the num_limbs (U32)
703 instructions.push_back(SET_32_Instruction{
704 .value_tag = bb::avm2::MemoryTag::U32, .result_address = num_limbs_addr, .value = num_limbs });
705
706 // SET the value (FF)
707 instructions.push_back(
708 SET_FF_Instruction{ .value_tag = bb::avm2::MemoryTag::FF, .result_address = value_addr, .value = value });
709
710 // TORADIXBE instruction
711 instructions.push_back(TORADIXBE_Instruction{ .value_address = value_addr,
712 .radix_address = radix_addr,
713 .num_limbs_address = num_limbs_addr,
714 .output_bits_address = output_bits_addr,
715 .dst_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
716 .is_output_bits = is_output_bits });
717 return instructions;
718}
719
720// A better way in the future is to pass in a vector of possible slots that have been written to,
721// this would allow us to supply external world state info.
723{
724 // 80% chance to use backfill (4 out of 5) to increase success rate
725 bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
726
727 if (!use_backfill) {
728 // Random mode: requires at least one prior SSTORE to have been processed
730 .slot_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
731 .contract_address_address = generate_variable_ref(rng),
732 .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
733 }
734
735 // Backfill mode: generate SSTORE first to ensure storage_addresses is non-empty
736 // This guarantees SLOAD will find a valid slot (get_slot uses modulo on non-empty vector)
737 std::vector<FuzzInstruction> instructions;
738 instructions.reserve(4);
739
740 AddressRef sstore_src = generate_address_ref(rng, MAX_16BIT_OPERAND);
741
742 // SET a value to store
743 instructions.push_back(SET_FF_Instruction{
744 .value_tag = bb::avm2::MemoryTag::FF, .result_address = sstore_src, .value = generate_random_field(rng) });
745
746 // SSTORE - appends to storage_addresses in memory_manager
747 instructions.push_back(SSTORE_Instruction{ .src_address = sstore_src,
748 .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
749 .slot = generate_random_field(rng) });
750
751 // Now set our own contract address
753 instructions.push_back(
754 GETENVVAR_Instruction{ .result_address = contract_address_address, /* contract address */ .type = 0 });
755
756 // SLOAD - now guaranteed to succeed (storage_addresses not empty, get_slot uses modulo)
757 instructions.push_back(SLOAD_Instruction{ .slot_index = generate_random_uint16(rng),
758 .slot_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
759 .contract_address_address = contract_address_address,
760 .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND) });
761
762 return instructions;
763}
764
766{
767 // 80% chance to use backfill (4 out of 5) to increase success rate
768 bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
769
770 if (!use_backfill) {
772 .log_values_address = generate_variable_ref(rng) } };
773 }
774
776 std::vector<FuzzInstruction> instructions;
777 instructions.reserve(3);
778
779 auto log_size_address = generate_address_ref(rng, MAX_16BIT_OPERAND);
780 auto log_values_address = generate_address_ref(rng, MAX_16BIT_OPERAND - log_size);
781
782 instructions.push_back(SET_32_Instruction{
783 .value_tag = bb::avm2::MemoryTag::U32, .result_address = log_size_address, .value = log_size });
784
785 // Write one random FF in the log
786 instructions.push_back(SET_FF_Instruction{ .value_tag = bb::avm2::MemoryTag::FF,
787 .result_address = log_values_address,
788 .value = generate_random_field(rng) });
789
790 instructions.push_back(
792
793 return instructions;
794}
795
797{
798 // 80% chance to use backfill (4 out of 5) to increase success rate
799 bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
800
801 if (!use_backfill) {
802
804 .da_gas_address = generate_variable_ref(rng),
805 .contract_address_address = generate_variable_ref(rng),
806 .calldata_address = generate_variable_ref(rng),
807 .calldata_size_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
808 .calldata_size = generate_random_uint16(rng),
809 .is_static_call = rng() % 2 == 0 } };
810 }
811
812 std::vector<FuzzInstruction> instructions;
813 instructions.reserve(5);
814
815 auto contract_address_address = generate_address_ref(rng, MAX_16BIT_OPERAND);
816 instructions.push_back(SET_FF_Instruction{ .value_tag = bb::avm2::MemoryTag::FF,
817 .result_address = contract_address_address,
818 .value = context.get_contract_address(generate_random_uint16(rng)) });
819
820 auto l2_gas_address = generate_address_ref(rng, MAX_16BIT_OPERAND);
821 instructions.push_back(SET_32_Instruction{ .value_tag = bb::avm2::MemoryTag::U32,
822 .result_address = l2_gas_address,
823 .value = generate_random_uint32(rng) });
824
825 auto da_gas_address = generate_address_ref(rng, MAX_16BIT_OPERAND);
826 instructions.push_back(SET_32_Instruction{ .value_tag = bb::avm2::MemoryTag::U32,
827 .result_address = da_gas_address,
828 .value = generate_random_uint32(rng) });
829
831 auto calldata_size_address = generate_address_ref(rng, MAX_16BIT_OPERAND);
832
833 auto calldata_address = generate_address_ref(rng, MAX_16BIT_OPERAND);
834 // Write one random FF in the calldata
835 instructions.push_back(SET_FF_Instruction{ .value_tag = bb::avm2::MemoryTag::FF,
836 .result_address = calldata_address,
837 .value = generate_random_field(rng) });
838
839 instructions.push_back(CALL_Instruction{ .l2_gas_address = l2_gas_address,
840 .da_gas_address = da_gas_address,
841 .contract_address_address = contract_address_address,
842 .calldata_address = calldata_address,
843 .calldata_size_address = calldata_size_address,
844 .calldata_size = calldata_size,
845 .is_static_call = rng() % 2 == 0 });
846
847 return instructions;
848}
849
851{
852 bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
853 if (!use_backfill) {
856 .member_enum = generate_random_uint8(rng),
857 .dst_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
858 } };
859 }
860
861 std::vector<FuzzInstruction> instructions;
862 instructions.reserve(2);
863
864 auto contract_address_address = generate_address_ref(rng, MAX_16BIT_OPERAND);
865 instructions.push_back(SET_FF_Instruction{ .value_tag = bb::avm2::MemoryTag::FF,
866 .result_address = contract_address_address,
867 .value = context.get_contract_address(generate_random_uint16(rng)) });
869
870 instructions.push_back(GETCONTRACTINSTANCE_Instruction{
872 .member_enum = member_enum,
873 .dst_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
874 });
875
876 return instructions;
877}
878
880{
881 bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
882 if (!use_backfill) {
884 .leaf_index_address = generate_variable_ref(rng),
885 .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
886 }
887 auto existing_note_hash = context.get_existing_note_hash(generate_random_uint16(rng));
888 FF note_hash = existing_note_hash.has_value() ? existing_note_hash.value().first : generate_random_field(rng);
889 uint64_t leaf_index =
890 existing_note_hash.has_value() ? existing_note_hash.value().second : generate_random_uint64(rng);
891 AddressRef note_hash_address = generate_address_ref(rng, MAX_16BIT_OPERAND);
892 AddressRef leaf_index_address = generate_address_ref(rng, MAX_16BIT_OPERAND);
893
894 std::vector<FuzzInstruction> instructions;
895 instructions.reserve(3);
896
897 instructions.push_back(SET_FF_Instruction{
899 instructions.push_back(SET_64_Instruction{
900 .value_tag = bb::avm2::MemoryTag::U64, .result_address = leaf_index_address, .value = leaf_index });
901
902 instructions.push_back(
904 .leaf_index_address = leaf_index_address,
905 .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND) });
906
907 return instructions;
908}
909
911{
912 return { RETURNDATASIZE_Instruction{ .dst_address = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
913}
914
916{
917 bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
918 if (!use_backfill) {
920 .rd_offset_address = generate_variable_ref(rng),
921 .dst_address = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
922 }
923 std::vector<FuzzInstruction> instructions;
924 instructions.reserve(3);
925 auto copy_size_address = generate_address_ref(rng, MAX_16BIT_OPERAND);
926 instructions.push_back(SET_32_Instruction{ .value_tag = bb::avm2::MemoryTag::U32,
927 .result_address = copy_size_address,
928 // We generate small sizes so we fail less often due to gas
929 // Mutations might change this to a larger value.
930 .value = generate_random_uint8(rng) });
931
932 auto rd_offset_address = generate_address_ref(rng, MAX_16BIT_OPERAND);
933 instructions.push_back(SET_32_Instruction{ .value_tag = bb::avm2::MemoryTag::U32,
934 .result_address = rd_offset_address,
935 .value = generate_random_uint8(rng) });
936
938 .rd_offset_address = rd_offset_address,
939 .dst_address = generate_address_ref(rng, MAX_16BIT_OPERAND) });
940
941 return instructions;
942}
943
945{
946 bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
947 if (!use_backfill) {
949 .cd_offset_address = generate_variable_ref(rng),
950 .dst_address = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
951 }
952 std::vector<FuzzInstruction> instructions;
953 instructions.reserve(3);
954 auto copy_size_address = generate_address_ref(rng, MAX_16BIT_OPERAND);
955 instructions.push_back(SET_32_Instruction{ .value_tag = bb::avm2::MemoryTag::U32,
956 .result_address = copy_size_address,
957 // We generate small sizes so we fail less often due to gas
958 // Mutations might change this to a larger value.
959 .value = generate_random_uint8(rng) });
960
961 auto cd_offset_address = generate_address_ref(rng, MAX_16BIT_OPERAND);
962 instructions.push_back(SET_32_Instruction{ .value_tag = bb::avm2::MemoryTag::U32,
963 .result_address = cd_offset_address,
964 .value = generate_random_uint8(rng) });
965
967 .cd_offset_address = cd_offset_address,
968 .dst_address = generate_address_ref(rng, MAX_16BIT_OPERAND) });
969
970 return instructions;
971}
972
974{
975 bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
976 if (!use_backfill) {
978 .content_address = generate_variable_ref(rng) } };
979 }
980 std::vector<FuzzInstruction> instructions;
981 instructions.reserve(3);
982
983 auto recipient_address = generate_address_ref(rng, MAX_16BIT_OPERAND);
984 instructions.push_back(SET_FF_Instruction{ .value_tag = bb::avm2::MemoryTag::FF,
985 .result_address = recipient_address,
987
988 auto content_address = generate_address_ref(rng, MAX_16BIT_OPERAND);
989 instructions.push_back(SET_FF_Instruction{
991
992 instructions.push_back(
994
995 return instructions;
996}
997
999 std::mt19937_64& rng,
1000 std::optional<MemoryTag> default_tag,
1001 uint32_t max_operand_value)
1002{
1003 std::visit(overloaded{ [&](VariableRef& var) { mutate_variable_ref(var, rng, default_tag); },
1004 [&](AddressRef& addr) { mutate_address_ref(addr, rng, max_operand_value); } },
1005 param);
1006}
1007
1008template <typename BinaryInstructionType>
1010{
1012 switch (option) {
1014 mutate_param_ref(instruction.a_address, rng, std::nullopt, MAX_8BIT_OPERAND);
1015 break;
1017 mutate_param_ref(instruction.b_address, rng, get_param_ref_tag(instruction.a_address), MAX_8BIT_OPERAND);
1018 break;
1020 mutate_address_ref(instruction.result_address, rng, MAX_8BIT_OPERAND);
1021 break;
1022 }
1023}
1024
1025template <typename BinaryInstructionType>
1027{
1029 switch (option) {
1031 mutate_param_ref(instruction.a_address, rng, std::nullopt, MAX_16BIT_OPERAND);
1032 break;
1034 mutate_param_ref(instruction.b_address, rng, get_param_ref_tag(instruction.a_address), MAX_16BIT_OPERAND);
1035 break;
1037 mutate_address_ref(instruction.result_address, rng, MAX_16BIT_OPERAND);
1038 break;
1039 }
1040}
1041
1054
1070
1086
1102
1118
1137
1153
1155{
1156 int choice = std::uniform_int_distribution<int>(0, 2)(rng);
1157 switch (choice) {
1158 case 0:
1160 break;
1161 case 1:
1162 mutate_param_ref(instruction.src_address, rng, std::nullopt, MAX_8BIT_OPERAND);
1163 break;
1164 case 2:
1165 mutate_address_ref(instruction.result_address, rng, MAX_8BIT_OPERAND);
1166 break;
1167 }
1168}
1169
1171{
1172 int choice = std::uniform_int_distribution<int>(0, 2)(rng);
1173 switch (choice) {
1174 case 0:
1176 break;
1177 case 1:
1178 mutate_param_ref(instruction.src_address, rng, std::nullopt, MAX_16BIT_OPERAND);
1179 break;
1180 case 2:
1181 mutate_address_ref(instruction.result_address, rng, MAX_16BIT_OPERAND);
1182 break;
1183 }
1184}
1185
1198
1214
1230
1232{
1234 switch (option) {
1236 mutate_param_ref(instruction.src_address, rng, MemoryTag::FF, MAX_16BIT_OPERAND);
1237 break;
1239 mutate_address_ref(instruction.result_address, rng, MAX_16BIT_OPERAND);
1240 break;
1243 break;
1244 }
1245}
1246
1248{
1250 switch (option) {
1253 break;
1255 mutate_address_ref(instruction.slot_address, rng, MAX_16BIT_OPERAND);
1256 break;
1258 mutate_param_ref(instruction.contract_address_address, rng, MemoryTag::FF, MAX_16BIT_OPERAND);
1259 break;
1261 mutate_address_ref(instruction.result_address, rng, MAX_16BIT_OPERAND);
1262 break;
1263 }
1264}
1265
1267{
1269 switch (option) {
1271 mutate_address_ref(instruction.result_address, rng, MAX_16BIT_OPERAND);
1272 break;
1274 instruction.type = generate_envvar_type(rng);
1275 break;
1276 }
1277}
1278
1280{
1281 // emitnulifier only has one field
1282
1283 mutate_param_ref(instruction.nullifier_address, rng, MemoryTag::FF, MAX_16BIT_OPERAND);
1284}
1285
1299
1301 std::mt19937_64& rng)
1302{
1304 switch (option) {
1306 mutate_param_ref(instruction.msg_hash_address, rng, MemoryTag::FF, MAX_16BIT_OPERAND);
1307 break;
1309 mutate_param_ref(instruction.leaf_index_address, rng, MemoryTag::U64, MAX_16BIT_OPERAND);
1310 break;
1312 mutate_address_ref(instruction.result_address, rng, MAX_16BIT_OPERAND);
1313 break;
1314 }
1315}
1316
1330 std::mt19937_64& rng)
1331{
1333 switch (option) {
1335 mutate_param_ref(instruction.notehash_address, rng, MemoryTag::FF, MAX_16BIT_OPERAND);
1336 break;
1338 mutate_param_ref(instruction.leaf_index_address, rng, MemoryTag::U64, MAX_16BIT_OPERAND);
1339 break;
1341 mutate_address_ref(instruction.result_address, rng, MAX_16BIT_OPERAND);
1342 break;
1343 }
1344}
1345
1347{
1349 switch (option) {
1351 mutate_param_ref(instruction.copy_size_address, rng, MemoryTag::U32, MAX_16BIT_OPERAND);
1352 break;
1354 mutate_param_ref(instruction.cd_offset_address, rng, MemoryTag::U32, MAX_16BIT_OPERAND);
1355 break;
1357 mutate_address_ref(instruction.dst_address, rng, MAX_16BIT_OPERAND);
1358 break;
1359 }
1360}
1361
1374
1387
1389{
1391 switch (option) {
1393 mutate_param_ref(instruction.l2_gas_address, rng, MemoryTag::U32, MAX_16BIT_OPERAND);
1394 break;
1396 mutate_param_ref(instruction.da_gas_address, rng, MemoryTag::U32, MAX_16BIT_OPERAND);
1397 break;
1399 mutate_param_ref(instruction.contract_address_address, rng, MemoryTag::FF, MAX_16BIT_OPERAND);
1400 break;
1402 mutate_address_ref(instruction.calldata_size_address, rng, MAX_16BIT_OPERAND);
1403 break;
1406 break;
1408 mutate_param_ref(instruction.calldata_address, rng, MemoryTag::FF, MAX_16BIT_OPERAND);
1409 break;
1411 // with 0.5 probability, set to true, otherwise false
1412 instruction.is_static_call = rng() % 2 == 0;
1413 }
1414}
1415
1421
1423 std::mt19937_64& rng)
1424{
1426 switch (option) {
1428 mutate_param_ref(instruction.copy_size_address, rng, MemoryTag::U32, MAX_16BIT_OPERAND);
1429 break;
1431 mutate_param_ref(instruction.rd_offset_address, rng, MemoryTag::U32, MAX_16BIT_OPERAND);
1432 break;
1434 mutate_address_ref(instruction.dst_address, rng, MAX_16BIT_OPERAND);
1435 break;
1436 }
1437}
1438
1455
1465
1467{
1468 // ECADD has 5 operands, select one to mutate
1469 int choice = std::uniform_int_distribution<int>(0, 4)(rng);
1470 switch (choice) {
1471 case 0:
1472 mutate_param_ref(instruction.p1_x, rng, MemoryTag::FF, MAX_16BIT_OPERAND);
1473 break;
1474 case 1:
1475 mutate_param_ref(instruction.p1_y, rng, MemoryTag::FF, MAX_16BIT_OPERAND);
1476 break;
1477 case 2:
1478 mutate_param_ref(instruction.p2_x, rng, MemoryTag::FF, MAX_16BIT_OPERAND);
1479 break;
1480 case 3:
1481 mutate_param_ref(instruction.p2_y, rng, MemoryTag::FF, MAX_16BIT_OPERAND);
1482 break;
1483 case 4:
1484 mutate_address_ref(instruction.result, rng, MAX_16BIT_OPERAND);
1485 break;
1486 }
1487}
1488
1490{
1491 int choice = std::uniform_int_distribution<int>(0, 1)(rng);
1492 switch (choice) {
1493 case 0:
1494 mutate_param_ref(instruction.src_address, rng, MemoryTag::U32, MAX_16BIT_OPERAND);
1495 break;
1496 case 1:
1497 mutate_address_ref(instruction.dst_address, rng, MAX_16BIT_OPERAND);
1498 break;
1499 }
1500}
1501
1503{
1504 int choice = std::uniform_int_distribution<int>(0, 1)(rng);
1505 switch (choice) {
1506 case 0:
1507 mutate_param_ref(instruction.src_address, rng, MemoryTag::U32, MAX_16BIT_OPERAND);
1508 break;
1509 case 1:
1510 mutate_address_ref(instruction.dst_address, rng, MAX_16BIT_OPERAND);
1511 break;
1512 }
1513}
1514
1516 std::mt19937_64& rng)
1517{
1518 int choice = std::uniform_int_distribution<int>(0, 2)(rng);
1519 switch (choice) {
1520 case 0:
1521 mutate_param_ref(instruction.state_address, rng, MemoryTag::U32, MAX_16BIT_OPERAND);
1522 break;
1523 case 1:
1524 mutate_param_ref(instruction.input_address, rng, MemoryTag::U32, MAX_16BIT_OPERAND);
1525 break;
1526 case 2:
1527 mutate_address_ref(instruction.dst_address, rng, MAX_16BIT_OPERAND);
1528 break;
1529 }
1530}
1531
1533{
1535 switch (option) {
1537 mutate_param_ref(instruction.value_address, rng, MemoryTag::FF, MAX_16BIT_OPERAND);
1538 break;
1540 mutate_param_ref(instruction.radix_address, rng, MemoryTag::U32, MAX_16BIT_OPERAND);
1541 break;
1543 mutate_param_ref(instruction.num_limbs_address, rng, MemoryTag::U32, MAX_16BIT_OPERAND);
1544 break;
1546 mutate_param_ref(instruction.output_bits_address, rng, MemoryTag::U1, MAX_16BIT_OPERAND);
1547 break;
1549 mutate_address_ref(instruction.dst_address, rng, MAX_16BIT_OPERAND);
1550 break;
1552 instruction.is_output_bits = !instruction.is_output_bits;
1553 break;
1554 }
1555}
1556
1558{
1560 switch (option) {
1562 mutate_param_ref(instruction.level_offset, rng, MemoryTag::U32, MAX_16BIT_OPERAND);
1563 break;
1565 mutate_param_ref(instruction.message_offset, rng, MemoryTag::U32, MAX_16BIT_OPERAND);
1566 break;
1568 mutate_param_ref(instruction.fields_offset, rng, MemoryTag::U32, MAX_16BIT_OPERAND);
1569 break;
1571 mutate_param_ref(instruction.fields_size_offset, rng, MemoryTag::U32, MAX_16BIT_OPERAND);
1572 break;
1575 break;
1576 }
1577}
1578
1579} // namespace bb::avm2::fuzzer
::FuzzInstruction FuzzInstruction
FF generate_random_field(std::mt19937_64 &rng)
Definition field.cpp:25
void mutate_field(bb::avm2::FF &value, std::mt19937_64 &rng, const FieldMutationConfig &config)
Definition field.cpp:99
#define FLAT_PUBLIC_LOGS_PAYLOAD_LENGTH
#define AVM_HIGHEST_MEM_ADDRESS
T select(std::mt19937_64 &rng) const
constexpr const BaseField & x() const noexcept
constexpr const BaseField & y() const noexcept
std::vector< FuzzInstruction > generate_getcontractinstance_instruction(std::mt19937_64 &rng)
void mutate_set_ff_instruction(SET_FF_Instruction &instruction, std::mt19937_64 &rng)
void mutate_sha256compression_instruction(SHA256COMPRESSION_Instruction &instruction, std::mt19937_64 &rng)
void mutate_l1tol2msgexists_instruction(L1TOL2MSGEXISTS_Instruction &instruction, std::mt19937_64 &rng)
void mutate_returndatasize_instruction(RETURNDATASIZE_Instruction &instruction, std::mt19937_64 &rng)
void mutate_emit_note_hash_instruction(EMITNOTEHASH_Instruction &instruction, std::mt19937_64 &rng)
void mutate_set_16_instruction(SET_16_Instruction &instruction, std::mt19937_64 &rng)
void mutate_mov_16_instruction(MOV_16_Instruction &instruction, std::mt19937_64 &rng)
void mutate_not_8_instruction(NOT_8_Instruction &instruction, std::mt19937_64 &rng)
void mutate_mov_8_instruction(MOV_8_Instruction &instruction, std::mt19937_64 &rng)
void mutate_binary_instruction_16(BinaryInstructionType &instruction, std::mt19937_64 &rng)
VariableRef generate_variable_ref(std::mt19937_64 &rng)
std::vector< FuzzInstruction > generate_alu_with_matching_tags(std::mt19937_64 &rng, uint32_t max_operand)
std::vector< FuzzInstruction > generate_call_instruction(std::mt19937_64 &rng)
std::vector< FuzzInstruction > generate_fdiv_instruction(std::mt19937_64 &rng, uint32_t max_operand)
void mutate_getenvvar_instruction(GETENVVAR_Instruction &instruction, std::mt19937_64 &rng)
std::vector< FuzzInstruction > generate_sload_instruction(std::mt19937_64 &rng)
std::vector< FuzzInstruction > generate_toradixbe_instruction(std::mt19937_64 &rng)
void mutate_not_16_instruction(NOT_16_Instruction &instruction, std::mt19937_64 &rng)
AddressingMode generate_addressing_mode(std::mt19937_64 &rng)
void mutate_successcopy_instruction(SUCCESSCOPY_Instruction &instruction, std::mt19937_64 &rng)
void mutate_calldatacopy_instruction(CALLDATACOPY_Instruction &instruction, std::mt19937_64 &rng)
void mutate_sload_instruction(SLOAD_Instruction &instruction, std::mt19937_64 &rng)
void mutate_emit_nullifier_instruction(EMITNULLIFIER_Instruction &instruction, std::mt19937_64 &rng)
std::vector< FuzzInstruction > generate_keccakf_instruction(std::mt19937_64 &rng)
void mutate_sstore_instruction(SSTORE_Instruction &instruction, std::mt19937_64 &rng)
void mutate_binary_instruction_8(BinaryInstructionType &instruction, std::mt19937_64 &rng)
std::vector< FuzzInstruction > generate_instruction(std::mt19937_64 &rng)
Generate one instruction and optionally backfill.
void mutate_set_32_instruction(SET_32_Instruction &instruction, std::mt19937_64 &rng)
std::vector< FuzzInstruction > generate_sendl2tol1msg_instruction(std::mt19937_64 &rng)
void mutate_sendl2tol1msg_instruction(SENDL2TOL1MSG_Instruction &instruction, std::mt19937_64 &rng)
std::vector< FuzzInstruction > generate_calldatacopy_instruction(std::mt19937_64 &rng)
void mutate_nullifier_exists_instruction(NULLIFIEREXISTS_Instruction &instruction, std::mt19937_64 &rng)
void mutate_note_hash_exists_instruction(NOTEHASHEXISTS_Instruction &instruction, std::mt19937_64 &rng)
void mutate_toradixbe_instruction(TORADIXBE_Instruction &instruction, std::mt19937_64 &rng)
void mutate_call_instruction(CALL_Instruction &instruction, std::mt19937_64 &rng)
void mutate_set_128_instruction(SET_128_Instruction &instruction, std::mt19937_64 &rng)
void mutate_instruction(FuzzInstruction &instruction, std::mt19937_64 &rng)
std::vector< FuzzInstruction > generate_returndatacopy_instruction(std::mt19937_64 &rng)
void mutate_debuglog_instruction(DEBUGLOG_Instruction &instruction, std::mt19937_64 &rng)
void mutate_keccakf1600_instruction(KECCAKF1600_Instruction &instruction, std::mt19937_64 &rng)
void mutate_address_ref(AddressRef &address, std::mt19937_64 &rng, uint32_t max_operand_value)
void mutate_variable_ref(VariableRef &variable, std::mt19937_64 &rng, std::optional< MemoryTag > default_tag)
Most of the tags will be equal to the default tag.
void mutate_cast_8_instruction(CAST_8_Instruction &instruction, std::mt19937_64 &rng)
void mutate_set_64_instruction(SET_64_Instruction &instruction, std::mt19937_64 &rng)
void mutate_getcontractinstance_instruction(GETCONTRACTINSTANCE_Instruction &instruction, std::mt19937_64 &rng)
std::vector< FuzzInstruction > generate_sha256compression_instruction(std::mt19937_64 &rng)
std::vector< FuzzInstruction > generate_emitpubliclog_instruction(std::mt19937_64 &rng)
void mutate_ecadd_instruction(ECADD_Instruction &instruction, std::mt19937_64 &rng)
void mutate_returndatacopy_instruction(RETURNDATACOPY_Instruction &instruction, std::mt19937_64 &rng)
void mutate_cast_16_instruction(CAST_16_Instruction &instruction, std::mt19937_64 &rng)
void mutate_set_8_instruction(SET_8_Instruction &instruction, std::mt19937_64 &rng)
std::vector< FuzzInstruction > generate_returndatasize_instruction(std::mt19937_64 &rng)
AddressRef generate_address_ref(std::mt19937_64 &rng, uint32_t max_operand_value)
std::vector< FuzzInstruction > generate_ecadd_instruction(std::mt19937_64 &rng)
void mutate_poseidon2perm_instruction(POSEIDON2PERM_Instruction &instruction, std::mt19937_64 &rng)
std::vector< FuzzInstruction > generate_alu_with_matching_tags_not_ff(std::mt19937_64 &rng, uint32_t max_operand)
void mutate_emitpubliclog_instruction(EMITPUBLICLOG_Instruction &instruction, std::mt19937_64 &rng)
void mutate_param_ref(ParamRef &param, std::mt19937_64 &rng, std::optional< MemoryTag > default_tag, uint32_t max_operand_value)
std::vector< FuzzInstruction > generate_notehashexists_instruction(std::mt19937_64 &rng)
Set32MutationOptions
constexpr Set128MutationConfig BASIC_SET_128_MUTATION_CONFIGURATION
constexpr AddressRefMutationConfig BASIC_ADDRESS_REF_MUTATION_CONFIGURATION
Set64MutationOptions
constexpr SLoadMutationConfig BASIC_SLOAD_MUTATION_CONFIGURATION
constexpr GetEnvVarMutationConfig BASIC_GETENVVAR_MUTATION_CONFIGURATION
constexpr Set16MutationConfig BASIC_SET_16_MUTATION_CONFIGURATION
L1ToL2MsgExistsMutationOptions
ReturndataCopyMutationOptions
constexpr NoteHashExistsMutationConfig BASIC_NOTEHASHEXISTS_MUTATION_CONFIGURATION
NoteHashExistsMutationOptions
constexpr ToRadixBEMutationConfig BASIC_TORADIXBE_MUTATION_CONFIGURATION
EmitPublicLogMutationOptions
constexpr Set64MutationConfig BASIC_SET_64_MUTATION_CONFIGURATION
EmitNoteHashMutationOptions
CallMutationOptions
SetFFMutationOptions
constexpr MemoryTagGenerationConfig BASIC_MEMORY_TAG_GENERATION_CONFIGURATION
SuccessCopyMutationOptions
constexpr DebugLogMutationConfig BASIC_DEBUGLOG_MUTATION_CONFIGURATION
constexpr Uint64MutationConfig BASIC_UINT64_T_MUTATION_CONFIGURATION
Set8MutationOptions
Set16MutationOptions
constexpr CalldataCopyMutationConfig BASIC_CALLDATACOPY_MUTATION_CONFIGURATION
constexpr GetContractInstanceMutationConfig BASIC_GETCONTRACTINSTANCE_MUTATION_CONFIGURATION
InstructionGenerationOptions
constexpr L1ToL2MsgExistsMutationConfig BASIC_L1TOL2MSGEXISTS_MUTATION_CONFIGURATION
constexpr Uint32MutationConfig BASIC_UINT32_T_MUTATION_CONFIGURATION
constexpr UnaryInstruction8MutationConfig BASIC_UNARY_INSTRUCTION_8_MUTATION_CONFIGURATION
SStoreMutationOptions
constexpr SetFFMutationConfig BASIC_SET_FF_MUTATION_CONFIGURATION
constexpr Set32MutationConfig BASIC_SET_32_MUTATION_CONFIGURATION
constexpr FieldMutationConfig BASIC_FIELD_MUTATION_CONFIGURATION
UnaryInstruction8MutationOptions
constexpr BinaryInstruction8MutationConfig BASIC_BINARY_INSTRUCTION_8_MUTATION_CONFIGURATION
constexpr Uint16MutationConfig BASIC_UINT16_T_MUTATION_CONFIGURATION
constexpr SStoreMutationConfig BASIC_SSTORE_MUTATION_CONFIGURATION
CalldataCopyMutationOptions
constexpr NullifierExistsMutationConfig BASIC_NULLIFIER_EXISTS_MUTATION_CONFIGURATION
constexpr CallMutationConfig BASIC_CALL_MUTATION_CONFIGURATION
constexpr SendL2ToL1MsgMutationConfig BASIC_SENDL2TOL1MSG_MUTATION_CONFIGURATION
constexpr VariableRefMutationConfig BASIC_VARIABLE_REF_MUTATION_CONFIGURATION
Set128MutationOptions
constexpr EmitNoteHashMutationConfig BASIC_EMITNOTEHASH_MUTATION_CONFIGURATION
ToRadixBEMutationOptions
constexpr MemoryTagMutationConfig BASIC_MEMORY_TAG_MUTATION_CONFIGURATION
SLoadMutationOptions
constexpr Uint8MutationConfig BASIC_UINT8_T_MUTATION_CONFIGURATION
VariableRefMutationOptions
constexpr InstructionGenerationConfig BASIC_INSTRUCTION_GENERATION_CONFIGURATION
constexpr SuccessCopyMutationConfig BASIC_SUCCESSCOPY_MUTATION_CONFIGURATION
GetContractInstanceMutationOptions
GetEnvVarMutationOptions
DebugLogMutationOptions
AddressRefMutationOptions
BinaryInstruction8MutationOptions
SendL2ToL1MsgMutationOptions
constexpr Set8MutationConfig BASIC_SET_8_MUTATION_CONFIGURATION
constexpr EmitPublicLogMutationConfig BASIC_EMITPUBLICLOG_MUTATION_CONFIGURATION
constexpr ReturndataCopyMutationConfig BASIC_RETURNDATACOPY_MUTATION_CONFIGURATION
NullifierExistsMutationOptions
EthAddress generate_random_eth_address(std::mt19937_64 &rng)
AddressingMode
std::variant< VariableRef, AddressRef > ParamRef
Instruction instruction
MemoryTag generate_memory_tag(std::mt19937_64 &rng, const MemoryTagGenerationConfig &config)
Definition memory_tag.cpp:8
void mutate_or_default_tag(MemoryTag &value, std::mt19937_64 &rng, MemoryTag default_tag, double probability=0.1)
Mutate the memory tag or set to the chosen tag with a given probability.
void mutate_memory_tag(MemoryTag &value, std::mt19937_64 &rng, const MemoryTagMutationConfig &config)
AvmFlavorSettings::FF FF
Definition field.hpp:10
AvmFlavorSettings::G1::Fq Fq
Definition field.hpp:11
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
mem[result_offset] = mem[a_address] + mem[b_address] (16-bit)
mem[result_offset] = mem[a_address] + mem[b_address]
mem[result_offset] = mem[a_address] & mem[b_address] (16-bit)
mem[result_offset] = mem[a_address] & mem[b_address]
AddressingModeWrapper mode
uint32_t address
ParamRef l2_gas_address
CAST_16: cast mem[src_offset_index] to target_tag and store at dst_offset.
CAST_8: cast mem[src_offset_index] to target_tag and store at dst_offset.
mem[result_offset] = mem[a_address] / mem[b_address] (16-bit)
mem[result_offset] = mem[a_address] / mem[b_address]
EMITNOTEHASH: M[note_hash_offset] = note_hash; emit note hash to the note hash tree.
EMITNULIFIER: inserts new nullifier to the nullifier tree.
mem[result_offset] = mem[a_address] == mem[b_address] (16-bit)
mem[result_offset] = mem[a_address] == mem[b_address]
GETENVVAR: M[result_offset] = getenvvar(type)
KECCAKF1600: Perform Keccak-f[1600] permutation on 25 U64 values M[dst_address:dst_address+25] = kecc...
L1TOL2MSGEXISTS: Check if a L1 to L2 message exists M[result_address] = L1TOL2MSGEXISTS(M[msg_hash_ad...
mem[result_offset] = mem[a_address] < mem[b_address] (16-bit)
mem[result_offset] = mem[a_address] < mem[b_address]
mem[result_offset] = mem[a_address] <= mem[b_address] (16-bit)
mem[result_offset] = mem[a_address] <= mem[b_address]
MOV_16 instruction: mem[dst_offset] = mem[src_offset].
MemoryTagWrapper value_tag
MOV_8 instruction: mem[dst_offset] = mem[src_offset].
MemoryTagWrapper value_tag
mem[result_offset] = mem[a_address] * mem[b_address] (16-bit)
mem[result_offset] = mem[a_address] * mem[b_address]
NULLIFIEREXISTS: checks if a siloed nullifier exists in the nullifier tree M[result_address] = NULLIF...
mem[result_offset] = mem[a_address] | mem[b_address] (16-bit)
mem[result_offset] = mem[a_address] | mem[b_address]
POSEIDON2PERM: Perform Poseidon2 permutation on 4 FF values M[dst_address:dst_address+4] = poseidon2_...
SET_128 instruction.
MemoryTagWrapper value_tag
SET_16 instruction.
MemoryTagWrapper value_tag
SET_32 instruction.
MemoryTagWrapper value_tag
SET_64 instruction.
MemoryTagWrapper value_tag
SET_8 instruction.
MemoryTagWrapper value_tag
SET_FF instruction.
MemoryTagWrapper value_tag
SHA256COMPRESSION: Perform SHA256 compression M[dst_address:dst_address+8] = sha256_compression(M[sta...
mem[result_offset] = mem[a_address] << mem[b_address] (16-bit)
mem[result_offset] = mem[a_address] << mem[b_address]
mem[result_offset] = mem[a_address] >> mem[b_address] (16-bit)
mem[result_offset] = mem[a_address] >> mem[b_address]
SLOAD: M[slot_offset] = slot; M[result_offset] = S[M[slotOffset]].
SSTORE: M[slot_offset_index] = slot; S[M[slotOffset]] = M[srcOffset].
mem[result_offset] = mem[a_address] - mem[b_address] (16-bit)
mem[result_offset] = mem[a_address] - mem[b_address]
TORADIXBE: Convert a field element to a vector of limbs in big-endian radix representation M[dst_addr...
AddressingModeWrapper mode
uint32_t index
Index of the variable in the memory_manager.stored_variables map.
MemoryTagWrapper tag
uint16_t pointer_address_seed
A seed for the generation of the pointer address Used for Indirect/IndirectRelative modes only.
mem[result_offset] = mem[a_address] ^ mem[b_address] (16-bit)
mem[result_offset] = mem[a_address] ^ mem[b_address]
BB_INLINE constexpr bool is_zero() const noexcept
void mutate_uint16_t(uint16_t &value, std::mt19937_64 &rng, const Uint16MutationConfig &config)
Definition uint16_t.cpp:4
void mutate_uint32_t(uint32_t &value, std::mt19937_64 &rng, const Uint32MutationConfig &config)
Definition uint32_t.cpp:4
void mutate_uint64_t(uint64_t &value, std::mt19937_64 &rng, const Uint64MutationConfig &config)
Definition uint64_t.cpp:4
void mutate_uint8_t(uint8_t &value, std::mt19937_64 &rng, const Uint8MutationConfig &config)
Definition uint8_t.cpp:4
uint64_t generate_random_uint64(std::mt19937_64 &rng)
uint32_t generate_random_uint32(std::mt19937_64 &rng)
uint16_t generate_random_uint16(std::mt19937_64 &rng)
uint8_t generate_random_uint8(std::mt19937_64 &rng)