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 .p1_infinite = generate_variable_ref(rng),
432 .p2_x = generate_variable_ref(rng),
433 .p2_y = generate_variable_ref(rng),
434 .p2_infinite = generate_variable_ref(rng),
435 .result = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
436 }
437
438 // Backfill mode: generate valid points on the Grumpkin curve and SET them
439 // 6 SET instructions (2 points * 3 fields each) + 1 ECADD = 7 instructions
440 std::vector<FuzzInstruction> instructions;
441 instructions.reserve(7);
442
443 // Generate a valid point via scalar multiplication of the generator (always on curve)
444 auto generate_point = [&rng]() {
446 return bb::avm2::EmbeddedCurvePoint::one() * scalar;
447 };
448
449 // Generate SET instructions to backfill a point at the given addresses
450 auto backfill_point = [&instructions](const bb::avm2::EmbeddedCurvePoint& point,
451 AddressRef x_addr,
452 AddressRef y_addr,
453 AddressRef inf_addr) {
454 instructions.push_back(
455 SET_FF_Instruction{ .value_tag = bb::avm2::MemoryTag::FF, .result_address = x_addr, .value = point.x() });
456 instructions.push_back(
457 SET_FF_Instruction{ .value_tag = bb::avm2::MemoryTag::FF, .result_address = y_addr, .value = point.y() });
458 instructions.push_back(SET_8_Instruction{ .value_tag = bb::avm2::MemoryTag::U1,
459 .result_address = inf_addr,
460 .value = static_cast<uint8_t>(point.is_infinity() ? 1 : 0) });
461 };
462
463 auto p1 = generate_point();
464 auto p2 = generate_point();
465
466 // Generate addresses (SET_FF uses 16-bit, SET_8 uses 8-bit operands)
467 AddressRef p1_x_addr = generate_address_ref(rng, MAX_16BIT_OPERAND);
468 AddressRef p1_y_addr = generate_address_ref(rng, MAX_16BIT_OPERAND);
469 AddressRef p1_inf_addr = generate_address_ref(rng, MAX_8BIT_OPERAND);
470 AddressRef p2_x_addr = generate_address_ref(rng, MAX_16BIT_OPERAND);
471 AddressRef p2_y_addr = generate_address_ref(rng, MAX_16BIT_OPERAND);
472 AddressRef p2_inf_addr = generate_address_ref(rng, MAX_8BIT_OPERAND);
473
474 backfill_point(p1, p1_x_addr, p1_y_addr, p1_inf_addr);
475 backfill_point(p2, p2_x_addr, p2_y_addr, p2_inf_addr);
476
477 instructions.push_back(ECADD_Instruction{ .p1_x = p1_x_addr,
478 .p1_y = p1_y_addr,
479 .p1_infinite = p1_inf_addr,
480 .p2_x = p2_x_addr,
481 .p2_y = p2_y_addr,
482 .p2_infinite = p2_inf_addr,
483 .result = generate_address_ref(rng, MAX_16BIT_OPERAND) });
484
485 return instructions;
486}
487
488// Generate binary ALU instruction with optional backfill for matching tagged operands
489template <typename InstructionType>
491 uint32_t max_operand)
492{
493 // 80% chance to use backfill (4 out of 5) to increase success rate
494 bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
495
496 if (!use_backfill) {
497 return { InstructionType{ .a_address = generate_variable_ref(rng),
498 .b_address = generate_variable_ref(rng),
499 .result_address = generate_address_ref(rng, max_operand) } };
500 }
501
503 AddressRef a_addr = generate_address_ref(rng, max_operand);
504 AddressRef b_addr = generate_address_ref(rng, max_operand);
505
506 std::vector<FuzzInstruction> instructions;
507 instructions.push_back(generate_set_for_tag(tag, a_addr, rng));
508 instructions.push_back(generate_set_for_tag(tag, b_addr, rng));
509 instructions.push_back(InstructionType{
510 .a_address = a_addr, .b_address = b_addr, .result_address = generate_address_ref(rng, max_operand) });
511 return instructions;
512}
513
514// Generate binary ALU instruction with optional backfill for matching non-FF tagged operands
515// Used for bitwise operations (AND, OR, XOR) and integer DIV which don't support FF
516template <typename InstructionType>
518 uint32_t max_operand)
519{
520 // 80% chance to use backfill (4 out of 5) to increase success rate
521 bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
522
523 if (!use_backfill) {
524 return { InstructionType{ .a_address = generate_variable_ref(rng),
525 .b_address = generate_variable_ref(rng),
526 .result_address = generate_address_ref(rng, max_operand) } };
527 }
528
529 // Pick a random non-FF tag (U1, U8, U16, U32, U64, U128)
530 static constexpr std::array<bb::avm2::MemoryTag, 6> int_tags = {
533 };
534 auto tag = int_tags[std::uniform_int_distribution<size_t>(0, int_tags.size() - 1)(rng)];
535
536 AddressRef a_addr = generate_address_ref(rng, max_operand);
537 AddressRef b_addr = generate_address_ref(rng, max_operand);
538
539 std::vector<FuzzInstruction> instructions;
540 instructions.push_back(generate_set_for_tag(tag, a_addr, rng));
541 instructions.push_back(generate_set_for_tag(tag, b_addr, rng));
542 instructions.push_back(InstructionType{
543 .a_address = a_addr, .b_address = b_addr, .result_address = generate_address_ref(rng, max_operand) });
544 return instructions;
545}
546
547std::vector<FuzzInstruction> InstructionMutator::generate_fdiv_instruction(std::mt19937_64& rng, uint32_t max_operand)
548{
549 // 80% chance to use backfill (4 out of 5) to increase success rate
550 bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
551
552 if (!use_backfill) {
553 // Random mode: use existing memory values
555 .b_address = generate_variable_ref(rng),
556 .result_address = generate_address_ref(rng, max_operand) } };
557 }
558
559 // Backfill mode: generate two non-zero FF values
560 std::vector<FuzzInstruction> instructions;
561 instructions.reserve(3);
562
563 // Generate non-zero field values (avoid division by zero)
564 auto generate_nonzero_field = [&rng]() {
566 do {
568 } while (value.is_zero());
569 return value;
570 };
571
572 AddressRef a_addr = generate_address_ref(rng, max_operand);
573 AddressRef b_addr = generate_address_ref(rng, max_operand);
574
575 // SET the dividend (a)
576 instructions.push_back(SET_FF_Instruction{
577 .value_tag = bb::avm2::MemoryTag::FF, .result_address = a_addr, .value = generate_nonzero_field() });
578
579 // SET the divisor (b) - must be non-zero
580 instructions.push_back(SET_FF_Instruction{
581 .value_tag = bb::avm2::MemoryTag::FF, .result_address = b_addr, .value = generate_nonzero_field() });
582
583 // FDIV instruction
584 instructions.push_back(FDIV_8_Instruction{
585 .a_address = a_addr, .b_address = b_addr, .result_address = generate_address_ref(rng, max_operand) });
586
587 return instructions;
588}
589
591{
592 // 80% chance to use backfill (4 out of 5) to increase success rate
593 bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
594 if (!use_backfill) {
595 // Random mode
597 .dst_address = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
598 }
599 // Backfill mode
600 std::vector<FuzzInstruction> instructions;
601
602 // Keccak needs to backfill 25 U64 values, these need be contiguous in memory
603 AddressRef src_address = generate_address_ref(rng, MAX_16BIT_OPERAND - 24);
604 for (size_t i = 0; i < 25; i++) {
605 AddressRef item_address = src_address;
606 item_address.address += static_cast<uint32_t>(i);
607 instructions.push_back(SET_64_Instruction{ .value_tag = bb::avm2::MemoryTag::U64,
608 .result_address = item_address,
609 .value = generate_random_uint64(rng) });
610 }
611 instructions.push_back(KECCAKF1600_Instruction{ .src_address = src_address,
612 .dst_address = generate_address_ref(rng, MAX_16BIT_OPERAND) });
613 return instructions;
614}
615
617{
618 // 80% chance to use backfill (4 out of 5) to increase success rate
619 bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
620 if (!use_backfill) {
621 // Random mode
623 .input_address = generate_variable_ref(rng),
624 .dst_address = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
625 }
626 // Backfill mode
627 // SHA256 compression needs 8 U32 values for state and 16 U32 values for input (contiguous)
628 std::vector<FuzzInstruction> instructions;
629 instructions.reserve(8 + 16 + 1);
630
631 // Generate state address (8 contiguous U32 values)
632 AddressRef state_address = generate_address_ref(rng, MAX_16BIT_OPERAND - 7);
633
634 for (size_t i = 0; i < 8; i++) {
635 AddressRef item_address = state_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 // Generate input address (16 contiguous U32 values)
643 AddressRef input_address = generate_address_ref(rng, MAX_16BIT_OPERAND - 15);
644
645 for (size_t i = 0; i < 16; i++) {
646 AddressRef item_address = input_address;
647 item_address.address += static_cast<uint32_t>(i);
648 instructions.push_back(SET_32_Instruction{ .value_tag = bb::avm2::MemoryTag::U32,
649 .result_address = item_address,
650 .value = generate_random_uint32(rng) });
651 }
652
653 instructions.push_back(
655 .input_address = input_address,
656 .dst_address = generate_address_ref(rng, MAX_16BIT_OPERAND) });
657 return instructions;
658}
659
661{
662 // 80% chance to use backfill (4 out of 5) to increase success rate
663 bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
664 if (!use_backfill) {
665 // Random mode
667 .radix_address = generate_variable_ref(rng),
668 .num_limbs_address = generate_variable_ref(rng),
669 .output_bits_address = generate_variable_ref(rng),
670 .dst_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
671 .is_output_bits = std::uniform_int_distribution<int>(0, 1)(rng) == 0 } };
672 }
673 // Backfill mode: set up proper typed values
674 // value: FF, radix: U32, num_limbs: U32, output_bits: U1
675 std::vector<FuzzInstruction> instructions;
676 instructions.reserve(5);
677
678 AddressRef value_addr = generate_address_ref(rng, MAX_16BIT_OPERAND);
679 AddressRef radix_addr = generate_address_ref(rng, MAX_16BIT_OPERAND);
680 AddressRef num_limbs_addr = generate_address_ref(rng, MAX_16BIT_OPERAND);
681 AddressRef output_bits_addr = generate_address_ref(rng, MAX_8BIT_OPERAND);
682
683 // SET the radix (U32) - pick radix between 2 and 256
684 uint32_t radix = std::uniform_int_distribution<uint32_t>(2, 256)(rng);
685 instructions.push_back(
686 SET_32_Instruction{ .value_tag = bb::avm2::MemoryTag::U32, .result_address = radix_addr, .value = radix });
687
688 // SET the output_bits (U1)
689 bool is_output_bits = radix == 2;
690 instructions.push_back(SET_8_Instruction{ .value_tag = bb::avm2::MemoryTag::U1,
691 .result_address = output_bits_addr,
692 .value = static_cast<uint8_t>(is_output_bits ? 1 : 0) });
693
694 // Generate value with num_limbs digits
695 uint32_t num_limbs = std::uniform_int_distribution<uint32_t>(0, 256)(rng);
697 bb::avm2::FF exponent = 1;
698 for (uint32_t i = 0; i < num_limbs; i++) {
699 uint32_t digit = std::uniform_int_distribution<uint32_t>(0, radix - 1)(rng);
700 value += bb::avm2::FF(digit) * exponent;
701 exponent *= radix;
702 }
703
704 // 20% chance to truncate - reduce the number of limbs we request or increment the value if we have 0 limbs
705 if (std::uniform_int_distribution<int>(0, 4)(rng) == 0) {
706 if (num_limbs > 0) {
707 num_limbs--;
708 } else {
709 value++;
710 }
711 }
712
713 // SET the num_limbs (U32)
714 instructions.push_back(SET_32_Instruction{
715 .value_tag = bb::avm2::MemoryTag::U32, .result_address = num_limbs_addr, .value = num_limbs });
716
717 // SET the value (FF)
718 instructions.push_back(
719 SET_FF_Instruction{ .value_tag = bb::avm2::MemoryTag::FF, .result_address = value_addr, .value = value });
720
721 // TORADIXBE instruction
722 instructions.push_back(TORADIXBE_Instruction{ .value_address = value_addr,
723 .radix_address = radix_addr,
724 .num_limbs_address = num_limbs_addr,
725 .output_bits_address = output_bits_addr,
726 .dst_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
727 .is_output_bits = is_output_bits });
728 return instructions;
729}
730
731// A better way in the future is to pass in a vector of possible slots that have been written to,
732// this would allow us to supply external world state info.
734{
735 // 80% chance to use backfill (4 out of 5) to increase success rate
736 bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
737
738 if (!use_backfill) {
739 // Random mode: requires at least one prior SSTORE to have been processed
741 .slot_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
742 .contract_address_address = generate_variable_ref(rng),
743 .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
744 }
745
746 // Backfill mode: generate SSTORE first to ensure storage_addresses is non-empty
747 // This guarantees SLOAD will find a valid slot (get_slot uses modulo on non-empty vector)
748 std::vector<FuzzInstruction> instructions;
749 instructions.reserve(4);
750
751 AddressRef sstore_src = generate_address_ref(rng, MAX_16BIT_OPERAND);
752
753 // SET a value to store
754 instructions.push_back(SET_FF_Instruction{
755 .value_tag = bb::avm2::MemoryTag::FF, .result_address = sstore_src, .value = generate_random_field(rng) });
756
757 // SSTORE - appends to storage_addresses in memory_manager
758 instructions.push_back(SSTORE_Instruction{ .src_address = sstore_src,
759 .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
760 .slot = generate_random_field(rng) });
761
762 // Now set our own contract address
764 instructions.push_back(
765 GETENVVAR_Instruction{ .result_address = contract_address_address, /* contract address */ .type = 0 });
766
767 // SLOAD - now guaranteed to succeed (storage_addresses not empty, get_slot uses modulo)
768 instructions.push_back(SLOAD_Instruction{ .slot_index = generate_random_uint16(rng),
769 .slot_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
770 .contract_address_address = contract_address_address,
771 .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND) });
772
773 return instructions;
774}
775
777{
778 // 80% chance to use backfill (4 out of 5) to increase success rate
779 bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
780
781 if (!use_backfill) {
783 .log_values_address = generate_variable_ref(rng) } };
784 }
785
787 std::vector<FuzzInstruction> instructions;
788 instructions.reserve(3);
789
790 auto log_size_address = generate_address_ref(rng, MAX_16BIT_OPERAND);
791 auto log_values_address = generate_address_ref(rng, MAX_16BIT_OPERAND - log_size);
792
793 instructions.push_back(SET_32_Instruction{
794 .value_tag = bb::avm2::MemoryTag::U32, .result_address = log_size_address, .value = log_size });
795
796 // Write one random FF in the log
797 instructions.push_back(SET_FF_Instruction{ .value_tag = bb::avm2::MemoryTag::FF,
798 .result_address = log_values_address,
799 .value = generate_random_field(rng) });
800
801 instructions.push_back(
803
804 return instructions;
805}
806
808{
809 // 80% chance to use backfill (4 out of 5) to increase success rate
810 bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
811
812 if (!use_backfill) {
813
815 .da_gas_address = generate_variable_ref(rng),
816 .contract_address_address = generate_variable_ref(rng),
817 .calldata_address = generate_variable_ref(rng),
818 .calldata_size_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
819 .calldata_size = generate_random_uint16(rng),
820 .is_static_call = rng() % 2 == 0 } };
821 }
822
823 std::vector<FuzzInstruction> instructions;
824 instructions.reserve(5);
825
826 auto contract_address_address = generate_address_ref(rng, MAX_16BIT_OPERAND);
827 instructions.push_back(SET_FF_Instruction{ .value_tag = bb::avm2::MemoryTag::FF,
828 .result_address = contract_address_address,
829 .value = context.get_contract_address(generate_random_uint16(rng)) });
830
831 auto l2_gas_address = generate_address_ref(rng, MAX_16BIT_OPERAND);
832 instructions.push_back(SET_32_Instruction{ .value_tag = bb::avm2::MemoryTag::U32,
833 .result_address = l2_gas_address,
834 .value = generate_random_uint32(rng) });
835
836 auto da_gas_address = generate_address_ref(rng, MAX_16BIT_OPERAND);
837 instructions.push_back(SET_32_Instruction{ .value_tag = bb::avm2::MemoryTag::U32,
838 .result_address = da_gas_address,
839 .value = generate_random_uint32(rng) });
840
842 auto calldata_size_address = generate_address_ref(rng, MAX_16BIT_OPERAND);
843
844 auto calldata_address = generate_address_ref(rng, MAX_16BIT_OPERAND);
845 // Write one random FF in the calldata
846 instructions.push_back(SET_FF_Instruction{ .value_tag = bb::avm2::MemoryTag::FF,
847 .result_address = calldata_address,
848 .value = generate_random_field(rng) });
849
850 instructions.push_back(CALL_Instruction{ .l2_gas_address = l2_gas_address,
851 .da_gas_address = da_gas_address,
852 .contract_address_address = contract_address_address,
853 .calldata_address = calldata_address,
854 .calldata_size_address = calldata_size_address,
855 .calldata_size = calldata_size,
856 .is_static_call = rng() % 2 == 0 });
857
858 return instructions;
859}
860
862{
863 bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
864 if (!use_backfill) {
867 .member_enum = generate_random_uint8(rng),
868 .dst_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
869 } };
870 }
871
872 std::vector<FuzzInstruction> instructions;
873 instructions.reserve(2);
874
875 auto contract_address_address = generate_address_ref(rng, MAX_16BIT_OPERAND);
876 instructions.push_back(SET_FF_Instruction{ .value_tag = bb::avm2::MemoryTag::FF,
877 .result_address = contract_address_address,
878 .value = context.get_contract_address(generate_random_uint16(rng)) });
880
881 instructions.push_back(GETCONTRACTINSTANCE_Instruction{
883 .member_enum = member_enum,
884 .dst_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
885 });
886
887 return instructions;
888}
889
891{
892 bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
893 if (!use_backfill) {
895 .leaf_index_address = generate_variable_ref(rng),
896 .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
897 }
898 auto existing_note_hash = context.get_existing_note_hash(generate_random_uint16(rng));
899 FF note_hash = existing_note_hash.has_value() ? existing_note_hash.value().first : generate_random_field(rng);
900 uint64_t leaf_index =
901 existing_note_hash.has_value() ? existing_note_hash.value().second : generate_random_uint64(rng);
902 AddressRef note_hash_address = generate_address_ref(rng, MAX_16BIT_OPERAND);
903 AddressRef leaf_index_address = generate_address_ref(rng, MAX_16BIT_OPERAND);
904
905 std::vector<FuzzInstruction> instructions;
906 instructions.reserve(3);
907
908 instructions.push_back(SET_FF_Instruction{
910 instructions.push_back(SET_64_Instruction{
911 .value_tag = bb::avm2::MemoryTag::U64, .result_address = leaf_index_address, .value = leaf_index });
912
913 instructions.push_back(
915 .leaf_index_address = leaf_index_address,
916 .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND) });
917
918 return instructions;
919}
920
922{
923 return { RETURNDATASIZE_Instruction{ .dst_address = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
924}
925
927{
928 bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
929 if (!use_backfill) {
931 .rd_offset_address = generate_variable_ref(rng),
932 .dst_address = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
933 }
934 std::vector<FuzzInstruction> instructions;
935 instructions.reserve(3);
936 auto copy_size_address = generate_address_ref(rng, MAX_16BIT_OPERAND);
937 instructions.push_back(SET_32_Instruction{ .value_tag = bb::avm2::MemoryTag::U32,
938 .result_address = copy_size_address,
939 // We generate small sizes so we fail less often due to gas
940 // Mutations might change this to a larger value.
941 .value = generate_random_uint8(rng) });
942
943 auto rd_offset_address = generate_address_ref(rng, MAX_16BIT_OPERAND);
944 instructions.push_back(SET_32_Instruction{ .value_tag = bb::avm2::MemoryTag::U32,
945 .result_address = rd_offset_address,
946 .value = generate_random_uint8(rng) });
947
949 .rd_offset_address = rd_offset_address,
950 .dst_address = generate_address_ref(rng, MAX_16BIT_OPERAND) });
951
952 return instructions;
953}
954
956{
957 bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
958 if (!use_backfill) {
960 .cd_offset_address = generate_variable_ref(rng),
961 .dst_address = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
962 }
963 std::vector<FuzzInstruction> instructions;
964 instructions.reserve(3);
965 auto copy_size_address = generate_address_ref(rng, MAX_16BIT_OPERAND);
966 instructions.push_back(SET_32_Instruction{ .value_tag = bb::avm2::MemoryTag::U32,
967 .result_address = copy_size_address,
968 // We generate small sizes so we fail less often due to gas
969 // Mutations might change this to a larger value.
970 .value = generate_random_uint8(rng) });
971
972 auto cd_offset_address = generate_address_ref(rng, MAX_16BIT_OPERAND);
973 instructions.push_back(SET_32_Instruction{ .value_tag = bb::avm2::MemoryTag::U32,
974 .result_address = cd_offset_address,
975 .value = generate_random_uint8(rng) });
976
978 .cd_offset_address = cd_offset_address,
979 .dst_address = generate_address_ref(rng, MAX_16BIT_OPERAND) });
980
981 return instructions;
982}
983
985{
986 bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
987 if (!use_backfill) {
989 .content_address = generate_variable_ref(rng) } };
990 }
991 std::vector<FuzzInstruction> instructions;
992 instructions.reserve(3);
993
994 auto recipient_address = generate_address_ref(rng, MAX_16BIT_OPERAND);
995 instructions.push_back(SET_FF_Instruction{ .value_tag = bb::avm2::MemoryTag::FF,
996 .result_address = recipient_address,
998
999 auto content_address = generate_address_ref(rng, MAX_16BIT_OPERAND);
1000 instructions.push_back(SET_FF_Instruction{
1002
1003 instructions.push_back(
1005
1006 return instructions;
1007}
1008
1010 std::mt19937_64& rng,
1011 std::optional<MemoryTag> default_tag,
1012 uint32_t max_operand_value)
1013{
1014 std::visit(overloaded{ [&](VariableRef& var) { mutate_variable_ref(var, rng, default_tag); },
1015 [&](AddressRef& addr) { mutate_address_ref(addr, rng, max_operand_value); } },
1016 param);
1017}
1018
1019template <typename BinaryInstructionType>
1021{
1023 switch (option) {
1025 mutate_param_ref(instruction.a_address, rng, std::nullopt, MAX_8BIT_OPERAND);
1026 break;
1028 mutate_param_ref(instruction.b_address, rng, get_param_ref_tag(instruction.a_address), MAX_8BIT_OPERAND);
1029 break;
1031 mutate_address_ref(instruction.result_address, rng, MAX_8BIT_OPERAND);
1032 break;
1033 }
1034}
1035
1036template <typename BinaryInstructionType>
1038{
1040 switch (option) {
1042 mutate_param_ref(instruction.a_address, rng, std::nullopt, MAX_16BIT_OPERAND);
1043 break;
1045 mutate_param_ref(instruction.b_address, rng, get_param_ref_tag(instruction.a_address), MAX_16BIT_OPERAND);
1046 break;
1048 mutate_address_ref(instruction.result_address, rng, MAX_16BIT_OPERAND);
1049 break;
1050 }
1051}
1052
1065
1081
1097
1113
1129
1148
1164
1166{
1167 int choice = std::uniform_int_distribution<int>(0, 2)(rng);
1168 switch (choice) {
1169 case 0:
1171 break;
1172 case 1:
1173 mutate_param_ref(instruction.src_address, rng, std::nullopt, MAX_8BIT_OPERAND);
1174 break;
1175 case 2:
1176 mutate_address_ref(instruction.result_address, rng, MAX_8BIT_OPERAND);
1177 break;
1178 }
1179}
1180
1182{
1183 int choice = std::uniform_int_distribution<int>(0, 2)(rng);
1184 switch (choice) {
1185 case 0:
1187 break;
1188 case 1:
1189 mutate_param_ref(instruction.src_address, rng, std::nullopt, MAX_16BIT_OPERAND);
1190 break;
1191 case 2:
1192 mutate_address_ref(instruction.result_address, rng, MAX_16BIT_OPERAND);
1193 break;
1194 }
1195}
1196
1209
1225
1241
1243{
1245 switch (option) {
1247 mutate_param_ref(instruction.src_address, rng, MemoryTag::FF, MAX_16BIT_OPERAND);
1248 break;
1250 mutate_address_ref(instruction.result_address, rng, MAX_16BIT_OPERAND);
1251 break;
1254 break;
1255 }
1256}
1257
1259{
1261 switch (option) {
1264 break;
1266 mutate_address_ref(instruction.slot_address, rng, MAX_16BIT_OPERAND);
1267 break;
1269 mutate_param_ref(instruction.contract_address_address, rng, MemoryTag::FF, MAX_16BIT_OPERAND);
1270 break;
1272 mutate_address_ref(instruction.result_address, rng, MAX_16BIT_OPERAND);
1273 break;
1274 }
1275}
1276
1278{
1280 switch (option) {
1282 mutate_address_ref(instruction.result_address, rng, MAX_16BIT_OPERAND);
1283 break;
1285 instruction.type = generate_envvar_type(rng);
1286 break;
1287 }
1288}
1289
1291{
1292 // emitnulifier only has one field
1293
1294 mutate_param_ref(instruction.nullifier_address, rng, MemoryTag::FF, MAX_16BIT_OPERAND);
1295}
1296
1310
1312 std::mt19937_64& rng)
1313{
1315 switch (option) {
1317 mutate_param_ref(instruction.msg_hash_address, rng, MemoryTag::FF, MAX_16BIT_OPERAND);
1318 break;
1320 mutate_param_ref(instruction.leaf_index_address, rng, MemoryTag::U64, MAX_16BIT_OPERAND);
1321 break;
1323 mutate_address_ref(instruction.result_address, rng, MAX_16BIT_OPERAND);
1324 break;
1325 }
1326}
1327
1341 std::mt19937_64& rng)
1342{
1344 switch (option) {
1346 mutate_param_ref(instruction.notehash_address, rng, MemoryTag::FF, MAX_16BIT_OPERAND);
1347 break;
1349 mutate_param_ref(instruction.leaf_index_address, rng, MemoryTag::U64, MAX_16BIT_OPERAND);
1350 break;
1352 mutate_address_ref(instruction.result_address, rng, MAX_16BIT_OPERAND);
1353 break;
1354 }
1355}
1356
1358{
1360 switch (option) {
1362 mutate_param_ref(instruction.copy_size_address, rng, MemoryTag::U32, MAX_16BIT_OPERAND);
1363 break;
1365 mutate_param_ref(instruction.cd_offset_address, rng, MemoryTag::U32, MAX_16BIT_OPERAND);
1366 break;
1368 mutate_address_ref(instruction.dst_address, rng, MAX_16BIT_OPERAND);
1369 break;
1370 }
1371}
1372
1385
1398
1400{
1402 switch (option) {
1404 mutate_param_ref(instruction.l2_gas_address, rng, MemoryTag::U32, MAX_16BIT_OPERAND);
1405 break;
1407 mutate_param_ref(instruction.da_gas_address, rng, MemoryTag::U32, MAX_16BIT_OPERAND);
1408 break;
1410 mutate_param_ref(instruction.contract_address_address, rng, MemoryTag::FF, MAX_16BIT_OPERAND);
1411 break;
1413 mutate_address_ref(instruction.calldata_size_address, rng, MAX_16BIT_OPERAND);
1414 break;
1417 break;
1419 mutate_param_ref(instruction.calldata_address, rng, MemoryTag::FF, MAX_16BIT_OPERAND);
1420 break;
1422 // with 0.5 probability, set to true, otherwise false
1423 instruction.is_static_call = rng() % 2 == 0;
1424 }
1425}
1426
1432
1434 std::mt19937_64& rng)
1435{
1437 switch (option) {
1439 mutate_param_ref(instruction.copy_size_address, rng, MemoryTag::U32, MAX_16BIT_OPERAND);
1440 break;
1442 mutate_param_ref(instruction.rd_offset_address, rng, MemoryTag::U32, MAX_16BIT_OPERAND);
1443 break;
1445 mutate_address_ref(instruction.dst_address, rng, MAX_16BIT_OPERAND);
1446 break;
1447 }
1448}
1449
1466
1476
1478{
1479 // ECADD has 7 operands, select one to mutate
1480 int choice = std::uniform_int_distribution<int>(0, 6)(rng);
1481 switch (choice) {
1482 case 0:
1483 mutate_param_ref(instruction.p1_x, rng, MemoryTag::FF, MAX_16BIT_OPERAND);
1484 break;
1485 case 1:
1486 mutate_param_ref(instruction.p1_y, rng, MemoryTag::FF, MAX_16BIT_OPERAND);
1487 break;
1488 case 2:
1489 mutate_param_ref(instruction.p1_infinite, rng, MemoryTag::U1, MAX_16BIT_OPERAND);
1490 break;
1491 case 3:
1492 mutate_param_ref(instruction.p2_x, rng, MemoryTag::FF, MAX_16BIT_OPERAND);
1493 break;
1494 case 4:
1495 mutate_param_ref(instruction.p2_y, rng, MemoryTag::FF, MAX_16BIT_OPERAND);
1496 break;
1497 case 5:
1498 mutate_param_ref(instruction.p2_infinite, rng, MemoryTag::U1, MAX_16BIT_OPERAND);
1499 break;
1500 case 6:
1501 mutate_address_ref(instruction.result, rng, MAX_16BIT_OPERAND);
1502 break;
1503 }
1504}
1505
1507{
1508 int choice = std::uniform_int_distribution<int>(0, 1)(rng);
1509 switch (choice) {
1510 case 0:
1511 mutate_param_ref(instruction.src_address, rng, MemoryTag::U32, MAX_16BIT_OPERAND);
1512 break;
1513 case 1:
1514 mutate_address_ref(instruction.dst_address, rng, MAX_16BIT_OPERAND);
1515 break;
1516 }
1517}
1518
1520{
1521 int choice = std::uniform_int_distribution<int>(0, 1)(rng);
1522 switch (choice) {
1523 case 0:
1524 mutate_param_ref(instruction.src_address, rng, MemoryTag::U32, MAX_16BIT_OPERAND);
1525 break;
1526 case 1:
1527 mutate_address_ref(instruction.dst_address, rng, MAX_16BIT_OPERAND);
1528 break;
1529 }
1530}
1531
1533 std::mt19937_64& rng)
1534{
1535 int choice = std::uniform_int_distribution<int>(0, 2)(rng);
1536 switch (choice) {
1537 case 0:
1538 mutate_param_ref(instruction.state_address, rng, MemoryTag::U32, MAX_16BIT_OPERAND);
1539 break;
1540 case 1:
1541 mutate_param_ref(instruction.input_address, rng, MemoryTag::U32, MAX_16BIT_OPERAND);
1542 break;
1543 case 2:
1544 mutate_address_ref(instruction.dst_address, rng, MAX_16BIT_OPERAND);
1545 break;
1546 }
1547}
1548
1550{
1552 switch (option) {
1554 mutate_param_ref(instruction.value_address, rng, MemoryTag::FF, MAX_16BIT_OPERAND);
1555 break;
1557 mutate_param_ref(instruction.radix_address, rng, MemoryTag::U32, MAX_16BIT_OPERAND);
1558 break;
1560 mutate_param_ref(instruction.num_limbs_address, rng, MemoryTag::U32, MAX_16BIT_OPERAND);
1561 break;
1563 mutate_param_ref(instruction.output_bits_address, rng, MemoryTag::U1, MAX_16BIT_OPERAND);
1564 break;
1566 mutate_address_ref(instruction.dst_address, rng, MAX_16BIT_OPERAND);
1567 break;
1569 instruction.is_output_bits = !instruction.is_output_bits;
1570 break;
1571 }
1572}
1573
1575{
1577 switch (option) {
1579 mutate_param_ref(instruction.level_offset, rng, MemoryTag::U32, MAX_16BIT_OPERAND);
1580 break;
1582 mutate_param_ref(instruction.message_offset, rng, MemoryTag::U32, MAX_16BIT_OPERAND);
1583 break;
1585 mutate_param_ref(instruction.fields_offset, rng, MemoryTag::U32, MAX_16BIT_OPERAND);
1586 break;
1588 mutate_param_ref(instruction.fields_size_offset, rng, MemoryTag::U32, MAX_16BIT_OPERAND);
1589 break;
1592 break;
1593 }
1594}
1595
1596} // 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 bool is_infinity() const noexcept
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)