Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
bc_decomposition.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
17
18namespace bb::avm2::constraining {
19namespace {
20
23using tracegen::BytecodeTraceBuilder;
25using tracegen::TestTraceContainer;
26
28using C = Column;
29using bc_decomposition = bb::avm2::bc_decomposition<FF>;
30
31void init_trace(TestTraceContainer& trace)
32{
33 // Add first row.
34 trace.set(C::precomputed_first_row, 0, 1);
35}
36
37TEST(BytecodeDecompositionConstrainingTest, EmptyRow)
38{
39 check_relation<bc_decomposition>(testing::empty_trace());
40}
41
42TEST(BytecodeDecompositionConstrainingTest, SingleBytecode)
43{
44 TestTraceContainer trace;
45 init_trace(trace);
46 BytecodeTraceBuilder builder;
47 builder.process_decomposition(
48 { { .bytecode_id = 1, .bytecode = std::make_shared<std::vector<uint8_t>>(random_bytes(40)) } }, trace);
49
50 EXPECT_EQ(trace.get_num_rows(), 1 + 40);
51 check_relation<bc_decomposition>(trace);
52}
53
54TEST(BytecodeDecompositionConstrainingTest, ShortSingleBytecode)
55{
56 // Bytecode is shorter than the sliding window.
57 TestTraceContainer trace;
58 init_trace(trace);
59 BytecodeTraceBuilder builder;
60 builder.process_decomposition(
61 { { .bytecode_id = 1, .bytecode = std::make_shared<std::vector<uint8_t>>(random_bytes(5)) } }, trace);
62
63 EXPECT_EQ(trace.get_num_rows(), 1 + 5);
64 check_relation<bc_decomposition>(trace);
65}
66
67TEST(BytecodeDecompositionConstrainingTest, MultipleBytecodes)
68{
69 TestTraceContainer trace;
70 init_trace(trace);
71 BytecodeTraceBuilder builder;
72 builder.process_decomposition(
73 { { .bytecode_id = 1, .bytecode = std::make_shared<std::vector<uint8_t>>(random_bytes(40)) },
74 { .bytecode_id = 2, .bytecode = std::make_shared<std::vector<uint8_t>>(random_bytes(55)) } },
75 trace);
76
77 EXPECT_EQ(trace.get_num_rows(), 1 + 40 + 55);
78 check_relation<bc_decomposition>(trace);
79}
80
81TEST(BytecodeDecompositionConstrainingTest, MultipleBytecodesWithShortOnes)
82{
83 TestTraceContainer trace;
84 init_trace(trace);
85 BytecodeTraceBuilder builder;
86 builder.process_decomposition(
87 { { .bytecode_id = 1, .bytecode = std::make_shared<std::vector<uint8_t>>(random_bytes(40)) },
88 { .bytecode_id = 2, .bytecode = std::make_shared<std::vector<uint8_t>>(random_bytes(5)) },
89 { .bytecode_id = 3, .bytecode = std::make_shared<std::vector<uint8_t>>(random_bytes(10)) },
90 { .bytecode_id = 4, .bytecode = std::make_shared<std::vector<uint8_t>>(random_bytes(55)) },
91 { .bytecode_id = 5, .bytecode = std::make_shared<std::vector<uint8_t>>(random_bytes(2)) } },
92 trace);
93
94 EXPECT_EQ(trace.get_num_rows(), 1 + 40 + 5 + 10 + 55 + 2);
95 check_relation<bc_decomposition>(trace);
96}
97
98TEST(BytecodeDecompositionConstrainingTest, NegativeDeactivatedSel)
99{
100 TestTraceContainer trace = TestTraceContainer::from_rows({
101 {
102 .bc_decomposition_bytes_rem_inv = FF(33).invert(),
103 .bc_decomposition_bytes_remaining = 33,
104 .bc_decomposition_sel = 1,
105 },
106 {
107 .bc_decomposition_bytes_rem_inv = FF(32).invert(),
108 .bc_decomposition_bytes_remaining = 32,
109 .bc_decomposition_sel = 1,
110 },
111 {
112 .bc_decomposition_bytes_rem_inv = FF(31).invert(),
113 .bc_decomposition_bytes_remaining = 31,
114 .bc_decomposition_sel = 1,
115 },
116 });
117
118 check_relation<bc_decomposition>(trace, bc_decomposition::SR_BC_DEC_SEL_BYTES_REM_NON_ZERO);
119 trace.set(C::bc_decomposition_sel, 2, 0); // Mutate to wrong value
121 check_relation<bc_decomposition>(trace, bc_decomposition::SR_BC_DEC_SEL_BYTES_REM_NON_ZERO),
122 "BC_DEC_SEL_BYTES_REM_NON_ZERO");
123}
124
125TEST(BytecodeDecompositionConstrainingTest, NegativeDeactivateLastContract)
126{
127 TestTraceContainer trace = TestTraceContainer::from_rows({
128 {
129 .bc_decomposition_bytes_rem_min_one_inv = FF(2).invert(),
130 .bc_decomposition_bytes_remaining = 3,
131 .bc_decomposition_sel = 1,
132 },
133 {
134 .bc_decomposition_bytes_rem_min_one_inv = 1,
135 .bc_decomposition_bytes_remaining = 2,
136 .bc_decomposition_sel = 1,
137 },
138 {
139 .bc_decomposition_bytes_rem_min_one_inv = 0,
140 .bc_decomposition_bytes_remaining = 1,
141 .bc_decomposition_last_of_contract = 1,
142 .bc_decomposition_sel = 1,
143 },
144 });
145
146 check_relation<bc_decomposition>(trace, bc_decomposition::SR_BC_DEC_LAST_CONTRACT_BYTES_REM_ONE);
147 trace.set(C::bc_decomposition_last_of_contract, 2, 0); // Mutate to wrong value
149 check_relation<bc_decomposition>(trace, bc_decomposition::SR_BC_DEC_LAST_CONTRACT_BYTES_REM_ONE),
150 "BC_DEC_LAST_CONTRACT_BYTES_REM_ONE");
151}
152
153TEST(BytecodeDecompositionConstrainingTest, NegativePcWrongInitializationFirstRow)
154{
155 TestTraceContainer trace = TestTraceContainer::from_rows({
156 { .precomputed_first_row = 1 },
157 {
158 .bc_decomposition_pc = 0,
159 .bc_decomposition_sel = 1,
160 },
161 });
162
163 check_relation<bc_decomposition>(trace, bc_decomposition::SR_BC_DEC_PC_ZERO_INITIALIZATION);
164 trace.set(C::bc_decomposition_pc, 1, 7); // Mutate to wrong value
166 check_relation<bc_decomposition>(trace, bc_decomposition::SR_BC_DEC_PC_ZERO_INITIALIZATION),
167 "BC_DEC_PC_ZERO_INITIALIZATION");
168}
169
170TEST(BytecodeDecompositionConstrainingTest, NegativePcWrongInitializationInside)
171{
172 TestTraceContainer trace = TestTraceContainer::from_rows({
173 { .bc_decomposition_last_of_contract = 1 },
174 {
175 .bc_decomposition_pc = 0,
176 .bc_decomposition_sel = 1,
177 },
178 });
179
180 check_relation<bc_decomposition>(trace, bc_decomposition::SR_BC_DEC_PC_ZERO_INITIALIZATION);
181 trace.set(C::bc_decomposition_pc, 1, 32); // Mutate to wrong value
183 check_relation<bc_decomposition>(trace, bc_decomposition::SR_BC_DEC_PC_ZERO_INITIALIZATION),
184 "BC_DEC_PC_ZERO_INITIALIZATION");
185}
186
187TEST(BytecodeDecompositionConstrainingTest, NegativePcWrongIncrement)
188{
189 TestTraceContainer trace = TestTraceContainer::from_rows({
190 {
191 .bc_decomposition_pc = 5,
192 .bc_decomposition_sel = 1,
193 },
194 {
195 .bc_decomposition_pc = 6,
196 .bc_decomposition_sel = 1,
197 },
198 {
199 .bc_decomposition_last_of_contract = 1, // Required otherwise the test passes trivially
200 .bc_decomposition_pc = 7,
201 .bc_decomposition_sel = 1,
202 },
203 });
204
205 check_relation<bc_decomposition>(trace, bc_decomposition::SR_BC_DEC_PC_INCREMENT);
206 trace.set(C::bc_decomposition_pc, 2, 6); // Mutate to wrong value
208 "BC_DEC_PC_INCREMENT");
209}
210
211TEST(BytecodeDecompositionConstrainingTest, NegativeBytesRemWrongDecrement)
212{
213 TestTraceContainer trace = TestTraceContainer::from_rows({
214 {
215 .bc_decomposition_bytes_remaining = 5,
216 .bc_decomposition_sel = 1,
217 },
218 {
219 .bc_decomposition_bytes_remaining = 4,
220 .bc_decomposition_sel = 1,
221 },
222 {
223 .bc_decomposition_bytes_remaining = 3,
224 .bc_decomposition_last_of_contract = 1, // Required otherwise the test passes trivially
225 .bc_decomposition_sel = 1,
226 },
227 });
228
229 check_relation<bc_decomposition>(trace, bc_decomposition::SR_BC_DEC_BYTES_REMAINING_DECREMENT);
230 trace.set(C::bc_decomposition_bytes_remaining, 0, 4); // Mutate to wrong value
232 check_relation<bc_decomposition>(trace, bc_decomposition::SR_BC_DEC_BYTES_REMAINING_DECREMENT),
233 "BC_DEC_BYTES_REMAINING_DECREMENT");
234}
235
236TEST(BytecodeDecompositionConstrainingTest, NegativeMutateBytecodeId)
237{
238 TestTraceContainer trace = TestTraceContainer::from_rows({
239 {
240 .bc_decomposition_id = 147,
241 .bc_decomposition_sel = 1,
242 },
243 {
244 .bc_decomposition_id = 147,
245 .bc_decomposition_sel = 1,
246 },
247 {
248 .bc_decomposition_id = 147,
249 .bc_decomposition_last_of_contract = 1, // Required otherwise the test passes trivially
250 .bc_decomposition_sel = 1,
251 },
252 });
253
254 check_relation<bc_decomposition>(trace, bc_decomposition::SR_BC_DEC_ID_CONSTANT);
255 trace.set(C::bc_decomposition_id, 2, 77); // Mutate to wrong value
257 "BC_DEC_ID_CONSTANT");
258}
259
260// Both positive and negative tests for sel_windows_gt_remaining initialization
261TEST(BytecodeDecompositionConstrainingTest, SelWindowsGtRemainingInitialization)
262{
263 TestTraceContainer trace = TestTraceContainer::from_rows({
264 {
265 .bc_decomposition_last_of_contract = 1,
266 .bc_decomposition_sel = 1,
267 .bc_decomposition_sel_windows_gt_remaining = 1,
268 },
269 });
270
271 check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_WINDOWS_GT_REMAINING_INIT);
272
273 trace.set(C::bc_decomposition_sel_windows_gt_remaining, 0, 0); // Mutate to wrong value
275 check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_WINDOWS_GT_REMAINING_INIT),
276 "SEL_WINDOWS_GT_REMAINING_INIT");
277}
278
279// Both positive and negative tests for sel_windows_gt_remaining propagation without mutation.
280TEST(BytecodeDecompositionConstrainingTest, SelWindowsGtRemainingPropagation)
281{
282 TestTraceContainer trace = TestTraceContainer::from_rows({
283 {
284 .bc_decomposition_sel = 1,
285 .bc_decomposition_sel_windows_gt_remaining = 1,
286 },
287 {
288 .bc_decomposition_last_of_contract = 1,
289 .bc_decomposition_sel = 1,
290 .bc_decomposition_sel_windows_gt_remaining = 1,
291 },
292 });
293
294 check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_WINDOWS_GT_REMAINING_PROPAGATION);
295
296 trace.set(C::bc_decomposition_sel_windows_gt_remaining, 0, 0); // Mutate to wrong value at the top
298 check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_WINDOWS_GT_REMAINING_PROPAGATION),
299 "SEL_WINDOWS_GT_REMAINING_PROPAGATION");
300
301 // Reset to correct value
302 trace.set(C::bc_decomposition_sel_windows_gt_remaining, 0, 1);
303
304 trace.set(C::bc_decomposition_sel_windows_gt_remaining, 1, 0); // Mutate to wrong value at the bottom
306 check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_WINDOWS_GT_REMAINING_PROPAGATION),
307 "SEL_WINDOWS_GT_REMAINING_PROPAGATION");
308
309 // Test propagattion of 0 instead of 1
310 trace.set(C::bc_decomposition_sel_windows_gt_remaining, 0, 0); // Mutate to correct value
311 check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_WINDOWS_GT_REMAINING_PROPAGATION);
312}
313
314// Both positive and negative tests for sel_windows_gt_remaining propagation with mutation.
315TEST(BytecodeDecompositionConstrainingTest, SelWindowsGtRemainingPropagationWithMutation)
316{
317 TestTraceContainer trace = TestTraceContainer::from_rows({
318 {
319 .bc_decomposition_is_windows_eq_remaining = 1,
320 .bc_decomposition_sel = 1,
321 .bc_decomposition_sel_windows_gt_remaining = 0,
322 },
323 {
324 .bc_decomposition_sel = 1,
325 .bc_decomposition_sel_windows_gt_remaining = 1,
326 },
327 {
328 .bc_decomposition_last_of_contract = 1,
329 .bc_decomposition_sel = 1,
330 .bc_decomposition_sel_windows_gt_remaining = 1,
331 },
332 });
333
334 check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_WINDOWS_GT_REMAINING_PROPAGATION);
335
336 trace.set(C::bc_decomposition_sel_windows_gt_remaining, 0, 1); // Mutate to wrong value
338 check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_WINDOWS_GT_REMAINING_PROPAGATION),
339 "SEL_WINDOWS_GT_REMAINING_PROPAGATION");
340}
341
342TEST(BytecodeDecompositionConstrainingTest, NegativeWrongBytesToReadNoCorrection)
343{
344 TestTraceContainer trace = TestTraceContainer::from_rows({
345 {
346 .bc_decomposition_bytes_remaining = 75,
347 .bc_decomposition_bytes_to_read = DECOMPOSE_WINDOW_SIZE,
348 .bc_decomposition_sel = 1,
349 },
350 });
351
352 check_relation<bc_decomposition>(trace, bc_decomposition::SR_SET_BYTES_TO_READ);
353 trace.set(C::bc_decomposition_bytes_to_read, 0, 75); // Mutate to wrong value (bytes_remaining)
355 "SET_BYTES_TO_READ");
356}
357
358TEST(BytecodeDecompositionConstrainingTest, NegativeWrongBytesToReadWithCorrection)
359{
360 TestTraceContainer trace = TestTraceContainer::from_rows({
361 {
362 .bc_decomposition_bytes_remaining = 13,
363 .bc_decomposition_bytes_to_read = 13,
364 .bc_decomposition_sel = 1,
365 .bc_decomposition_sel_windows_gt_remaining = 1,
366 },
367 });
368
369 check_relation<bc_decomposition>(trace, bc_decomposition::SR_SET_BYTES_TO_READ);
370 trace.set(C::bc_decomposition_bytes_to_read, 0, DECOMPOSE_WINDOW_SIZE); // Mutate to wrong value
372 "SET_BYTES_TO_READ");
373}
374
375TEST(BytecodeDecompositionConstrainingTest, NegativeWrongPacking)
376{
377 TestTraceContainer trace;
378 trace.set(0,
379 { {
380 { C::bc_decomposition_sel_packed, 1 },
381 { C::bc_decomposition_bytes, 0x12 },
382 { C::bc_decomposition_bytes_pc_plus_1, 0x34 },
383 { C::bc_decomposition_bytes_pc_plus_2, 0x56 },
384 { C::bc_decomposition_bytes_pc_plus_3, 0x78 },
385 { C::bc_decomposition_bytes_pc_plus_4, 0x9A },
386 { C::bc_decomposition_bytes_pc_plus_5, 0xBC },
387 { C::bc_decomposition_bytes_pc_plus_6, 0xDE },
388 { C::bc_decomposition_bytes_pc_plus_7, 0xF0 },
389 { C::bc_decomposition_bytes_pc_plus_8, 0x12 },
390 { C::bc_decomposition_bytes_pc_plus_9, 0x34 },
391 { C::bc_decomposition_bytes_pc_plus_10, 0x56 },
392 { C::bc_decomposition_bytes_pc_plus_11, 0x78 },
393 { C::bc_decomposition_bytes_pc_plus_12, 0x9A },
394 { C::bc_decomposition_bytes_pc_plus_13, 0xBC },
395 { C::bc_decomposition_bytes_pc_plus_14, 0xDE },
396 { C::bc_decomposition_bytes_pc_plus_15, 0xF0 },
397 { C::bc_decomposition_bytes_pc_plus_16, 0x12 },
398 { C::bc_decomposition_bytes_pc_plus_17, 0x34 },
399 { C::bc_decomposition_bytes_pc_plus_18, 0x56 },
400 { C::bc_decomposition_bytes_pc_plus_19, 0x78 },
401 { C::bc_decomposition_bytes_pc_plus_20, 0x9A },
402 { C::bc_decomposition_bytes_pc_plus_21, 0xBC },
403 { C::bc_decomposition_bytes_pc_plus_22, 0xDE },
404 { C::bc_decomposition_bytes_pc_plus_23, 0xF0 },
405 { C::bc_decomposition_bytes_pc_plus_24, 0x12 },
406 { C::bc_decomposition_bytes_pc_plus_25, 0x34 },
407 { C::bc_decomposition_bytes_pc_plus_26, 0x56 },
408 { C::bc_decomposition_bytes_pc_plus_27, 0x78 },
409 { C::bc_decomposition_bytes_pc_plus_28, 0x9A },
410 { C::bc_decomposition_bytes_pc_plus_29, 0xBC },
411 { C::bc_decomposition_bytes_pc_plus_30, 0xDE },
412 { C::bc_decomposition_packed_field,
413 // Note that we have to prepend 0x00 to the packed field to make it 32 bytes long
414 // since the constructor for FF expects 32 bytes.
415 FF("0x00123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE") },
416 } });
417
418 check_relation<bc_decomposition>(trace, bc_decomposition::SR_BC_DECOMPOSITION_REPACKING);
419 trace.set(C::bc_decomposition_bytes_pc_plus_20, 0, 0); // Mutate to wrong value
421 "BC_DECOMPOSITION_REPACKING");
422}
423
424// Negative test where sel_packed == 1 and sel == 0
425TEST(BytecodeDecompositionConstrainingTest, NegativeSelPackedNotSel)
426{
427 TestTraceContainer trace;
428 trace.set(0,
429 { {
430 { C::bc_decomposition_sel_packed, 1 },
431 { C::bc_decomposition_sel, 1 },
432 } });
433
434 check_relation<bc_decomposition>(trace, bc_decomposition::SR_SEL_TOGGLED_AT_PACKED);
435 trace.set(C::bc_decomposition_sel, 0, 0); // Mutate to wrong value
437 "SEL_TOGGLED_AT_PACKED");
438}
439
440} // namespace
441} // namespace bb::avm2::constraining
static constexpr size_t SR_SEL_TOGGLED_AT_PACKED
static constexpr size_t SR_BC_DECOMPOSITION_REPACKING
static constexpr size_t SR_BC_DEC_LAST_CONTRACT_BYTES_REM_ONE
static constexpr size_t SR_SEL_WINDOWS_GT_REMAINING_PROPAGATION
static constexpr size_t SR_BC_DEC_PC_INCREMENT
static constexpr size_t SR_BC_DEC_SEL_BYTES_REM_NON_ZERO
static constexpr size_t SR_BC_DEC_PC_ZERO_INITIALIZATION
static constexpr size_t SR_SEL_WINDOWS_GT_REMAINING_INIT
static constexpr size_t SR_BC_DEC_ID_CONSTANT
static constexpr size_t SR_BC_DEC_BYTES_REMAINING_DECREMENT
static constexpr size_t SR_SET_BYTES_TO_READ
static TestTraceContainer from_rows(const std::vector< AvmFullRow > &rows)
void set(Column col, uint32_t row, const FF &value)
AluTraceBuilder builder
Definition alu.test.cpp:123
TestTraceContainer trace
#define EXPECT_THROW_WITH_MESSAGE(code, expectedMessage)
Definition macros.hpp:7
AvmFlavorSettings::FF FF
TEST(TxExecutionConstrainingTest, WriteTreeValue)
Definition tx.test.cpp:508
ContractClass random_contract_class(size_t bytecode_size)
Definition fixtures.cpp:174
std::vector< uint8_t > random_bytes(size_t n)
Definition fixtures.cpp:33
TestTraceContainer empty_trace()
Definition fixtures.cpp:153
constexpr uint32_t DECOMPOSE_WINDOW_SIZE
typename Flavor::FF FF
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13