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 = { GENERATOR_INDEX__PUBLIC_BYTECODE };
72 hash_input.insert(hash_input.end(), bytecode_fields.begin(), bytecode_fields.end());
73 // Compute the bytecode commitment separately
74 FF bytecode_commitment = RawPoseidon2::hash(hash_input);
75 builder.process_hashing({ { .bytecode_id = bytecode_commitment,
76 .bytecode_length = bytecode_size,
77 .bytecode_fields = bytecode_fields } },
78 trace);
79 contract_instance_retrieval_builder.process({ {
80 .address = instance.deployer,
81 .contract_instance = { instance },
82 .nullifier_tree_root = nullifier_root,
83 .public_data_tree_root = public_data_tree_root,
84 .exists = true,
85 } },
86 trace);
87 ContractClassWithCommitment klass_with_commitment = {
88 .id = instance.current_contract_class_id,
89 .artifact_hash = klass.artifact_hash,
90 .private_functions_root = klass.private_functions_root,
91 .packed_bytecode = klass.packed_bytecode,
92 .public_bytecode_commitment = bytecode_commitment,
93 };
94 class_id_builder.process({ { .klass = klass_with_commitment } }, trace);
95
96 AppendOnlyTreeSnapshot snapshot_before = AppendOnlyTreeSnapshot{
98 .next_available_leaf_index = AVM_RETRIEVED_BYTECODES_TREE_INITIAL_SIZE,
99 };
100
101 AppendOnlyTreeSnapshot snapshot_after = AppendOnlyTreeSnapshot{
102 .root = FF(42),
103 .next_available_leaf_index = AVM_RETRIEVED_BYTECODES_TREE_INITIAL_SIZE + 1,
104 };
105
106 // Read the tree of the retrieved bytecodes
107 retrieved_bytecodes_tree_check_builder.process(
108 { RetrievedBytecodesTreeCheckEvent{
109 .class_id = instance.current_contract_class_id,
110 .prev_snapshot = snapshot_before,
111 .next_snapshot = snapshot_after,
112 .low_leaf_preimage = RetrievedBytecodesTreeLeafPreimage(ClassIdLeafValue(0), 0, 0),
113 .low_leaf_index = 0,
114 } },
115 trace);
116
117 // Insertion in the retrieved bytecodes tree
118 retrieved_bytecodes_tree_check_builder.process(
119 { RetrievedBytecodesTreeCheckEvent{
120 .class_id = instance.current_contract_class_id,
121 .prev_snapshot = snapshot_before,
122 .next_snapshot = snapshot_after,
123 .low_leaf_preimage = RetrievedBytecodesTreeLeafPreimage(ClassIdLeafValue(0), 0, 0),
124 .low_leaf_index = 0,
125 .write = true,
126 } },
127 trace);
128
129 // Build a bytecode retrieval event where instance exists
130 builder.process_retrieval({ {
131 .bytecode_id = bytecode_commitment, // bytecode_id equals commitment
132 .address = instance.deployer,
133 .current_class_id = instance.current_contract_class_id,
134 .contract_class = klass,
135 .nullifier_root = nullifier_root,
136 .public_data_tree_root = public_data_tree_root,
137 .retrieved_bytecodes_snapshot_before = snapshot_before,
138 .retrieved_bytecodes_snapshot_after = snapshot_after,
139 .is_new_class = true,
140 } },
141 trace);
142
143 check_relation<bc_retrieval>(trace);
144 check_interaction<BytecodeTraceBuilder,
149}
150
151TEST(BytecodeRetrievalConstrainingTest, TooManyBytecodes)
152{
153 TestTraceContainer trace;
154 init_trace(trace);
155 BytecodeTraceBuilder builder;
156
157 FF nullifier_root = FF::random_element();
158 FF public_data_tree_root = FF::random_element();
159
160 ContractInstance instance = random_contract_instance();
161 uint32_t bytecode_size = 20;
162 ContractClass klass = random_contract_class(/*bytecode_size=*/bytecode_size);
163
164 AppendOnlyTreeSnapshot snapshot_before = AppendOnlyTreeSnapshot{
165 .root = FF(42),
166 .next_available_leaf_index =
168 };
169
170 AppendOnlyTreeSnapshot snapshot_after = AppendOnlyTreeSnapshot{
171 .root = FF(42),
172 .next_available_leaf_index =
174 };
175
176 // Build a bytecode retrieval event where instance exists
177 builder.process_retrieval({ {
178 .bytecode_id = 0, // bytecode_id equals commitment
179 .address = instance.deployer,
180 .current_class_id = instance.current_contract_class_id,
181 .nullifier_root = nullifier_root,
182 .public_data_tree_root = public_data_tree_root,
183 .retrieved_bytecodes_snapshot_before = snapshot_before,
184 .retrieved_bytecodes_snapshot_after = snapshot_after,
185 .is_new_class = true,
186 .limit_error = true,
187 } },
188 trace);
189
190 check_relation<bc_retrieval>(trace);
191}
192
193TEST(BytecodeRetrievalConstrainingTest, NonExistentInstance)
194{
195
196 TestTraceContainer trace;
197 init_trace(trace);
198
200
201 // Manually set up a row where instance_exists = 0
202 // All other fields should be forced to 0 by constraints
203 trace.set(
204 1,
205 { {
206 { C::bc_retrieval_sel, 1 },
207 { C::bc_retrieval_instance_exists, 0 },
208 { C::bc_retrieval_current_class_id, 0 },
209 { C::bc_retrieval_artifact_hash, 0 },
210 { C::bc_retrieval_private_functions_root, 0 },
211 { C::bc_retrieval_bytecode_id, 0 },
212 { C::bc_retrieval_address, contract_address },
213 { C::bc_retrieval_prev_retrieved_bytecodes_tree_size, 1 },
214 { C::bc_retrieval_next_retrieved_bytecodes_tree_size, 1 },
215 { C::bc_retrieval_remaining_bytecodes_inv, FF(MAX_PUBLIC_CALLS_TO_UNIQUE_CONTRACT_CLASS_IDS).invert() },
216 { C::bc_retrieval_error, 1 },
217 } });
218
219 check_relation<bc_retrieval>(trace);
220
221 // mutate the current_class_id and confirm that a violation as it should be 0
222 trace.set(C::bc_retrieval_current_class_id, 1, 99);
223 EXPECT_THROW_WITH_MESSAGE(check_relation<bc_retrieval>(trace),
224 "CURRENT_CLASS_ID_IS_ZERO_IF_INSTANCE_DOES_NOT_EXIST");
225 // reset
226 trace.set(C::bc_retrieval_current_class_id, 1, 0);
227
228 // mutate the artifact_hash and confirm that it is a violation
229 trace.set(C::bc_retrieval_artifact_hash, 1, 99);
230 EXPECT_THROW_WITH_MESSAGE(check_relation<bc_retrieval>(trace), "ARTIFACT_HASH_IS_ZERO_IF_ERROR");
231 // reset
232 trace.set(C::bc_retrieval_artifact_hash, 1, 0);
233
234 // mutate the private_functions_root and confirm that it is a violation
235 trace.set(C::bc_retrieval_private_functions_root, 1, 99);
236 EXPECT_THROW_WITH_MESSAGE(check_relation<bc_retrieval>(trace), "PRIVATE_FUNCTION_ROOT_IS_ZERO_IF_ERROR");
237 // reset
238 trace.set(C::bc_retrieval_private_functions_root, 1, 0);
239
240 // mutate the bytecode_id and confirm that it is a violation
241 trace.set(C::bc_retrieval_bytecode_id, 1, 99);
242 EXPECT_THROW_WITH_MESSAGE(check_relation<bc_retrieval>(trace), "BYTECODE_ID_IS_ZERO_IF_ERROR");
243 // reset
244 trace.set(C::bc_retrieval_bytecode_id, 1, 0);
245}
246
247} // namespace
248} // namespace bb::avm2::constraining
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
#define GENERATOR_INDEX__PUBLIC_BYTECODE
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
#define EXPECT_THROW_WITH_MESSAGE(code, expectedMessage)
Definition macros.hpp:7
void check_interaction(tracegen::TestTraceContainer &trace)
TEST(TxExecutionConstrainingTest, WriteTreeValue)
Definition tx.test.cpp:441
IndexedLeaf< ClassIdLeafValue > RetrievedBytecodesTreeLeafPreimage
std::vector< FF > encode_bytecode(std::span< const uint8_t > bytecode)
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
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
AvmFlavorSettings::FF FF
Definition field.hpp:10
constexpr field invert() const noexcept
static field random_element(numeric::RNG *engine=nullptr) noexcept