Skip to content

Commit 0333250

Browse files
authored
feat(avm): emit unencrypted log gadget fuzzer (#18817)
### Emit Unencrypted Log Fuzzer Closes: [AVM-106](https://linear.app/aztec-labs/issue/AVM-106/fuzz-emit-unencryptedlog) Currently tests a single event (i.e. one log per run) with all interactions. Coverage is nearly 100% with caveats: - Trace: it seems like there are no gaps - the coverage tool is a bit confused about branches - Gadget: only the checkpointing functions (e.g. EmitUnencryptedLog::on_checkpoint_created()) aren't hit Uses similar logic to the memory and calldata fuzzers to fill a field vector to emit as a log while being able to fuzz its length. Covers log values, size, memory address, contract address, and some specific edge cases (static calls, tag mismatch) to hit all errors. Discovered a possible underflow, addressed here: #19076 Unfortunately this needed a lot of surrounding gadget setup so I just threw it into a new file (`context_helper`) for readability - we don't have to use this class, happy to remove it! In future I can integrate it with the existing simulation helpers for fuzzing.
1 parent f25ce51 commit 0333250

File tree

5 files changed

+626
-1
lines changed

5 files changed

+626
-1
lines changed

barretenberg/cpp/src/barretenberg/avm_fuzzer/fuzz_lib/simulator.hpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,15 @@ class JsSimulator : public Simulator {
8282
const Tx& tx) override;
8383
};
8484

85+
GlobalVariables create_default_globals();
86+
87+
Tx create_default_tx(const AztecAddress& contract_address,
88+
const AztecAddress& sender_address,
89+
const std::vector<FF>& calldata,
90+
[[maybe_unused]] const FF& transaction_fee,
91+
bool is_static_call,
92+
const Gas& gas_limit);
93+
8594
bool compare_simulator_results(const SimulatorResult& result1, const SimulatorResult& result2);
8695

