Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
written_public_data_slots_tree_check.test.cpp
Go to the documentation of this file.
1#include <gmock/gmock.h>
2#include <gtest/gtest.h>
3
4#include <cmath>
5#include <cstdint>
6
31
32namespace bb::avm2::constraining {
33namespace {
34
35using ::testing::NiceMock;
36using ::testing::TestWithParam;
37
38using testing::TestMemoryTree;
39
41using simulation::EventEmitter;
42using simulation::FieldGreaterThan;
43using simulation::FieldGreaterThanEvent;
44using simulation::MerkleCheck;
45using simulation::MerkleCheckEvent;
46using simulation::MockExecutionIdManager;
47using simulation::MockGreaterThan;
48using simulation::MockRangeCheck;
49using simulation::NoopEventEmitter;
50using simulation::Poseidon2;
51using simulation::Poseidon2HashEvent;
52using simulation::Poseidon2PermutationEvent;
53using simulation::Poseidon2PermutationMemoryEvent;
56using simulation::WrittenPublicDataSlotLeafValue;
58using simulation::WrittenPublicDataSlotsTreeCheck;
59using simulation::WrittenPublicDataSlotsTreeCheckEvent;
61
62using tracegen::FieldGreaterThanTraceBuilder;
63using tracegen::MerkleCheckTraceBuilder;
64using tracegen::Poseidon2TraceBuilder;
65using tracegen::TestTraceContainer;
66using tracegen::WrittenPublicDataSlotsTreeCheckTraceBuilder;
67
69using C = Column;
72
73class WrittenPublicDataSlotsTreeCheckConstrainingTest : public ::testing::Test {
74 protected:
75 WrittenPublicDataSlotsTreeCheckConstrainingTest() = default;
76
77 EventEmitter<Poseidon2HashEvent> hash_event_emitter;
78 // Interactions involve the poseidon2 hash, so the others can be noop
79 NoopEventEmitter<Poseidon2PermutationEvent> perm_event_emitter;
80 NoopEventEmitter<Poseidon2PermutationMemoryEvent> perm_mem_event_emitter;
81
82 NiceMock<MockGreaterThan> mock_gt;
83 NiceMock<MockExecutionIdManager> mock_execution_id_manager;
84
86 Poseidon2(mock_execution_id_manager, mock_gt, hash_event_emitter, perm_event_emitter, perm_mem_event_emitter);
87};
88
89TEST_F(WrittenPublicDataSlotsTreeCheckConstrainingTest, EmptyRow)
90{
91 check_relation<written_public_data_slots_tree_check>(testing::empty_trace());
92}
93
94struct TestParams {
97 bool exists;
99};
100
101std::vector<TestParams> positive_read_tests = {
102 // Exists = true, leaf pointers to infinity
103 TestParams{
104 .slot = 42,
105 .contract_address = 27,
106 .exists = true,
107 .pre_existing_leaves = { { WrittenPublicDataSlotLeafValue(unconstrained_compute_leaf_slot(27, 42)) } } },
108 // Exists = true, leaf points to higher value
109 TestParams{ .slot = 42,
110 .contract_address = 27,
111 .exists = true,
112 .pre_existing_leaves = { { WrittenPublicDataSlotLeafValue(unconstrained_compute_leaf_slot(27, 42)),
113 WrittenPublicDataSlotLeafValue(unconstrained_compute_leaf_slot(27, 42) +
114 FF(1)) } } },
115 // Exists = false, low leaf points to infinity
116 TestParams{ .slot = 42, .contract_address = 27, .exists = false, .pre_existing_leaves = { {} } },
117 // Exists = false, low leaf points to higher value
118 TestParams{
119 .slot = 42,
120 .contract_address = 27,
121 .exists = false,
122 .pre_existing_leaves = { { WrittenPublicDataSlotLeafValue(unconstrained_compute_leaf_slot(27, 42) + FF(1)) } } }
123};
124
125class WrittenPublicDataSlotsReadPositiveTests : public WrittenPublicDataSlotsTreeCheckConstrainingTest,
126 public ::testing::WithParamInterface<TestParams> {};
127
128TEST_P(WrittenPublicDataSlotsReadPositiveTests, Positive)
129{
130 const auto& param = GetParam();
131
132 EventEmitter<MerkleCheckEvent> merkle_event_emitter;
133 MerkleCheck merkle_check(poseidon2, merkle_event_emitter);
134
135 NiceMock<MockRangeCheck> range_check;
136
137 EventEmitter<FieldGreaterThanEvent> field_gt_event_emitter;
138 FieldGreaterThan field_gt(range_check, field_gt_event_emitter);
139
140 EventEmitter<WrittenPublicDataSlotsTreeCheckEvent> written_public_data_slots_tree_check_event_emitter;
141
142 TestTraceContainer trace({ { { C::precomputed_first_row, 1 } } });
143
144 Poseidon2TraceBuilder poseidon2_builder;
145 MerkleCheckTraceBuilder merkle_check_builder;
146 FieldGreaterThanTraceBuilder field_gt_builder;
147 WrittenPublicDataSlotsTreeCheckTraceBuilder written_public_data_slots_tree_check_builder;
148
150 initial_state.insert_indexed_leaves(param.pre_existing_leaves);
151
152 WrittenPublicDataSlotsTreeCheck written_public_data_slots_tree_check_simulator(
153 poseidon2, merkle_check, field_gt, initial_state, written_public_data_slots_tree_check_event_emitter);
154
155 written_public_data_slots_tree_check_simulator.contains(param.contract_address, param.slot);
156
157 written_public_data_slots_tree_check_builder.process(
158 written_public_data_slots_tree_check_event_emitter.dump_events(), trace);
159 EXPECT_EQ(trace.get_num_rows(), 1);
160
161 poseidon2_builder.process_hash(hash_event_emitter.dump_events(), trace);
162 merkle_check_builder.process(merkle_event_emitter.dump_events(), trace);
163 field_gt_builder.process(field_gt_event_emitter.dump_events(), trace);
164
165 check_relation<written_public_data_slots_tree_check>(trace);
166 check_all_interactions<WrittenPublicDataSlotsTreeCheckTraceBuilder>(trace);
167}
168
169INSTANTIATE_TEST_SUITE_P(WrittenPublicDataSlotsTreeCheckConstrainingTest,
170 WrittenPublicDataSlotsReadPositiveTests,
171 ::testing::ValuesIn(positive_read_tests));
172
173TEST_F(WrittenPublicDataSlotsTreeCheckConstrainingTest, PositiveWriteAppend)
174{
175 EventEmitter<MerkleCheckEvent> merkle_event_emitter;
176 MerkleCheck merkle_check(poseidon2, merkle_event_emitter);
177
178 NiceMock<MockRangeCheck> range_check;
179
180 EventEmitter<FieldGreaterThanEvent> field_gt_event_emitter;
181 FieldGreaterThan field_gt(range_check, field_gt_event_emitter);
182
183 EventEmitter<WrittenPublicDataSlotsTreeCheckEvent> written_public_data_slots_tree_check_event_emitter;
184
185 TestTraceContainer trace({ { { C::precomputed_first_row, 1 } } });
186
187 Poseidon2TraceBuilder poseidon2_builder;
188 MerkleCheckTraceBuilder merkle_check_builder;
189 FieldGreaterThanTraceBuilder field_gt_builder;
190 WrittenPublicDataSlotsTreeCheckTraceBuilder written_public_data_slots_tree_check_builder;
191
192 FF slot = 100;
194
196
197 WrittenPublicDataSlotsTreeCheck written_public_data_slots_tree_check_simulator(
198 poseidon2, merkle_check, field_gt, initial_state, written_public_data_slots_tree_check_event_emitter);
199
200 written_public_data_slots_tree_check_simulator.insert(contract_address, slot);
201
202 written_public_data_slots_tree_check_builder.process(
203 written_public_data_slots_tree_check_event_emitter.dump_events(), trace);
204
205 EXPECT_EQ(trace.get_num_rows(), 1);
206
207 poseidon2_builder.process_hash(hash_event_emitter.dump_events(), trace);
208 merkle_check_builder.process(merkle_event_emitter.dump_events(), trace);
209 field_gt_builder.process(field_gt_event_emitter.dump_events(), trace);
210
211 check_relation<written_public_data_slots_tree_check>(trace);
212 check_all_interactions<WrittenPublicDataSlotsTreeCheckTraceBuilder>(trace);
213}
214
215TEST_F(WrittenPublicDataSlotsTreeCheckConstrainingTest, PositiveWriteMembership)
216{
217 FF slot = 42;
220 auto low_leaf = WrittenPublicDataSlotsTreeLeafPreimage(WrittenPublicDataSlotLeafValue(leaf_slot), 0, 0);
221
222 EventEmitter<MerkleCheckEvent> merkle_event_emitter;
223 MerkleCheck merkle_check(poseidon2, merkle_event_emitter);
224
225 NiceMock<MockRangeCheck> range_check;
226
227 EventEmitter<FieldGreaterThanEvent> field_gt_event_emitter;
228 FieldGreaterThan field_gt(range_check, field_gt_event_emitter);
229
230 EventEmitter<WrittenPublicDataSlotsTreeCheckEvent> written_public_data_slots_tree_check_event_emitter;
231
232 TestTraceContainer trace({ { { C::precomputed_first_row, 1 } } });
233
234 Poseidon2TraceBuilder poseidon2_builder;
235 MerkleCheckTraceBuilder merkle_check_builder;
236 FieldGreaterThanTraceBuilder field_gt_builder;
237 WrittenPublicDataSlotsTreeCheckTraceBuilder written_public_data_slots_tree_check_builder;
238
240 initial_state.insert_indexed_leaves({ { WrittenPublicDataSlotLeafValue(leaf_slot) } });
241
242 WrittenPublicDataSlotsTreeCheck written_public_data_slots_tree_check_simulator(
243 poseidon2, merkle_check, field_gt, initial_state, written_public_data_slots_tree_check_event_emitter);
244
245 written_public_data_slots_tree_check_simulator.insert(contract_address, slot);
246
247 written_public_data_slots_tree_check_builder.process(
248 written_public_data_slots_tree_check_event_emitter.dump_events(), trace);
249
250 EXPECT_EQ(trace.get_num_rows(), 1);
251
252 poseidon2_builder.process_hash(hash_event_emitter.dump_events(), trace);
253 merkle_check_builder.process(merkle_event_emitter.dump_events(), trace);
254 field_gt_builder.process(field_gt_event_emitter.dump_events(), trace);
255
256 check_relation<written_public_data_slots_tree_check>(trace);
257 check_all_interactions<WrittenPublicDataSlotsTreeCheckTraceBuilder>(trace);
258}
259
260TEST_F(WrittenPublicDataSlotsTreeCheckConstrainingTest, NegativeExistsFlagCheck)
261{
262 // Test constraint: sel * (SLOT_LOW_LEAF_SLOT_DIFF * (EXISTS * (1 - slot_low_leaf_slot_diff_inv)
263 // + slot_low_leaf_slot_diff_inv) - 1 + EXISTS) = 0
264 TestTraceContainer trace({
265 { { C::written_public_data_slots_tree_check_sel, 1 },
266 { C::written_public_data_slots_tree_check_leaf_slot, 27 },
267 { C::written_public_data_slots_tree_check_low_leaf_slot, 27 },
268 { C::written_public_data_slots_tree_check_slot_low_leaf_slot_diff_inv, 0 },
269 { C::written_public_data_slots_tree_check_leaf_not_exists, 0 } },
270 { { C::written_public_data_slots_tree_check_sel, 1 },
271 { C::written_public_data_slots_tree_check_leaf_slot, 28 },
272 { C::written_public_data_slots_tree_check_low_leaf_slot, 27 },
273 { C::written_public_data_slots_tree_check_slot_low_leaf_slot_diff_inv, FF(1).invert() },
274 { C::written_public_data_slots_tree_check_leaf_not_exists, 1 } },
275 });
276
277 check_relation<written_public_data_slots_tree_check>(trace, written_public_data_slots_tree_check::SR_EXISTS_CHECK);
278 trace.set(C::written_public_data_slots_tree_check_leaf_not_exists, 0, 1);
279
280 EXPECT_THROW_WITH_MESSAGE(check_relation<written_public_data_slots_tree_check>(
282 "EXISTS_CHECK");
283 trace.set(C::written_public_data_slots_tree_check_leaf_not_exists, 0, 0);
284 trace.set(C::written_public_data_slots_tree_check_leaf_not_exists, 1, 0);
285
286 EXPECT_THROW_WITH_MESSAGE(check_relation<written_public_data_slots_tree_check>(
288 "EXISTS_CHECK");
289}
290
291TEST_F(WrittenPublicDataSlotsTreeCheckConstrainingTest, NegativeNextSlotIsZero)
292{
293 // Test constraint: leaf_not_exists * (low_leaf_next_slot * (NEXT_SLOT_IS_ZERO * (1 - next_slot_inv)
294 // + next_slot_inv) - 1 + NEXT_SLOT_IS_ZERO) = 0
295 TestTraceContainer trace({
296 {
297 { C::written_public_data_slots_tree_check_leaf_not_exists, 1 },
298 { C::written_public_data_slots_tree_check_low_leaf_next_slot, 0 },
299 { C::written_public_data_slots_tree_check_next_slot_inv, 0 },
300 { C::written_public_data_slots_tree_check_next_slot_is_nonzero, 0 },
301 },
302 {
303 { C::written_public_data_slots_tree_check_leaf_not_exists, 1 },
304 { C::written_public_data_slots_tree_check_low_leaf_next_slot, 1 },
305 { C::written_public_data_slots_tree_check_next_slot_inv, FF(1).invert() },
306 { C::written_public_data_slots_tree_check_next_slot_is_nonzero, 1 },
307 },
308 });
309
310 check_relation<written_public_data_slots_tree_check>(
312
313 trace.set(C::written_public_data_slots_tree_check_next_slot_is_nonzero, 0, 1);
314
315 EXPECT_THROW_WITH_MESSAGE(check_relation<written_public_data_slots_tree_check>(
317 "NEXT_SLOT_IS_ZERO_CHECK");
318
319 trace.set(C::written_public_data_slots_tree_check_next_slot_is_nonzero, 0, 0);
320 trace.set(C::written_public_data_slots_tree_check_next_slot_is_nonzero, 1, 0);
321
322 EXPECT_THROW_WITH_MESSAGE(check_relation<written_public_data_slots_tree_check>(
324 "NEXT_SLOT_IS_ZERO_CHECK");
325}
326
327} // namespace
328} // namespace bb::avm2::constraining
INSTANTIATE_TEST_SUITE_P(AcirTests, AcirIntegrationSingleTest, testing::Values("a_1327_concrete_in_generic", "a_1_mul", "a_2_div", "a_3_add", "a_4_sub", "a_5_over", "a_6", "a_6_array", "a_7", "a_7_function", "aes128_encrypt", "arithmetic_binary_operations", "array_dynamic", "array_dynamic_blackbox_input", "array_dynamic_main_output", "array_dynamic_nested_blackbox_input", "array_eq", "array_if_cond_simple", "array_len", "array_neq", "array_sort", "array_to_slice", "array_to_slice_constant_length", "assert", "assert_statement", "assign_ex", "bigint", "bit_and", "bit_not", "bit_shifts_comptime", "bit_shifts_runtime", "blake3", "bool_not", "bool_or", "break_and_continue", "brillig_acir_as_brillig", "brillig_array_eq", "brillig_array_to_slice", "brillig_arrays", "brillig_assert", "brillig_bit_shifts_runtime", "brillig_blake2s", "brillig_blake3", "brillig_calls", "brillig_calls_array", "brillig_calls_conditionals", "brillig_conditional", "brillig_cow", "brillig_cow_assign", "brillig_cow_regression", "brillig_ecdsa_secp256k1", "brillig_ecdsa_secp256r1", "brillig_embedded_curve", "brillig_fns_as_values", "brillig_hash_to_field", "brillig_identity_function", "brillig_keccak", "brillig_loop", "brillig_nested_arrays", "brillig_not", "brillig_oracle", "brillig_pedersen", "brillig_recursion", "brillig_references", "brillig_schnorr", "brillig_sha256", "brillig_signed_cmp", "brillig_signed_div", "brillig_slices", "brillig_to_be_bytes", "brillig_to_bits", "brillig_to_bytes_integration", "brillig_to_le_bytes", "brillig_top_level", "brillig_uninitialized_arrays", "brillig_wrapping", "cast_bool", "closures_mut_ref", "conditional_1", "conditional_2", "conditional_regression_421", "conditional_regression_547", "conditional_regression_661", "conditional_regression_short_circuit", "conditional_regression_underflow", "custom_entry", "databus", "debug_logs", "diamond_deps_0", "double_verify_nested_proof", "double_verify_proof", "ecdsa_secp256k1", "ecdsa_secp256r1", "ecdsa_secp256r1_3x", "eddsa", "embedded_curve_ops", "field_attribute", "generics", "global_consts", "hash_to_field", "hashmap", "higher_order_functions", "if_else_chain", "import", "inline_never_basic", "integer_array_indexing", "keccak256", "main_bool_arg", "main_return", "merkle_insert", "missing_closure_env", "modules", "modules_more", "modulus", "nested_array_dynamic", "nested_array_dynamic_simple", "nested_array_in_slice", "nested_arrays_from_brillig", "no_predicates_basic", "no_predicates_brillig", "no_predicates_numeric_generic_poseidon", "operator_overloading", "pedersen_check", "pedersen_commitment", "pedersen_hash", "poseidon_bn254_hash", "poseidonsponge_x5_254", "pred_eq", "prelude", "references", "regression", "regression_2660", "regression_3051", "regression_3394", "regression_3607", "regression_3889", "regression_4088", "regression_4124", "regression_4202", "regression_4449", "regression_4709", "regression_5045", "regression_capacity_tracker", "regression_mem_op_predicate", "regression_method_cannot_be_found", "regression_struct_array_conditional", "schnorr", "sha256", "sha2_byte", "side_effects_constrain_array", "signed_arithmetic", "signed_comparison", "signed_division", "simple_2d_array", "simple_add_and_ret_arr", "simple_array_param", "simple_bitwise", "simple_comparison", "simple_mut", "simple_not", "simple_print", "simple_program_addition", "simple_radix", "simple_shield", "simple_shift_left_right", "slice_coercion", "slice_dynamic_index", "slice_loop", "slices", "strings", "struct", "struct_array_inputs", "struct_fields_ordering", "struct_inputs", "submodules", "to_be_bytes", "to_bytes_consistent", "to_bytes_integration", "to_le_bytes", "trait_as_return_type", "trait_impl_base_type", "traits_in_crates_1", "traits_in_crates_2", "tuple_inputs", "tuples", "type_aliases", "u128", "u16_support", "unconstrained_empty", "unit_value", "unsafe_range_constraint", "witness_compression", "xor"))
TEST_P(AcirIntegrationSingleTest, DISABLED_ProveAndVerifyProgram)
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...
FieldGreaterThanTraceBuilder field_gt_builder
Definition alu.test.cpp:121
RangeCheck range_check
TestTraceContainer trace
NoopEventEmitter< Poseidon2PermutationEvent > perm_event_emitter
NoopEventEmitter< Poseidon2PermutationMemoryEvent > perm_mem_event_emitter
NiceMock< MockGreaterThan > mock_gt
EventEmitter< Poseidon2HashEvent > hash_event_emitter
NullifierTreeLeafPreimage low_leaf
NiceMock< MockExecutionIdManager > mock_execution_id_manager
std::vector< WrittenPublicDataSlotLeafValue > pre_existing_leaves
#define EXPECT_THROW_WITH_MESSAGE(code, expectedMessage)
Definition macros.hpp:7
TEST_F(AvmRecursiveTests, GoblinRecursion)
A test of the Goblinized AVM recursive verifier.
AvmFlavorSettings::FF FF
IndexedLeaf< WrittenPublicDataSlotLeafValue > WrittenPublicDataSlotsTreeLeafPreimage
FF unconstrained_root_from_path(const FF &leaf_value, const uint64_t leaf_index, std::span< const FF > path)
Definition merkle.cpp:12
WrittenPublicDataSlotsTree build_public_data_slots_tree()
FF unconstrained_compute_leaf_slot(const AztecAddress &contract_address, const FF &slot)
Definition merkle.cpp:26
IndexedMemoryTree< WrittenPublicDataSlotLeafValue, Poseidon2HashPolicy > WrittenPublicDataSlotsTree
TestTraceContainer empty_trace()
Definition fixtures.cpp:153
typename Flavor::FF FF
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
NiceMock< MockFieldGreaterThan > field_gt
NiceMock< MockWrittenPublicDataSlotsTreeCheck > written_public_data_slots_tree_check