1#include <gmock/gmock.h>
2#include <gtest/gtest.h>
26using tracegen::ExecutionTraceBuilder;
27using tracegen::IndexedTreeCheckTraceBuilder;
28using tracegen::TestTraceContainer;
30using simulation::EventEmitter;
31using simulation::IndexedTreeCheck;
33using simulation::IndexedTreeLeafData;
34using simulation::IndexedTreeSiloingParameters;
35using simulation::MockFieldGreaterThan;
36using simulation::MockMerkleCheck;
37using simulation::MockPoseidon2;
38using simulation::MockRangeCheck;
43using testing::StrictMock;
50TEST(EmitNullifierConstrainingTest, Positive)
53 TestTraceContainer
trace({ {
54 { C::execution_sel_execute_emit_nullifier, 1 },
55 { C::execution_register_0_, 42 },
56 { C::execution_mem_tag_reg_0_,
static_cast<uint8_t
>(
MemoryTag::FF) },
58 { C::execution_sel_write_nullifier, 1 },
59 { C::execution_sel_opcode_error, 0 },
61 { C::execution_prev_nullifier_tree_size, 1 },
62 { C::execution_nullifier_tree_size, 2 },
63 { C::execution_prev_num_nullifiers_emitted, prev_num_nullifiers_emitted },
64 { C::execution_nullifier_pi_offset,
66 { C::execution_num_nullifiers_emitted, prev_num_nullifiers_emitted + 1 },
70 check_relation<emit_nullifier>(trace);
73TEST(EmitNullifierConstrainingTest, LimitReached)
76 TestTraceContainer
trace({ {
77 { C::execution_sel_execute_emit_nullifier, 1 },
78 { C::execution_register_0_, 42 },
79 { C::execution_mem_tag_reg_0_,
static_cast<uint8_t
>(
MemoryTag::FF) },
80 { C::execution_sel_reached_max_nullifiers, 1 },
81 { C::execution_remaining_nullifiers_inv, 0 },
82 { C::execution_sel_write_nullifier, 0 },
83 { C::execution_sel_opcode_error, 1 },
85 { C::execution_prev_nullifier_tree_size, 1 },
86 { C::execution_nullifier_tree_size, 1 },
87 { C::execution_prev_num_nullifiers_emitted, prev_num_nullifiers_emitted },
88 { C::execution_nullifier_pi_offset,
90 { C::execution_num_nullifiers_emitted, prev_num_nullifiers_emitted },
92 check_relation<emit_nullifier>(trace);
95 trace.
set(C::execution_sel_reached_max_nullifiers, 0, 0);
97 "MAX_NULLIFIER_WRITES_REACHED");
98 trace.
set(C::execution_sel_reached_max_nullifiers, 0, 1);
101 trace.
set(C::execution_sel_opcode_error, 0, 0);
104 "OPCODE_ERROR_IF_VALIDATION_ERROR");
105 trace.
set(C::execution_sel_opcode_error, 0, 1);
108 trace.
set(C::execution_nullifier_tree_root, 0, 28);
111 "EMIT_NULLIFIER_TREE_ROOT_NOT_CHANGED");
114 trace.
set(C::execution_nullifier_tree_size, 0, 2);
117 "EMIT_NULLIFIER_TREE_SIZE_INCREASE");
120 trace.
set(C::execution_num_nullifiers_emitted, 0, prev_num_nullifiers_emitted + 1);
123 "EMIT_NULLIFIER_NUM_NULLIFIERS_EMITTED_INCREASE");
126TEST(EmitNullifierConstrainingTest, Interactions)
131 StrictMock<MockFieldGreaterThan>
field_gt;
137 auto siloing_params = IndexedTreeSiloingParameters{
138 .address = 0xdeadbeef,
141 FF siloed_nullifier = 66;
142 FF low_leaf_nullifier = 99;
143 FF low_leaf_hash = 77;
144 FF updated_low_leaf_hash = 101;
145 FF new_leaf_hash = 111;
146 FF pre_write_root = 27;
147 FF intermediate_root = 33;
148 FF post_write_root = 88;
151 std::vector<FF> insertion_sibling_path = { 1, 2, 3 };
153 AppendOnlyTreeSnapshot prev_snapshot = AppendOnlyTreeSnapshot{
154 .root = pre_write_root,
155 .next_available_leaf_index = 128,
157 uint32_t prev_num_nullifiers_emitted = 2;
160 EXPECT_CALL(
field_gt, ff_gt).WillOnce(Return(
true));
163 .WillOnce(Return(siloed_nullifier))
164 .WillOnce(Return(low_leaf_hash))
165 .WillOnce(Return(updated_low_leaf_hash))
166 .WillOnce(Return(new_leaf_hash));
168 EXPECT_CALL(merkle_check,
write).WillOnce(Return(intermediate_root)).WillOnce(Return(post_write_root));
171 IndexedTreeLeafData low_leaf_preimage = {
172 .value = low_leaf_nullifier,
184 low_leaf_sibling_path,
186 insertion_sibling_path);
188 TestTraceContainer
trace({ {
189 { C::execution_sel_execute_emit_nullifier, 1 },
190 { C::execution_register_0_, nullifier },
191 { C::execution_mem_tag_reg_0_,
static_cast<uint8_t
>(
MemoryTag::FF) },
193 { C::execution_sel_write_nullifier, 1 },
194 { C::execution_sel_opcode_error, 0 },
196 { C::execution_prev_num_nullifiers_emitted, prev_num_nullifiers_emitted },
197 { C::execution_nullifier_pi_offset,
199 { C::execution_num_nullifiers_emitted, prev_num_nullifiers_emitted + 1 },
200 { C::execution_prev_nullifier_tree_root, prev_snapshot.root },
201 { C::execution_nullifier_tree_root, next_snapshot.root },
202 { C::execution_prev_nullifier_tree_size, prev_snapshot.next_available_leaf_index },
203 { C::execution_nullifier_tree_size, next_snapshot.next_available_leaf_index },
204 { C::execution_contract_address, siloing_params.address },
209 IndexedTreeCheckTraceBuilder indexed_tree_check_trace_builder;
211 check_relation<emit_nullifier>(trace);
213 check_interaction<ExecutionTraceBuilder, lookup_emit_nullifier_write_nullifier_settings>(trace);
216TEST(EmitNullifierConstrainingTest, InteractionsCollision)
221 StrictMock<MockFieldGreaterThan>
field_gt;
227 auto siloing_params = IndexedTreeSiloingParameters{
228 .address = 0xdeadbeef,
231 FF siloed_nullifier = 66;
232 FF low_leaf_hash = 77;
233 FF pre_write_root = 27;
235 AppendOnlyTreeSnapshot prev_snapshot = AppendOnlyTreeSnapshot{
236 .root = pre_write_root,
237 .next_available_leaf_index = 128,
239 uint32_t prev_num_nullifiers_emitted = 2;
242 EXPECT_CALL(
poseidon2, hash).WillOnce(Return(siloed_nullifier)).WillOnce(Return(low_leaf_hash));
244 EXPECT_CALL(merkle_check, assert_membership).WillOnce(Return());
247 IndexedTreeLeafData low_leaf_preimage = {
248 .value = siloed_nullifier,
261 low_leaf_sibling_path,
265 TestTraceContainer
trace({ {
266 { C::execution_sel_execute_emit_nullifier, 1 },
267 { C::execution_register_0_, nullifier },
268 { C::execution_mem_tag_reg_0_,
static_cast<uint8_t
>(
MemoryTag::FF) },
270 { C::execution_sel_write_nullifier, 1 },
271 { C::execution_sel_opcode_error, 1 },
273 { C::execution_prev_num_nullifiers_emitted, prev_num_nullifiers_emitted },
274 { C::execution_nullifier_pi_offset,
276 { C::execution_num_nullifiers_emitted, prev_num_nullifiers_emitted },
277 { C::execution_prev_nullifier_tree_root, prev_snapshot.root },
278 { C::execution_nullifier_tree_root, next_snapshot.root },
279 { C::execution_prev_nullifier_tree_size, prev_snapshot.next_available_leaf_index },
280 { C::execution_nullifier_tree_size, next_snapshot.next_available_leaf_index },
281 { C::execution_contract_address, siloing_params.address },
286 IndexedTreeCheckTraceBuilder indexed_tree_check_trace_builder;
288 check_relation<emit_nullifier>(trace);
290 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 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