3#include <gmock/gmock.h>
4#include <gtest/gtest.h>
19using ::testing::ElementsAre;
20using ::testing::Return;
21using ::testing::StrictMock;
27TEST(AvmSimulationIndexedTreeCheck, ReadExists)
31 StrictMock<MockFieldGreaterThan>
field_gt;
36 IndexedTreeLeafData
low_leaf = { .
value = 42, .next_value = 0, .next_index = 0 };
38 uint64_t low_leaf_index = 30;
39 std::vector<FF> sibling_path = { 1, 2, 3, 4, 5 };
40 AppendOnlyTreeSnapshot snapshot = { .root = 123456, .next_available_leaf_index = 128 };
45 EXPECT_CALL(merkle_check, assert_membership(low_leaf_hash, low_leaf_index, _, snapshot.root))
46 .WillRepeatedly(Return());
51 IndexedTreeReadWriteEvent expect_event = {
53 .prev_snapshot = snapshot,
54 .next_snapshot = snapshot,
55 .tree_height = sibling_path.size(),
57 .low_leaf_hash = low_leaf_hash,
58 .low_leaf_index = low_leaf_index,
60 EXPECT_THAT(
event_emitter.dump_events(), ElementsAre(expect_event));
66 "non-membership check failed");
69TEST(AvmSimulationIndexedTreeCheck, ReadNotExistsLowPointsToInfinity)
73 StrictMock<MockFieldGreaterThan>
field_gt;
78 IndexedTreeLeafData
low_leaf = { .
value = 40, .next_value = 0, .next_index = 0 };
80 uint64_t low_leaf_index = 30;
81 std::vector<FF> sibling_path = { 1, 2, 3, 4, 5 };
82 AppendOnlyTreeSnapshot snapshot = { .root = 123456, .next_available_leaf_index = 128 };
86 EXPECT_CALL(merkle_check, assert_membership(low_leaf_hash, low_leaf_index, _, snapshot.root))
87 .WillRepeatedly(Return());
92 IndexedTreeReadWriteEvent expect_event = {
94 .prev_snapshot = snapshot,
95 .next_snapshot = snapshot,
96 .tree_height = sibling_path.size(),
98 .low_leaf_hash = low_leaf_hash,
99 .low_leaf_index = low_leaf_index,
101 EXPECT_THAT(
event_emitter.dump_events(), ElementsAre(expect_event));
107 "membership check failed");
114 "Low leaf value is GTE leaf value");
117TEST(AvmSimulationIndexedTreeCheck, ReadNotExistsLowPointsToAnotherLeaf)
121 StrictMock<MockFieldGreaterThan>
field_gt;
126 IndexedTreeLeafData
low_leaf = { .
value = 40, .next_value = 50, .next_index = 28 };
128 uint64_t low_leaf_index = 30;
129 std::vector<FF> sibling_path = { 1, 2, 3, 4, 5 };
130 AppendOnlyTreeSnapshot snapshot = { .root = 123456, .next_available_leaf_index = 128 };
134 EXPECT_CALL(merkle_check, assert_membership(low_leaf_hash, low_leaf_index, _, snapshot.root))
135 .WillRepeatedly(Return());
141 IndexedTreeReadWriteEvent expect_event = {
143 .prev_snapshot = snapshot,
144 .next_snapshot = snapshot,
145 .tree_height = sibling_path.size(),
147 .low_leaf_hash = low_leaf_hash,
148 .low_leaf_index = low_leaf_index,
150 EXPECT_THAT(
event_emitter.dump_events(), ElementsAre(expect_event));
156 "membership check failed");
163 "Leaf value is GTE low leaf next value");
166TEST(AvmSimulationIndexedTreeCheck, WriteExists)
170 StrictMock<MockFieldGreaterThan>
field_gt;
175 IndexedTreeLeafData
low_leaf = { .
value = 42, .next_value = 0, .next_index = 0 };
177 uint64_t low_leaf_index = 30;
178 std::vector<FF> sibling_path = { 1, 2, 3, 4, 5 };
179 AppendOnlyTreeSnapshot snapshot = { .root = 123456, .next_available_leaf_index = 128 };
184 EXPECT_CALL(merkle_check, assert_membership(low_leaf_hash, low_leaf_index, _, snapshot.root))
185 .WillRepeatedly(Return());
196 EXPECT_EQ(result_snapshot, snapshot);
198 IndexedTreeReadWriteEvent expect_event = {
200 .prev_snapshot = snapshot,
201 .next_snapshot = snapshot,
202 .tree_height = sibling_path.size(),
204 .low_leaf_hash = low_leaf_hash,
205 .low_leaf_index = low_leaf_index,
207 .public_inputs_index = 10,
209 EXPECT_THAT(
event_emitter.dump_events(), ElementsAre(expect_event));
212TEST(AvmSimulationIndexedTreeCheck, Siloing)
216 StrictMock<MockFieldGreaterThan>
field_gt;
224 IndexedTreeSiloingParameters siloing_params = { .address =
address, .siloing_separator = separator };
225 std::vector<FF> siloed_hash_inputs = { separator,
address,
value };
228 IndexedTreeLeafData
low_leaf = { .
value = siloed_value, .next_value = 0, .next_index = 0 };
230 uint64_t low_leaf_index = 30;
231 std::vector<FF> sibling_path = { 1, 2, 3, 4, 5 };
232 AppendOnlyTreeSnapshot snapshot = { .root = 123456, .next_available_leaf_index = 128 };
234 EXPECT_CALL(
poseidon2, hash(siloed_hash_inputs)).WillRepeatedly(Return(siloed_value));
236 EXPECT_CALL(merkle_check, assert_membership(low_leaf_hash, low_leaf_index, _, snapshot.root))
237 .WillRepeatedly(Return());
241 IndexedLeafSiloingData expected_siloing_data = { .siloed_value = siloed_value, .parameters = siloing_params };
242 IndexedTreeReadWriteEvent read_event = {
244 .prev_snapshot = snapshot,
245 .next_snapshot = snapshot,
246 .tree_height = sibling_path.size(),
248 .low_leaf_hash = low_leaf_hash,
249 .low_leaf_index = low_leaf_index,
250 .siloing_data = expected_siloing_data,
261 IndexedTreeReadWriteEvent write_event = {
263 .prev_snapshot = snapshot,
264 .next_snapshot = snapshot,
265 .tree_height = sibling_path.size(),
267 .low_leaf_hash = low_leaf_hash,
268 .low_leaf_index = low_leaf_index,
270 .siloing_data = expected_siloing_data,
271 .public_inputs_index = 10,
273 EXPECT_THAT(
event_emitter.dump_events(), ElementsAre(read_event, write_event));
276TEST(AvmSimulationIndexedTreeCheck, WriteAppend)
280 StrictMock<MockFieldGreaterThan>
field_gt;
290 IndexedTreeLeafData
low_leaf = { .
value = low_value, .next_value =
value + 1, .next_index = 10 };
292 uint64_t low_leaf_index = 0;
293 tree.update_element(low_leaf_index, low_leaf_hash);
295 AppendOnlyTreeSnapshot prev_snapshot = { .root = tree.root(), .next_available_leaf_index = 128 };
296 std::vector<FF> low_leaf_sibling_path = tree.get_sibling_path(low_leaf_index);
298 IndexedTreeLeafData updated_low_leaf = {
301 .next_index = prev_snapshot.next_available_leaf_index,
304 tree.update_element(low_leaf_index, updated_low_leaf_hash);
306 FF intermediate_root = tree.root();
307 std::vector<FF> insertion_sibling_path = tree.get_sibling_path(prev_snapshot.next_available_leaf_index);
310 IndexedTreeLeafData new_leaf = { .value =
value,
314 tree.update_element(prev_snapshot.next_available_leaf_index, new_leaf_hash);
316 AppendOnlyTreeSnapshot next_snapshot = {
318 .next_available_leaf_index = prev_snapshot.next_available_leaf_index + 1,
321 EXPECT_CALL(
poseidon2, hash(_)).WillRepeatedly([](
const std::vector<FF>& input) {
324 EXPECT_CALL(merkle_check,
write(low_leaf_hash, updated_low_leaf_hash, low_leaf_index, _, prev_snapshot.root))
325 .WillRepeatedly(Return(intermediate_root));
328 EXPECT_CALL(merkle_check,
329 write(
FF(0), new_leaf_hash, prev_snapshot.next_available_leaf_index, _, intermediate_root))
330 .WillRepeatedly(Return(next_snapshot.root));
337 low_leaf_sibling_path,
339 insertion_sibling_path);
341 EXPECT_EQ(next_snapshot, result_snapshot);
343 IndexedTreeReadWriteEvent expect_event = {
345 .prev_snapshot = prev_snapshot,
346 .next_snapshot = next_snapshot,
347 .tree_height = low_leaf_sibling_path.size(),
349 .low_leaf_hash = low_leaf_hash,
350 .low_leaf_index = low_leaf_index,
353 IndexedLeafAppendData{
354 .updated_low_leaf_hash = updated_low_leaf_hash,
355 .new_leaf_hash = new_leaf_hash,
356 .intermediate_root = intermediate_root,
360 EXPECT_THAT(
event_emitter.dump_events(), ElementsAre(expect_event));
363 IndexedTreeLeafData matching_leaf = { .value =
value,
371 low_leaf_sibling_path,
373 insertion_sibling_path),
374 "non-membership check failed");
383 low_leaf_sibling_path,
385 insertion_sibling_path),
386 "Low leaf value is GTE leaf value");
396 low_leaf_sibling_path,
398 insertion_sibling_path),
399 "Leaf value is GTE low leaf next value");
#define EXPECT_THROW_WITH_MESSAGE(code, expectedMessageRegex)
FieldGreaterThan field_gt
IndexedTreeCheck indexed_tree_check
void assert_read(const FF &value, std::optional< IndexedTreeSiloingParameters > siloing_params, bool exists, const IndexedTreeLeafData &low_leaf_preimage, uint64_t low_leaf_index, std::span< const FF > sibling_path, const AppendOnlyTreeSnapshot &snapshot) override
Performs a membership/non-membership read check on an indexed tree.
AppendOnlyTreeSnapshot write(const FF &value, std::optional< IndexedTreeSiloingParameters > siloing_params, std::optional< uint64_t > public_inputs_index, const IndexedTreeLeafData &low_leaf_preimage, uint64_t low_leaf_index, std::span< const FF > low_leaf_sibling_path, const AppendOnlyTreeSnapshot &prev_snapshot, std::optional< std::span< const FF > > insertion_sibling_path) override
Writes a value into an indexed tree, or validates it already exists.
static FF hash(const std::vector< FF > &input)
Hashes a vector of field elements.
EventEmitter< DataCopyEvent > event_emitter
IndexedTreeLeafData low_leaf
AVM range check gadget for witness generation.
crypto::Poseidon2< crypto::Poseidon2Bn254ScalarFieldParams > poseidon2
void write(B &buf, field2< base_field, Params > const &value)
TEST(BoomerangMegaCircuitBuilder, BasicCircuit)
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
std::vector< FF > get_hash_inputs() const