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
19
20namespace {
21
22// Maximum operand values based on instruction operand size
23constexpr uint32_t MAX_8BIT_OPERAND = 255;
24constexpr uint32_t MAX_16BIT_OPERAND = 65535;
25
26// Helper to generate a SET instruction for a given tag at a given address
28{
29 switch (tag) {
30 // We use set 16 for u1 and u8 because using set_8 will limit the address range to 255.
32 return SET_16_Instruction{ .value_tag = tag, .result_address = addr, .value = static_cast<uint8_t>(rng() & 1) };
34 return SET_16_Instruction{ .value_tag = tag, .result_address = addr, .value = generate_random_uint8(rng) };
36 return SET_16_Instruction{ .value_tag = tag, .result_address = addr, .value = generate_random_uint16(rng) };
38 return SET_32_Instruction{ .value_tag = tag, .result_address = addr, .value = generate_random_uint32(rng) };
40 return SET_64_Instruction{ .value_tag = tag, .result_address = addr, .value = generate_random_uint64(rng) };
43 .result_address = addr,
44 .value_low = generate_random_uint64(rng),
45 .value_high = generate_random_uint64(rng) };
47 default:
48 return SET_FF_Instruction{ .value_tag = tag, .result_address = addr, .value = generate_random_field(rng) };
49 }
50}
51
52uint8_t generate_envvar_type(std::mt19937_64& rng)
53{
54 bool valid_type = std::uniform_int_distribution<int>(0, 9)(rng) != 0;
55
56 if (valid_type) {
57 // 0 -> ADDRESS, 1 -> SENDER, 2 -> TRANSACTIONFEE, 3 -> CHAINID, 4 -> VERSION, 5 -> BLOCKNUMBER, 6 -> TIMESTAMP,
58 // 7 -> MINFEEPERDAGAS, 8 -> MINFEEPERL2GAS, 9 -> ISSTATICCALL, 10 -> L2GASLEFT, 11 -> DAGASLEFT
60 } else {
61 return generate_random_uint8(rng);
62 }
63}
64
65std::optional<MemoryTag> get_param_ref_tag(const ParamRef& param)
66{
67 return std::visit(overloaded{ [](const VariableRef& var) -> std::optional<MemoryTag> { return var.tag.value; },
68 [](const AddressRef&) -> std::optional<MemoryTag> { return std::nullopt; } },
69 param);
70}
71
72void sanitize_address_ref(AddressRef& address_ref, uint32_t base_offset, uint32_t max_operand_value)
73{
74
75 // For Direct mode, constrain address to fit in the operand
76 if (address_ref.mode == AddressingMode::Direct) {
77 address_ref.address = address_ref.address % (max_operand_value + 1);
78 }
79 // For Relative mode, we can reach from base_pointer to base_pointer + max_operand_value
80 if (address_ref.mode == AddressingMode::Relative) {
81 address_ref.address = base_offset + (address_ref.address % (max_operand_value + 1));
82 }
83}
84
85} // namespace
86
87namespace bb::avm2::fuzzer {
88
90{
92 // forgive me
93 switch (option) {
95 return generate_alu_with_matching_tags<ADD_8_Instruction>(rng, MAX_8BIT_OPERAND);
97 return generate_alu_with_matching_tags<SUB_8_Instruction>(rng, MAX_8BIT_OPERAND);
99 return generate_alu_with_matching_tags<MUL_8_Instruction>(rng, MAX_8BIT_OPERAND);
101 return generate_alu_with_matching_tags_not_ff<DIV_8_Instruction>(rng, MAX_8BIT_OPERAND);
103 return generate_fdiv_instruction(rng, MAX_8BIT_OPERAND);
106 .b_address = generate_variable_ref(rng),
107 .result_address = generate_address_ref(rng, MAX_8BIT_OPERAND) } };
110 .b_address = generate_variable_ref(rng),
111 .result_address = generate_address_ref(rng, MAX_8BIT_OPERAND) } };
114 .b_address = generate_variable_ref(rng),
115 .result_address = generate_address_ref(rng, MAX_8BIT_OPERAND) } };
117 return generate_alu_with_matching_tags_not_ff<AND_8_Instruction>(rng, MAX_8BIT_OPERAND);
119 return generate_alu_with_matching_tags_not_ff<OR_8_Instruction>(rng, MAX_8BIT_OPERAND);
121 return generate_alu_with_matching_tags_not_ff<XOR_8_Instruction>(rng, MAX_8BIT_OPERAND);
124 .result_address = generate_address_ref(rng, MAX_8BIT_OPERAND) } };
127 .b_address = generate_variable_ref(rng),
128 .result_address = generate_address_ref(rng, MAX_8BIT_OPERAND) } };
129
132 .b_address = generate_variable_ref(rng),
133 .result_address = generate_address_ref(rng, MAX_8BIT_OPERAND) } };
136 .result_address = generate_address_ref(rng, MAX_8BIT_OPERAND),
137 .value = generate_random_uint8(rng) } };
140 .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
141 .value = generate_random_uint16(rng) } };
144 .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
145 .value = generate_random_uint32(rng) } };
148 .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
149 .value = generate_random_uint64(rng) } };
152 .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
153 .value_low = generate_random_uint64(rng),
154 .value_high = generate_random_uint64(rng) } };
157 .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
158 .value = generate_random_field(rng) } };
161 .src_address = generate_variable_ref(rng),
162 .result_address = generate_address_ref(rng, MAX_8BIT_OPERAND) } };
165 .src_address = generate_variable_ref(rng),
166 .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
168 return generate_alu_with_matching_tags<ADD_16_Instruction>(rng, MAX_16BIT_OPERAND);
170 return generate_alu_with_matching_tags<SUB_16_Instruction>(rng, MAX_16BIT_OPERAND);
172 return generate_alu_with_matching_tags<MUL_16_Instruction>(rng, MAX_16BIT_OPERAND);
174 return generate_alu_with_matching_tags_not_ff<DIV_16_Instruction>(rng, MAX_16BIT_OPERAND);
177 .b_address = generate_variable_ref(rng),
178 .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
181 .b_address = generate_variable_ref(rng),
182 .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
185 .b_address = generate_variable_ref(rng),
186 .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
189 .b_address = generate_variable_ref(rng),
190 .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
192 return generate_alu_with_matching_tags_not_ff<AND_16_Instruction>(rng, MAX_16BIT_OPERAND);
194 return generate_alu_with_matching_tags_not_ff<OR_16_Instruction>(rng, MAX_16BIT_OPERAND);
196 return generate_alu_with_matching_tags_not_ff<XOR_16_Instruction>(rng, MAX_16BIT_OPERAND);
199 .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
202 .b_address = generate_variable_ref(rng),
203 .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
206 .b_address = generate_variable_ref(rng),
207 .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
210 .result_address = generate_address_ref(rng, MAX_8BIT_OPERAND),
211 .target_tag =
215 .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
216 .target_tag =
220 .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
221 .slot = generate_random_field(rng) } };
223 return generate_sload_instruction(rng);
225 return { GETENVVAR_Instruction{ .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
226 .type = generate_envvar_type(rng) } };
231 .contract_address_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
232 .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
235 .leaf_index_address = generate_variable_ref(rng),
236 .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
238 return { EMITNOTEHASH_Instruction{ .note_hash_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
239 .note_hash = generate_random_field(rng) } };
246 .recipient_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
247 .content = generate_random_field(rng),
248 .content_address = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
252 return generate_call_instruction(rng);
260 return { SUCCESSCOPY_Instruction{ .dst_address = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
262 return generate_ecadd_instruction(rng);
264 return { POSEIDON2PERM_Instruction{ .src_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
265 .dst_address = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
274 .message_offset = generate_variable_ref(rng),
275 .fields_offset = generate_variable_ref(rng),
276 .fields_size_offset = generate_variable_ref(rng),
277 .message_size = generate_random_uint16(rng) } } };
278 }
279}
280
282{
283 std::visit(
285 [&rng, this](ADD_8_Instruction& instr) { mutate_binary_instruction_8(instr, rng); },
286 [&rng, this](SUB_8_Instruction& instr) { mutate_binary_instruction_8(instr, rng); },
287 [&rng, this](MUL_8_Instruction& instr) { mutate_binary_instruction_8(instr, rng); },
288 [&rng, this](DIV_8_Instruction& instr) { mutate_binary_instruction_8(instr, rng); },
289 [&rng, this](EQ_8_Instruction& instr) { mutate_binary_instruction_8(instr, rng); },
290 [&rng, this](LT_8_Instruction& instr) { mutate_binary_instruction_8(instr, rng); },
291 [&rng, this](LTE_8_Instruction& instr) { mutate_binary_instruction_8(instr, rng); },
292 [&rng, this](AND_8_Instruction& instr) { mutate_binary_instruction_8(instr, rng); },
293 [&rng, this](OR_8_Instruction& instr) { mutate_binary_instruction_8(instr, rng); },
294 [&rng, this](XOR_8_Instruction& instr) { mutate_binary_instruction_8(instr, rng); },
295 [&rng, this](SHL_8_Instruction& instr) { mutate_binary_instruction_8(instr, rng); },
296 [&rng, this](SHR_8_Instruction& instr) { mutate_binary_instruction_8(instr, rng); },
297 [&rng, this](SET_8_Instruction& instr) { mutate_set_8_instruction(instr, rng); },
298 [&rng, this](SET_16_Instruction& instr) { mutate_set_16_instruction(instr, rng); },
299 [&rng, this](SET_32_Instruction& instr) { mutate_set_32_instruction(instr, rng); },
300 [&rng, this](SET_64_Instruction& instr) { mutate_set_64_instruction(instr, rng); },
301 [&rng, this](SET_128_Instruction& instr) { mutate_set_128_instruction(instr, rng); },
302 [&rng, this](SET_FF_Instruction& instr) { mutate_set_ff_instruction(instr, rng); },
303 [&rng, this](MOV_8_Instruction& instr) { mutate_mov_8_instruction(instr, rng); },
304 [&rng, this](MOV_16_Instruction& instr) { mutate_mov_16_instruction(instr, rng); },
305 [&rng, this](FDIV_8_Instruction& instr) { mutate_binary_instruction_8(instr, rng); },
306 [&rng, this](NOT_8_Instruction& instr) { mutate_not_8_instruction(instr, rng); },
307 [&rng, this](ADD_16_Instruction& instr) { mutate_binary_instruction_16(instr, rng); },
308 [&rng, this](SUB_16_Instruction& instr) { mutate_binary_instruction_16(instr, rng); },
309 [&rng, this](MUL_16_Instruction& instr) { mutate_binary_instruction_16(instr, rng); },
310 [&rng, this](DIV_16_Instruction& instr) { mutate_binary_instruction_16(instr, rng); },
311 [&rng, this](FDIV_16_Instruction& instr) { mutate_binary_instruction_16(instr, rng); },
312 [&rng, this](EQ_16_Instruction& instr) { mutate_binary_instruction_16(instr, rng); },
313 [&rng, this](LT_16_Instruction& instr) { mutate_binary_instruction_16(instr, rng); },
314 [&rng, this](LTE_16_Instruction& instr) { mutate_binary_instruction_16(instr, rng); },
315 [&rng, this](AND_16_Instruction& instr) { mutate_binary_instruction_16(instr, rng); },
316 [&rng, this](OR_16_Instruction& instr) { mutate_binary_instruction_16(instr, rng); },
317 [&rng, this](XOR_16_Instruction& instr) { mutate_binary_instruction_16(instr, rng); },
318 [&rng, this](NOT_16_Instruction& instr) { mutate_not_16_instruction(instr, rng); },
319 [&rng, this](SHL_16_Instruction& instr) { mutate_binary_instruction_16(instr, rng); },
320 [&rng, this](SHR_16_Instruction& instr) { mutate_binary_instruction_16(instr, rng); },
321 [&rng, this](CAST_8_Instruction& instr) { mutate_cast_8_instruction(instr, rng); },
322 [&rng, this](CAST_16_Instruction& instr) { mutate_cast_16_instruction(instr, rng); },
323 [&rng, this](SSTORE_Instruction& instr) { mutate_sstore_instruction(instr, rng); },
324 [&rng, this](SLOAD_Instruction& instr) { mutate_sload_instruction(instr, rng); },
325 [&rng, this](GETENVVAR_Instruction& instr) { mutate_getenvvar_instruction(instr, rng); },
326 [&rng, this](EMITNULLIFIER_Instruction& instr) { mutate_emit_nullifier_instruction(instr, rng); },
327 [&rng, this](NULLIFIEREXISTS_Instruction& instr) { mutate_nullifier_exists_instruction(instr, rng); },
328 [&rng, this](L1TOL2MSGEXISTS_Instruction& instr) { mutate_l1tol2msgexists_instruction(instr, rng); },
329 [&rng, this](EMITNOTEHASH_Instruction& instr) { mutate_emit_note_hash_instruction(instr, rng); },
330 [&rng, this](NOTEHASHEXISTS_Instruction& instr) { mutate_note_hash_exists_instruction(instr, rng); },
331 [&rng, this](CALLDATACOPY_Instruction& instr) { mutate_calldatacopy_instruction(instr, rng); },
332 [&rng, this](SENDL2TOL1MSG_Instruction& instr) { mutate_sendl2tol1msg_instruction(instr, rng); },
333 [&rng, this](EMITUNENCRYPTEDLOG_Instruction& instr) { mutate_emitunencryptedlog_instruction(instr, rng); },
334 [&rng, this](CALL_Instruction& instr) { mutate_call_instruction(instr, rng); },
335 [&rng, this](RETURNDATASIZE_Instruction& instr) { mutate_returndatasize_instruction(instr, rng); },
336 [&rng, this](RETURNDATACOPY_Instruction& instr) { mutate_returndatacopy_instruction(instr, rng); },
337 [&rng, this](GETCONTRACTINSTANCE_Instruction& instr) {
339 },
340 [&rng, this](SUCCESSCOPY_Instruction& instr) { mutate_successcopy_instruction(instr, rng); },
341 [&rng, this](ECADD_Instruction& instr) { mutate_ecadd_instruction(instr, rng); },
342 [&rng, this](POSEIDON2PERM_Instruction& instr) { mutate_poseidon2perm_instruction(instr, rng); },
343 [&rng, this](KECCAKF1600_Instruction& instr) { mutate_keccakf1600_instruction(instr, rng); },
344 [&rng, this](SHA256COMPRESSION_Instruction& instr) { mutate_sha256compression_instruction(instr, rng); },
345 [&rng, this](TORADIXBE_Instruction& instr) { mutate_toradixbe_instruction(instr, rng); },
346 [&rng, this](DEBUGLOG_Instruction& instr) { mutate_debuglog_instruction(instr, rng); },
347 [](auto&) { throw std::runtime_error("Unknown instruction"); } },
349}
350
355
357{
359 .pointer_address_seed = generate_random_uint16(rng),
360 .mode = generate_addressing_mode(rng) };
361 sanitize_address_ref(address_ref, base_offset, max_operand_value);
362 return address_ref;
363}
364
366{
368 switch (option) {
371 break;
374 break;
377 break;
378 }
379 sanitize_address_ref(address, base_offset, max_operand_value);
380}
381
390
393 std::mt19937_64& rng,
394 std::optional<MemoryTag> default_tag)
395{
397 switch (option) {
399 if (default_tag.has_value()) {
400 mutate_or_default_tag(variable.tag.value, rng, default_tag.value());
401 } else {
403 }
404 break;
407 break;
410 break;
412 variable.mode = generate_addressing_mode(rng);
413 break;
414 }
415}
416
418{
419 // 80% chance to use backfill (4 out of 5) to increase success rate
420 bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
421
422 if (!use_backfill) {
423 // Random mode: use existing memory values (may fail if not valid points on curve)
425 .p1_y = generate_variable_ref(rng),
426 .p1_infinite = generate_variable_ref(rng),
427 .p2_x = generate_variable_ref(rng),
428 .p2_y = generate_variable_ref(rng),
429 .p2_infinite = generate_variable_ref(rng),
430 .result = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
431 }
432
433 // Backfill mode: generate valid points on the Grumpkin curve and SET them
434 // 6 SET instructions (2 points * 3 fields each) + 1 ECADD = 7 instructions
435 std::vector<FuzzInstruction> instructions;
436 instructions.reserve(7);
437
438 // Generate a valid point via scalar multiplication of the generator (always on curve)
439 auto generate_point = [&rng]() {
441 return bb::avm2::EmbeddedCurvePoint::one() * scalar;
442 };
443
444 // Generate SET instructions to backfill a point at the given addresses
445 auto backfill_point = [&instructions](const bb::avm2::EmbeddedCurvePoint& point,
446 AddressRef x_addr,
447 AddressRef y_addr,
448 AddressRef inf_addr) {
449 instructions.push_back(
450 SET_FF_Instruction{ .value_tag = bb::avm2::MemoryTag::FF, .result_address = x_addr, .value = point.x() });
451 instructions.push_back(
452 SET_FF_Instruction{ .value_tag = bb::avm2::MemoryTag::FF, .result_address = y_addr, .value = point.y() });
453 instructions.push_back(SET_8_Instruction{ .value_tag = bb::avm2::MemoryTag::U1,
454 .result_address = inf_addr,
455 .value = static_cast<uint8_t>(point.is_infinity() ? 1 : 0) });
456 };
457
458 auto p1 = generate_point();
459 auto p2 = generate_point();
460
461 // Generate addresses (SET_FF uses 16-bit, SET_8 uses 8-bit operands)
462 AddressRef p1_x_addr = generate_address_ref(rng, MAX_16BIT_OPERAND);
463 AddressRef p1_y_addr = generate_address_ref(rng, MAX_16BIT_OPERAND);
464 AddressRef p1_inf_addr = generate_address_ref(rng, MAX_8BIT_OPERAND);
465 AddressRef p2_x_addr = generate_address_ref(rng, MAX_16BIT_OPERAND);
466 AddressRef p2_y_addr = generate_address_ref(rng, MAX_16BIT_OPERAND);
467 AddressRef p2_inf_addr = generate_address_ref(rng, MAX_8BIT_OPERAND);
468
469 backfill_point(p1, p1_x_addr, p1_y_addr, p1_inf_addr);
470 backfill_point(p2, p2_x_addr, p2_y_addr, p2_inf_addr);
471
472 instructions.push_back(ECADD_Instruction{ .p1_x = p1_x_addr,
473 .p1_y = p1_y_addr,
474 .p1_infinite = p1_inf_addr,
475 .p2_x = p2_x_addr,
476 .p2_y = p2_y_addr,
477 .p2_infinite = p2_inf_addr,
478 .result = generate_address_ref(rng, MAX_16BIT_OPERAND) });
479
480 return instructions;
481}
482
483// Generate binary ALU instruction with optional backfill for matching tagged operands
484template <typename InstructionType>
486 uint32_t max_operand)
487{
488 // 80% chance to use backfill (4 out of 5) to increase success rate
489 bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
490
491 if (!use_backfill) {
492 return { InstructionType{ .a_address = generate_variable_ref(rng),
493 .b_address = generate_variable_ref(rng),
494 .result_address = generate_address_ref(rng, max_operand) } };
495 }
496
498 AddressRef a_addr = generate_address_ref(rng, max_operand);
499 AddressRef b_addr = generate_address_ref(rng, max_operand);
500
501 std::vector<FuzzInstruction> instructions;
502 instructions.push_back(generate_set_for_tag(tag, a_addr, rng));
503 instructions.push_back(generate_set_for_tag(tag, b_addr, rng));
504 instructions.push_back(InstructionType{
505 .a_address = a_addr, .b_address = b_addr, .result_address = generate_address_ref(rng, max_operand) });
506 return instructions;
507}
508
509// Generate binary ALU instruction with optional backfill for matching non-FF tagged operands
510// Used for bitwise operations (AND, OR, XOR) and integer DIV which don't support FF
511template <typename InstructionType>
513 uint32_t max_operand)
514{
515 // 80% chance to use backfill (4 out of 5) to increase success rate
516 bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
517
518 if (!use_backfill) {
519 return { InstructionType{ .a_address = generate_variable_ref(rng),
520 .b_address = generate_variable_ref(rng),
521 .result_address = generate_address_ref(rng, max_operand) } };
522 }
523
524 // Pick a random non-FF tag (U1, U8, U16, U32, U64, U128)
525 static constexpr std::array<bb::avm2::MemoryTag, 6> int_tags = {
528 };
529 auto tag = int_tags[std::uniform_int_distribution<size_t>(0, int_tags.size() - 1)(rng)];
530
531 AddressRef a_addr = generate_address_ref(rng, max_operand);
532 AddressRef b_addr = generate_address_ref(rng, max_operand);
533
534 std::vector<FuzzInstruction> instructions;
535 instructions.push_back(generate_set_for_tag(tag, a_addr, rng));
536 instructions.push_back(generate_set_for_tag(tag, b_addr, rng));
537 instructions.push_back(InstructionType{
538 .a_address = a_addr, .b_address = b_addr, .result_address = generate_address_ref(rng, max_operand) });
539 return instructions;
540}
541
542std::vector<FuzzInstruction> InstructionMutator::generate_fdiv_instruction(std::mt19937_64& rng, uint32_t max_operand)
543{
544 // 80% chance to use backfill (4 out of 5) to increase success rate
545 bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
546
547 if (!use_backfill) {
548 // Random mode: use existing memory values
550 .b_address = generate_variable_ref(rng),
551 .result_address = generate_address_ref(rng, max_operand) } };
552 }
553
554 // Backfill mode: generate two non-zero FF values
555 std::vector<FuzzInstruction> instructions;
556 instructions.reserve(3);
557
558 // Generate non-zero field values (avoid division by zero)
559 auto generate_nonzero_field = [&rng]() {
561 do {
563 } while (value.is_zero());
564 return value;
565 };
566
567 AddressRef a_addr = generate_address_ref(rng, max_operand);
568 AddressRef b_addr = generate_address_ref(rng, max_operand);
569
570 // SET the dividend (a)
571 instructions.push_back(SET_FF_Instruction{
572 .value_tag = bb::avm2::MemoryTag::FF, .result_address = a_addr, .value = generate_nonzero_field() });
573
574 // SET the divisor (b) - must be non-zero
575 instructions.push_back(SET_FF_Instruction{
576 .value_tag = bb::avm2::MemoryTag::FF, .result_address = b_addr, .value = generate_nonzero_field() });
577
578 // FDIV instruction
579 instructions.push_back(FDIV_8_Instruction{
580 .a_address = a_addr, .b_address = b_addr, .result_address = generate_address_ref(rng, max_operand) });
581
582 return instructions;
583}
584
586{
587 // 80% chance to use backfill (4 out of 5) to increase success rate
588 bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
589 if (!use_backfill) {
590 // Random mode
592 .dst_address = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
593 }
594 // Backfill mode
595 std::vector<FuzzInstruction> instructions;
596
597 // Keccak needs to backfill 25 U64 values, these need be contiguous in memory
598 AddressRef src_address = generate_address_ref(rng, MAX_16BIT_OPERAND - 24);
599 for (size_t i = 0; i < 25; i++) {
600 AddressRef item_address = src_address;
601 item_address.address += static_cast<uint32_t>(i);
602 instructions.push_back(SET_64_Instruction{ .value_tag = bb::avm2::MemoryTag::U64,
603 .result_address = item_address,
604 .value = generate_random_uint64(rng) });
605 }
606 instructions.push_back(KECCAKF1600_Instruction{ .src_address = src_address,
607 .dst_address = generate_address_ref(rng, MAX_16BIT_OPERAND) });
608 return instructions;
609}
610
612{
613 // 80% chance to use backfill (4 out of 5) to increase success rate
614 bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
615 if (!use_backfill) {
616 // Random mode
618 .input_address = generate_variable_ref(rng),
619 .dst_address = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
620 }
621 // Backfill mode
622 // SHA256 compression needs 8 U32 values for state and 16 U32 values for input (contiguous)
623 std::vector<FuzzInstruction> instructions;
624 instructions.reserve(8 + 16 + 1);
625
626 // Generate state address (8 contiguous U32 values)
627 AddressRef state_address = generate_address_ref(rng, MAX_16BIT_OPERAND - 7);
628
629 for (size_t i = 0; i < 8; i++) {
630 AddressRef item_address = state_address;
631 item_address.address += static_cast<uint32_t>(i);
632 instructions.push_back(SET_32_Instruction{ .value_tag = bb::avm2::MemoryTag::U32,
633 .result_address = item_address,
634 .value = generate_random_uint32(rng) });
635 }
636
637 // Generate input address (16 contiguous U32 values)
638 AddressRef input_address = generate_address_ref(rng, MAX_16BIT_OPERAND - 15);
639
640 for (size_t i = 0; i < 16; i++) {
641 AddressRef item_address = input_address;
642 item_address.address += static_cast<uint32_t>(i);
643 instructions.push_back(SET_32_Instruction{ .value_tag = bb::avm2::MemoryTag::U32,
644 .result_address = item_address,
645 .value = generate_random_uint32(rng) });
646 }
647
648 instructions.push_back(
650 .input_address = input_address,
651 .dst_address = generate_address_ref(rng, MAX_16BIT_OPERAND) });
652 return instructions;
653}
654
656{
657 // 80% chance to use backfill (4 out of 5) to increase success rate
658 bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
659 if (!use_backfill) {
660 // Random mode
662 .radix_address = generate_variable_ref(rng),
663 .num_limbs_address = generate_variable_ref(rng),
664 .output_bits_address = generate_variable_ref(rng),
665 .dst_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
666 .is_output_bits = std::uniform_int_distribution<int>(0, 1)(rng) == 0 } };
667 }
668 // Backfill mode: set up proper typed values
669 // value: FF, radix: U32, num_limbs: U32, output_bits: U1
670 std::vector<FuzzInstruction> instructions;
671 instructions.reserve(5);
672
673 AddressRef value_addr = generate_address_ref(rng, MAX_16BIT_OPERAND);
674 AddressRef radix_addr = generate_address_ref(rng, MAX_16BIT_OPERAND);
675 AddressRef num_limbs_addr = generate_address_ref(rng, MAX_16BIT_OPERAND);
676 AddressRef output_bits_addr = generate_address_ref(rng, MAX_8BIT_OPERAND);
677
678 // SET the radix (U32) - pick radix between 2 and 256
679 uint32_t radix = std::uniform_int_distribution<uint32_t>(2, 256)(rng);
680 instructions.push_back(
681 SET_32_Instruction{ .value_tag = bb::avm2::MemoryTag::U32, .result_address = radix_addr, .value = radix });
682
683 // SET the output_bits (U1)
684 bool is_output_bits = radix == 2;
685 instructions.push_back(SET_8_Instruction{ .value_tag = bb::avm2::MemoryTag::U1,
686 .result_address = output_bits_addr,
687 .value = static_cast<uint8_t>(is_output_bits ? 1 : 0) });
688
689 // Generate value with num_limbs digits
690 uint32_t num_limbs = std::uniform_int_distribution<uint32_t>(1, 256)(rng);
692 bb::avm2::FF exponent = 1;
693 for (uint32_t i = 0; i < num_limbs; i++) {
694 uint32_t digit = std::uniform_int_distribution<uint32_t>(0, radix - 1)(rng);
695 value += bb::avm2::FF(digit) * exponent;
696 exponent *= radix;
697 }
698
699 // 20% chance to truncate - reduce the number of limbs we request
700 if (std::uniform_int_distribution<int>(0, 4)(rng) == 0) {
701 num_limbs--;
702 }
703
704 // SET the num_limbs (U32)
705 instructions.push_back(SET_32_Instruction{
706 .value_tag = bb::avm2::MemoryTag::U32, .result_address = num_limbs_addr, .value = num_limbs });
707
708 // SET the value (FF)
709 instructions.push_back(
710 SET_FF_Instruction{ .value_tag = bb::avm2::MemoryTag::FF, .result_address = value_addr, .value = value });
711
712 // TORADIXBE instruction
713 instructions.push_back(TORADIXBE_Instruction{ .value_address = value_addr,
714 .radix_address = radix_addr,
715 .num_limbs_address = num_limbs_addr,
716 .output_bits_address = output_bits_addr,
717 .dst_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
718 .is_output_bits = is_output_bits });
719 return instructions;
720}
721
722// A better way in the future is to pass in a vector of possible slots that have been written to,
723// this would allow us to supply external world state info.
725{
726 // 80% chance to use backfill (4 out of 5) to increase success rate
727 bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
728
729 if (!use_backfill) {
730 // Random mode: requires at least one prior SSTORE to have been processed
732 .slot_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
733 .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
734 }
735
736 // Backfill mode: generate SSTORE first to ensure storage_addresses is non-empty
737 // This guarantees SLOAD will find a valid slot (get_slot uses modulo on non-empty vector)
738 std::vector<FuzzInstruction> instructions;
739 instructions.reserve(3);
740
741 AddressRef sstore_src = generate_address_ref(rng, MAX_16BIT_OPERAND);
742
743 // SET a value to store
744 instructions.push_back(SET_FF_Instruction{
745 .value_tag = bb::avm2::MemoryTag::FF, .result_address = sstore_src, .value = generate_random_field(rng) });
746
747 // SSTORE - appends to storage_addresses in memory_manager
748 instructions.push_back(SSTORE_Instruction{ .src_address = sstore_src,
749 .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
750 .slot = generate_random_field(rng) });
751
752 // SLOAD - now guaranteed to succeed (storage_addresses not empty, get_slot uses modulo)
753 instructions.push_back(SLOAD_Instruction{ .slot_index = generate_random_uint16(rng),
754 .slot_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
755 .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND) });
756
757 return instructions;
758}
759
761{
762 // 80% chance to use backfill (4 out of 5) to increase success rate
763 bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
764
765 if (!use_backfill) {
767 .log_values_address = generate_variable_ref(rng) } };
768 }
769
771 std::vector<FuzzInstruction> instructions;
772 instructions.reserve(3);
773
774 auto log_size_address = generate_address_ref(rng, MAX_16BIT_OPERAND);
775 auto log_values_address = generate_address_ref(rng, MAX_16BIT_OPERAND - log_size);
776
777 instructions.push_back(SET_32_Instruction{
778 .value_tag = bb::avm2::MemoryTag::U32, .result_address = log_size_address, .value = log_size });
779
780 // Write one random FF in the log
781 instructions.push_back(SET_FF_Instruction{ .value_tag = bb::avm2::MemoryTag::FF,
782 .result_address = log_values_address,
783 .value = generate_random_field(rng) });
784
786 .log_values_address = log_values_address });
787
788 return instructions;
789}
790
792{
793 // 80% chance to use backfill (4 out of 5) to increase success rate
794 bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
795
796 if (!use_backfill) {
797
799 .da_gas_address = generate_variable_ref(rng),
800 .contract_address_address = generate_variable_ref(rng),
801 .calldata_address = generate_variable_ref(rng),
802 .calldata_size_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
803 .calldata_size = generate_random_uint16(rng),
804 .is_static_call = rng() % 2 == 0 } };
805 }
806
807 std::vector<FuzzInstruction> instructions;
808 instructions.reserve(5);
809
810 auto contract_address_address = generate_address_ref(rng, MAX_16BIT_OPERAND);
811 instructions.push_back(SET_FF_Instruction{ .value_tag = bb::avm2::MemoryTag::FF,
812 .result_address = contract_address_address,
813 .value = context.get_contract_address(generate_random_uint16(rng)) });
814
815 auto l2_gas_address = generate_address_ref(rng, MAX_16BIT_OPERAND);
816 instructions.push_back(SET_32_Instruction{ .value_tag = bb::avm2::MemoryTag::U32,
817 .result_address = l2_gas_address,
818 .value = generate_random_uint32(rng) });
819
820 auto da_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 = da_gas_address,
823 .value = generate_random_uint32(rng) });
824
826 auto calldata_size_address = generate_address_ref(rng, MAX_16BIT_OPERAND);
827
828 auto calldata_address = generate_address_ref(rng, MAX_16BIT_OPERAND);
829 // Write one random FF in the calldata
830 instructions.push_back(SET_FF_Instruction{ .value_tag = bb::avm2::MemoryTag::FF,
831 .result_address = calldata_address,
832 .value = generate_random_field(rng) });
833
834 instructions.push_back(CALL_Instruction{ .l2_gas_address = l2_gas_address,
835 .da_gas_address = da_gas_address,
836 .contract_address_address = contract_address_address,
837 .calldata_address = calldata_address,
838 .calldata_size_address = calldata_size_address,
839 .calldata_size = calldata_size,
840 .is_static_call = rng() % 2 == 0 });
841
842 return instructions;
843}
844
846{
847 bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
848 if (!use_backfill) {
851 .member_enum = generate_random_uint8(rng),
852 .dst_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
853 } };
854 }
855
856 std::vector<FuzzInstruction> instructions;
857 instructions.reserve(2);
858
859 auto contract_address_address = generate_address_ref(rng, MAX_16BIT_OPERAND);
860 instructions.push_back(SET_FF_Instruction{ .value_tag = bb::avm2::MemoryTag::FF,
861 .result_address = contract_address_address,
862 .value = context.get_contract_address(generate_random_uint16(rng)) });
864
865 instructions.push_back(GETCONTRACTINSTANCE_Instruction{
867 .member_enum = member_enum,
868 .dst_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
869 });
870
871 return instructions;
872}
873
875{
876 bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
877 if (!use_backfill) {
879 .leaf_index_address = generate_variable_ref(rng),
880 .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
881 }
882 auto existing_note_hash = context.get_existing_note_hash(generate_random_uint16(rng));
883 FF note_hash = existing_note_hash.has_value() ? existing_note_hash.value().first : generate_random_field(rng);
884 uint64_t leaf_index =
885 existing_note_hash.has_value() ? existing_note_hash.value().second : generate_random_uint64(rng);
886 AddressRef note_hash_address = generate_address_ref(rng, MAX_16BIT_OPERAND);
887 AddressRef leaf_index_address = generate_address_ref(rng, MAX_16BIT_OPERAND);
888
889 std::vector<FuzzInstruction> instructions;
890 instructions.reserve(3);
891
892 instructions.push_back(SET_FF_Instruction{
894 instructions.push_back(SET_64_Instruction{
895 .value_tag = bb::avm2::MemoryTag::U64, .result_address = leaf_index_address, .value = leaf_index });
896
897 instructions.push_back(
899 .leaf_index_address = leaf_index_address,
900 .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND) });
901
902 return instructions;
903}
904
906{
907 return { RETURNDATASIZE_Instruction{ .dst_address = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
908}
909
911{
912 bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
913 if (!use_backfill) {
915 .rd_offset_address = generate_variable_ref(rng),
916 .dst_address = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
917 }
918 std::vector<FuzzInstruction> instructions;
919 instructions.reserve(3);
920 auto copy_size_address = generate_address_ref(rng, MAX_16BIT_OPERAND);
921 instructions.push_back(SET_32_Instruction{ .value_tag = bb::avm2::MemoryTag::U32,
922 .result_address = copy_size_address,
923 // We generate small sizes so we fail less often due to gas
924 // Mutations might change this to a larger value.
925 .value = generate_random_uint8(rng) });
926
927 auto rd_offset_address = generate_address_ref(rng, MAX_16BIT_OPERAND);
928 instructions.push_back(SET_32_Instruction{ .value_tag = bb::avm2::MemoryTag::U32,
929 .result_address = rd_offset_address,
930 .value = generate_random_uint8(rng) });
931
933 .rd_offset_address = rd_offset_address,
934 .dst_address = generate_address_ref(rng, MAX_16BIT_OPERAND) });
935
936 return instructions;
937}
938
940{
941 bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
942 if (!use_backfill) {
944 .cd_offset_address = generate_variable_ref(rng),
945 .dst_address = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
946 }
947 std::vector<FuzzInstruction> instructions;
948 instructions.reserve(3);
949 auto copy_size_address = generate_address_ref(rng, MAX_16BIT_OPERAND);
950 instructions.push_back(SET_32_Instruction{ .value_tag = bb::avm2::MemoryTag::U32,
951 .result_address = copy_size_address,
952 // We generate small sizes so we fail less often due to gas
953 // Mutations might change this to a larger value.
954 .value = generate_random_uint8(rng) });
955
956 auto cd_offset_address = generate_address_ref(rng, MAX_16BIT_OPERAND);
957 instructions.push_back(SET_32_Instruction{ .value_tag = bb::avm2::MemoryTag::U32,
958 .result_address = cd_offset_address,
959 .value = generate_random_uint8(rng) });
960
962 .cd_offset_address = cd_offset_address,
963 .dst_address = generate_address_ref(rng, MAX_16BIT_OPERAND) });
964
965 return instructions;
966}
967
969 std::mt19937_64& rng,
970 std::optional<MemoryTag> default_tag,
971 uint32_t max_operand_value)
972{
973 std::visit(overloaded{ [&](VariableRef& var) { mutate_variable_ref(var, rng, default_tag); },
974 [&](AddressRef& addr) { mutate_address_ref(addr, rng, max_operand_value); } },
975 param);
976}
977
978template <typename BinaryInstructionType>
980{
982 switch (option) {
984 mutate_param_ref(instruction.a_address, rng, std::nullopt, MAX_8BIT_OPERAND);
985 break;
987 mutate_param_ref(instruction.b_address, rng, get_param_ref_tag(instruction.a_address), MAX_8BIT_OPERAND);
988 break;
990 mutate_address_ref(instruction.result_address, rng, MAX_8BIT_OPERAND);
991 break;
992 }
993}
994
995template <typename BinaryInstructionType>
997{
999 switch (option) {
1001 mutate_param_ref(instruction.a_address, rng, std::nullopt, MAX_16BIT_OPERAND);
1002 break;
1004 mutate_param_ref(instruction.b_address, rng, get_param_ref_tag(instruction.a_address), MAX_16BIT_OPERAND);
1005 break;
1007 mutate_address_ref(instruction.result_address, rng, MAX_16BIT_OPERAND);
1008 break;
1009 }
1010}
1011
1024
1040
1056
1072
1088
1107
1123
1125{
1126 int choice = std::uniform_int_distribution<int>(0, 2)(rng);
1127 switch (choice) {
1128 case 0:
1130 break;
1131 case 1:
1132 mutate_param_ref(instruction.src_address, rng, std::nullopt, MAX_8BIT_OPERAND);
1133 break;
1134 case 2:
1135 mutate_address_ref(instruction.result_address, rng, MAX_8BIT_OPERAND);
1136 break;
1137 }
1138}
1139
1141{
1142 int choice = std::uniform_int_distribution<int>(0, 2)(rng);
1143 switch (choice) {
1144 case 0:
1146 break;
1147 case 1:
1148 mutate_param_ref(instruction.src_address, rng, std::nullopt, MAX_16BIT_OPERAND);
1149 break;
1150 case 2:
1151 mutate_address_ref(instruction.result_address, rng, MAX_16BIT_OPERAND);
1152 break;
1153 }
1154}
1155
1168
1184
1200
1202{
1204 switch (option) {
1206 mutate_param_ref(instruction.src_address, rng, MemoryTag::FF, MAX_16BIT_OPERAND);
1207 break;
1209 mutate_address_ref(instruction.result_address, rng, MAX_16BIT_OPERAND);
1210 break;
1213 break;
1214 }
1215}
1216
1218{
1220 switch (option) {
1223 break;
1225 mutate_address_ref(instruction.slot_address, rng, MAX_16BIT_OPERAND);
1226 break;
1228 mutate_address_ref(instruction.result_address, rng, MAX_16BIT_OPERAND);
1229 break;
1230 }
1231}
1232
1234{
1236 switch (option) {
1238 mutate_address_ref(instruction.result_address, rng, MAX_16BIT_OPERAND);
1239 break;
1241 instruction.type = generate_envvar_type(rng);
1242 break;
1243 }
1244}
1245
1247{
1248 // emitnulifier only has one field
1249
1250 mutate_param_ref(instruction.nullifier_address, rng, MemoryTag::FF, MAX_16BIT_OPERAND);
1251}
1252
1254 std::mt19937_64& rng)
1255{
1257 switch (option) {
1259 mutate_param_ref(instruction.nullifier_address, rng, MemoryTag::FF, MAX_16BIT_OPERAND);
1260 break;
1262 mutate_address_ref(instruction.contract_address_address, rng, MAX_16BIT_OPERAND);
1263 break;
1265 mutate_address_ref(instruction.result_address, rng, MAX_16BIT_OPERAND);
1266 break;
1267 }
1268}
1269
1271 std::mt19937_64& rng)
1272{
1274 switch (option) {
1276 mutate_param_ref(instruction.msg_hash_address, rng, MemoryTag::FF, MAX_16BIT_OPERAND);
1277 break;
1279 mutate_param_ref(instruction.leaf_index_address, rng, MemoryTag::U64, MAX_16BIT_OPERAND);
1280 break;
1282 mutate_address_ref(instruction.result_address, rng, MAX_16BIT_OPERAND);
1283 break;
1284 }
1285}
1286
1300 std::mt19937_64& rng)
1301{
1303 switch (option) {
1305 mutate_param_ref(instruction.notehash_address, rng, MemoryTag::FF, MAX_16BIT_OPERAND);
1306 break;
1308 mutate_param_ref(instruction.leaf_index_address, rng, MemoryTag::U64, MAX_16BIT_OPERAND);
1309 break;
1311 mutate_address_ref(instruction.result_address, rng, MAX_16BIT_OPERAND);
1312 break;
1313 }
1314}
1315
1317{
1319 switch (option) {
1321 mutate_param_ref(instruction.copy_size_address, rng, MemoryTag::U32, MAX_16BIT_OPERAND);
1322 break;
1324 mutate_param_ref(instruction.cd_offset_address, rng, MemoryTag::U32, MAX_16BIT_OPERAND);
1325 break;
1327 mutate_address_ref(instruction.dst_address, rng, MAX_16BIT_OPERAND);
1328 break;
1329 }
1330}
1331
1350
1364
1366{
1368 switch (option) {
1370 mutate_param_ref(instruction.l2_gas_address, rng, MemoryTag::U32, MAX_16BIT_OPERAND);
1371 break;
1373 mutate_param_ref(instruction.da_gas_address, rng, MemoryTag::U32, MAX_16BIT_OPERAND);
1374 break;
1376 mutate_param_ref(instruction.contract_address_address, rng, MemoryTag::FF, MAX_16BIT_OPERAND);
1377 break;
1379 mutate_address_ref(instruction.calldata_size_address, rng, MAX_16BIT_OPERAND);
1380 break;
1383 break;
1385 mutate_param_ref(instruction.calldata_address, rng, MemoryTag::FF, MAX_16BIT_OPERAND);
1386 break;
1388 // with 0.5 probability, set to true, otherwise false
1389 instruction.is_static_call = rng() % 2 == 0;
1390 }
1391}
1392
1398
1400 std::mt19937_64& rng)
1401{
1403 switch (option) {
1405 mutate_param_ref(instruction.copy_size_address, rng, MemoryTag::U32, MAX_16BIT_OPERAND);
1406 break;
1408 mutate_param_ref(instruction.rd_offset_address, rng, MemoryTag::U32, MAX_16BIT_OPERAND);
1409 break;
1411 mutate_address_ref(instruction.dst_address, rng, MAX_16BIT_OPERAND);
1412 break;
1413 }
1414}
1415
1432
1442
1444{
1445 // ECADD has 7 operands, select one to mutate
1446 int choice = std::uniform_int_distribution<int>(0, 6)(rng);
1447 switch (choice) {
1448 case 0:
1449 mutate_param_ref(instruction.p1_x, rng, MemoryTag::FF, MAX_16BIT_OPERAND);
1450 break;
1451 case 1:
1452 mutate_param_ref(instruction.p1_y, rng, MemoryTag::FF, MAX_16BIT_OPERAND);
1453 break;
1454 case 2:
1455 mutate_param_ref(instruction.p1_infinite, rng, MemoryTag::U1, MAX_16BIT_OPERAND);
1456 break;
1457 case 3:
1458 mutate_param_ref(instruction.p2_x, rng, MemoryTag::FF, MAX_16BIT_OPERAND);
1459 break;
1460 case 4:
1461 mutate_param_ref(instruction.p2_y, rng, MemoryTag::FF, MAX_16BIT_OPERAND);
1462 break;
1463 case 5:
1464 mutate_param_ref(instruction.p2_infinite, rng, MemoryTag::U1, MAX_16BIT_OPERAND);
1465 break;
1466 case 6:
1467 mutate_address_ref(instruction.result, rng, MAX_16BIT_OPERAND);
1468 break;
1469 }
1470}
1471
1473{
1474 int choice = std::uniform_int_distribution<int>(0, 1)(rng);
1475 switch (choice) {
1476 case 0:
1477 mutate_param_ref(instruction.src_address, rng, MemoryTag::U32, MAX_16BIT_OPERAND);
1478 break;
1479 case 1:
1480 mutate_address_ref(instruction.dst_address, rng, MAX_16BIT_OPERAND);
1481 break;
1482 }
1483}
1484
1486{
1487 int choice = std::uniform_int_distribution<int>(0, 1)(rng);
1488 switch (choice) {
1489 case 0:
1490 mutate_param_ref(instruction.src_address, rng, MemoryTag::U32, MAX_16BIT_OPERAND);
1491 break;
1492 case 1:
1493 mutate_address_ref(instruction.dst_address, rng, MAX_16BIT_OPERAND);
1494 break;
1495 }
1496}
1497
1499 std::mt19937_64& rng)
1500{
1501 int choice = std::uniform_int_distribution<int>(0, 2)(rng);
1502 switch (choice) {
1503 case 0:
1504 mutate_param_ref(instruction.state_address, rng, MemoryTag::U32, MAX_16BIT_OPERAND);
1505 break;
1506 case 1:
1507 mutate_param_ref(instruction.input_address, rng, MemoryTag::U32, MAX_16BIT_OPERAND);
1508 break;
1509 case 2:
1510 mutate_address_ref(instruction.dst_address, rng, MAX_16BIT_OPERAND);
1511 break;
1512 }
1513}
1514
1516{
1518 switch (option) {
1520 mutate_param_ref(instruction.value_address, rng, MemoryTag::FF, MAX_16BIT_OPERAND);
1521 break;
1523 mutate_param_ref(instruction.radix_address, rng, MemoryTag::U32, MAX_16BIT_OPERAND);
1524 break;
1526 mutate_param_ref(instruction.num_limbs_address, rng, MemoryTag::U32, MAX_16BIT_OPERAND);
1527 break;
1529 mutate_param_ref(instruction.output_bits_address, rng, MemoryTag::U1, MAX_16BIT_OPERAND);
1530 break;
1532 mutate_address_ref(instruction.dst_address, rng, MAX_16BIT_OPERAND);
1533 break;
1535 instruction.is_output_bits = !instruction.is_output_bits;
1536 break;
1537 }
1538}
1539
1541{
1543 switch (option) {
1545 mutate_param_ref(instruction.level_offset, rng, MemoryTag::U32, MAX_16BIT_OPERAND);
1546 break;
1548 mutate_param_ref(instruction.message_offset, rng, MemoryTag::U32, MAX_16BIT_OPERAND);
1549 break;
1551 mutate_param_ref(instruction.fields_offset, rng, MemoryTag::U32, MAX_16BIT_OPERAND);
1552 break;
1554 mutate_param_ref(instruction.fields_size_offset, rng, MemoryTag::U32, MAX_16BIT_OPERAND);
1555 break;
1558 break;
1559 }
1560}
1561
1562} // 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
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_emitunencryptedlog_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_emitunencryptedlog_instruction(EMITUNENCRYPTEDLOG_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)
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)
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_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
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
EmitUnencryptedLogMutationOptions
constexpr NullifierExistsMutationConfig BASIC_NULLIFIER_EXISTS_MUTATION_CONFIGURATION
constexpr EmitUnencryptedLogMutationConfig BASIC_EMITUNENCRYPTEDLOG_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 ReturndataCopyMutationConfig BASIC_RETURNDATACOPY_MUTATION_CONFIGURATION
NullifierExistsMutationOptions
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::G1::Fq Fq
Definition field.hpp:11
AvmFlavorSettings::FF FF
Definition field.hpp:10
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 nullifier exists in the nullifier tree Gets contract's address by GETENVVA...
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)