Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
bc_retrieval.test.cpp
Go to the documentation of this file.
1#include <gmock/gmock.h>
2#include <gtest/gtest.h>
3
4#include <cstdint>
5#include <memory>
6#include <vector>
7
23
24namespace bb::avm2::constraining {
25namespace {
26
29using tracegen::BytecodeTraceBuilder;
30using tracegen::ClassIdDerivationTraceBuilder;
31using tracegen::ContractInstanceRetrievalTraceBuilder;
32using tracegen::RetrievedBytecodesTreeCheckTraceBuilder;
33using tracegen::TestTraceContainer;
34
35using simulation::ClassIdLeafValue;
36using simulation::RetrievedBytecodesTreeCheckEvent;
38
40using C = Column;
41using bc_retrieval = bb::avm2::bc_retrieval<FF>;
43
44void init_trace(TestTraceContainer& trace)
45{
46 // Add first row.
47 trace.set(C::precomputed_first_row, 0, 1);
48}
49
50TEST(BytecodeRetrievalConstrainingTest, EmptyRow)
51{
52 check_relation<bc_retrieval>(testing::empty_trace());
53}
54
55TEST(BytecodeRetrievalConstrainingTest, SuccessfulRetrieval)
56{
57 TestTraceContainer trace;
58 init_trace(trace);
59 BytecodeTraceBuilder builder;
60 ContractInstanceRetrievalTraceBuilder contract_instance_retrieval_builder;
61 ClassIdDerivationTraceBuilder class_id_builder;
62 RetrievedBytecodesTreeCheckTraceBuilder retrieved_bytecodes_tree_check_builder;
63
64 FF nullifier_root = FF::random_element();
65 FF public_data_tree_root = FF::random_element();
66
67 ContractInstance instance = random_contract_instance();
68 uint32_t bytecode_size = 20;
69 ContractClass klass = random_contract_class(/*bytecode_size=*/bytecode_size);
70 std::vector<FF> bytecode_fields = simulation::encode_bytecode(klass.packed_bytecode);
71 std::vector<FF> hash_input = { simulation::compute_public_bytecode_first_field(klass.packed_bytecode.size()) };
72 hash_input.reserve(1 + bytecode_fields.size());
73 hash_input.insert(hash_input.end(), bytecode_fields.begin(), bytecode_fields.end());
74 // Compute the bytecode commitment separately
75 FF bytecode_commitment = RawPoseidon2::hash(hash_input);
76 builder.process_hashing({ { .bytecode_id = bytecode_commitment,
77 .bytecode_length = bytecode_size,
78 .bytecode_fields = bytecode_fields } },
79 trace);
80 contract_instance_retrieval_builder.process({ {
81 .address = instance.deployer,
82 .contract_instance = { instance },
83 .nullifier_tree_root = nullifier_root,
84 .public_data_tree_root = public_data_tree_root,
85 .exists = true,
86 } },
87 trace);
88 ContractClassWithCommitment klass_with_commitment = {
89 .id = instance.current_contract_class_id,
90 .artifact_hash = klass.artifact_hash,
91 .private_functions_root = klass.private_functions_root,
92 .packed_bytecode = klass.packed_bytecode,
93 .public_bytecode_commitment = bytecode_commitment,
94 };
95 class_id_builder.process({ { .klass = klass_with_commitment } }, trace);
96
97 AppendOnlyTreeSnapshot snapshot_before = AppendOnlyTreeSnapshot{
99 .next_available_leaf_index = AVM_RETRIEVED_BYTECODES_TREE_INITIAL_SIZE,
100 };
101
102 AppendOnlyTreeSnapshot snapshot_after = AppendOnlyTreeSnapshot{
103 .root = FF(42),
104 .next_available_leaf_index = AVM_RETRIEVED_BYTECODES_TREE_INITIAL_SIZE + 1,
105 };
106
107 // Read the tree of the retrieved bytecodes
108 retrieved_bytecodes_tree_check_builder.process(
109 { RetrievedBytecodesTreeCheckEvent{
110 .class_id = instance.current_contract_class_id,
111 .prev_snapshot = snapshot_before,
112 .next_snapshot = snapshot_after,
113 .low_leaf_preimage = RetrievedBytecodesTreeLeafPreimage(ClassIdLeafValue(0), 0, 0),
114 .low_leaf_index = 0,
115 } },
116 trace);
117
118 // Insertion in the retrieved bytecodes tree
119 retrieved_bytecodes_tree_check_builder.process(
120 { RetrievedBytecodesTreeCheckEvent{
121 .class_id = instance.current_contract_class_id,
122 .prev_snapshot = snapshot_before,
123 .next_snapshot = snapshot_after,
124 .low_leaf_preimage = RetrievedBytecodesTreeLeafPreimage(ClassIdLeafValue(0), 0, 0),
125 .low_leaf_index = 0,
126 .write = true,
127 } },
128 trace);
129
130 // Build a bytecode retrieval event where instance exists
131 builder.process_retrieval({ {
132 .bytecode_id = bytecode_commitment, // bytecode_id equals commitment
133 .address = instance.deployer,
134 .current_class_id = instance.current_contract_class_id,
135 .contract_class = klass,
136 .nullifier_root = nullifier_root,
137 .public_data_tree_root = public_data_tree_root,
138 .retrieved_bytecodes_snapshot_before = snapshot_before,
139 .retrieved_bytecodes_snapshot_after = snapshot_after,
140 .is_new_class = true,
141 } },
142 trace);
143
144 check_relation<bc_retrieval>(trace);
145 check_interaction<BytecodeTraceBuilder,
150}
151
152TEST(BytecodeRetrievalConstrainingTest, TooManyBytecodes)
153{
154 TestTraceContainer trace;
155 init_trace(trace);
156 BytecodeTraceBuilder builder;
157
158 FF nullifier_root = FF::random_element();
159 FF public_data_tree_root = FF::random_element();
160
161 ContractInstance instance = random_contract_instance();
162 uint32_t bytecode_size = 20;
163 ContractClass klass = random_contract_class(/*bytecode_size=*/bytecode_size);
164
165 AppendOnlyTreeSnapshot snapshot_before = AppendOnlyTreeSnapshot{
166 .root = FF(42),
167 .next_available_leaf_index =
169 };
170
171 AppendOnlyTreeSnapshot snapshot_after = AppendOnlyTreeSnapshot{
172 .root = FF(42),
173 .next_available_leaf_index =
175 };
176
177 // Build a bytecode retrieval event where instance exists
178 builder.process_retrieval({ {
179 .bytecode_id = 0, // bytecode_id equals commitment
180 .address = instance.deployer,
181 .current_class_id = instance.current_contract_class_id,
182 .nullifier_root = nullifier_root,
183 .public_data_tree_root = public_data_tree_root,
184 .retrieved_bytecodes_snapshot_before = snapshot_before,
185 .retrieved_bytecodes_snapshot_after = snapshot_after,
186 .is_new_class = true,
187 .limit_error = true,
188 } },
189 trace);
190
191 check_relation<bc_retrieval>(trace);
192}
193
194TEST(BytecodeRetrievalConstrainingTest, NonExistentInstance)
195{
196
197 TestTraceContainer trace;
198 init_trace(trace);
199
201
202 // Manually set up a row where instance_exists = 0
203 // All other fields should be forced to 0 by constraints
204 trace.set(
205 1,
206 { {
207 { C::bc_retrieval_sel, 1 },
208 { C::bc_retrieval_instance_exists, 0 },
209 { C::bc_retrieval_current_class_id, 0 },
210 { C::bc_retrieval_artifact_hash, 0 },
211 { C::bc_retrieval_private_functions_root, 0 },
212 { C::bc_retrieval_bytecode_id, 0 },
213 { C::bc_retrieval_address, contract_address },
214 { C::bc_retrieval_prev_retrieved_bytecodes_tree_size, 1 },
215 { C::bc_retrieval_next_retrieved_bytecodes_tree_size, 1 },
216 { C::bc_retrieval_remaining_bytecodes_inv, FF(MAX_PUBLIC_CALLS_TO_UNIQUE_CONTRACT_CLASS_IDS).invert() },
217 { C::bc_retrieval_error, 1 },
218 } });
219
220 check_relation<bc_retrieval>(trace);
221
222 // mutate the current_class_id and confirm that a violation as it should be 0
223 trace.set(C::bc_retrieval_current_class_id, 1, 99);
224 EXPECT_THROW_WITH_MESSAGE(check_relation<bc_retrieval>(trace),
225 "CURRENT_CLASS_ID_IS_ZERO_IF_INSTANCE_DOES_NOT_EXIST");
226 // reset
227 trace.set(C::bc_retrieval_current_class_id, 1, 0);
228
229 // mutate the artifact_hash and confirm that it is a violation
230 trace.set(C::bc_retrieval_artifact_hash, 1, 99);
231 EXPECT_THROW_WITH_MESSAGE(check_relation<bc_retrieval>(trace), "ARTIFACT_HASH_IS_ZERO_IF_ERROR");
232 // reset
233 trace.set(C::bc_retrieval_artifact_hash, 1, 0);
234
235 // mutate the private_functions_root and confirm that it is a violation
236 trace.set(C::bc_retrieval_private_functions_root, 1, 99);
237 EXPECT_THROW_WITH_MESSAGE(check_relation<bc_retrieval>(trace), "PRIVATE_FUNCTION_ROOT_IS_ZERO_IF_ERROR");
238 // reset
239 trace.set(C::bc_retrieval_private_functions_root, 1, 0);
240
241 // mutate the bytecode_id and confirm that it is a violation
242 trace.set(C::bc_retrieval_bytecode_id, 1, 99);
243 EXPECT_THROW_WITH_MESSAGE(check_relation<bc_retrieval>(trace), "BYTECODE_ID_IS_ZERO_IF_ERROR");
244 // reset
245 trace.set(C::bc_retrieval_bytecode_id, 1, 0);
246}
247
248} // namespace
249} // namespace bb::avm2::constraining
#define EXPECT_THROW_WITH_MESSAGE(code, expectedMessageRegex)
Definition assert.hpp:193
std::shared_ptr< Napi::ThreadSafeFunction > instance
#define AVM_RETRIEVED_BYTECODES_TREE_INITIAL_ROOT
#define AVM_RETRIEVED_BYTECODES_TREE_INITIAL_SIZE
#define MAX_PUBLIC_CALLS_TO_UNIQUE_CONTRACT_CLASS_IDS
void process(const simulation::EventEmitterInterface< simulation::AluEvent >::Container &events, TraceContainer &trace)
Process the ALU events and populate the ALU relevant columns in the trace.
void set(Column col, uint32_t row, const FF &value)
static FF hash(const std::vector< FF > &input)
Hashes a vector of field elements.
AluTraceBuilder builder
Definition alu.test.cpp:124
TestTraceContainer trace
void check_interaction(tracegen::TestTraceContainer &trace)
TEST(AvmFixedVKTests, FixedVKCommitments)
Test that the fixed VK commitments agree with the ones computed from precomputed columns.
IndexedLeaf< ClassIdLeafValue > RetrievedBytecodesTreeLeafPreimage
std::vector< FF > encode_bytecode(std::span< const uint8_t > bytecode)
FF compute_public_bytecode_first_field(size_t bytecode_size)
ContractClass random_contract_class(size_t bytecode_size)
Definition fixtures.cpp:175
ContractInstance random_contract_instance()
Definition fixtures.cpp:159
TestTraceContainer empty_trace()
Definition fixtures.cpp:153
lookup_settings< lookup_bc_retrieval_retrieved_bytecodes_insertion_settings_ > lookup_bc_retrieval_retrieved_bytecodes_insertion_settings
lookup_settings< lookup_bc_retrieval_contract_instance_retrieval_settings_ > lookup_bc_retrieval_contract_instance_retrieval_settings
AvmFlavorSettings::FF FF
Definition field.hpp:10
lookup_settings< lookup_bc_retrieval_class_id_derivation_settings_ > lookup_bc_retrieval_class_id_derivation_settings
lookup_settings< lookup_bc_retrieval_is_new_class_check_settings_ > lookup_bc_retrieval_is_new_class_check_settings
constexpr field invert() const noexcept
static field random_element(numeric::RNG *engine=nullptr) noexcept