1#include <gmock/gmock.h>
2#include <gtest/gtest.h>
27using tracegen::ExecutionTraceBuilder;
28using tracegen::IndexedTreeCheckTraceBuilder;
29using tracegen::TestTraceContainer;
31using simulation::EventEmitter;
32using simulation::IndexedTreeCheck;
34using simulation::IndexedTreeLeafData;
35using simulation::IndexedTreeSiloingParameters;
36using simulation::MockFieldGreaterThan;
37using simulation::MockMerkleCheck;
38using simulation::MockPoseidon2;
39using simulation::MockRangeCheck;
44using testing::StrictMock;
51TEST(EmitNullifierConstrainingTest, Positive)
54 TestTraceContainer
trace({ {
55 { C::execution_sel_execute_emit_nullifier, 1 },
56 { C::execution_register_0_, 42 },
57 { C::execution_mem_tag_reg_0_,
static_cast<uint8_t
>(
MemoryTag::FF) },
59 { C::execution_sel_write_nullifier, 1 },
60 { C::execution_sel_opcode_error, 0 },
62 { C::execution_prev_nullifier_tree_size, 1 },
63 { C::execution_nullifier_tree_size, 2 },
64 { C::execution_prev_num_nullifiers_emitted, prev_num_nullifiers_emitted },
65 { C::execution_nullifier_pi_offset,
67 { C::execution_num_nullifiers_emitted, prev_num_nullifiers_emitted + 1 },
72 check_relation<emit_nullifier>(trace);
75TEST(EmitNullifierConstrainingTest, LimitReached)
78 TestTraceContainer
trace({ {
79 { C::execution_sel_execute_emit_nullifier, 1 },
80 { C::execution_register_0_, 42 },
81 { C::execution_mem_tag_reg_0_,
static_cast<uint8_t
>(
MemoryTag::FF) },
82 { C::execution_sel_reached_max_nullifiers, 1 },
83 { C::execution_remaining_nullifiers_inv, 0 },
84 { C::execution_sel_write_nullifier, 0 },
85 { C::execution_sel_opcode_error, 1 },
87 { C::execution_prev_nullifier_tree_size, 1 },
88 { C::execution_nullifier_tree_size, 1 },
89 { C::execution_prev_num_nullifiers_emitted, prev_num_nullifiers_emitted },
90 { C::execution_nullifier_pi_offset,
92 { C::execution_num_nullifiers_emitted, prev_num_nullifiers_emitted },
94 check_relation<emit_nullifier>(trace);
97 trace.
set(C::execution_sel_reached_max_nullifiers, 0, 0);
99 "MAX_NULLIFIER_WRITES_REACHED");
100 trace.
set(C::execution_sel_reached_max_nullifiers, 0, 1);
103 trace.
set(C::execution_sel_opcode_error, 0, 0);
106 "OPCODE_ERROR_IF_VALIDATION_ERROR");
107 trace.
set(C::execution_sel_opcode_error, 0, 1);
110 trace.
set(C::execution_nullifier_tree_root, 0, 28);
113 "EMIT_NULLIFIER_TREE_ROOT_NOT_CHANGED");
116 trace.
set(C::execution_nullifier_tree_size, 0, 2);
119 "EMIT_NULLIFIER_TREE_SIZE_INCREASE");
122 trace.
set(C::execution_num_nullifiers_emitted, 0, prev_num_nullifiers_emitted + 1);
125 "EMIT_NULLIFIER_NUM_NULLIFIERS_EMITTED_INCREASE");
128TEST(EmitNullifierConstrainingTest, Interactions)
133 StrictMock<MockFieldGreaterThan>
field_gt;
140 auto siloing_params = IndexedTreeSiloingParameters{
141 .address = 0xdeadbeef,
144 FF siloed_nullifier = 66;
145 FF low_leaf_nullifier = 99;
146 FF low_leaf_hash = 77;
147 FF updated_low_leaf_hash = 101;
148 FF new_leaf_hash = 111;
149 FF pre_write_root = 27;
150 FF intermediate_root = 33;
151 FF post_write_root = 88;
154 std::vector<FF> insertion_sibling_path = { 1, 2, 3 };
156 AppendOnlyTreeSnapshot prev_snapshot = AppendOnlyTreeSnapshot{
157 .root = pre_write_root,
158 .next_available_leaf_index = 128,
160 uint32_t prev_num_nullifiers_emitted = 2;
163 EXPECT_CALL(
field_gt, ff_gt).WillOnce(Return(
true));
166 .WillOnce(Return(siloed_nullifier))
167 .WillOnce(Return(low_leaf_hash))
168 .WillOnce(Return(updated_low_leaf_hash))
169 .WillOnce(Return(new_leaf_hash));
171 EXPECT_CALL(merkle_check,
write).WillOnce(Return(intermediate_root)).WillOnce(Return(post_write_root));
174 IndexedTreeLeafData low_leaf_preimage = {
175 .value = low_leaf_nullifier,
187 low_leaf_sibling_path,
189 insertion_sibling_path);
191 TestTraceContainer
trace({ {
192 { C::execution_sel_execute_emit_nullifier, 1 },
193 { C::execution_register_0_, nullifier },
194 { C::execution_mem_tag_reg_0_,
static_cast<uint8_t
>(
MemoryTag::FF) },
196 { C::execution_sel_write_nullifier, 1 },
197 { C::execution_sel_opcode_error, 0 },
199 { C::execution_prev_num_nullifiers_emitted, prev_num_nullifiers_emitted },
200 { C::execution_nullifier_pi_offset,
202 { C::execution_num_nullifiers_emitted, prev_num_nullifiers_emitted + 1 },
203 { C::execution_prev_nullifier_tree_root, prev_snapshot.root },
204 { C::execution_nullifier_tree_root, next_snapshot.root },
205 { C::execution_prev_nullifier_tree_size, prev_snapshot.next_available_leaf_index },
206 { C::execution_nullifier_tree_size, next_snapshot.next_available_leaf_index },
207 { C::execution_contract_address, siloing_params.address },
213 IndexedTreeCheckTraceBuilder indexed_tree_check_trace_builder;
215 check_relation<emit_nullifier>(trace);
217 check_interaction<ExecutionTraceBuilder, lookup_emit_nullifier_write_nullifier_settings>(trace);
220TEST(EmitNullifierConstrainingTest, InteractionsCollision)
225 StrictMock<MockFieldGreaterThan>
field_gt;
232 auto siloing_params = IndexedTreeSiloingParameters{
233 .address = 0xdeadbeef,
236 FF siloed_nullifier = 66;
237 FF low_leaf_hash = 77;
238 FF pre_write_root = 27;
240 AppendOnlyTreeSnapshot prev_snapshot = AppendOnlyTreeSnapshot{
241 .root = pre_write_root,
242 .next_available_leaf_index = 128,
244 uint32_t prev_num_nullifiers_emitted = 2;
247 EXPECT_CALL(
poseidon2, hash).WillOnce(Return(siloed_nullifier)).WillOnce(Return(low_leaf_hash));
249 EXPECT_CALL(merkle_check, assert_membership).WillOnce(Return());
252 IndexedTreeLeafData low_leaf_preimage = {
253 .value = siloed_nullifier,
266 low_leaf_sibling_path,
270 TestTraceContainer
trace({ {
271 { C::execution_sel_execute_emit_nullifier, 1 },
272 { C::execution_register_0_, nullifier },
273 { C::execution_mem_tag_reg_0_,
static_cast<uint8_t
>(
MemoryTag::FF) },
275 { C::execution_sel_write_nullifier, 1 },
276 { C::execution_sel_opcode_error, 1 },
278 { C::execution_prev_num_nullifiers_emitted, prev_num_nullifiers_emitted },
279 { C::execution_nullifier_pi_offset,
281 { C::execution_num_nullifiers_emitted, prev_num_nullifiers_emitted },
282 { C::execution_prev_nullifier_tree_root, prev_snapshot.root },
283 { C::execution_nullifier_tree_root, next_snapshot.root },
284 { C::execution_prev_nullifier_tree_size, prev_snapshot.next_available_leaf_index },
285 { C::execution_nullifier_tree_size, next_snapshot.next_available_leaf_index },
286 { C::execution_contract_address, siloing_params.address },
292 IndexedTreeCheckTraceBuilder indexed_tree_check_trace_builder;
294 check_relation<emit_nullifier>(trace);
296 check_interaction<ExecutionTraceBuilder, lookup_emit_nullifier_write_nullifier_settings>(trace);
#define EXPECT_THROW_WITH_MESSAGE(code, expectedMessageRegex)
#define AVM_EXEC_OP_ID_EMIT_NULLIFIER
#define AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_NULLIFIERS_ROW_IDX
#define DOM_SEP__SILOED_NULLIFIER
#define NULLIFIER_TREE_HEIGHT
#define DOM_SEP__NULLIFIER_MERKLE
#define MAX_NULLIFIERS_PER_TX
FieldGreaterThan field_gt
IndexedTreeCheck indexed_tree_check
EventEmitter< simulation::IndexedTreeCheckEvent > indexed_tree_check_event_emitter
static constexpr size_t SR_OPCODE_ERROR_IF_VALIDATION_ERROR
static constexpr size_t SR_EMIT_NULLIFIER_TREE_ROOT_NOT_CHANGED
static constexpr size_t SR_EMIT_NULLIFIER_NUM_NULLIFIERS_EMITTED_INCREASE
static constexpr size_t SR_MAX_NULLIFIER_WRITES_REACHED
static constexpr size_t SR_EMIT_NULLIFIER_TREE_SIZE_INCREASE
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.
void set(Column col, uint32_t row, const FF &value)
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
crypto::Poseidon2< crypto::Poseidon2Bn254ScalarFieldParams > poseidon2
std::variant< IndexedTreeReadWriteEvent, CheckPointEventType > IndexedTreeCheckEvent
void write(B &buf, field2< base_field, Params > const &value)
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
constexpr field invert() const noexcept