Skip to content

Commit 225fe4f

Browse files
authored
fix(avm): improve backfill and sload (#19241)
Increased the backfill rate to 80% since it was still rare to find an ADD,SUB or MUL. Also added backfills for sload
1 parent c6efa6a commit 225fe4f

File tree

1 file changed

+101
-10
lines changed
  • barretenberg/cpp/src/barretenberg/avm_fuzzer/mutations/instructions

1 file changed

+101
-10
lines changed

barretenberg/cpp/src/barretenberg/avm_fuzzer/mutations/instructions/instruction.cpp

Lines changed: 101 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ AddressRef generate_address_ref(std::mt19937_64& rng, uint32_t max_operand_value
5151

5252
std::vector<FuzzInstruction> generate_ecadd_instruction(std::mt19937_64& rng)
5353
{
54-
bool use_backfill = std::uniform_int_distribution<int>(0, 1)(rng) == 0;
54+
// 80% chance to use backfill (4 out of 5) to increase success rate
55+
bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
5556

5657
if (!use_backfill) {
5758
// Random mode: use existing memory values (may fail if not valid points on curve)
@@ -100,6 +101,16 @@ std::vector<FuzzInstruction> generate_ecadd_instruction(std::mt19937_64& rng)
100101
AddressRef p2_y_addr = generate_address_ref(rng, MAX_16BIT_OPERAND);
101102
AddressRef p2_inf_addr = generate_address_ref(rng, MAX_8BIT_OPERAND);
102103

104+
// Force Direct addressing so SET instructions write to the same addresses that ECADD reads from.
105+
// TODO: Implement smart backfilling for indirect addressing modes by also setting up
106+
// the pointer addresses (e.g., M[pointer_address_seed] = target_address).
107+
p1_x_addr.mode = AddressingMode::Direct;
108+
p1_y_addr.mode = AddressingMode::Direct;
109+
p1_inf_addr.mode = AddressingMode::Direct;
110+
p2_x_addr.mode = AddressingMode::Direct;
111+
p2_y_addr.mode = AddressingMode::Direct;
112+
p2_inf_addr.mode = AddressingMode::Direct;
113+
103114
backfill_point(p1, p1_x_addr, p1_y_addr, p1_inf_addr);
104115
backfill_point(p2, p2_x_addr, p2_y_addr, p2_inf_addr);
105116

@@ -143,7 +154,8 @@ FuzzInstruction generate_set_for_tag(bb::avm2::MemoryTag tag, AddressRef addr, s
143154
template <typename InstructionType>
144155
std::vector<FuzzInstruction> generate_alu_with_matching_tags(std::mt19937_64& rng, uint32_t max_operand)
145156
{
146-
bool use_backfill = std::uniform_int_distribution<int>(0, 1)(rng) == 0;
157+
// 80% chance to use backfill (4 out of 5) to increase success rate
158+
bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
147159

148160
if (!use_backfill) {
149161
return { InstructionType{ .a_address = generate_variable_ref(rng),
@@ -155,6 +167,12 @@ std::vector<FuzzInstruction> generate_alu_with_matching_tags(std::mt19937_64& rn
155167
AddressRef a_addr = generate_address_ref(rng, max_operand);
156168
AddressRef b_addr = generate_address_ref(rng, max_operand);
157169

170+
// Force Direct addressing so SET instructions write to the same addresses that ALU reads from.
171+
// TODO: Implement smart backfilling for indirect addressing modes by also setting up
172+
// the pointer addresses (e.g., M[pointer_address_seed] = target_address).
173+
a_addr.mode = AddressingMode::Direct;
174+
b_addr.mode = AddressingMode::Direct;
175+
158176
std::vector<FuzzInstruction> instructions;
159177
instructions.push_back(generate_set_for_tag(tag, a_addr, rng));
160178
instructions.push_back(generate_set_for_tag(tag, b_addr, rng));
@@ -168,7 +186,8 @@ std::vector<FuzzInstruction> generate_alu_with_matching_tags(std::mt19937_64& rn
168186
template <typename InstructionType>
169187
std::vector<FuzzInstruction> generate_alu_with_matching_tags_not_ff(std::mt19937_64& rng, uint32_t max_operand)
170188
{
171-
bool use_backfill = std::uniform_int_distribution<int>(0, 1)(rng) == 0;
189+
// 80% chance to use backfill (4 out of 5) to increase success rate
190+
bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
172191

173192
if (!use_backfill) {
174193
return { InstructionType{ .a_address = generate_variable_ref(rng),
@@ -186,6 +205,12 @@ std::vector<FuzzInstruction> generate_alu_with_matching_tags_not_ff(std::mt19937
186205
AddressRef a_addr = generate_address_ref(rng, max_operand);
187206
AddressRef b_addr = generate_address_ref(rng, max_operand);
188207

208+
// Force Direct addressing so SET instructions write to the same addresses that ALU reads from.
209+
// TODO: Implement smart backfilling for indirect addressing modes by also setting up
210+
// the pointer addresses (e.g., M[pointer_address_seed] = target_address).
211+
a_addr.mode = AddressingMode::Direct;
212+
b_addr.mode = AddressingMode::Direct;
213+
189214
std::vector<FuzzInstruction> instructions;
190215
instructions.push_back(generate_set_for_tag(tag, a_addr, rng));
191216
instructions.push_back(generate_set_for_tag(tag, b_addr, rng));
@@ -196,7 +221,8 @@ std::vector<FuzzInstruction> generate_alu_with_matching_tags_not_ff(std::mt19937
196221

197222
std::vector<FuzzInstruction> generate_fdiv_instruction(std::mt19937_64& rng, uint32_t max_operand)
198223
{
199-
bool use_backfill = std::uniform_int_distribution<int>(0, 1)(rng) == 0;
224+
// 80% chance to use backfill (4 out of 5) to increase success rate
225+
bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
200226

201227
if (!use_backfill) {
202228
// Random mode: use existing memory values
@@ -221,6 +247,12 @@ std::vector<FuzzInstruction> generate_fdiv_instruction(std::mt19937_64& rng, uin
221247
AddressRef a_addr = generate_address_ref(rng, max_operand);
222248
AddressRef b_addr = generate_address_ref(rng, max_operand);
223249

250+
// Force Direct addressing so SET instructions write to the same addresses that FDIV reads from.
251+
// TODO: Implement smart backfilling for indirect addressing modes by also setting up
252+
// the pointer addresses (e.g., M[pointer_address_seed] = target_address).
253+
a_addr.mode = AddressingMode::Direct;
254+
b_addr.mode = AddressingMode::Direct;
255+
224256
// SET the dividend (a)
225257
instructions.push_back(SET_FF_Instruction{
226258
.value_tag = bb::avm2::MemoryTag::FF, .result_address = a_addr, .value = generate_nonzero_field() });
@@ -238,7 +270,8 @@ std::vector<FuzzInstruction> generate_fdiv_instruction(std::mt19937_64& rng, uin
238270

239271
std::vector<FuzzInstruction> generate_keccakf_instruction(std::mt19937_64& rng)
240272
{
241-
bool use_backfill = std::uniform_int_distribution<int>(0, 1)(rng) == 0;
273+
// 80% chance to use backfill (4 out of 5) to increase success rate
274+
bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
242275
if (!use_backfill) {
243276
// Random mode
244277
return { KECCAKF1600_Instruction{ .src_address = generate_variable_ref(rng),
@@ -249,6 +282,10 @@ std::vector<FuzzInstruction> generate_keccakf_instruction(std::mt19937_64& rng)
249282
// Keccak needs to backfill 25 U64 values, these need be contiguous in memory
250283

251284
AddressRef src_address = generate_address_ref(rng, MAX_16BIT_OPERAND - 24);
285+
// Force Direct addressing so SET instructions write to the same addresses that KECCAKF1600 reads from.
286+
// TODO: Implement smart backfilling for indirect addressing modes by also setting up
287+
// the pointer addresses (e.g., M[pointer_address_seed] = target_address).
288+
src_address.mode = AddressingMode::Direct;
252289
for (size_t i = 0; i < 25; i++) {
253290
instructions.push_back(
254291
SET_64_Instruction{ .value_tag = bb::avm2::MemoryTag::U64,
@@ -263,7 +300,8 @@ std::vector<FuzzInstruction> generate_keccakf_instruction(std::mt19937_64& rng)
263300

264301
std::vector<FuzzInstruction> generate_sha256compression_instruction(std::mt19937_64& rng)
265302
{
266-
bool use_backfill = std::uniform_int_distribution<int>(0, 1)(rng) == 0;
303+
// 80% chance to use backfill (4 out of 5) to increase success rate
304+
bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
267305
if (!use_backfill) {
268306
// Random mode
269307
return { SHA256COMPRESSION_Instruction{ .state_address = generate_variable_ref(rng),
@@ -277,6 +315,10 @@ std::vector<FuzzInstruction> generate_sha256compression_instruction(std::mt19937
277315

278316
// Generate state address (8 contiguous U32 values)
279317
AddressRef state_address = generate_address_ref(rng, MAX_16BIT_OPERAND - 7);
318+
// Force Direct addressing so SET instructions write to the same addresses that SHA256COMPRESSION reads from.
319+
// TODO: Implement smart backfilling for indirect addressing modes by also setting up
320+
// the pointer addresses (e.g., M[pointer_address_seed] = target_address).
321+
state_address.mode = AddressingMode::Direct;
280322
for (size_t i = 0; i < 8; i++) {
281323
instructions.push_back(SET_32_Instruction{
282324
.value_tag = bb::avm2::MemoryTag::U32,
@@ -287,6 +329,7 @@ std::vector<FuzzInstruction> generate_sha256compression_instruction(std::mt19937
287329

288330
// Generate input address (16 contiguous U32 values)
289331
AddressRef input_address = generate_address_ref(rng, MAX_16BIT_OPERAND - 15);
332+
input_address.mode = AddressingMode::Direct;
290333
for (size_t i = 0; i < 16; i++) {
291334
instructions.push_back(SET_32_Instruction{
292335
.value_tag = bb::avm2::MemoryTag::U32,
@@ -304,7 +347,8 @@ std::vector<FuzzInstruction> generate_sha256compression_instruction(std::mt19937
304347

305348
std::vector<FuzzInstruction> generate_toradixbe_instruction(std::mt19937_64& rng)
306349
{
307-
bool use_backfill = std::uniform_int_distribution<int>(0, 1)(rng) == 0;
350+
// 80% chance to use backfill (4 out of 5) to increase success rate
351+
bool use_backfill = std::uniform_int_distribution<int>(0, 4)(rng) != 0;
308352
if (!use_backfill) {
309353
// Random mode
310354
return { TORADIXBE_Instruction{ .value_address = generate_variable_ref(rng),
@@ -324,6 +368,14 @@ std::vector<FuzzInstruction> generate_toradixbe_instruction(std::mt19937_64& rng
324368
AddressRef num_limbs_addr = generate_address_ref(rng, MAX_16BIT_OPERAND);
325369
AddressRef output_bits_addr = generate_address_ref(rng, MAX_8BIT_OPERAND);
326370

371+
// Force Direct addressing so SET instructions write to the same addresses that TORADIXBE reads from.
372+
// TODO: Implement smart backfilling for indirect addressing modes by also setting up
373+
// the pointer addresses (e.g., M[pointer_address_seed] = target_address).
374+
value_addr.mode = AddressingMode::Direct;
375+
radix_addr.mode = AddressingMode::Direct;
376+
num_limbs_addr.mode = AddressingMode::Direct;
377+
output_bits_addr.mode = AddressingMode::Direct;
378+
327379
// SET the radix (U32) - pick radix between 2 and 256
328380
uint32_t radix = std::uniform_int_distribution<uint32_t>(2, 256)(rng);
329381
instructions.push_back(
@@ -360,6 +412,47 @@ std::vector<FuzzInstruction> generate_toradixbe_instruction(std::mt19937_64& rng
360412
return instructions;
361413
}
362414

415+
// A better way in the future is to pass in a vector of possible slots that have been written to,
416+
// this would allow us to supply external world state info.
417+
std::vector<FuzzInstruction> generate_sload_instruction(std::mt19937_64& rng)
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: requires at least one prior SSTORE to have been processed
424+
return { SLOAD_Instruction{ .slot_index = generate_random_uint16(rng),
425+
.slot_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
426+
.result_address = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
427+
}
428+
429+
// Backfill mode: generate SSTORE first to ensure storage_addresses is non-empty
430+
// This guarantees SLOAD will find a valid slot (get_slot uses modulo on non-empty vector)
431+
std::vector<FuzzInstruction> instructions;
432+
instructions.reserve(3);
433+
434+
AddressRef sstore_src = generate_address_ref(rng, MAX_16BIT_OPERAND);
435+
// Force Direct addressing so SET writes to the same address that SSTORE reads from.
436+
// TODO: Implement smart backfilling for indirect addressing modes.
437+
sstore_src.mode = AddressingMode::Direct;
438+
439+
// SET a value to store
440+
instructions.push_back(SET_FF_Instruction{
441+
.value_tag = bb::avm2::MemoryTag::FF, .result_address = sstore_src, .value = generate_random_field(rng) });
442+
443+
// SSTORE - appends to storage_addresses in memory_manager
444+
instructions.push_back(SSTORE_Instruction{ .src_address = sstore_src,
445+
.result_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
446+
.slot = generate_random_field(rng) });
447+
448+
// SLOAD - now guaranteed to succeed (storage_addresses not empty, get_slot uses modulo)
449+
instructions.push_back(SLOAD_Instruction{ .slot_index = generate_random_uint16(rng),
450+
.slot_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
451+
.result_address = generate_address_ref(rng, MAX_16BIT_OPERAND) });
452+
453+
return instructions;
454+
}
455+
363456
std::vector<FuzzInstruction> generate_instruction(std::mt19937_64& rng)
364457
{
365458
InstructionGenerationOptions option = BASIC_INSTRUCTION_GENERATION_CONFIGURATION.select(rng);
@@ -494,9 +587,7 @@ std::vector<FuzzInstruction> generate_instruction(std::mt19937_64& rng)
494587
.result_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
495588
.slot = generate_random_field(rng) } };
496589
case InstructionGenerationOptions::SLOAD:
497-
return { SLOAD_Instruction{ .slot_index = generate_random_uint16(rng),
498-
.slot_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
499-
.result_address = generate_address_ref(rng, MAX_16BIT_OPERAND) } };
590+
return generate_sload_instruction(rng);
500591
case InstructionGenerationOptions::GETENVVAR:
501592
return { GETENVVAR_Instruction{ .result_address = generate_address_ref(rng, MAX_16BIT_OPERAND),
502593
.type = generate_random_uint8(rng) } };

0 commit comments

Comments
 (0)