1#include <gmock/gmock.h>
2#include <gtest/gtest.h>
26using ::testing::NiceMock;
28using simulation::EventEmitter;
29using simulation::MerkleCheck;
30using simulation::MerkleCheckEvent;
31using simulation::MockExecutionIdManager;
32using simulation::MockGreaterThan;
33using simulation::NoopEventEmitter;
34using simulation::Poseidon2;
35using simulation::Poseidon2HashEvent;
36using simulation::Poseidon2PermutationEvent;
37using simulation::Poseidon2PermutationMemoryEvent;
40using tracegen::MerkleCheckTraceBuilder;
41using tracegen::Poseidon2TraceBuilder;
42using tracegen::TestTraceContainer;
49TEST(MerkleCheckConstrainingTest, EmptyRow)
54TEST(MerkleCheckConstrainingTest, TraceContinuity)
57 TestTraceContainer
trace({
58 { { C::precomputed_first_row, 1 }, { C::merkle_check_sel, 0 } },
59 { { C::merkle_check_sel, 1 } },
60 { { C::merkle_check_sel, 1 } },
61 { { C::merkle_check_sel, 0 } },
62 { { C::merkle_check_sel, 0 } },
67 const uint32_t last_row_idx = 4;
69 trace.
set(C::merkle_check_sel, last_row_idx, 1);
75TEST(MerkleCheckConstrainingTest, EndCannotBeOneOnFirstRow)
78 TestTraceContainer
trace({
80 { { C::precomputed_first_row, 1 }, { C::merkle_check_sel, 0 }, { C::merkle_check_end, 0 } },
84 check_relation<merkle_check>(
trace);
87 trace.
set(C::merkle_check_sel, 0, 1);
88 trace.
set(C::merkle_check_end, 0, 1);
93TEST(MerkleCheckConstrainingTest, StartAfterLatch)
97 TestTraceContainer
trace({
98 { { C::merkle_check_sel, 1 },
99 { C::merkle_check_start, 0 },
100 { C::merkle_check_end, 1 } },
101 { { C::merkle_check_sel, 1 }, { C::merkle_check_start, 1 } },
107 TestTraceContainer trace2({
108 { { C::precomputed_first_row, 1 }, { C::merkle_check_sel, 0 } },
109 { { C::merkle_check_sel, 1 }, { C::merkle_check_start, 1 } },
115 trace.
set(C::merkle_check_start, 1, 0);
118 "START_AFTER_LATCH");
121TEST(MerkleCheckConstrainingTest, SelectorOnEnd)
125 TestTraceContainer
trace({
126 { { C::merkle_check_end, 1 }, { C::merkle_check_sel, 1 } },
132 trace.
set(C::merkle_check_sel, 0, 0);
137TEST(MerkleCheckConstrainingTest, PropagateReadRoot)
142 TestTraceContainer
trace({
143 { { C::merkle_check_sel, 1 }, { C::merkle_check_end, 0 }, { C::merkle_check_read_root, 123 } },
145 { { C::merkle_check_sel, 1 }, { C::merkle_check_end, 1 }, { C::merkle_check_read_root, 123 } },
147 { { C::merkle_check_sel, 1 }, { C::merkle_check_end, 1 }, { C::merkle_check_read_root, 456 } },
153 trace.
set(C::merkle_check_read_root, 1, 456);
156 "PROPAGATE_READ_ROOT");
159TEST(MerkleCheckConstrainingTest, PropagateWriteRoot)
164 TestTraceContainer
trace({
165 { { C::merkle_check_sel, 1 }, { C::merkle_check_end, 0 }, { C::merkle_check_write_root, 123 } },
167 { { C::merkle_check_sel, 1 }, { C::merkle_check_end, 1 }, { C::merkle_check_write_root, 123 } },
169 { { C::merkle_check_sel, 1 }, { C::merkle_check_end, 1 }, { C::merkle_check_write_root, 456 } },
175 trace.
set(C::merkle_check_write_root, 1, 456);
178 "PROPAGATE_WRITE_ROOT");
181TEST(MerkleCheckConstrainingTest, PropagateWrite)
186 TestTraceContainer
trace({
187 { { C::merkle_check_sel, 1 }, { C::merkle_check_end, 0 }, { C::merkle_check_write, 1 } },
189 { { C::merkle_check_sel, 1 }, { C::merkle_check_end, 1 }, { C::merkle_check_write, 1 } },
191 { { C::merkle_check_sel, 1 }, { C::merkle_check_end, 1 }, { C::merkle_check_write, 0 } },
197 trace.
set(C::merkle_check_write, 1, 0);
202TEST(MerkleCheckConstrainingTest, PathLenDecrements)
204 TestTraceContainer
trace({
206 { { C::merkle_check_sel, 1 }, { C::merkle_check_end, 0 }, { C::merkle_check_path_len, 3 } },
207 { { C::merkle_check_sel, 1 }, { C::merkle_check_end, 0 }, { C::merkle_check_path_len, 2 } },
208 { { C::merkle_check_sel, 1 }, { C::merkle_check_end, 1 }, { C::merkle_check_path_len, 1 } },
210 { { C::merkle_check_sel, 1 }, { C::merkle_check_end, 1 }, { C::merkle_check_path_len, 5 } },
216 trace.
set(C::merkle_check_path_len, 1, 1);
219 "PATH_LEN_DECREMENTS");
222TEST(MerkleCheckConstrainingTest, EndWhenPathLenOne)
224 TestTraceContainer
trace({
225 { { C::merkle_check_sel, 1 },
226 { C::merkle_check_path_len, 2 },
227 { C::merkle_check_remaining_path_len_inv,
FF(1).invert() },
228 { C::merkle_check_end, 0 } },
229 { { C::merkle_check_sel, 1 },
230 { C::merkle_check_path_len, 1 },
231 { C::merkle_check_remaining_path_len_inv, 0 },
232 { C::merkle_check_end, 1 } },
238 trace.
set(C::merkle_check_end, 1, 0);
241 "END_WHEN_PATH_EMPTY");
244TEST(MerkleCheckConstrainingTest, NextIndexIsHalved)
246 TestTraceContainer
trace({
247 { { C::merkle_check_sel, 1 },
248 { C::merkle_check_end, 0 },
249 { C::merkle_check_index, 6 },
250 { C::merkle_check_index_is_even, 1 } },
251 { { C::merkle_check_sel, 1 },
252 { C::merkle_check_end, 0 },
253 { C::merkle_check_index, 3 },
254 { C::merkle_check_index_is_even, 0 } },
255 { { C::merkle_check_sel, 1 },
256 { C::merkle_check_end, 1 },
257 { C::merkle_check_index, 1 },
258 { C::merkle_check_index_is_even, 0 } },
264 TestTraceContainer trace2({
265 { { C::merkle_check_sel, 1 },
266 { C::merkle_check_end, 0 },
267 { C::merkle_check_index, 7 },
268 { C::merkle_check_index_is_even, 0 } },
269 { { C::merkle_check_sel, 1 },
270 { C::merkle_check_end, 0 },
271 { C::merkle_check_index, 3 },
272 { C::merkle_check_index_is_even, 0 } },
273 { { C::merkle_check_sel, 1 },
274 { C::merkle_check_end, 1 },
275 { C::merkle_check_index, 1 },
276 { C::merkle_check_index_is_even, 0 } },
282 trace2.set(C::merkle_check_index, 1, 4);
285 "NEXT_INDEX_IS_HALVED");
288TEST(MerkleCheckConstrainingTest, AssignCurrentReadNodeLeftOrRight)
291 TestTraceContainer
trace({
292 { { C::merkle_check_sel, 1 },
293 { C::merkle_check_index_is_even, 1 },
294 { C::merkle_check_read_node, 123 },
295 { C::merkle_check_sibling, 456 },
296 { C::merkle_check_read_left_node, 123 },
297 { C::merkle_check_read_right_node, 456 } },
303 TestTraceContainer trace2({
304 { { C::merkle_check_sel, 1 },
305 { C::merkle_check_index_is_even, 0 },
306 { C::merkle_check_read_node, 123 },
307 { C::merkle_check_sibling, 456 },
308 { C::merkle_check_read_left_node, 456 },
309 { C::merkle_check_read_right_node, 123 } },
315 trace2.set(C::merkle_check_read_left_node, 0, 123);
316 trace2.set(C::merkle_check_read_right_node, 0, 456);
319 "ASSIGN_NODE_LEFT_OR_RIGHT_READ");
322TEST(MerkleCheckConstrainingTest, AssignCurrentWriteNodeLeftOrRight)
325 TestTraceContainer
trace({
326 { { C::merkle_check_write, 1 },
327 { C::merkle_check_index_is_even, 1 },
328 { C::merkle_check_write_node, 123 },
329 { C::merkle_check_sibling, 456 },
330 { C::merkle_check_write_left_node, 123 },
331 { C::merkle_check_write_right_node, 456 } },
337 TestTraceContainer trace2({
338 { { C::merkle_check_write, 1 },
339 { C::merkle_check_index_is_even, 0 },
340 { C::merkle_check_write_node, 123 },
341 { C::merkle_check_sibling, 456 },
342 { C::merkle_check_write_left_node, 456 },
343 { C::merkle_check_write_right_node, 123 } },
349 trace2.set(C::merkle_check_write_left_node, 0, 123);
350 trace2.set(C::merkle_check_write_right_node, 0, 456);
353 "ASSIGN_NODE_LEFT_OR_RIGHT_WRITE");
356TEST(MerkleCheckConstrainingTest, AssignSiblingLeftOrRightRead)
359 TestTraceContainer
trace({
360 { { C::merkle_check_sel, 1 },
361 { C::merkle_check_index_is_even, 1 },
362 { C::merkle_check_read_node, 123 },
363 { C::merkle_check_sibling, 456 },
364 { C::merkle_check_read_left_node, 123 },
365 { C::merkle_check_read_right_node, 456 } },
371 TestTraceContainer trace2({
372 { { C::merkle_check_sel, 1 },
373 { C::merkle_check_index_is_even, 0 },
374 { C::merkle_check_read_node, 123 },
375 { C::merkle_check_sibling, 456 },
376 { C::merkle_check_read_left_node, 456 },
377 { C::merkle_check_read_right_node, 123 } },
383 trace2.set(C::merkle_check_read_left_node, 0, 123);
384 trace2.set(C::merkle_check_read_right_node, 0, 456);
387 "ASSIGN_SIBLING_LEFT_OR_RIGHT_READ");
390TEST(MerkleCheckConstrainingTest, AssignSiblingLeftOrRightWrite)
393 TestTraceContainer
trace({
394 { { C::merkle_check_write, 1 },
395 { C::merkle_check_index_is_even, 1 },
396 { C::merkle_check_write_node, 123 },
397 { C::merkle_check_sibling, 456 },
398 { C::merkle_check_write_left_node, 123 },
399 { C::merkle_check_write_right_node, 456 } },
405 TestTraceContainer trace2({
406 { { C::merkle_check_write, 1 },
407 { C::merkle_check_index_is_even, 0 },
408 { C::merkle_check_write_node, 123 },
409 { C::merkle_check_sibling, 456 },
410 { C::merkle_check_write_left_node, 456 },
411 { C::merkle_check_write_right_node, 123 } },
417 trace2.set(C::merkle_check_write_left_node, 0, 123);
418 trace2.set(C::merkle_check_write_right_node, 0, 456);
421 "ASSIGN_SIBLING_LEFT_OR_RIGHT_WRITE");
424TEST(MerkleCheckConstrainingTest, ReadOutputHashIsNextRowsNode)
426 FF left_node =
FF(123);
427 FF right_node =
FF(456);
428 FF output_hash = UnconstrainedPoseidon2::hash({ left_node, right_node });
430 TestTraceContainer
trace({
431 { { C::merkle_check_sel, 1 },
432 { C::merkle_check_end, 0 },
433 { C::merkle_check_read_node, left_node },
434 { C::merkle_check_read_right_node, right_node },
435 { C::merkle_check_read_output_hash, output_hash } },
436 { { C::merkle_check_sel, 1 },
437 { C::merkle_check_end, 1 },
438 { C::merkle_check_read_node, output_hash } },
444 trace.
set(C::merkle_check_read_node, 1, output_hash + 1);
447 "OUTPUT_HASH_IS_NEXT_ROWS_READ_NODE");
450TEST(MerkleCheckConstrainingTest, WriteOutputHashIsNextRowsNode)
452 FF left_node =
FF(123);
453 FF right_node =
FF(456);
454 FF output_hash = UnconstrainedPoseidon2::hash({ left_node, right_node });
456 TestTraceContainer
trace({
457 { { C::merkle_check_sel, 1 },
458 { C::merkle_check_end, 0 },
459 { C::merkle_check_write_node, left_node },
460 { C::merkle_check_write_right_node, right_node },
461 { C::merkle_check_write_output_hash, output_hash } },
462 { { C::merkle_check_sel, 1 },
463 { C::merkle_check_end, 1 },
464 { C::merkle_check_write_node, output_hash } },
470 trace.
set(C::merkle_check_write_node, 1, output_hash + 1);
473 "OUTPUT_HASH_IS_NEXT_ROWS_WRITE_NODE");
476TEST(MerkleCheckConstrainingTest, OutputHashIsNotNextRowsCurrentNodeValueForLastRow)
478 FF output_hash =
FF(456);
479 FF next_current_node =
FF(789);
481 TestTraceContainer
trace({
482 { { C::merkle_check_sel, 1 },
483 { C::merkle_check_end, 1 },
484 { C::merkle_check_read_output_hash, output_hash },
485 { C::merkle_check_write_output_hash, output_hash } },
486 { { C::merkle_check_sel, 1 },
487 { C::merkle_check_read_node, next_current_node },
488 { C::merkle_check_write_node, next_current_node } },
495TEST(MerkleCheckConstrainingTest, ReadWithTracegen)
498 { .precomputed_first_row = 1 },
500 MerkleCheckTraceBuilder
builder;
503 FF leaf_value =
FF(123);
504 uint64_t leaf_index = 5;
507 std::vector<FF> sibling_path = {
FF(456),
FF(789),
FF(3333) };
512 MerkleCheckEvent
event = {
513 .leaf_value = leaf_value, .leaf_index = leaf_index, .sibling_path = sibling_path, .root = root
519 check_relation<merkle_check>(
trace);
524 trace.
set(C::merkle_check_path_len, last_row, 66);
529TEST(MerkleCheckConstrainingTest, WriteWithTracegen)
532 { .precomputed_first_row = 1 },
534 MerkleCheckTraceBuilder
builder;
537 FF leaf_value =
FF(123);
538 FF new_leaf_value =
FF(456);
539 uint64_t leaf_index = 5;
542 std::vector<FF> sibling_path = {
FF(456),
FF(789),
FF(3333) };
549 MerkleCheckEvent
event = { .leaf_value = leaf_value,
550 .new_leaf_value = new_leaf_value,
551 .leaf_index = leaf_index,
552 .sibling_path = sibling_path,
554 .new_root = new_root };
559 check_relation<merkle_check>(
trace);
562class MerkleCheckPoseidon2Test :
public ::testing::Test {
564 MerkleCheckPoseidon2Test() =
default;
573 Poseidon2(execution_id_manager, mock_gt, hash_event_emitter, perm_event_emitter, perm_mem_event_emitter);
576TEST_F(MerkleCheckPoseidon2Test, ReadWithInteractions)
578 EventEmitter<MerkleCheckEvent> merkle_event_emitter;
579 MerkleCheck merkle_check_sim(
poseidon2, merkle_event_emitter);
581 TestTraceContainer
trace({ { { C::precomputed_first_row, 1 } } });
582 Poseidon2TraceBuilder poseidon2_builder;
583 MerkleCheckTraceBuilder merkle_check_builder;
586 uint64_t leaf_index = 30;
587 std::vector<FF> sibling_path = { 10, 2, 30, 4, 50, 6 };
589 merkle_check_sim.assert_membership(leaf_value, leaf_index, sibling_path, root);
592 merkle_check_builder.process(merkle_event_emitter.dump_events(),
trace);
598 check_relation<merkle_check>(
trace);
601 trace.
set(Column::merkle_check_read_output_hash,
static_cast<uint32_t
>(sibling_path.size()), 66);
604 (check_interaction<MerkleCheckTraceBuilder, lookup_merkle_check_merkle_poseidon2_read_settings>(
trace)),
605 "Failed.*LOOKUP_MERKLE_CHECK_MERKLE_POSEIDON2.* Could not find tuple in destination");
606 check_interaction<MerkleCheckTraceBuilder, lookup_merkle_check_merkle_poseidon2_write_settings>(
trace);
609TEST_F(MerkleCheckPoseidon2Test, WriteWithInteractions)
611 EventEmitter<MerkleCheckEvent> merkle_event_emitter;
612 MerkleCheck merkle_check_sim(
poseidon2, merkle_event_emitter);
614 TestTraceContainer
trace({ { { C::precomputed_first_row, 1 } } });
615 Poseidon2TraceBuilder poseidon2_builder;
616 MerkleCheckTraceBuilder merkle_check_builder;
619 FF new_leaf_value = 444;
620 uint64_t leaf_index = 30;
621 std::vector<FF> sibling_path = { 10, 2, 30, 4, 50, 6 };
625 FF new_root = merkle_check_sim.write(leaf_value, new_leaf_value, leaf_index, sibling_path, root);
627 EXPECT_EQ(new_root, expected_new_root);
630 merkle_check_builder.process(merkle_event_emitter.dump_events(),
trace);
636 check_relation<merkle_check>(
trace);
639 trace.
set(Column::merkle_check_read_output_hash,
static_cast<uint32_t
>(sibling_path.size()), 66);
640 trace.
set(Column::merkle_check_write_output_hash,
static_cast<uint32_t
>(sibling_path.size()), 77);
643 (check_interaction<MerkleCheckTraceBuilder, lookup_merkle_check_merkle_poseidon2_read_settings>(
trace)),
644 "Failed.*LOOKUP_MERKLE_CHECK_MERKLE_POSEIDON2.* Could not find tuple in destination");
647 (check_interaction<MerkleCheckTraceBuilder, lookup_merkle_check_merkle_poseidon2_write_settings>(
trace)),
648 "Failed.*LOOKUP_MERKLE_CHECK_MERKLE_POSEIDON2_WRITE.* Could not find tuple in "
652TEST_F(MerkleCheckPoseidon2Test, MultipleWithTracegen)
655 { .precomputed_first_row = 1 },
657 MerkleCheckTraceBuilder
builder;
660 uint64_t leaf_index = 30;
661 std::vector<FF> sibling_path = { 10, 2, 30, 4, 50, 6 };
663 MerkleCheckEvent
event = {
664 .leaf_value = leaf_value, .leaf_index = leaf_index, .sibling_path = sibling_path, .root = root
667 FF leaf_value2 = 444;
668 FF new_leaf_value2 = 555;
669 uint64_t leaf_index2 = 40;
670 std::vector<FF> sibling_path2 = { 11, 22, 33, 44, 55, 66 };
673 MerkleCheckEvent event2 = { .leaf_value = leaf_value2,
674 .new_leaf_value = new_leaf_value2,
675 .leaf_index = leaf_index2,
676 .sibling_path = sibling_path2,
678 .new_root = new_root2 };
683 uint32_t after_last_row_index = 1 +
static_cast<uint32_t
>(sibling_path.size() + sibling_path2.size());
684 trace.
set(Column::merkle_check_sel, after_last_row_index, 0);
685 trace.
set(Column::merkle_check_write, after_last_row_index, 0);
686 trace.
set(Column::merkle_check_read_node, after_last_row_index, 0);
687 trace.
set(Column::merkle_check_write_node, after_last_row_index, 0);
688 trace.
set(Column::merkle_check_index, after_last_row_index, 0);
689 trace.
set(Column::merkle_check_path_len, after_last_row_index, 0);
690 trace.
set(Column::merkle_check_remaining_path_len_inv, after_last_row_index, 0);
691 trace.
set(Column::merkle_check_read_root, after_last_row_index, 0);
692 trace.
set(Column::merkle_check_write_root, after_last_row_index, 0);
693 trace.
set(Column::merkle_check_sibling, after_last_row_index, 0);
694 trace.
set(Column::merkle_check_start, after_last_row_index, 0);
695 trace.
set(Column::merkle_check_end, after_last_row_index, 0);
696 trace.
set(Column::merkle_check_index_is_even, after_last_row_index, 0);
697 trace.
set(Column::merkle_check_read_left_node, after_last_row_index, 0);
698 trace.
set(Column::merkle_check_read_right_node, after_last_row_index, 0);
699 trace.
set(Column::merkle_check_write_left_node, after_last_row_index, 0);
700 trace.
set(Column::merkle_check_write_right_node, after_last_row_index, 0);
701 trace.
set(Column::merkle_check_constant_2, after_last_row_index, 0);
702 trace.
set(Column::merkle_check_read_output_hash, after_last_row_index, 0);
703 trace.
set(Column::merkle_check_write_output_hash, after_last_row_index, 0);
705 check_relation<merkle_check>(
trace);
708TEST_F(MerkleCheckPoseidon2Test, MultipleWithInteractions)
710 EventEmitter<MerkleCheckEvent> merkle_event_emitter;
711 MerkleCheck merkle_check_sim(
poseidon2, merkle_event_emitter);
713 TestTraceContainer
trace({ { { C::precomputed_first_row, 1 } } });
714 MerkleCheckTraceBuilder merkle_check_builder;
715 Poseidon2TraceBuilder poseidon2_builder;
718 uint64_t leaf_index = 30;
719 std::vector<FF> sibling_path = { 10, 2, 30, 4, 50, 6 };
722 merkle_check_sim.assert_membership(leaf_value, leaf_index, sibling_path, root);
724 FF leaf_value2 = 444;
725 FF new_leaf_value2 = 555;
726 uint64_t leaf_index2 = 40;
727 std::vector<FF> sibling_path2 = { 11, 22, 33, 44, 55, 66 };
731 FF new_root2 = merkle_check_sim.write(leaf_value2, new_leaf_value2, leaf_index2, sibling_path2, root2);
732 EXPECT_EQ(new_root2, expected_new_root2);
735 merkle_check_builder.process(merkle_event_emitter.dump_events(),
trace);
741 check_relation<merkle_check>(
trace);
static constexpr size_t SR_END_WHEN_PATH_EMPTY
static constexpr size_t SR_OUTPUT_HASH_IS_NEXT_ROWS_WRITE_NODE
static constexpr size_t SR_PROPAGATE_READ_ROOT
static constexpr size_t SR_ASSIGN_NODE_LEFT_OR_RIGHT_READ
static constexpr size_t SR_PROPAGATE_WRITE
static constexpr size_t SR_TRACE_CONTINUITY
static constexpr size_t SR_NEXT_INDEX_IS_HALVED
static constexpr size_t SR_PROPAGATE_WRITE_ROOT
static constexpr size_t SR_SELECTOR_ON_END
static constexpr size_t SR_PATH_LEN_DECREMENTS
static constexpr size_t SR_ASSIGN_NODE_LEFT_OR_RIGHT_WRITE
static constexpr size_t SR_OUTPUT_HASH_IS_NEXT_ROWS_READ_NODE
static constexpr size_t SR_START_AFTER_LATCH
static constexpr size_t SR_ASSIGN_SIBLING_LEFT_OR_RIGHT_READ
static constexpr size_t SR_ASSIGN_SIBLING_LEFT_OR_RIGHT_WRITE
static TestTraceContainer from_rows(const std::vector< AvmFullRow > &rows)
uint32_t get_num_rows() const
void set(Column col, uint32_t row, const FF &value)
Implements a parallelized batch insertion indexed tree Accepts template argument of the type of store...
ExecutionIdManager execution_id_manager
NoopEventEmitter< Poseidon2PermutationEvent > perm_event_emitter
NoopEventEmitter< Poseidon2PermutationMemoryEvent > perm_mem_event_emitter
NiceMock< MockGreaterThan > mock_gt
EventEmitter< Poseidon2HashEvent > hash_event_emitter
#define EXPECT_THROW_WITH_MESSAGE(code, expectedMessage)
TEST_F(AvmRecursiveTests, GoblinRecursion)
A test of the Goblinized AVM recursive verifier.
void check_interaction(tracegen::TestTraceContainer &trace)
TEST(TxExecutionConstrainingTest, WriteTreeValue)
FF unconstrained_root_from_path(const FF &leaf_value, const uint64_t leaf_index, std::span< const FF > path)
TestTraceContainer empty_trace()
lookup_settings< lookup_merkle_check_merkle_poseidon2_read_settings_ > lookup_merkle_check_merkle_poseidon2_read_settings
lookup_settings< lookup_merkle_check_merkle_poseidon2_write_settings_ > lookup_merkle_check_merkle_poseidon2_write_settings
simulation::PublicDataTreeReadWriteEvent event