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 // random_contract_class() assigns a random FF as the commitment, so we overwrite to ensure the below passes:
74 klass.public_bytecode_commitment = RawPoseidon2::hash(hash_input);
75 builder.process_hashing({ { .bytecode_id = klass.public_bytecode_commitment,
76 .bytecode_length = bytecode_size,
77 .bytecode_fields = bytecode_fields } },
78 trace);
79 contract_instance_retrieval_builder.process({ {
80 .address = instance.deployer_addr,
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 class_id_builder.process({ { .class_id = instance.current_class_id, .klass = klass } }, trace);
88
89 AppendOnlyTreeSnapshot snapshot_before = AppendOnlyTreeSnapshot{
91 .nextAvailableLeafIndex = AVM_RETRIEVED_BYTECODES_TREE_INITIAL_SIZE,
92 };
93
94 AppendOnlyTreeSnapshot snapshot_after = AppendOnlyTreeSnapshot{
95 .root = FF(42),
96 .nextAvailableLeafIndex = AVM_RETRIEVED_BYTECODES_TREE_INITIAL_SIZE + 1,
97 };
98
99 // Read the tree of the retrieved bytecodes
100 retrieved_bytecodes_tree_check_builder.process(
101 { RetrievedBytecodesTreeCheckEvent{
102 .class_id = instance.current_class_id,
103 .prev_snapshot = snapshot_before,
104 .next_snapshot = snapshot_after,
105 .low_leaf_preimage = RetrievedBytecodesTreeLeafPreimage(ClassIdLeafValue(0), 0, 0),
106 .low_leaf_index = 0,
107 } },
108 trace);
109
110 // Insertion in the retrieved bytecodes tree
111 retrieved_bytecodes_tree_check_builder.process(
112 { RetrievedBytecodesTreeCheckEvent{
113 .class_id = instance.current_class_id,
114 .prev_snapshot = snapshot_before,
115 .next_snapshot = snapshot_after,
116 .low_leaf_preimage = RetrievedBytecodesTreeLeafPreimage(ClassIdLeafValue(0), 0, 0),
117 .low_leaf_index = 0,
118 .write = true,
119 } },
120 trace);
121
122 // Build a bytecode retrieval event where instance exists
123 builder.process_retrieval({ {
124 .bytecode_id = klass.public_bytecode_commitment, // bytecode_id equals commitment
125 .address = instance.deployer_addr,
126 .current_class_id = instance.current_class_id,
127 .contract_class = klass,
128 .nullifier_root = nullifier_root,
129 .public_data_tree_root = public_data_tree_root,
130 .retrieved_bytecodes_snapshot_before = snapshot_before,
131 .retrieved_bytecodes_snapshot_after = snapshot_after,
132 .is_new_class = true,
133 } },
134 trace);
135
136 check_relation<bc_retrieval>(trace);
137 check_interaction<BytecodeTraceBuilder,
142}
143
144TEST(BytecodeRetrievalConstrainingTest, TooManyBytecodes)
145{
146 TestTraceContainer trace;
147 init_trace(trace);
148 BytecodeTraceBuilder builder;
149
150 FF nullifier_root = FF::random_element();
151 FF public_data_tree_root = FF::random_element();
152
153 ContractInstance instance = random_contract_instance();
154 uint32_t bytecode_size = 20;
155 ContractClass klass = random_contract_class(/*bytecode_size=*/bytecode_size);
156
157 AppendOnlyTreeSnapshot snapshot_before = AppendOnlyTreeSnapshot{
158 .root = FF(42),
159 .nextAvailableLeafIndex =
161 };
162
163 AppendOnlyTreeSnapshot snapshot_after = AppendOnlyTreeSnapshot{
164 .root = FF(42),
165 .nextAvailableLeafIndex =
167 };
168
169 // Build a bytecode retrieval event where instance exists
170 builder.process_retrieval({ {
171 .bytecode_id = 0, // bytecode_id equals commitment
172 .address = instance.deployer_addr,
173 .current_class_id = instance.current_class_id,
174 .nullifier_root = nullifier_root,
175 .public_data_tree_root = public_data_tree_root,
176 .retrieved_bytecodes_snapshot_before = snapshot_before,
177 .retrieved_bytecodes_snapshot_after = snapshot_after,
178 .is_new_class = true,
179 .limit_error = true,
180 } },
181 trace);
182
183 check_relation<bc_retrieval>(trace);
184}
185
186TEST(BytecodeRetrievalConstrainingTest, NonExistentInstance)
187{
188
189 TestTraceContainer trace;
190 init_trace(trace);
191
192 FF contract_address = FF::random_element();
193
194 // Manually set up a row where instance_exists = 0
195 // All other fields should be forced to 0 by constraints
196 trace.set(
197 1,
198 { {
199 { C::bc_retrieval_sel, 1 },
200 { C::bc_retrieval_instance_exists, 0 },
201 { C::bc_retrieval_current_class_id, 0 },
202 { C::bc_retrieval_artifact_hash, 0 },
203 { C::bc_retrieval_private_function_root, 0 },
204 { C::bc_retrieval_bytecode_id, 0 },
205 { C::bc_retrieval_address, contract_address },
206 { C::bc_retrieval_prev_retrieved_bytecodes_tree_size, 1 },
207 { C::bc_retrieval_next_retrieved_bytecodes_tree_size, 1 },
208 { C::bc_retrieval_remaining_bytecodes_inv, FF(MAX_PUBLIC_CALLS_TO_UNIQUE_CONTRACT_CLASS_IDS).invert() },
209 { C::bc_retrieval_error, 1 },
210 } });
211
212 check_relation<bc_retrieval>(trace);
213
214 // mutate the current_class_id and confirm that a violation as it should be 0
215 trace.set(C::bc_retrieval_current_class_id, 1, 99);
216 EXPECT_THROW_WITH_MESSAGE(check_relation<bc_retrieval>(trace),
217 "CURRENT_CLASS_ID_IS_ZERO_IF_INSTANCE_DOES_NOT_EXIST");
218 // reset
219 trace.set(C::bc_retrieval_current_class_id, 1, 0);
220
221 // mutate the artifact_hash and confirm that it is a violation
222 trace.set(C::bc_retrieval_artifact_hash, 1, 99);
223 EXPECT_THROW_WITH_MESSAGE(check_relation<bc_retrieval>(trace), "ARTIFACT_HASH_IS_ZERO_IF_ERROR");
224 // reset
225 trace.set(C::bc_retrieval_artifact_hash, 1, 0);
226
227 // mutate the private_function_root and confirm that it is a violation
228 trace.set(C::bc_retrieval_private_function_root, 1, 99);
229 EXPECT_THROW_WITH_MESSAGE(check_relation<bc_retrieval>(trace), "PRIVATE_FUNCTION_ROOT_IS_ZERO_IF_ERROR");
230 // reset
231 trace.set(C::bc_retrieval_private_function_root, 1, 0);
232
233 // mutate the bytecode_id and confirm that it is a violation
234 trace.set(C::bc_retrieval_bytecode_id, 1, 99);
235 EXPECT_THROW_WITH_MESSAGE(check_relation<bc_retrieval>(trace), "BYTECODE_ID_IS_ZERO_IF_ERROR");
236 // reset
237 trace.set(C::bc_retrieval_bytecode_id, 1, 0);
238}
239
240} // namespace
241} // namespace bb::avm2::constraining
#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)
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:123
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:402
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
typename Flavor::FF FF