Skip to content

Commit 00c514f

Browse files
authored
feat: merge-train/avm (#18994)
BEGIN_COMMIT_OVERRIDE test: Add merkle check fuzzer (#18986) feat!: Fix AVM VK in the recursive verifier (#18923) END_COMMIT_OVERRIDE
2 parents f33f2f5 + 859b9b0 commit 00c514f

File tree

57 files changed

+5233
-5557
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+5233
-5557
lines changed
Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
#include "barretenberg/vm2/simulation/gadgets/merkle_check.hpp"
2+
3+
#include <cassert>
4+
#include <cstdint>
5+
#include <fuzzer/FuzzedDataProvider.h>
6+
7+
#include "barretenberg/avm_fuzzer/fuzz_lib/constants.hpp"
8+
#include "barretenberg/avm_fuzzer/harness/mutation_helper.hpp"
9+
#include "barretenberg/common/serialize.hpp"
10+
#include "barretenberg/numeric/uint128/uint128.hpp"
11+
#include "barretenberg/vm2/constraining/testing/check_relation.hpp"
12+
#include "barretenberg/vm2/generated/columns.hpp"
13+
#include "barretenberg/vm2/simulation/events/event_emitter.hpp"
14+
#include "barretenberg/vm2/simulation/events/merkle_check_event.hpp"
15+
#include "barretenberg/vm2/simulation/events/poseidon2_event.hpp"
16+
#include "barretenberg/vm2/simulation/gadgets/poseidon2.hpp"
17+
#include "barretenberg/vm2/simulation/lib/execution_id_manager.hpp"
18+
#include "barretenberg/vm2/simulation/lib/merkle.hpp"
19+
#include "barretenberg/vm2/simulation/standalone/pure_gt.hpp"
20+
#include "barretenberg/vm2/tooling/debugger.hpp"
21+
#include "barretenberg/vm2/tracegen/merkle_check_trace.hpp"
22+
#include "barretenberg/vm2/tracegen/poseidon2_trace.hpp"
23+
#include "barretenberg/vm2/tracegen/precomputed_trace.hpp"
24+
#include "barretenberg/vm2/tracegen/test_trace_container.hpp"
25+
26+
using namespace bb::avm2::simulation;
27+
using namespace bb::avm2::tracegen;
28+
using namespace bb::avm2::constraining;
29+
using namespace bb::avm2::fuzzing;
30+
31+
using bb::avm2::FF;
32+
33+
using merkle_check_rel = bb::avm2::merkle_check<FF>;
34+
35+
struct MerkleCheckFuzzerInput {
36+
bool is_write = false;
37+
FF current_value = 0;
38+
FF new_value = 0;
39+
uint64_t leaf_index = 0;
40+
std::array<FF, 64> sibling_path;
41+
FF root = 0;
42+
uint64_t tree_height = 10;
43+
44+
uint64_t trimmed_leaf_index() const
45+
{
46+
// Truncate upper bits of leaf index by 2**tree_height
47+
return leaf_index & ((1ULL << tree_height) - 1);
48+
}
49+
50+
std::span<const FF> trimmed_sibling_path() const
51+
{
52+
// Trim sibling path by tree height
53+
return std::span<const FF>(sibling_path).subspan(0, tree_height);
54+
}
55+
56+
MSGPACK_FIELDS(is_write, current_value, new_value, leaf_index, sibling_path, root, tree_height);
57+
};
58+
59+
namespace {
60+
61+
bool predict_if_will_throw(const MerkleCheckFuzzerInput& input)
62+
{
63+
if (static_cast<uint128_t>(input.leaf_index) > (static_cast<uint128_t>(1) << input.tree_height)) {
64+
fuzz_info("Should throw: leaf index is too large, leaf index: ",
65+
input.leaf_index,
66+
", tree height: ",
67+
input.tree_height);
68+
return true;
69+
}
70+
71+
if (input.tree_height > 64) {
72+
fuzz_info("Should throw: tree height is too large, tree height: ", input.tree_height);
73+
return true;
74+
}
75+
76+
FF expected_root =
77+
unconstrained_root_from_path(input.current_value, input.trimmed_leaf_index(), input.trimmed_sibling_path());
78+
79+
if (expected_root != input.root) {
80+
fuzz_info("Should throw: root does not match expected root");
81+
return true;
82+
}
83+
84+
return false;
85+
}
86+
87+
} // namespace
88+
89+
extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* data, size_t size, size_t max_size, unsigned int seed)
90+
{
91+
MerkleCheckFuzzerInput input;
92+
try {
93+
// Deserialize current input
94+
msgpack::unpack((reinterpret_cast<const char*>(data)), size).get().convert(input);
95+
} catch (const std::exception& e) {
96+
// Leave default
97+
input = {};
98+
}
99+
100+
std::mt19937_64 rng(seed);
101+
102+
// Choose mutation
103+
auto dist = std::uniform_int_distribution<int>(0, 6);
104+
105+
int choice = dist(rng);
106+
107+
auto random_field = [&rng]() -> FF {
108+
std::uniform_int_distribution<uint64_t> dist(0, std::numeric_limits<uint64_t>::max());
109+
return FF(dist(rng), dist(rng), dist(rng), dist(rng));
110+
};
111+
112+
switch (choice) {
113+
case 0: {
114+
// Set correct root
115+
input.root =
116+
unconstrained_root_from_path(input.current_value, input.trimmed_leaf_index(), input.trimmed_sibling_path());
117+
118+
break;
119+
}
120+
case 1: {
121+
// Flip is_write
122+
input.is_write = !input.is_write;
123+
break;
124+
}
125+
case 2: {
126+
// Random new current value
127+
input.current_value = random_field();
128+
break;
129+
}
130+
case 3: {
131+
// Swap current and new value
132+
std::swap(input.current_value, input.new_value);
133+
break;
134+
}
135+
case 4: {
136+
// Modify leaf index
137+
std::uniform_int_distribution<uint64_t> dist(0, std::numeric_limits<uint64_t>::max());
138+
input.leaf_index = dist(rng);
139+
break;
140+
}
141+
case 5: {
142+
// Modify tree height
143+
std::uniform_int_distribution<uint64_t> dist(1, 64);
144+
input.tree_height = dist(rng);
145+
break;
146+
}
147+
case 6: {
148+
// Update sibling path item at random index
149+
std::uniform_int_distribution<size_t> dist(0, input.sibling_path.size() - 1);
150+
size_t index = dist(rng);
151+
input.sibling_path[index] = random_field();
152+
break;
153+
}
154+
default:
155+
break;
156+
}
157+
158+
auto [mutated_data, mutated_data_size] = msgpack_encode_buffer(input);
159+
if (mutated_data_size > max_size) {
160+
delete[] mutated_data;
161+
return 0;
162+
}
163+
164+
memcpy(data, mutated_data, mutated_data_size);
165+
delete[] mutated_data;
166+
167+
return mutated_data_size;
168+
}
169+
170+
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
171+
{
172+
MerkleCheckFuzzerInput input;
173+
try {
174+
msgpack::unpack((reinterpret_cast<const char*>(data)), size).get().convert(input);
175+
} catch (const std::exception& e) {
176+
// Invalid input, return early
177+
return 0;
178+
}
179+
180+
// Setup gadgets
181+
ExecutionIdManager execution_id_manager(1);
182+
// Pure since it's unused
183+
PureGreaterThan gt;
184+
185+
EventEmitter<Poseidon2HashEvent> poseidon2_hash_emitter;
186+
EventEmitter<Poseidon2PermutationEvent> poseidon2_perm_emitter;
187+
EventEmitter<Poseidon2PermutationMemoryEvent> poseidon2_perm_mem_emitter;
188+
Poseidon2 poseidon2(
189+
execution_id_manager, gt, poseidon2_hash_emitter, poseidon2_perm_emitter, poseidon2_perm_mem_emitter);
190+
191+
EventEmitter<MerkleCheckEvent> merkle_check_emitter;
192+
MerkleCheck merkle_check(poseidon2, merkle_check_emitter);
193+
194+
bool will_throw = predict_if_will_throw(input);
195+
std::optional<FF> new_root = std::nullopt;
196+
197+
try {
198+
if (input.is_write) {
199+
new_root = merkle_check.write(
200+
input.current_value, input.new_value, input.leaf_index, input.trimmed_sibling_path(), input.root);
201+
} else {
202+
merkle_check.assert_membership(
203+
input.current_value, input.leaf_index, input.trimmed_sibling_path(), input.root);
204+
}
205+
} catch (std::exception& e) {
206+
if (!will_throw) {
207+
// Unexpected throw
208+
throw e;
209+
}
210+
// We can't continue executing since the gadget threw
211+
return 0;
212+
}
213+
214+
if (will_throw) {
215+
throw std::runtime_error("Expected exception was not thrown");
216+
}
217+
218+
if (new_root.has_value()) {
219+
FF expected_new_root =
220+
unconstrained_root_from_path(input.new_value, input.trimmed_leaf_index(), input.trimmed_sibling_path());
221+
if (new_root.value() != expected_new_root) {
222+
throw std::runtime_error("New root does not match expected root");
223+
}
224+
}
225+
226+
if (poseidon2_perm_mem_emitter.get_events().size() > 0) {
227+
throw std::runtime_error("Poseidon2 permutation memory events were emitted");
228+
}
229+
230+
// Build the trace
231+
232+
auto trace = TestTraceContainer({ { { avm2::Column::precomputed_first_row, 1 } } });
233+
234+
Poseidon2TraceBuilder poseidon2_trace_builder;
235+
poseidon2_trace_builder.process_permutation(poseidon2_perm_emitter.dump_events(), trace);
236+
poseidon2_trace_builder.process_hash(poseidon2_hash_emitter.dump_events(), trace);
237+
238+
MerkleCheckTraceBuilder merkle_check_trace_builder;
239+
merkle_check_trace_builder.process(merkle_check_emitter.dump_events(), trace);
240+
241+
if (getenv("AVM_DEBUG") != nullptr) {
242+
info("Debugging trace:");
243+
bb::avm2::InteractiveDebugger debugger(trace);
244+
debugger.run();
245+
}
246+
247+
check_relation<merkle_check_rel>(trace);
248+
check_all_interactions<MerkleCheckTraceBuilder>(trace);
249+
250+
return 0;
251+
}

barretenberg/cpp/src/barretenberg/avm_fuzzer/run_fuzzer.sh

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ if [ "$COMMAND" = "list-targets" ]; then
3030
echo " bitwise - Bitwise fuzzer (harness_bitwise_fuzzer)"
3131
echo " ecc - ECC fuzzer (harness_ecc_fuzzer)"
3232
echo " gt - Greater Than fuzzer (harness_gt_fuzzer)"
33+
echo " merkle_check - Merkle Check fuzzer (harness_merkle_check_fuzzer)"
3334
exit 0
3435
fi
3536

@@ -62,9 +63,10 @@ case "$FUZZER_ALIAS" in
6263
bitwise) FUZZER_TYPE="harness_bitwise_fuzzer" ;;
6364
ecc) FUZZER_TYPE="harness_ecc_fuzzer" ;;
6465
gt) FUZZER_TYPE="harness_gt_fuzzer" ;;
66+
merkle_check) FUZZER_TYPE="harness_merkle_check_fuzzer" ;;
6567
*)
6668
echo "Error: Invalid fuzzer type '$FUZZER_ALIAS'"
67-
echo "Valid options: 'avm', 'alu', 'bitwise', 'ecc' or 'gt'"
69+
echo "Valid options: 'avm', 'alu', 'bitwise', 'ecc', 'gt' or 'merkle_check'"
6870
exit 1
6971
;;
7072
esac
@@ -133,7 +135,6 @@ cd "$BUILD_DIR"
133135

