1#include <gmock/gmock.h>
2#include <gtest/gtest.h>
6#include "barretenberg/aztec/aztec_constants.hpp"
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)
53 uint64_t prev_num_nullifiers_emitted = MAX_NULLIFIERS_PER_TX - 1;
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) },
58 { C::execution_remaining_nullifiers_inv,
FF(MAX_NULLIFIERS_PER_TX - prev_num_nullifiers_emitted).invert() },
59 { C::execution_sel_write_nullifier, 1 },
60 { C::execution_sel_opcode_error, 0 },
61 { C::execution_subtrace_operation_id, AVM_EXEC_OP_ID_EMIT_NULLIFIER },
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,
66 prev_num_nullifiers_emitted + AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_NULLIFIERS_ROW_IDX },
67 { C::execution_num_nullifiers_emitted, prev_num_nullifiers_emitted + 1 },
68 { C::execution_nullifier_siloing_separator, DOM_SEP__SILOED_NULLIFIER },
69 { C::execution_nullifier_tree_height, NULLIFIER_TREE_HEIGHT },
70 { C::execution_nullifier_merkle_separator, DOM_SEP__NULLIFIER_MERKLE },
72 check_relation<emit_nullifier>(trace);
75TEST(EmitNullifierConstrainingTest, LimitReached)
77 uint64_t prev_num_nullifiers_emitted = MAX_NULLIFIERS_PER_TX;
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 },
86 { C::execution_subtrace_operation_id, AVM_EXEC_OP_ID_EMIT_NULLIFIER },
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,
91 prev_num_nullifiers_emitted + AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_NULLIFIERS_ROW_IDX },
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);
100 trace.
set(C::execution_sel_reached_max_nullifiers, 0, 1);
103 trace.
set(C::execution_sel_opcode_error, 0, 0);
107 trace.
set(C::execution_sel_opcode_error, 0, 1);
110 trace.
set(C::execution_nullifier_tree_root, 0, 28);
116 trace.
set(C::execution_nullifier_tree_size, 0, 2);
122 trace.
set(C::execution_num_nullifiers_emitted, 0, prev_num_nullifiers_emitted + 1);
128TEST(EmitNullifierConstrainingTest, Interactions)
133 StrictMock<MockFieldGreaterThan>
field_gt;
140 auto siloing_params = IndexedTreeSiloingParameters{
141 .address = 0xdeadbeef,
142 .siloing_separator = DOM_SEP__SILOED_NULLIFIER,
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,
179 std::vector<FF> low_leaf_sibling_path(NULLIFIER_TREE_HEIGHT);
184 prev_num_nullifiers_emitted + AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_NULLIFIERS_ROW_IDX,
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) },
195 { C::execution_remaining_nullifiers_inv,
FF(MAX_NULLIFIERS_PER_TX - prev_num_nullifiers_emitted).
invert() },
196 { C::execution_sel_write_nullifier, 1 },
197 { C::execution_sel_opcode_error, 0 },
198 { C::execution_subtrace_operation_id, AVM_EXEC_OP_ID_EMIT_NULLIFIER },
199 { C::execution_prev_num_nullifiers_emitted, prev_num_nullifiers_emitted },
200 { C::execution_nullifier_pi_offset,
201 prev_num_nullifiers_emitted + AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_NULLIFIERS_ROW_IDX },
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 },
208 { C::execution_nullifier_siloing_separator, DOM_SEP__SILOED_NULLIFIER },
209 { C::execution_nullifier_tree_height, NULLIFIER_TREE_HEIGHT },
210 { C::execution_nullifier_merkle_separator, DOM_SEP__NULLIFIER_MERKLE },
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,
234 .siloing_separator = DOM_SEP__SILOED_NULLIFIER,
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,
258 std::vector<FF> low_leaf_sibling_path(NULLIFIER_TREE_HEIGHT);
263 AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_NULLIFIERS_ROW_IDX + prev_num_nullifiers_emitted,
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) },
274 { C::execution_remaining_nullifiers_inv,
FF(MAX_NULLIFIERS_PER_TX - prev_num_nullifiers_emitted).
invert() },
275 { C::execution_sel_write_nullifier, 1 },
276 { C::execution_sel_opcode_error, 1 },
277 { C::execution_subtrace_operation_id, AVM_EXEC_OP_ID_EMIT_NULLIFIER },
278 { C::execution_prev_num_nullifiers_emitted, prev_num_nullifiers_emitted },
279 { C::execution_nullifier_pi_offset,
280 prev_num_nullifiers_emitted + AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_NULLIFIERS_ROW_IDX },
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 },
287 { C::execution_nullifier_siloing_separator, DOM_SEP__SILOED_NULLIFIER },
288 { C::execution_nullifier_tree_height, NULLIFIER_TREE_HEIGHT },
289 { C::execution_nullifier_merkle_separator, DOM_SEP__NULLIFIER_MERKLE },
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)
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 std::string get_subrelation_label(size_t index)
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, bool use_atomic_limbs=false)
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