8796
GlobalVariables create_default_globals();
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
#include "context_helper.hpp"
2+
3+
#include "barretenberg/avm_fuzzer/fuzz_lib/constants.hpp"
4+
#include "barretenberg/avm_fuzzer/fuzz_lib/simulator.hpp"
5+
#include "barretenberg/vm2/common/aztec_types.hpp"
6+
#include "barretenberg/vm2/simulation/events/update_check.hpp"
7+
#include "barretenberg/vm2/simulation/gadgets/bytecode_manager.hpp"
8+
#include "barretenberg/vm2/simulation/gadgets/context_provider.hpp"
9+
#include "barretenberg/vm2/simulation/gadgets/poseidon2.hpp"
10+
#include "barretenberg/vm2/simulation/interfaces/context.hpp"
11+
#include "barretenberg/vm2/simulation/lib/raw_data_dbs.hpp"
12+
#include "barretenberg/vm2/simulation/lib/side_effect_tracking_db.hpp"
13+
#include "barretenberg/vm2/simulation/standalone/concrete_dbs.hpp"
14+
15+
namespace bb::avm2::fuzzing {
16+
17+
using namespace bb::avm2::simulation;
18+
19+
GadgetFuzzerContextHelper::GadgetFuzzerContextHelper(AztecAddress contract_address, bool is_static, uint32_t start_clk)
20+
: execution_id_manager(start_clk)
21+
, range_check(range_check_emitter)
22+
, field_gt(range_check, field_gt_emitter)
23+
, greater_than(field_gt, range_check, greater_than_emitter)
24+
, memory_provider(range_check, execution_id_manager, memory_emitter)
25+
, merkle_check(poseidon2, merkle_check_emitter)
26+
, poseidon2(execution_id_manager, greater_than, hash_event_emitter, perm_event_emitter, perm_mem_event_emitter)
27+
, written_public_data_slots_tree_check(poseidon2,
28+
merkle_check,
29+
field_gt,
30+
build_public_data_slots_tree(),
31+
written_public_data_slots_tree_check_emitter)
32+
, retrieved_bytecodes_tree_check(
33+
poseidon2, merkle_check, field_gt, build_retrieved_bytecodes_tree(), retrieved_bytecodes_tree_check_emitter)
34+
35+
{
36+
global_variables = create_default_globals();
37+
hints.global_variables = global_variables;
38+
hints.tx = create_default_tx(contract_address, contract_address, {}, FF(0), is_static, GAS_LIMIT);
39+
40+
HintedRawContractDB contract_db(hints);
41+
auto merkle_db = make_empty_merkle_db();
42+
43+
BytecodeHasher bytecode_hasher(poseidon2, bytecode_hashing_emitter);
44+
CalldataHashingProvider calldata_hashing_provider(poseidon2, calldata_event_emitter);
45+
46+
UpdateCheck update_check(
47+
poseidon2, range_check, greater_than, merkle_db, update_check_emitter, hints.global_variables);
48+
RetrievedBytecodesTreeCheck retrieved_bytecodes_tree_check(
49+
poseidon2, merkle_check, field_gt, build_retrieved_bytecodes_tree(), retrieved_bytecodes_tree_check_emitter);
50+
ContractInstanceManager contract_instance_manager(
51+
contract_db, merkle_db, update_check, field_gt, hints.protocol_contracts, contract_instance_retrieval_emitter);
52+
InternalCallStackManagerProvider internal_call_stack_manager_provider(internal_call_stack_emitter);
53+
tx_bytecode_manager = std::make_unique<TxBytecodeManager>(contract_db,
54+
merkle_db,
55+
bytecode_hasher,
56+
range_check,
57+
contract_instance_manager,
58+
retrieved_bytecodes_tree_check,
59+
bytecode_retrieval_emitter,
60+
bytecode_decomposition_emitter,
61+
instruction_fetching_emitter);
62+
63+
MemoryProvider mem_provider(range_check, execution_id_manager, memory_emitter);
64+
context_provider = std::make_unique<ContextProvider>(*tx_bytecode_manager,
65+
mem_provider,
66+
calldata_hashing_provider,
67+
internal_call_stack_manager_provider,
68+
merkle_db,
69+
written_public_data_slots_tree_check,
70+
retrieved_bytecodes_tree_check,
71+
side_effect_tracker,
72+
hints.global_variables);
73+
}
74+
75+
// A lighter version of ContextProvider::make_enqueued_context
76+
std::unique_ptr<ContextInterface> GadgetFuzzerContextHelper::make_enqueued_fuzzing_context(AztecAddress address,
77+
AztecAddress msg_sender,
78+
bool is_static,
79+
FF transaction_fee,
80+
std::span<const FF> calldata,
81+
Gas gas_limit,
82+
Gas gas_used,
83+
TransactionPhase phase)
84+
{
85+
auto merkle_db = make_empty_merkle_db();
86+
// Note: not incremented between contexts
87+
uint32_t context_id = context_provider->get_next_context_id();
88+
return std::make_unique<EnqueuedCallContext>(
89+
context_id,
90+
address,
91+
msg_sender,
92+
transaction_fee,
93+
is_static,
94+
gas_limit,
95+
gas_used,
96+
global_variables,
97+
std::make_unique<BytecodeManager>(address, *tx_bytecode_manager),
98+
memory_provider.make_memory(static_cast<uint16_t>(context_id)),
99+
InternalCallStackManagerProvider(internal_call_stack_emitter).make_internal_call_stack_manager(context_id),
100+
merkle_db,
101+
written_public_data_slots_tree_check,
102+
retrieved_bytecodes_tree_check,
103+
side_effect_tracker,
104+
phase,
105+
calldata);
106+
}
107+
108+
// A lighter version of ContextProvider::make_nested_context
109+
std::unique_ptr<ContextInterface> GadgetFuzzerContextHelper::make_nested_fuzzing_context(
110+
AztecAddress address, AztecAddress msg_sender, ContextInterface& parent_context, Gas gas_limit)
111+
{
112+
113+
auto merkle_db = make_empty_merkle_db();
114+
// Note: not incremented between contexts
115+
uint32_t context_id = context_provider->get_next_context_id();
116+
return std::make_unique<NestedContext>(
117+
context_id,
118+
parent_context.get_address(),
119+
msg_sender,
120+
parent_context.get_transaction_fee(),
121+
parent_context.get_is_static(),
122+
gas_limit,
123+
parent_context.get_globals(),
124+
std::make_unique<BytecodeManager>(address, *tx_bytecode_manager),
125+
memory_provider.make_memory(static_cast<uint16_t>(context_id)),
126+
InternalCallStackManagerProvider(internal_call_stack_emitter).make_internal_call_stack_manager(context_id),
127+
merkle_db,
128+
written_public_data_slots_tree_check,
129+
retrieved_bytecodes_tree_check,
130+
side_effect_tracker,
131+
parent_context.get_phase(),
132+
parent_context,
133+
0,
134+
0);
135+
}
136+
137+
SideEffectTrackingDB GadgetFuzzerContextHelper::make_empty_merkle_db()
138+
{
139+
// DBs: Just for now - TODO(MW) use fuzzing dbs?
140+
HintedRawMerkleDB raw_merkle_db(hints);
141+
PureMerkleDB base_merkle_db(
142+
hints.tx.non_revertible_accumulated_data.nullifiers[0], raw_merkle_db, written_public_data_slots_tree_check);
143+
SideEffectTrackingDB merkle_db(
144+
hints.tx.non_revertible_accumulated_data.nullifiers[0], base_merkle_db, side_effect_tracker);
145+
return merkle_db;
146+
}
147+
} // namespace bb::avm2::fuzzing
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
#pragma once
2+
3+
#include "barretenberg/avm_fuzzer/fuzz_lib/constants.hpp"
4+
#include "barretenberg/vm2/common/avm_io.hpp"
5+
#include "barretenberg/vm2/common/aztec_types.hpp"
6+
#include "barretenberg/vm2/simulation/gadgets/bytecode_hashing.hpp"
7+
#include "barretenberg/vm2/simulation/gadgets/bytecode_manager.hpp"
8+
#include "barretenberg/vm2/simulation/gadgets/calldata_hashing.hpp"
9+
#include "barretenberg/vm2/simulation/gadgets/context_provider.hpp"
10+
#include "barretenberg/vm2/simulation/gadgets/contract_instance_manager.hpp"
11+
#include "barretenberg/vm2/simulation/gadgets/field_gt.hpp"
12+
#include "barretenberg/vm2/simulation/gadgets/gt.hpp"
13+
#include "barretenberg/vm2/simulation/gadgets/internal_call_stack_manager.hpp"
14+
#include "barretenberg/vm2/simulation/gadgets/merkle_check.hpp"
15+
#include "barretenberg/vm2/simulation/gadgets/poseidon2.hpp"
16+
#include "barretenberg/vm2/simulation/gadgets/range_check.hpp"
17+
#include "barretenberg/vm2/simulation/gadgets/update_check.hpp"
18+
#include "barretenberg/vm2/simulation/gadgets/written_public_data_slots_tree_check.hpp"
19+
#include "barretenberg/vm2/simulation/interfaces/context.hpp"
20+
#include "barretenberg/vm2/simulation/lib/execution_id_manager.hpp"
21+
#include "barretenberg/vm2/simulation/lib/side_effect_tracker.hpp"
22+
#include "barretenberg/vm2/simulation/lib/side_effect_tracking_db.hpp"
23+
24+
namespace bb::avm2::fuzzing {
25+
26+
using namespace bb::avm2::simulation;
27+
28+
/**
29+
* @brief Sets up gadgets and instance managers to provide a
30+
* context for fuzzing. NOTE: rudimentary set up for testing, should likely be merged
31+
* with TestSimulator in fuzz_lib in future
32+
*
33+
* TODO(MW): I just set the ones I needed to be accessed as public, with others in private and
34+
* gadgets in the constructor - will clean this up
35+
*
36+
* @param contract_address The address to be configured in the context
37+
* @param is_static Whether this call is static (defaults to false)
38+
* @param phase The phase (defaults to APP_LOGIC)
39+
* @param start_clk The starting clk (defaults to 0)
40+
* @return A context interface to be passed to fuzzed gadgets
41+
*/
42+
class GadgetFuzzerContextHelper {
43+
public:
44+
GadgetFuzzerContextHelper(AztecAddress contract_address = AztecAddress(0),
45+
bool is_static = false,
46+
uint32_t start_clk = 0);
47+
// Commonly used emitters:
48+
DeduplicatingEventEmitter<RangeCheckEvent> range_check_emitter;
49+
DeduplicatingEventEmitter<GreaterThanEvent> greater_than_emitter;
50+
DeduplicatingEventEmitter<FieldGreaterThanEvent> field_gt_emitter;
51+
52+
// Commonly used gadgets:
53+
ExecutionIdManager execution_id_manager;
54+
RangeCheck range_check;
55+
FieldGreaterThan field_gt;
56+
GreaterThan greater_than;
57+
// Side effect tracker:
58+
SideEffectTracker side_effect_tracker;
59+
// Memory provider:
60+
MemoryProvider memory_provider;
61+
// Context provider:
62+
std::unique_ptr<simulation::ContextProvider> context_provider;
63+
// Context:
64+
std::unique_ptr<simulation::ContextInterface> make_enqueued_fuzzing_context(
65+
AztecAddress address,
66+
AztecAddress msg_sender,
67+
bool is_static = false,
68+
FF transaction_fee = FF(0),
69+
std::span<const FF> calldata = {},
70+
Gas gas_limit = GAS_LIMIT,
71+
Gas gas_used = GAS_USED_BY_PRIVATE,
72+
TransactionPhase phase = TransactionPhase::APP_LOGIC);
73+
74+
std::unique_ptr<simulation::ContextInterface> make_nested_fuzzing_context(AztecAddress address,
75+
AztecAddress msg_sender,
76+
ContextInterface& parent_context,
77+
Gas gas_limit = GAS_LIMIT);
78+
79+
private:
80+
// Emitters:
81+
EventEmitter<MemoryEvent> memory_emitter;
82+
EventEmitter<Poseidon2HashEvent> hash_event_emitter;
83+
EventEmitter<Poseidon2PermutationEvent> perm_event_emitter;
84+
EventEmitter<Poseidon2PermutationMemoryEvent> perm_mem_event_emitter;
85+
EventEmitter<UpdateCheckEvent> update_check_emitter;
86+
EventEmitter<MerkleCheckEvent> merkle_check_emitter;
87+
EventEmitter<ContractInstanceRetrievalEvent> contract_instance_retrieval_emitter;
88+
EventEmitter<WrittenPublicDataSlotsTreeCheckEvent> written_public_data_slots_tree_check_emitter;
89+
EventEmitter<BytecodeRetrievalEvent> bytecode_retrieval_emitter;
90+
EventEmitter<BytecodeHashingEvent> bytecode_hashing_emitter;
91+
EventEmitter<BytecodeDecompositionEvent> bytecode_decomposition_emitter;
92+
EventEmitter<RetrievedBytecodesTreeCheckEvent> retrieved_bytecodes_tree_check_emitter;
93+
EventEmitter<CalldataEvent> calldata_event_emitter;
94+
EventEmitter<InternalCallStackEvent> internal_call_stack_emitter;
95+
DeduplicatingEventEmitter<InstructionFetchingEvent> instruction_fetching_emitter;
96+
97+
// Gadgets:
98+
MerkleCheck merkle_check;
99+
Poseidon2 poseidon2;
100+
WrittenPublicDataSlotsTreeCheck written_public_data_slots_tree_check;
101+
RetrievedBytecodesTreeCheck retrieved_bytecodes_tree_check;
102+
std::unique_ptr<TxBytecodeManager> tx_bytecode_manager;
103+
104+
// Misc:
105+
GlobalVariables global_variables;
106+
ExecutionHints hints;
107+
SideEffectTrackingDB make_empty_merkle_db();
108+
};
109+
110+
} // namespace bb::avm2::fuzzing

0 commit comments

Comments
 (0)