134136
# Default fuzzer parameters
135137
TIMEOUT=5
136-
LEN_CONTROL=500
137138
WORKERS=1 # EVERYTHING TUNED TO 1 BY DEFAULT UNTIL DIFFERENTIAL FUZZER WORKS IN PARALLEL
138139
JOBS=1 # EVERYTHING TUNED TO 1 BY DEFAULT UNTIL DIFFERENTIAL FUZZER WORKS IN PARALLEL
139140
ENTROPIC=1
@@ -150,7 +151,6 @@ echo "Crashes directory: $CRASHES_DIR"
150151
if [ "$COMMAND" = "fuzz" ]; then
151152
echo "Parameters:"
152153
echo " -timeout=$TIMEOUT"
153-
echo " -len_control=$LEN_CONTROL"
154154
echo " -workers=$WORKERS"
155155
echo " -jobs=$JOBS"
156156
echo " -entropic=$ENTROPIC"
@@ -177,7 +177,6 @@ else
177177
# Normal fuzzing with full parameters
178178
FUZZER_CMD+=(
179179
-timeout=$TIMEOUT
180-
-len_control=$LEN_CONTROL
181180
-workers=$WORKERS
182181
-jobs=$JOBS
183182
-entropic=$ENTROPIC

barretenberg/cpp/src/barretenberg/ecc/groups/affine_element.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ template <typename Fq_, typename Fr_, typename Params_> class alignas(64) affine
8787
typename CompileTimeEnabled = std::enable_if_t<(BaseField::modulus >> 255) == uint256_t(0), void>>
8888
[[nodiscard]] constexpr uint256_t compress() const noexcept;
8989

90-
static affine_element infinity();
90+
static constexpr affine_element infinity();
9191
constexpr affine_element set_infinity() const noexcept;
9292
constexpr void self_set_infinity() noexcept;
9393

barretenberg/cpp/src/barretenberg/ecc/groups/affine_element_impl.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ constexpr uint256_t affine_element<Fq, Fr, T>::compress() const noexcept
9292
return out;
9393
}
9494

95-
template <class Fq, class Fr, class T> affine_element<Fq, Fr, T> affine_element<Fq, Fr, T>::infinity()
95+
template <class Fq, class Fr, class T> constexpr affine_element<Fq, Fr, T> affine_element<Fq, Fr, T>::infinity()
9696
{
9797
affine_element e{};
9898
e.self_set_infinity();

barretenberg/cpp/src/barretenberg/vm2/avm_api.cpp

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,13 +72,8 @@ bool AvmAPI::verify(const AvmProof& proof, const PublicInputs& pi, const AvmVeri
7272

7373
AvmAPI::AvmVerificationKey AvmAPI::get_verification_key()
7474
{
75-
vinfo("Generating trace...");
76-
AvmTraceGenHelper tracegen_helper;
77-
auto trace = tracegen_helper.generate_precomputed_columns();
78-
79-
vinfo("Computing verification key...");
8075
AvmProvingHelper proving_helper;
81-
return proving_helper.compute_verification_key(trace);
76+
return proving_helper.get_verification_key();
8277
}
8378

8479
} // namespace bb::avm2

0 commit comments

Comments
 (0)