1#include <gmock/gmock.h>
2#include <gtest/gtest.h>
31using ::testing::NiceMock;
32using ::testing::TestWithParam;
34using testing::TestMemoryTree;
36using simulation::EventEmitter;
37using simulation::FieldGreaterThan;
38using simulation::FieldGreaterThanEvent;
39using simulation::IndexedTreeCheck;
41using simulation::IndexedTreeLeafData;
42using simulation::IndexedTreeSiloingParameters;
43using simulation::MerkleCheck;
44using simulation::MerkleCheckEvent;
45using simulation::MockExecutionIdManager;
46using simulation::MockGreaterThan;
47using simulation::MockRangeCheck;
48using simulation::NoopEventEmitter;
49using simulation::Poseidon2;
50using simulation::Poseidon2HashEvent;
51using simulation::Poseidon2PermutationEvent;
52using simulation::Poseidon2PermutationMemoryEvent;
55using tracegen::IndexedTreeCheckTraceBuilder;
56using tracegen::TestTraceContainer;
63TEST(IndexedTreeCheckConstrainingTest, EmptyRow)
76 TestParams{ .value = 42, .exists =
true, .low_leaf = { .value = 42, .next_value = 0, .next_index = 0 } },
78 TestParams{ .value = 42, .exists =
true, .low_leaf = { .value = 42, .next_value = 50, .next_index = 28 } },
80 TestParams{ .value = 42, .exists =
false, .low_leaf = { .value = 10, .next_value = 0, .next_index = 0 } },
82 TestParams{ .value = 42, .exists =
false, .low_leaf = { .value = 10, .next_value = 50, .next_index = 28 } }
85class IndexedTreeReadPositiveTests :
public TestWithParam<TestParams> {};
87TEST_P(IndexedTreeReadPositiveTests, Positive)
89 const auto& param = GetParam();
95 NiceMock<MockGreaterThan>
mock_gt;
96 NiceMock<MockExecutionIdManager> mock_exec_id_manager;
98 NoopEventEmitter<MerkleCheckEvent> merkle_event_emitter;
107 IndexedTreeCheck indexed_tree_check_simulator(
110 TestTraceContainer
trace({ { { C::precomputed_first_row, 1 } } });
114 uint64_t leaf_index = 30;
115 std::vector<FF> sibling_path;
118 sibling_path.emplace_back(i);
122 indexed_tree_check_simulator.assert_read(param.value,
128 AppendOnlyTreeSnapshot{ .root = root, .next_available_leaf_index = 128 });
133 check_relation<IndexedTreeCheckRelation>(trace);
137 IndexedTreeReadPositiveTests,
138 ::testing::ValuesIn(positive_read_tests));
140TEST(IndexedTreeCheckConstrainingTest, PositiveWriteAppend)
146 NiceMock<MockGreaterThan>
mock_gt;
147 NiceMock<MockExecutionIdManager> mock_exec_id_manager;
149 NoopEventEmitter<MerkleCheckEvent> merkle_event_emitter;
158 IndexedTreeCheck indexed_tree_check_simulator(
161 TestTraceContainer
trace({ { { C::precomputed_first_row, 1 } } });
168 IndexedTreeLeafData
low_leaf = { .
value = low_value, .next_value =
value + 1, .next_index = 10 };
170 uint64_t low_leaf_index = 0;
171 tree.update_element(low_leaf_index, low_leaf_hash);
173 AppendOnlyTreeSnapshot prev_snapshot =
174 AppendOnlyTreeSnapshot{ .root = tree.root(), .next_available_leaf_index = 128 };
175 std::vector<FF> low_leaf_sibling_path = tree.get_sibling_path(low_leaf_index);
177 IndexedTreeLeafData updated_low_leaf =
low_leaf;
178 updated_low_leaf.
next_index = prev_snapshot.next_available_leaf_index;
179 updated_low_leaf.next_value =
value;
181 tree.update_element(low_leaf_index, updated_low_leaf_hash);
183 std::vector<FF> insertion_sibling_path = tree.get_sibling_path(prev_snapshot.next_available_leaf_index);
185 IndexedTreeLeafData new_leaf = { .value =
value,
189 tree.update_element(prev_snapshot.next_available_leaf_index, new_leaf_hash);
191 indexed_tree_check_simulator.write(
value,
196 low_leaf_sibling_path,
198 insertion_sibling_path);
204 check_relation<IndexedTreeCheckRelation>(trace);
207TEST(IndexedTreeCheckConstrainingTest, PositiveWriteMembership)
210 IndexedTreeLeafData
low_leaf = { .
value = 42, .next_value = 0, .next_index = 0 };
216 NiceMock<MockGreaterThan>
mock_gt;
217 NiceMock<MockExecutionIdManager> mock_exec_id_manager;
219 NoopEventEmitter<MerkleCheckEvent> merkle_event_emitter;
228 IndexedTreeCheck indexed_tree_check_simulator(
231 TestTraceContainer
trace({ { { C::precomputed_first_row, 1 } } });
235 uint64_t leaf_index = 30;
236 std::vector<FF> sibling_path;
239 sibling_path.emplace_back(i);
243 indexed_tree_check_simulator.write(
value,
249 AppendOnlyTreeSnapshot{ .root = root, .next_available_leaf_index = 128 },
255 check_relation<IndexedTreeCheckRelation>(trace);
258TEST(IndexedTreeCheckConstrainingTest, Siloing)
263 IndexedTreeLeafData
low_leaf = { .
value = siloed_value, .next_value = 0, .next_index = 0 };
269 NiceMock<MockGreaterThan>
mock_gt;
270 NiceMock<MockExecutionIdManager> mock_exec_id_manager;
272 NoopEventEmitter<MerkleCheckEvent> merkle_event_emitter;
281 IndexedTreeCheck indexed_tree_check_simulator(
284 TestTraceContainer
trace({ { { C::precomputed_first_row, 1 } } });
288 uint64_t leaf_index = 30;
289 std::vector<FF> sibling_path;
292 sibling_path.emplace_back(i);
296 indexed_tree_check_simulator.write(
303 AppendOnlyTreeSnapshot{ .root = root, .next_available_leaf_index = 128 },
309 check_relation<IndexedTreeCheckRelation>(trace);
312TEST(IndexedTreeCheckConstrainingTest, NegativeExistsFlagCheck)
316 TestTraceContainer
trace({
317 { { C::indexed_tree_check_sel, 1 },
318 { C::indexed_tree_check_siloed_value, 27 },
319 { C::indexed_tree_check_low_leaf_value, 27 },
320 { C::indexed_tree_check_value_low_leaf_value_diff_inv, 0 },
321 { C::indexed_tree_check_exists, 1 } },
322 { { C::indexed_tree_check_sel, 1 },
323 { C::indexed_tree_check_siloed_value, 28 },
324 { C::indexed_tree_check_low_leaf_value, 27 },
325 { C::indexed_tree_check_value_low_leaf_value_diff_inv,
FF(1).invert() },
326 { C::indexed_tree_check_exists, 0 } },
329 check_relation<IndexedTreeCheckRelation>(trace, IndexedTreeCheckRelation::SR_EXISTS_CHECK);
330 trace.
set(C::indexed_tree_check_exists, 0, 0);
333 check_relation<IndexedTreeCheckRelation>(trace, IndexedTreeCheckRelation::SR_EXISTS_CHECK),
"EXISTS_CHECK");
334 trace.
set(C::indexed_tree_check_exists, 0, 1);
335 trace.
set(C::indexed_tree_check_exists, 1, 1);
338 check_relation<IndexedTreeCheckRelation>(trace, IndexedTreeCheckRelation::SR_EXISTS_CHECK),
"EXISTS_CHECK");
341TEST(IndexedTreeCheckConstrainingTest, NegativeNextValueIsZero)
345 TestTraceContainer
trace({
347 { C::indexed_tree_check_not_exists, 1 },
348 { C::indexed_tree_check_low_leaf_next_value, 0 },
349 { C::indexed_tree_check_next_value_inv, 0 },
350 { C::indexed_tree_check_next_value_is_nonzero, 0 },
353 { C::indexed_tree_check_not_exists, 1 },
354 { C::indexed_tree_check_low_leaf_next_value, 1 },
355 { C::indexed_tree_check_next_value_inv,
FF(1).invert() },
356 { C::indexed_tree_check_next_value_is_nonzero, 1 },
360 check_relation<IndexedTreeCheckRelation>(trace, IndexedTreeCheckRelation::SR_NEXT_VALUE_IS_ZERO_CHECK);
362 trace.
set(C::indexed_tree_check_next_value_is_nonzero, 0, 1);
365 check_relation<IndexedTreeCheckRelation>(trace, IndexedTreeCheckRelation::SR_NEXT_VALUE_IS_ZERO_CHECK),
366 "NEXT_VALUE_IS_ZERO_CHECK");
368 trace.
set(C::indexed_tree_check_next_value_is_nonzero, 0, 0);
369 trace.
set(C::indexed_tree_check_next_value_is_nonzero, 1, 0);
372 check_relation<IndexedTreeCheckRelation>(trace, IndexedTreeCheckRelation::SR_NEXT_VALUE_IS_ZERO_CHECK),
373 "NEXT_VALUE_IS_ZERO_CHECK");
376TEST(IndexedTreeCheckConstrainingTest, NegativePassthroughSiloing)
379 TestTraceContainer
trace({
381 { C::indexed_tree_check_sel, 1 },
382 { C::indexed_tree_check_sel_silo, 1 },
383 { C::indexed_tree_check_value, 27 },
384 { C::indexed_tree_check_siloed_value, 42 },
387 { C::indexed_tree_check_sel, 1 },
388 { C::indexed_tree_check_sel_silo, 0 },
389 { C::indexed_tree_check_value, 27 },
390 { C::indexed_tree_check_siloed_value, 27 },
394 check_relation<IndexedTreeCheckRelation>(trace, IndexedTreeCheckRelation::SR_PASSTHROUGH_SILOING);
396 trace.
set(C::indexed_tree_check_siloed_value, 1, 28);
399 check_relation<IndexedTreeCheckRelation>(trace, IndexedTreeCheckRelation::SR_PASSTHROUGH_SILOING),
400 "PASSTHROUGH_SILOING");
#define EXPECT_THROW_WITH_MESSAGE(code, expectedMessageRegex)
#define DOM_SEP__SILOED_NULLIFIER
#define NULLIFIER_TREE_HEIGHT
#define DOM_SEP__NULLIFIER_MERKLE
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
std::variant< IndexedTreeReadWriteEvent, CheckPointEventType > IndexedTreeCheckEvent
FF unconstrained_root_from_path(uint64_t domain_separator, const FF &leaf_value, const uint64_t leaf_index, std::span< const FF > path)
TestTraceContainer empty_trace()
::testing::Types< TestParam< curve::BN254, 9 >, TestParam< curve::BN254, CHONK_MAX_NUM_CIRCUITS >, TestParam< stdlib::bn254< MegaCircuitBuilder >, 9 >, TestParam< stdlib::bn254< MegaCircuitBuilder >, CHONK_MAX_NUM_CIRCUITS > > TestParams
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
NoopEventEmitter< FieldGreaterThanEvent > field_gt_event_emitter
std::vector< FF > get_hash_inputs() const