Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
nullifier_exists.test.cpp
Go to the documentation of this file.
1#include <gtest/gtest.h>
2
3#include <cstdint>
4
22
23namespace bb::avm2::constraining {
24namespace {
25
26using tracegen::ExecutionTraceBuilder;
27using tracegen::IndexedTreeCheckTraceBuilder;
28using tracegen::TestTraceContainer;
29
30using simulation::DeduplicatingEventEmitter;
31using simulation::EventEmitter;
32using simulation::FieldGreaterThan;
33using simulation::FieldGreaterThanEvent;
34using simulation::IndexedTreeCheck;
36using simulation::IndexedTreeLeafData;
37using simulation::MockMerkleCheck;
38using simulation::MockPoseidon2;
39using simulation::MockRangeCheck;
42
43using testing::NiceMock;
44
46using C = Column;
47using nullifier_exists = bb::avm2::nullifier_exists<FF>;
49
50TEST(NullifierExistsConstrainingTest, PositiveTest)
51{
52 TestTraceContainer trace({ { { C::execution_sel, 1 },
53 { C::execution_sel_execute_nullifier_exists, 1 },
54 { C::execution_register_0_, /*siloed_nullifier=*/FF(0x123456) },
55 { C::execution_register_1_, /*exists=*/1 },
56 { C::execution_prev_nullifier_tree_root, FF(0xabc) },
57 { C::execution_mem_tag_reg_0_, static_cast<uint8_t>(MemoryTag::FF) },
58 { C::execution_mem_tag_reg_1_, static_cast<uint8_t>(MemoryTag::U1) },
59 { C::execution_nullifier_tree_height, NULLIFIER_TREE_HEIGHT },
60 { C::execution_sel_opcode_error, 0 },
61 { C::execution_subtrace_operation_id, AVM_EXEC_OP_ID_NULLIFIER_EXISTS } } });
62 check_relation<nullifier_exists>(trace);
63}
64
65TEST(NullifierExistsConstrainingTest, PositiveNullifierNotExists)
66{
67 TestTraceContainer trace({ { { C::execution_sel, 1 },
68 { C::execution_sel_execute_nullifier_exists, 1 },
69 { C::execution_register_0_, /*siloed_nullifier=*/FF(0x123456) },
70 { C::execution_register_1_, /*exists=*/0 }, // nullifier does not exist!
71 { C::execution_prev_nullifier_tree_root, FF(0xabc) },
72 { C::execution_mem_tag_reg_0_, static_cast<uint8_t>(MemoryTag::FF) },
73 { C::execution_mem_tag_reg_1_, static_cast<uint8_t>(MemoryTag::U1) },
74 { C::execution_nullifier_tree_height, NULLIFIER_TREE_HEIGHT },
75 { C::execution_sel_opcode_error, 0 },
76 { C::execution_subtrace_operation_id, AVM_EXEC_OP_ID_NULLIFIER_EXISTS } } });
77 check_relation<nullifier_exists>(trace);
78}
79
80TEST(NullifierExistsConstrainingTest, NegativeInvalidOutputTag)
81{
82 TestTraceContainer trace({ { { C::execution_sel, 1 },
83 { C::execution_sel_execute_nullifier_exists, 1 },
84 { C::execution_register_0_, /*siloed_nullifier=*/FF(0x123456) },
85 { C::execution_register_1_, /*exists=*/0 }, // nullifier does not exist!
86 { C::execution_prev_nullifier_tree_root, FF(0xabc) },
87 { C::execution_mem_tag_reg_0_, static_cast<uint8_t>(MemoryTag::FF) },
88 { C::execution_mem_tag_reg_1_, static_cast<uint8_t>(MemoryTag::U8) }, // WRONG!
89 { C::execution_nullifier_tree_height, NULLIFIER_TREE_HEIGHT },
90 { C::execution_sel_opcode_error, 0 },
91 { C::execution_subtrace_operation_id, AVM_EXEC_OP_ID_NULLIFIER_EXISTS } } });
93 check_relation<nullifier_exists>(trace, nullifier_exists::SR_NULLIFIER_EXISTS_U1_OUTPUT_TAG),
94 "NULLIFIER_EXISTS_U1_OUTPUT_TAG");
95}
96
97TEST(NullifierExistsConstrainingTest, NegativeNullifierExistsSuccess)
98{
99 TestTraceContainer trace({ {
100 { C::execution_sel_execute_nullifier_exists, 1 },
101 { C::execution_sel_opcode_error, 1 },
102 } });
103
105 "INFALLIBLE_OPCODES_SUCCESS");
106}
107
108TEST(NullifierExistsConstrainingTest, Interactions)
109{
110 NiceMock<MockPoseidon2> poseidon2;
111 NiceMock<MockMerkleCheck> merkle_check;
112
113 NiceMock<MockRangeCheck> range_check;
114 DeduplicatingEventEmitter<FieldGreaterThanEvent> event_emitter;
115 FieldGreaterThan field_gt(range_check, event_emitter);
116
117 EventEmitter<IndexedTreeCheckEvent> indexed_tree_check_event_emitter;
119
120 // Siloed nullifier (no siloing happens in the opcode now)
121 FF siloed_nullifier = 42;
122
123 // For exists=true, the low leaf's nullifier must match the searched nullifier
124 IndexedTreeLeafData low_leaf = {
125 .value = siloed_nullifier,
126 .next_value = 0,
127 .next_index = 0,
128 };
129
130 AppendOnlyTreeSnapshot nullifier_tree_snapshot = AppendOnlyTreeSnapshot{
131 .root = 42,
132 .next_available_leaf_index = 128,
133 };
134
135 std::vector<FF> sibling_path(NULLIFIER_TREE_HEIGHT);
136
137 // sel_silo=false
138 indexed_tree_check.assert_read(siloed_nullifier,
139 /*siloing_params=*/std::nullopt,
140 /*exists=*/true,
141 low_leaf,
142 0,
143 sibling_path,
144 nullifier_tree_snapshot);
145
146 TestTraceContainer trace({ {
147 { C::execution_sel_execute_nullifier_exists, 1 },
148 { C::execution_register_0_, siloed_nullifier },
149 { C::execution_register_1_, /*exists=*/1 },
150 { C::execution_mem_tag_reg_0_, static_cast<uint8_t>(MemoryTag::FF) },
151 { C::execution_mem_tag_reg_1_, static_cast<uint8_t>(MemoryTag::U1) },
152 { C::execution_prev_nullifier_tree_root, nullifier_tree_snapshot.root },
153 { C::execution_nullifier_tree_height, NULLIFIER_TREE_HEIGHT },
154 { C::execution_sel_opcode_error, 0 },
155 { C::execution_subtrace_operation_id, AVM_EXEC_OP_ID_NULLIFIER_EXISTS },
156 } });
157
158 IndexedTreeCheckTraceBuilder indexed_tree_check_trace_builder;
159 indexed_tree_check_trace_builder.process(indexed_tree_check_event_emitter.dump_events(), trace);
160
161 check_relation<nullifier_exists>(trace);
162
163 check_interaction<ExecutionTraceBuilder, lookup_nullifier_exists_nullifier_exists_check_settings>(trace);
164}
165
166// TODO(dbanks12): interaction tests
167
168} // namespace
169} // namespace bb::avm2::constraining
#define EXPECT_THROW_WITH_MESSAGE(code, expectedMessageRegex)
Definition assert.hpp:193
#define AVM_EXEC_OP_ID_NULLIFIER_EXISTS
#define NULLIFIER_TREE_HEIGHT
FieldGreaterThan field_gt
MerkleCheck merkle_check
IndexedTreeCheck indexed_tree_check
EventEmitter< simulation::IndexedTreeCheckEvent > indexed_tree_check_event_emitter
RangeCheck range_check
static constexpr size_t SR_INFALLIBLE_OPCODES_SUCCESS
Definition execution.hpp:78
static constexpr size_t SR_NULLIFIER_EXISTS_U1_OUTPUT_TAG
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.
Native Poseidon2 hash function implementation.
Definition poseidon2.hpp:22
EventEmitter< DataCopyEvent > event_emitter
TestTraceContainer trace
IndexedTreeLeafData low_leaf
TEST(AvmFixedVKTests, FixedVKCommitments)
Test that the fixed VK commitments agree with the ones computed from precomputed columns.
crypto::merkle_tree::IndexedLeaf< crypto::merkle_tree::NullifierLeafValue > NullifierTreeLeafPreimage
Definition db_types.hpp:12
crypto::Poseidon2< crypto::Poseidon2Bn254ScalarFieldParams > poseidon2
std::variant< IndexedTreeReadWriteEvent, CheckPointEventType > IndexedTreeCheckEvent
AvmFlavorSettings::FF FF
Definition field.hpp:10
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
NiceMock< MockExecution > execution