1#include <gmock/gmock.h>
2#include <gtest/gtest.h>
29using ::testing::NiceMock;
30using ::testing::TestWithParam;
32using testing::TestMemoryTree;
34using simulation::EventEmitter;
35using simulation::FieldGreaterThan;
36using simulation::FieldGreaterThanEvent;
37using simulation::IndexedTreeCheck;
39using simulation::IndexedTreeLeafData;
40using simulation::IndexedTreeSiloingParameters;
41using simulation::MerkleCheck;
42using simulation::MerkleCheckEvent;
43using simulation::MockExecutionIdManager;
44using simulation::MockGreaterThan;
45using simulation::MockRangeCheck;
46using simulation::NoopEventEmitter;
47using simulation::Poseidon2;
48using simulation::Poseidon2HashEvent;
49using simulation::Poseidon2PermutationEvent;
50using simulation::Poseidon2PermutationMemoryEvent;
53using tracegen::IndexedTreeCheckTraceBuilder;
54using tracegen::TestTraceContainer;
61TEST(IndexedTreeCheckConstrainingTest, EmptyRow)
74 TestParams{ .value = 42, .exists =
true, .low_leaf = { .value = 42, .next_value = 0, .next_index = 0 } },
76 TestParams{ .value = 42, .exists =
true, .low_leaf = { .value = 42, .next_value = 50, .next_index = 28 } },
78 TestParams{ .value = 42, .exists =
false, .low_leaf = { .value = 10, .next_value = 0, .next_index = 0 } },
80 TestParams{ .value = 42, .exists =
false, .low_leaf = { .value = 10, .next_value = 50, .next_index = 28 } }
83class IndexedTreeReadPositiveTests :
public TestWithParam<TestParams> {};
85TEST_P(IndexedTreeReadPositiveTests, Positive)
87 const auto& param = GetParam();
93 NiceMock<MockGreaterThan>
mock_gt;
94 NiceMock<MockExecutionIdManager> mock_exec_id_manager;
96 NoopEventEmitter<MerkleCheckEvent> merkle_event_emitter;
107 TestTraceContainer
trace({ { { C::precomputed_first_row, 1 } } });
111 uint64_t leaf_index = 30;
112 std::vector<FF> sibling_path;
115 sibling_path.emplace_back(i);
119 indexed_tree_check_simulator.assert_read(param.value,
125 AppendOnlyTreeSnapshot{ .root = root, .next_available_leaf_index = 128 });
130 check_relation<IndexedTreeCheckRelation>(trace);
134 IndexedTreeReadPositiveTests,
135 ::testing::ValuesIn(positive_read_tests));
137TEST(IndexedTreeCheckConstrainingTest, PositiveWriteAppend)
143 NiceMock<MockGreaterThan>
mock_gt;
144 NiceMock<MockExecutionIdManager> mock_exec_id_manager;
146 NoopEventEmitter<MerkleCheckEvent> merkle_event_emitter;
157 TestTraceContainer
trace({ { { C::precomputed_first_row, 1 } } });
164 IndexedTreeLeafData
low_leaf = { .
value = low_value, .next_value =
value + 1, .next_index = 10 };
166 uint64_t low_leaf_index = 0;
167 tree.update_element(low_leaf_index, low_leaf_hash);
169 AppendOnlyTreeSnapshot prev_snapshot =
170 AppendOnlyTreeSnapshot{ .root = tree.root(), .next_available_leaf_index = 128 };
171 std::vector<FF> low_leaf_sibling_path = tree.get_sibling_path(low_leaf_index);
173 IndexedTreeLeafData updated_low_leaf =
low_leaf;
174 updated_low_leaf.
next_index = prev_snapshot.next_available_leaf_index;
175 updated_low_leaf.next_value =
value;
177 tree.update_element(low_leaf_index, updated_low_leaf_hash);
179 std::vector<FF> insertion_sibling_path = tree.get_sibling_path(prev_snapshot.next_available_leaf_index);
181 IndexedTreeLeafData new_leaf = { .value =
value,
185 tree.update_element(prev_snapshot.next_available_leaf_index, new_leaf_hash);
187 indexed_tree_check_simulator.write(
value,
192 low_leaf_sibling_path,
194 insertion_sibling_path);
200 check_relation<IndexedTreeCheckRelation>(trace);
203TEST(IndexedTreeCheckConstrainingTest, PositiveWriteMembership)
206 IndexedTreeLeafData
low_leaf = { .
value = 42, .next_value = 0, .next_index = 0 };
212 NiceMock<MockGreaterThan>
mock_gt;
213 NiceMock<MockExecutionIdManager> mock_exec_id_manager;
215 NoopEventEmitter<MerkleCheckEvent> merkle_event_emitter;
226 TestTraceContainer
trace({ { { C::precomputed_first_row, 1 } } });
230 uint64_t leaf_index = 30;
231 std::vector<FF> sibling_path;
234 sibling_path.emplace_back(i);
238 indexed_tree_check_simulator.write(
value,
244 AppendOnlyTreeSnapshot{ .root = root, .next_available_leaf_index = 128 },
250 check_relation<IndexedTreeCheckRelation>(trace);
253TEST(IndexedTreeCheckConstrainingTest, Siloing)
258 IndexedTreeLeafData
low_leaf = { .
value = siloed_value, .next_value = 0, .next_index = 0 };
264 NiceMock<MockGreaterThan>
mock_gt;
265 NiceMock<MockExecutionIdManager> mock_exec_id_manager;
267 NoopEventEmitter<MerkleCheckEvent> merkle_event_emitter;
278 TestTraceContainer
trace({ { { C::precomputed_first_row, 1 } } });
282 uint64_t leaf_index = 30;
283 std::vector<FF> sibling_path;
286 sibling_path.emplace_back(i);
290 indexed_tree_check_simulator.write(
297 AppendOnlyTreeSnapshot{ .root = root, .next_available_leaf_index = 128 },
303 check_relation<IndexedTreeCheckRelation>(trace);
306TEST(IndexedTreeCheckConstrainingTest, NegativeExistsFlagCheck)
310 TestTraceContainer
trace({
311 { { C::indexed_tree_check_sel, 1 },
312 { C::indexed_tree_check_siloed_value, 27 },
313 { C::indexed_tree_check_low_leaf_value, 27 },
314 { C::indexed_tree_check_value_low_leaf_value_diff_inv, 0 },
315 { C::indexed_tree_check_exists, 1 } },
316 { { C::indexed_tree_check_sel, 1 },
317 { C::indexed_tree_check_siloed_value, 28 },
318 { C::indexed_tree_check_low_leaf_value, 27 },
319 { C::indexed_tree_check_value_low_leaf_value_diff_inv,
FF(1).invert() },
320 { C::indexed_tree_check_exists, 0 } },
323 check_relation<IndexedTreeCheckRelation>(trace, IndexedTreeCheckRelation::SR_EXISTS_CHECK);
324 trace.
set(C::indexed_tree_check_exists, 0, 0);
327 check_relation<IndexedTreeCheckRelation>(trace, IndexedTreeCheckRelation::SR_EXISTS_CHECK),
"EXISTS_CHECK");
328 trace.
set(C::indexed_tree_check_exists, 0, 1);
329 trace.
set(C::indexed_tree_check_exists, 1, 1);
332 check_relation<IndexedTreeCheckRelation>(trace, IndexedTreeCheckRelation::SR_EXISTS_CHECK),
"EXISTS_CHECK");
335TEST(IndexedTreeCheckConstrainingTest, NegativeNextValueIsZero)
339 TestTraceContainer
trace({
341 { C::indexed_tree_check_not_exists, 1 },
342 { C::indexed_tree_check_low_leaf_next_value, 0 },
343 { C::indexed_tree_check_next_value_inv, 0 },
344 { C::indexed_tree_check_next_value_is_nonzero, 0 },
347 { C::indexed_tree_check_not_exists, 1 },
348 { C::indexed_tree_check_low_leaf_next_value, 1 },
349 { C::indexed_tree_check_next_value_inv,
FF(1).invert() },
350 { C::indexed_tree_check_next_value_is_nonzero, 1 },
354 check_relation<IndexedTreeCheckRelation>(trace, IndexedTreeCheckRelation::SR_NEXT_VALUE_IS_ZERO_CHECK);
356 trace.
set(C::indexed_tree_check_next_value_is_nonzero, 0, 1);
359 check_relation<IndexedTreeCheckRelation>(trace, IndexedTreeCheckRelation::SR_NEXT_VALUE_IS_ZERO_CHECK),
360 "NEXT_VALUE_IS_ZERO_CHECK");
362 trace.
set(C::indexed_tree_check_next_value_is_nonzero, 0, 0);
363 trace.
set(C::indexed_tree_check_next_value_is_nonzero, 1, 0);
366 check_relation<IndexedTreeCheckRelation>(trace, IndexedTreeCheckRelation::SR_NEXT_VALUE_IS_ZERO_CHECK),
367 "NEXT_VALUE_IS_ZERO_CHECK");
370TEST(IndexedTreeCheckConstrainingTest, NegativePassthroughSiloing)
373 TestTraceContainer
trace({
375 { C::indexed_tree_check_sel, 1 },
376 { C::indexed_tree_check_sel_silo, 1 },
377 { C::indexed_tree_check_value, 27 },
378 { C::indexed_tree_check_siloed_value, 42 },
381 { C::indexed_tree_check_sel, 1 },
382 { C::indexed_tree_check_sel_silo, 0 },
383 { C::indexed_tree_check_value, 27 },
384 { C::indexed_tree_check_siloed_value, 27 },
388 check_relation<IndexedTreeCheckRelation>(trace, IndexedTreeCheckRelation::SR_PASSTHROUGH_SILOING);
390 trace.
set(C::indexed_tree_check_siloed_value, 1, 28);
393 check_relation<IndexedTreeCheckRelation>(trace, IndexedTreeCheckRelation::SR_PASSTHROUGH_SILOING),
394 "PASSTHROUGH_SILOING");
#define EXPECT_THROW_WITH_MESSAGE(code, expectedMessageRegex)
#define DOM_SEP__SILOED_NULLIFIER
#define NULLIFIER_TREE_HEIGHT
StrictMock< MockGreaterThan > mock_gt
EventEmitter< Poseidon2PermutationMemoryEvent > perm_mem_event_emitter
EventEmitter< Poseidon2PermutationEvent > perm_event_emitter
EventEmitter< Poseidon2HashEvent > hash_event_emitter
FieldGreaterThan field_gt
IndexedTreeCheckTraceBuilder indexed_tree_check_builder
EventEmitter< simulation::IndexedTreeCheckEvent > indexed_tree_check_event_emitter
void process(const simulation::EventEmitterInterface< simulation::IndexedTreeCheckEvent >::Container &events, TraceContainer &trace)
Process generic indexed tree check events and populate the relevant columns in the trace.
uint32_t get_num_rows() const
void set(Column col, uint32_t row, const FF &value)
static FF hash(const std::vector< FF > &input)
Hashes a vector of field elements.
IndexedTreeLeafData low_leaf
TEST_P(AvmRecursiveTestsParameterized, TwoLayerAvmRecursion)
A test of the Two Layer AVM recursive verifier.
INSTANTIATE_TEST_SUITE_P(PaddingVariants, AvmRecursiveTestsParameterized, ::testing::Values(false, true), [](const auto &info) { return info.param ? "Padded" :"Unpadded";})
TEST(AvmFixedVKTests, FixedVKCommitments)
Test that the fixed VK commitments agree with the ones computed from precomputed columns.
crypto::Poseidon2< crypto::Poseidon2Bn254ScalarFieldParams > poseidon2
FF unconstrained_root_from_path(const FF &leaf_value, const uint64_t leaf_index, std::span< const FF > path)
std::variant< IndexedTreeReadWriteEvent, CheckPointEventType > IndexedTreeCheckEvent
TestTraceContainer empty_trace()
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
NoopEventEmitter< FieldGreaterThanEvent > field_gt_event_emitter
std::vector< FF > get_hash_inputs() const