3#include <gmock/gmock.h>
4#include <gtest/gtest.h>
20using ::testing::ElementsAre;
21using ::testing::Return;
22using ::testing::StrictMock;
28TEST(AvmSimulationIndexedTreeCheck, ReadExists)
32 StrictMock<MockFieldGreaterThan>
field_gt;
37 IndexedTreeLeafData
low_leaf = { .
value = 42, .next_value = 0, .next_index = 0 };
39 uint64_t low_leaf_index = 30;
40 std::vector<FF> sibling_path = { 1, 2, 3, 4, 5 };
41 AppendOnlyTreeSnapshot snapshot = { .root = 123456, .next_available_leaf_index = 128 };
46 EXPECT_CALL(merkle_check,
48 .WillRepeatedly(Return());
53 IndexedTreeReadWriteEvent expect_event = {
55 .prev_snapshot = snapshot,
56 .next_snapshot = snapshot,
57 .tree_height = sibling_path.size(),
60 .low_leaf_hash = low_leaf_hash,
61 .low_leaf_index = low_leaf_index,
63 EXPECT_THAT(
event_emitter.dump_events(), ElementsAre(expect_event));
69 "non-membership check failed");
72TEST(AvmSimulationIndexedTreeCheck, ReadNotExistsLowPointsToInfinity)
76 StrictMock<MockFieldGreaterThan>
field_gt;
81 IndexedTreeLeafData
low_leaf = { .
value = 40, .next_value = 0, .next_index = 0 };
83 uint64_t low_leaf_index = 30;
84 std::vector<FF> sibling_path = { 1, 2, 3, 4, 5 };
85 AppendOnlyTreeSnapshot snapshot = { .root = 123456, .next_available_leaf_index = 128 };
89 EXPECT_CALL(merkle_check,
91 .WillRepeatedly(Return());
96 IndexedTreeReadWriteEvent expect_event = {
98 .prev_snapshot = snapshot,
99 .next_snapshot = snapshot,
100 .tree_height = sibling_path.size(),
103 .low_leaf_hash = low_leaf_hash,
104 .low_leaf_index = low_leaf_index,
106 EXPECT_THAT(
event_emitter.dump_events(), ElementsAre(expect_event));
112 "membership check failed");
119 "Low leaf value is GTE leaf value");
122TEST(AvmSimulationIndexedTreeCheck, ReadNotExistsLowPointsToAnotherLeaf)
126 StrictMock<MockFieldGreaterThan>
field_gt;
131 IndexedTreeLeafData
low_leaf = { .
value = 40, .next_value = 50, .next_index = 28 };
133 uint64_t low_leaf_index = 30;
134 std::vector<FF> sibling_path = { 1, 2, 3, 4, 5 };
135 AppendOnlyTreeSnapshot snapshot = { .root = 123456, .next_available_leaf_index = 128 };
139 EXPECT_CALL(merkle_check,
141 .WillRepeatedly(Return());
147 IndexedTreeReadWriteEvent expect_event = {
149 .prev_snapshot = snapshot,
150 .next_snapshot = snapshot,
151 .tree_height = sibling_path.size(),
154 .low_leaf_hash = low_leaf_hash,
155 .low_leaf_index = low_leaf_index,
157 EXPECT_THAT(
event_emitter.dump_events(), ElementsAre(expect_event));
163 "membership check failed");
170 "Leaf value is GTE low leaf next value");
173TEST(AvmSimulationIndexedTreeCheck, WriteExists)
177 StrictMock<MockFieldGreaterThan>
field_gt;
182 IndexedTreeLeafData
low_leaf = { .
value = 42, .next_value = 0, .next_index = 0 };
184 uint64_t low_leaf_index = 30;
185 std::vector<FF> sibling_path = { 1, 2, 3, 4, 5 };
186 AppendOnlyTreeSnapshot snapshot = { .root = 123456, .next_available_leaf_index = 128 };
191 EXPECT_CALL(merkle_check,
193 .WillRepeatedly(Return());
204 EXPECT_EQ(result_snapshot, snapshot);
206 IndexedTreeReadWriteEvent expect_event = {
208 .prev_snapshot = snapshot,
209 .next_snapshot = snapshot,
210 .tree_height = sibling_path.size(),
213 .low_leaf_hash = low_leaf_hash,
214 .low_leaf_index = low_leaf_index,
216 .public_inputs_index = 10,
218 EXPECT_THAT(
event_emitter.dump_events(), ElementsAre(expect_event));
221TEST(AvmSimulationIndexedTreeCheck, Siloing)
225 StrictMock<MockFieldGreaterThan>
field_gt;
233 IndexedTreeSiloingParameters siloing_params = { .address =
address, .siloing_separator = separator };
234 std::vector<FF> siloed_hash_inputs = { separator,
address,
value };
237 IndexedTreeLeafData
low_leaf = { .
value = siloed_value, .next_value = 0, .next_index = 0 };
239 uint64_t low_leaf_index = 30;
240 std::vector<FF> sibling_path = { 1, 2, 3, 4, 5 };
241 AppendOnlyTreeSnapshot snapshot = { .root = 123456, .next_available_leaf_index = 128 };
243 EXPECT_CALL(
poseidon2, hash(siloed_hash_inputs)).WillRepeatedly(Return(siloed_value));
245 EXPECT_CALL(merkle_check,
247 .WillRepeatedly(Return());
251 IndexedLeafSiloingData expected_siloing_data = { .siloed_value = siloed_value, .parameters = siloing_params };
252 IndexedTreeReadWriteEvent read_event = {
254 .prev_snapshot = snapshot,
255 .next_snapshot = snapshot,
256 .tree_height = sibling_path.size(),
259 .low_leaf_hash = low_leaf_hash,
260 .low_leaf_index = low_leaf_index,
261 .siloing_data = expected_siloing_data,
272 IndexedTreeReadWriteEvent write_event = {
274 .prev_snapshot = snapshot,
275 .next_snapshot = snapshot,
276 .tree_height = sibling_path.size(),
279 .low_leaf_hash = low_leaf_hash,
280 .low_leaf_index = low_leaf_index,
282 .siloing_data = expected_siloing_data,
283 .public_inputs_index = 10,
285 EXPECT_THAT(
event_emitter.dump_events(), ElementsAre(read_event, write_event));
288TEST(AvmSimulationIndexedTreeCheck, WriteAppend)
292 StrictMock<MockFieldGreaterThan>
field_gt;
302 IndexedTreeLeafData
low_leaf = { .
value = low_value, .next_value =
value + 1, .next_index = 10 };
304 uint64_t low_leaf_index = 0;
305 tree.update_element(low_leaf_index, low_leaf_hash);
307 AppendOnlyTreeSnapshot prev_snapshot = { .root = tree.root(), .next_available_leaf_index = 128 };
308 std::vector<FF> low_leaf_sibling_path = tree.get_sibling_path(low_leaf_index);
310 IndexedTreeLeafData updated_low_leaf = {
313 .next_index = prev_snapshot.next_available_leaf_index,
316 tree.update_element(low_leaf_index, updated_low_leaf_hash);
318 FF intermediate_root = tree.root();
319 std::vector<FF> insertion_sibling_path = tree.get_sibling_path(prev_snapshot.next_available_leaf_index);
322 IndexedTreeLeafData new_leaf = { .value =
value,
326 tree.update_element(prev_snapshot.next_available_leaf_index, new_leaf_hash);
328 AppendOnlyTreeSnapshot next_snapshot = {
330 .next_available_leaf_index = prev_snapshot.next_available_leaf_index + 1,
333 EXPECT_CALL(
poseidon2, hash(_)).WillRepeatedly([](
const std::vector<FF>& input) {
339 .WillRepeatedly(Return(intermediate_root));
342 EXPECT_CALL(merkle_check,
346 prev_snapshot.next_available_leaf_index,
349 .WillRepeatedly(Return(next_snapshot.root));
356 low_leaf_sibling_path,
358 insertion_sibling_path);
360 EXPECT_EQ(next_snapshot, result_snapshot);
362 IndexedTreeReadWriteEvent expect_event = {
364 .prev_snapshot = prev_snapshot,
365 .next_snapshot = next_snapshot,
366 .tree_height = low_leaf_sibling_path.size(),
369 .low_leaf_hash = low_leaf_hash,
370 .low_leaf_index = low_leaf_index,
373 IndexedLeafAppendData{
374 .updated_low_leaf_hash = updated_low_leaf_hash,
375 .new_leaf_hash = new_leaf_hash,
376 .intermediate_root = intermediate_root,
380 EXPECT_THAT(
event_emitter.dump_events(), ElementsAre(expect_event));
383 IndexedTreeLeafData matching_leaf = { .value =
value,
391 low_leaf_sibling_path,
393 insertion_sibling_path),
394 "non-membership check failed");
403 low_leaf_sibling_path,
405 insertion_sibling_path),
406 "Low leaf value is GTE leaf value");
416 low_leaf_sibling_path,
418 insertion_sibling_path),
419 "Leaf value is GTE low leaf next value");
#define EXPECT_THROW_WITH_MESSAGE(code, expectedMessageRegex)
#define DOM_SEP__NULLIFIER_MERKLE
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