Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
memory.test.cpp
Go to the documentation of this file.
1#include <gmock/gmock.h>
2#include <gtest/gtest.h>
3
4#include <cstdint>
5
17
18namespace bb::avm2::constraining {
19namespace {
20
21using simulation::MemoryEvent;
22using simulation::RangeCheckEvent;
23
24using tracegen::MemoryTraceBuilder;
25using tracegen::PrecomputedTraceBuilder;
26using tracegen::RangeCheckTraceBuilder;
27using tracegen::TestTraceContainer;
29using C = Column;
31
32TEST(MemoryConstrainingTest, EmptyRow)
33{
34 check_relation<memory>(testing::empty_trace());
35}
36
37// Several memory events with trace generation.
38TEST(MemoryConstrainingTest, MultipleEventsWithTraceGen)
39{
40 TestTraceContainer trace;
41 MemoryTraceBuilder memory_trace_builder;
42 PrecomputedTraceBuilder precomputed_trace_builder;
43 RangeCheckTraceBuilder range_check_trace_builder;
44
45 std::vector<MemoryEvent> mem_events = {
46 // 1) READ: space_id = 17, addr = 120, clk = 13787, value = 0, tag = FF
47 {
48 .execution_clk = 13787,
50 .addr = 120,
52 .space_id = 17,
53 },
54 // 2) WRITE: space_id = 17, addr = 120, clk = 13787, value = 12345, tag = U16
55 {
56 .execution_clk = 13787,
58 .addr = 120,
60 .space_id = 17,
61 },
62 // 3) WRITE: space_id = 17, addr = 120, clk = 13788, value = 123, tag = U32
63 {
64 .execution_clk = 13788,
66 .addr = 120,
68 .space_id = 17,
69 },
70 // 4) READ: space_id = 17, addr = 120, clk = 25000, value = 123, tag = U32
71 {
72 .execution_clk = 25000,
74 .addr = 120,
76 .space_id = 17,
77 },
78 // 5) WRITE: space_id = 17, addr = 121, clk = 45, value = 99999, tag = U128
79 {
80 .execution_clk = 45,
82 .addr = 121,
84 .space_id = 17,
85 },
86 // 6) READ: space_id = 17, addr = 121, clk = 49, value = 99999, tag = U128
87 {
88 .execution_clk = 49,
90 .addr = 121,
92 .space_id = 17,
93 },
94 // 7) READ: space_id = 17, addr = 121, clk = 49, value = 99999, tag = U128
95 {
96 .execution_clk = 49,
98 .addr = 121,
100 .space_id = 17,
101 },
102 // 8) READ: space_id = 17, addr = 121, clk = 765, value = 99999, tag = U128
103 {
104 .execution_clk = 765,
106 .addr = 121,
108 .space_id = 17,
109 },
110 // 9) WRITE: space_id = 18, addr = 2, clk = 10, value = p-1, tag = FF
111 {
112 .execution_clk = 10,
114 .addr = 2,
116 .space_id = 18,
117 },
118 };
119
120 // Range check event per non-FF memory write event.
121 std::vector<RangeCheckEvent> range_check_events = {
122 {
123 .value = 12345,
124 .num_bits = 16,
125 },
126 {
127 .value = 123,
128 .num_bits = 32,
129 },
130 {
131 .value = 99999,
132 .num_bits = 128,
133 },
134 };
135
136 precomputed_trace_builder.process_sel_range_8(trace);
137 precomputed_trace_builder.process_sel_range_16(trace);
138 precomputed_trace_builder.process_misc(trace, 1 << 16);
139 precomputed_trace_builder.process_tag_parameters(trace);
140 range_check_trace_builder.process(range_check_events, trace);
141 memory_trace_builder.process(mem_events, trace);
142
143 // For the selector consistency, we need to make the read/write come from some trace.
144 trace.visit_column(Column::memory_sel,
145 [&](uint32_t row, const FF&) { trace.set(Column::memory_sel_register_op_0_, row, 1); });
146
147 check_relation<memory>(trace);
148 check_all_interactions<MemoryTraceBuilder>(trace);
149}
150
151// Trace must be contiguous.
152TEST(MemoryConstrainingTest, ContiguousTrace)
153{
154 TestTraceContainer trace({
155 { { C::precomputed_first_row, 1 }, { C::memory_sel, 0 } },
156 { { C::memory_sel, 1 } },
157 { { C::memory_sel, 1 } },
158 { { C::memory_sel, 1 } },
159 { { C::memory_sel, 0 } },
160 });
161
162 check_relation<memory>(trace, memory::SR_MEM_CONTINUITY);
163
164 // Mutate the trace to make it non-contiguous.
165 trace.set(C::memory_sel, 2, 0);
166 EXPECT_THROW_WITH_MESSAGE(check_relation<memory>(trace, memory::SR_MEM_CONTINUITY),
168}
169
170// Boolean selector for range check is active at all active rows except the last one.
171TEST(MemoryConstrainingTest, SelRngChk)
172{
173 TestTraceContainer trace({
174 { { C::memory_sel, 1 }, { C::memory_sel_rng_chk, 1 } },
175 { { C::memory_sel, 1 }, { C::memory_sel_rng_chk, 1 } },
176 { { C::memory_sel, 1 }, { C::memory_sel_rng_chk, 0 } },
177 { { C::memory_sel, 0 }, { C::memory_sel_rng_chk, 0 } },
178 });
179
180 check_relation<memory>(trace, memory::SR_SEL_RNG_CHK);
181
182 // Disable the range check for the penultimate row.
183 trace.set(C::memory_sel_rng_chk, 1, 0);
184 EXPECT_THROW_WITH_MESSAGE(check_relation<memory>(trace, memory::SR_SEL_RNG_CHK),
186
187 // Reset
188 trace.set(C::memory_sel_rng_chk, 1, 1);
189
190 // Disable the range check at the first row.
191 trace.set(C::memory_sel_rng_chk, 0, 0);
192 EXPECT_THROW_WITH_MESSAGE(check_relation<memory>(trace, memory::SR_SEL_RNG_CHK),
194
195 // Reset
196 trace.set(C::memory_sel_rng_chk, 0, 1);
197
198 // Enable the range check at the last active row.
199 trace.set(C::memory_sel_rng_chk, 2, 1);
200 EXPECT_THROW_WITH_MESSAGE(check_relation<memory>(trace, memory::SR_SEL_RNG_CHK),
202}
203
204// last_access is derived from whether the next row has the same (space_id, address).
205TEST(MemoryConstrainingTest, LastAccess)
206{
207 // global_addr = space_id * 2^32 + address. Using space_id=0 so global_addr == address.
208 TestTraceContainer trace({
209 { { C::memory_sel_rng_chk, 1 },
210 { C::memory_address, 12345 },
211 { C::memory_last_access, 1 },
212 { C::memory_glob_addr_diff_inv, 1 } },
213 { { C::memory_sel_rng_chk, 1 }, { C::memory_address, 12346 }, { C::memory_last_access, 0 } },
214 { { C::memory_sel_rng_chk, 1 }, { C::memory_address, 12346 }, { C::memory_last_access, 0 } },
215 { { C::memory_sel_rng_chk, 1 },
216 { C::memory_address, 12346 },
217 { C::memory_last_access, 1 },
218 { C::memory_glob_addr_diff_inv, 1 } },
219 { { C::memory_sel_rng_chk, 0 },
220 { C::memory_address, 12347 },
221 { C::memory_last_access, 1 },
222 { C::memory_glob_addr_diff_inv, 1 } },
223 });
224
225 check_relation<memory>(trace, memory::SR_LAST_ACCESS);
226
227 // Mutate the trace to make the last access incorrect (last_access == 0 instead of 1).
228 trace.set(C::memory_last_access, 0, 0);
229 EXPECT_THROW_WITH_MESSAGE(check_relation<memory>(trace, memory::SR_LAST_ACCESS),
231
232 // Reset
233 trace.set(C::memory_last_access, 0, 1);
234 check_relation<memory>(trace, memory::SR_LAST_ACCESS);
235
236 // Mutate glob_addr_diff_inv == 0.
237 trace.set(C::memory_glob_addr_diff_inv, 0, 0);
238 EXPECT_THROW_WITH_MESSAGE(check_relation<memory>(trace, memory::SR_LAST_ACCESS),
240
241 // Reset
242 trace.set(C::memory_glob_addr_diff_inv, 0, 1);
243 check_relation<memory>(trace, memory::SR_LAST_ACCESS);
244
245 // Mutate the trace to make the last access == 1, instead of 0.
246 trace.set(C::memory_last_access, 2, 1);
247 EXPECT_THROW_WITH_MESSAGE(check_relation<memory>(trace, memory::SR_LAST_ACCESS),
249}
250
251// diff is derived as GLOBAL_ADDR_DIFF when last_access == 1.
252TEST(MemoryConstrainingTest, DiffWithLastAccess)
253{
254 // We set some dummy values for clk and rw to ensure that they do not interfere with diff derivation.
255 // global_addr = space_id * 2^32 + address. Using space_id=0 so global_addr == address.
256 TestTraceContainer trace({
257 { { C::memory_sel_rng_chk, 1 },
258 { C::memory_address, 12345 },
259 { C::memory_last_access, 1 },
260 { C::memory_diff, 10000 },
261 { C::memory_clk, 38 },
262 { C::memory_rw, 1 } },
263 { { C::memory_sel_rng_chk, 1 },
264 { C::memory_address, 22345 },
265 { C::memory_last_access, 1 },
266 { C::memory_diff, 12 },
267 { C::memory_clk, 127 },
268 { C::memory_rw, 1 } },
269 { { C::memory_sel_rng_chk, 1 },
270 { C::memory_address, 22357 },
271 { C::memory_last_access, 1 },
272 { C::memory_diff, FF(-22357) },
273 { C::memory_clk, 130 },
274 { C::memory_rw, 1 } },
275 { { C::memory_sel_rng_chk, 0 }, { C::memory_last_access, 0 } },
276 });
277
278 check_relation<memory>(trace, memory::SR_DIFF);
279
280 // Mutate the trace to make the diff incorrect.
281 trace.set(C::memory_diff, 1, trace.get(C::memory_diff, 1) + 1);
282 EXPECT_THROW_WITH_MESSAGE(check_relation<memory>(trace, memory::SR_DIFF),
284}
285
286// diff is derived as TIMESTAMP_DIFF - rw' * rw when last_access == 0.
287// TIMESTAMP_DIFF = 2*(clk' - clk) + (rw' - rw).
288TEST(MemoryConstrainingTest, DiffWithoutLastAccess)
289{
290 // Choose clk/rw such that timestamps are consistent:
291 // Row 0: clk=38, rw=1 -> ts=77. diff = (79-77) - 1*1 = 1
292 // Row 1: clk=39, rw=1 -> ts=79. diff = (8780-79) - 0*1 = 8701
293 // Row 2: clk=4390, rw=0 -> ts=8780. diff = (18780-8780) - 0*0 = 10000
294 // Row 3: clk=9390, rw=0 -> ts=18780. diff = (18781-18780) - 1*0 = 1
295 // Row 4: clk=9390, rw=1 -> ts=18781. diff = (0-18781) - 0*1 = -18781
296 TestTraceContainer trace({
297 { { C::memory_sel_rng_chk, 1 }, { C::memory_clk, 38 }, { C::memory_rw, 1 }, { C::memory_diff, 1 } },
298 { { C::memory_sel_rng_chk, 1 }, { C::memory_clk, 39 }, { C::memory_rw, 1 }, { C::memory_diff, 8701 } },
299 { { C::memory_sel_rng_chk, 1 }, { C::memory_clk, 4390 }, { C::memory_rw, 0 }, { C::memory_diff, 10000 } },
300 { { C::memory_sel_rng_chk, 1 }, { C::memory_clk, 9390 }, { C::memory_rw, 0 }, { C::memory_diff, 1 } },
301 { { C::memory_sel_rng_chk, 1 }, { C::memory_clk, 9390 }, { C::memory_rw, 1 }, { C::memory_diff, FF(-18781) } },
302 { { C::memory_sel_rng_chk, 0 }, { C::memory_last_access, 0 } },
303 });
304
305 check_relation<memory>(trace, memory::SR_DIFF);
306
307 // Mutate the trace to make the diff incorrect.
308 trace.set(C::memory_diff, 0, trace.get(C::memory_diff, 0) + 1);
309 EXPECT_THROW_WITH_MESSAGE(check_relation<memory>(trace, memory::SR_DIFF),
311
312 // Reset
313 trace.set(C::memory_diff, 0, trace.get(C::memory_diff, 0) - 1);
314 check_relation<memory>(trace, memory::SR_DIFF);
315
316 // Mutate the trace to make the diff incorrect.
317 trace.set(C::memory_diff, 1, trace.get(C::memory_diff, 1) + 1);
318 EXPECT_THROW_WITH_MESSAGE(check_relation<memory>(trace, memory::SR_DIFF),
320}
321
322// diff correct decomposition into 3 16-bit limbs.
323TEST(MemoryConstrainingTest, DiffDecomp)
324{
325 TestTraceContainer trace({
326 { { C::memory_diff, 87 }, { C::memory_limb_0_, 87 }, { C::memory_limb_1_, 0 }, { C::memory_limb_2_, 0 } },
327 { { C::memory_diff, 1ULL << 16 },
328 { C::memory_limb_0_, 0 },
329 { C::memory_limb_1_, 1 },
330 { C::memory_limb_2_, 0 } },
331 { { C::memory_diff, 1ULL << 32 },
332 { C::memory_limb_0_, 0 },
333 { C::memory_limb_1_, 0 },
334 { C::memory_limb_2_, 1 } },
335 { { C::memory_diff, UINT64_MAX >> 16 },
336 { C::memory_limb_0_, UINT16_MAX },
337 { C::memory_limb_1_, UINT16_MAX },
338 { C::memory_limb_2_, UINT16_MAX } },
339 });
340
341 check_relation<memory>(trace, memory::SR_DIFF_DECOMP);
342
343 // Mutate the trace to make the diff decomposition incorrect.
344 trace.set(C::memory_limb_0_, 0, trace.get(C::memory_limb_0_, 0) + 1);
345 EXPECT_THROW_WITH_MESSAGE(check_relation<memory>(trace, memory::SR_DIFF_DECOMP),
347
348 // Reset
349 trace.set(C::memory_limb_0_, 0, trace.get(C::memory_limb_0_, 0) - 1);
350 check_relation<memory>(trace, memory::SR_DIFF_DECOMP);
351
352 // Mutate the trace to make the diff decomposition incorrect.
353 trace.set(C::memory_limb_1_, 1, trace.get(C::memory_limb_1_, 1) + 1);
354 EXPECT_THROW_WITH_MESSAGE(check_relation<memory>(trace, memory::SR_DIFF_DECOMP),
356
357 // Reset
358 trace.set(C::memory_limb_1_, 1, trace.get(C::memory_limb_1_, 1) - 1);
359 check_relation<memory>(trace, memory::SR_DIFF_DECOMP);
360
361 // Mutate the trace to make the diff decomposition incorrect.
362 trace.set(C::memory_limb_2_, 2, trace.get(C::memory_limb_2_, 2) + 1);
363 EXPECT_THROW_WITH_MESSAGE(check_relation<memory>(trace, memory::SR_DIFF_DECOMP),
365}
366
367// Correct memory value (and tag) initialization after first row.
368TEST(MemoryConstrainingTest, MemoryInitValueFirstRow)
369{
370 TestTraceContainer trace({
371 { { C::precomputed_first_row, 1 } },
372 { { C::memory_sel, 1 }, { C::memory_value, 0 }, { C::memory_tag, static_cast<uint8_t>(MemoryTag::FF) } },
373 });
374
375 check_relation<memory>(trace, memory::SR_MEMORY_INIT_VALUE, memory::SR_MEMORY_INIT_TAG);
376
377 // Mutate the trace to make the memory value incorrect.
378 trace.set(C::memory_value, 1, trace.get(C::memory_value, 1) + 1);
379 EXPECT_THROW_WITH_MESSAGE(check_relation<memory>(trace, memory::SR_MEMORY_INIT_VALUE),
381
382 // Reset
383 trace.set(C::memory_value, 1, trace.get(C::memory_value, 1) - 1);
384 check_relation<memory>(trace, memory::SR_MEMORY_INIT_VALUE, memory::SR_MEMORY_INIT_TAG);
385
386 // Mutate the trace to make the memory tag incorrect.
387 trace.set(C::memory_tag, 1, static_cast<uint8_t>(MemoryTag::U16));
388 EXPECT_THROW_WITH_MESSAGE(check_relation<memory>(trace, memory::SR_MEMORY_INIT_TAG),
390}
391
392// Correct memory value (and tag) initialization after last_access == 1.
393TEST(MemoryConstrainingTest, MemoryInitValueLastAccess)
394{
395 TestTraceContainer trace({
396 { { C::memory_sel, 1 }, { C::memory_last_access, 1 } },
397 { { C::memory_sel, 1 }, { C::memory_value, 0 }, { C::memory_tag, static_cast<uint8_t>(MemoryTag::FF) } },
398 });
399
400 check_relation<memory>(trace, memory::SR_MEMORY_INIT_VALUE, memory::SR_MEMORY_INIT_TAG);
401
402 // Mutate the trace to make the memory value incorrect.
403 trace.set(C::memory_value, 1, trace.get(C::memory_value, 1) + 1);
404 EXPECT_THROW_WITH_MESSAGE(check_relation<memory>(trace, memory::SR_MEMORY_INIT_VALUE),
406
407 // Reset
408 trace.set(C::memory_value, 1, trace.get(C::memory_value, 1) - 1);
409 check_relation<memory>(trace, memory::SR_MEMORY_INIT_VALUE, memory::SR_MEMORY_INIT_TAG);
410
411 // Mutate the trace to make the memory tag incorrect.
412 trace.set(C::memory_tag, 1, static_cast<uint8_t>(MemoryTag::U1));
413 EXPECT_THROW_WITH_MESSAGE(check_relation<memory>(trace, memory::SR_MEMORY_INIT_TAG),
415}
416
417// Correct read-write consistency for memory value (and tag).
418TEST(MemoryConstrainingTest, ReadWriteConsistency)
419{
420 TestTraceContainer trace({
421 { { C::memory_sel, 1 },
422 { C::memory_rw, 1 },
423 { C::memory_value, 12 },
424 { C::memory_tag, static_cast<uint8_t>(MemoryTag::U8) } }, // Write U8(12)
425 { { C::memory_sel, 1 },
426 { C::memory_rw, 0 },
427 { C::memory_value, 12 },
428 { C::memory_tag, static_cast<uint8_t>(MemoryTag::U8) } }, // Read U8(12)
429 { { C::memory_sel, 1 },
430 { C::memory_rw, 1 },
431 { C::memory_value, 17 },
432 { C::memory_tag, static_cast<uint8_t>(MemoryTag::U64) } }, // Write U64(17)
433 { { C::memory_sel, 1 },
434 { C::memory_rw, 1 },
435 { C::memory_value, 12345 },
436 { C::memory_tag, static_cast<uint8_t>(MemoryTag::U128) } }, // Write U128(12345)
437 { { C::memory_sel, 1 },
438 { C::memory_rw, 0 },
439 { C::memory_value, 12345 },
440 { C::memory_tag, static_cast<uint8_t>(MemoryTag::U128) } }, // Read U128(12345)
441 { { C::memory_sel, 1 },
442 { C::memory_last_access, 1 },
443 { C::memory_rw, 0 },
444 { C::memory_value, 12345 },
445 { C::memory_tag, static_cast<uint8_t>(MemoryTag::U128) } }, // Read U128(12345)
446 });
447
449
450 // Mutate the trace to make the first read value (row 1) incorrect.
451 trace.set(C::memory_value, 1, trace.get(C::memory_value, 1) + 1);
454
455 // Reset
456 trace.set(C::memory_value, 1, trace.get(C::memory_value, 1) - 1);
458
459 // Mutate the trace to make the first read tag (row 1) incorrect.
460 trace.set(C::memory_tag, 1, static_cast<uint8_t>(MemoryTag::U16));
463}
464
465// Selector on tag == FF.
466TEST(MemoryConstrainingTest, TagIsFF)
467{
468 TestTraceContainer trace({
469 { { C::memory_sel, 1 },
470 { C::memory_tag, static_cast<uint8_t>(MemoryTag::FF) },
471 { C::memory_sel_tag_is_ff, 1 } },
472 { { C::memory_sel, 1 },
473 { C::memory_tag, static_cast<uint8_t>(MemoryTag::U1) },
474 { C::memory_sel_tag_is_ff, 0 },
475 { C::memory_tag_ff_diff_inv,
476 (FF(static_cast<uint8_t>(MemoryTag::U1)) - FF(static_cast<uint8_t>(MemoryTag::FF))).invert() } },
477 { { C::memory_sel, 1 },
478 { C::memory_tag, static_cast<uint8_t>(MemoryTag::U8) },
479 { C::memory_sel_tag_is_ff, 0 },
480 { C::memory_tag_ff_diff_inv,
481 (FF(static_cast<uint8_t>(MemoryTag::U8)) - FF(static_cast<uint8_t>(MemoryTag::FF))).invert() } },
482 { { C::memory_sel, 1 },
483 { C::memory_tag, static_cast<uint8_t>(MemoryTag::U16) },
484 { C::memory_sel_tag_is_ff, 0 },
485 { C::memory_tag_ff_diff_inv,
486 (FF(static_cast<uint8_t>(MemoryTag::U16)) - FF(static_cast<uint8_t>(MemoryTag::FF))).invert() } },
487 { { C::memory_sel, 1 },
488 { C::memory_tag, static_cast<uint8_t>(MemoryTag::U32) },
489 { C::memory_sel_tag_is_ff, 0 },
490 { C::memory_tag_ff_diff_inv,
491 (FF(static_cast<uint8_t>(MemoryTag::U32)) - FF(static_cast<uint8_t>(MemoryTag::FF))).invert() } },
492 { { C::memory_sel, 1 },
493 { C::memory_tag, static_cast<uint8_t>(MemoryTag::U64) },
494 { C::memory_sel_tag_is_ff, 0 },
495 { C::memory_tag_ff_diff_inv,
496 (FF(static_cast<uint8_t>(MemoryTag::U64)) - FF(static_cast<uint8_t>(MemoryTag::FF))).invert() } },
497 { { C::memory_sel, 1 },
498 { C::memory_tag, static_cast<uint8_t>(MemoryTag::U128) },
499 { C::memory_sel_tag_is_ff, 0 },
500 { C::memory_tag_ff_diff_inv,
501 (FF(static_cast<uint8_t>(MemoryTag::U128)) - FF(static_cast<uint8_t>(MemoryTag::FF))).invert() } },
502 });
503
504 check_relation<memory>(trace, memory::SR_TAG_IS_FF);
505
506 // Attempt to de-activate sel_tag_is_ff when tag == FF.
507 trace.set(C::memory_sel_tag_is_ff, 0, 0);
508 EXPECT_THROW_WITH_MESSAGE(check_relation<memory>(trace, memory::SR_TAG_IS_FF),
510
511 // Try to change value for diff_inv
512 trace.set(C::memory_tag_ff_diff_inv, 0, 1);
513 EXPECT_THROW_WITH_MESSAGE(check_relation<memory>(trace, memory::SR_TAG_IS_FF),
515
516 // Reset
517 trace.set(C::memory_sel_tag_is_ff, 0, 1);
518 trace.set(C::memory_tag_ff_diff_inv, 0, 0);
519 check_relation<memory>(trace, memory::SR_TAG_IS_FF);
520
521 // Attempt to activate sel_tag_is_ff when tag != FF.
522 trace.set(C::memory_sel_tag_is_ff, 1, 1);
523 EXPECT_THROW_WITH_MESSAGE(check_relation<memory>(trace, memory::SR_TAG_IS_FF),
525
526 // Try to modify value for tag_ff_diff_inv
527 trace.set(C::memory_tag_ff_diff_inv, 1, 0);
528 EXPECT_THROW_WITH_MESSAGE(check_relation<memory>(trace, memory::SR_TAG_IS_FF),
530}
531
532// Boolean selector sel_rng_write is active for write operations and tag != FF.
533TEST(MemoryConstrainingTest, SelRngWrite)
534{
535 TestTraceContainer trace({
536 { { C::memory_sel, 1 }, { C::memory_rw, 1 }, { C::memory_sel_tag_is_ff, 1 }, { C::memory_sel_rng_write, 0 } },
537 { { C::memory_sel, 1 }, { C::memory_rw, 1 }, { C::memory_sel_tag_is_ff, 0 }, { C::memory_sel_rng_write, 1 } },
538 { { C::memory_sel, 1 }, { C::memory_rw, 0 }, { C::memory_sel_tag_is_ff, 1 }, { C::memory_sel_rng_write, 0 } },
539 { { C::memory_sel, 1 }, { C::memory_rw, 0 }, { C::memory_sel_tag_is_ff, 0 }, { C::memory_sel_rng_write, 0 } },
540 });
541
542 check_relation<memory>(trace, memory::SR_SEL_RNG_WRITE);
543}
544
545// Negative test: attempts to write a value which is not present in the range check trace.
546TEST(MemoryConstrainingTest, NegativeWriteValueOutOfRange)
547{
548 TestTraceContainer trace({
549 { { C::memory_sel, 1 },
550 { C::memory_rw, 1 },
551 { C::memory_value, 12345 },
552 { C::memory_tag, static_cast<uint8_t>(MemoryTag::U16) },
553 { C::memory_sel_rng_write, 1 },
554 { C::memory_max_bits, 128 },
555 { C::range_check_sel, 1 },
556 { C::range_check_value, 12345 },
557 { C::range_check_rng_chk_bits, 128 } },
558 });
559
560 check_interaction<MemoryTraceBuilder, lookup_memory_range_check_write_tagged_value_settings>(trace);
561
562 // Mutate the trace to make the value incorrect in range check.
563 trace.set(C::range_check_value, 0, trace.get(C::range_check_value, 1) + 1);
565 (check_interaction<MemoryTraceBuilder, lookup_memory_range_check_write_tagged_value_settings>(trace)),
566 "Failed.*RANGE_CHECK_WRITE_TAGGED_VALUE. Could not find tuple in destination.");
567}
568
569// Negative test: retrieve wrong max_bits value from precomputed table.
570TEST(MemoryConstrainingTest, NegativeMaxBitsOutOfRange)
571{
572 TestTraceContainer trace({
573 { { C::memory_sel, 1 },
574 { C::memory_sel_rng_write, 1 },
575 { C::memory_tag, static_cast<uint8_t>(MemoryTag::U32) },
576 { C::memory_max_bits, 32 } },
577 });
578
579 PrecomputedTraceBuilder precomputed_trace_builder;
580 precomputed_trace_builder.process_tag_parameters(trace);
581 precomputed_trace_builder.process_misc(trace, 100); // 100 is an arbitrary upper bound for the number of tags.
582
583 check_interaction<MemoryTraceBuilder, lookup_memory_tag_max_bits_settings>(trace);
584
585 // Mutate the trace to make the max_bits incorrect.
586 trace.set(C::memory_max_bits, 0, trace.get(C::memory_max_bits, 0) + 1);
587 EXPECT_THROW_WITH_MESSAGE((check_interaction<MemoryTraceBuilder, lookup_memory_tag_max_bits_settings>(trace)),
588 "Failed.*LOOKUP_MEMORY_TAG_MAX_BITS. Could not find tuple in destination.");
589}
590
591// Negative test: limbs of diff cannot be larger than 16 bits.
592TEST(MemoryConstrainingTest, NegativeDiffLimbOutOfRange)
593{
594 TestTraceContainer trace({
595 { { C::memory_sel, 1 },
596 { C::memory_sel_rng_chk, 1 },
597 { C::memory_limb_0_, UINT16_MAX },
598 { C::memory_limb_1_, UINT16_MAX },
599 { C::memory_limb_2_, UINT16_MAX } },
600 });
601
602 PrecomputedTraceBuilder precomputed_trace_builder;
603 precomputed_trace_builder.process_misc(trace, 1 << 16);
604 precomputed_trace_builder.process_sel_range_16(trace);
605
606 check_interaction<MemoryTraceBuilder,
610
611 // Mutate the trace to make the limb_0 incorrect.
612 trace.set(C::memory_limb_0_, 0, UINT16_MAX + 1);
613 EXPECT_THROW_WITH_MESSAGE((check_interaction<MemoryTraceBuilder, lookup_memory_range_check_limb_0_settings>(trace)),
614 "Failed.*RANGE_CHECK_LIMB_0. Could not find tuple in destination.");
615
616 check_interaction<MemoryTraceBuilder, lookup_memory_range_check_limb_1_settings>(trace);
617
618 // Mutate the trace to make the limb_1 incorrect.
619 trace.set(C::memory_limb_1_, 0, UINT16_MAX + 1);
620 EXPECT_THROW_WITH_MESSAGE((check_interaction<MemoryTraceBuilder, lookup_memory_range_check_limb_1_settings>(trace)),
621 "Failed.*RANGE_CHECK_LIMB_1. Could not find tuple in destination.");
622
623 check_interaction<MemoryTraceBuilder, lookup_memory_range_check_limb_2_settings>(trace);
624
625 // Mutate the trace to make the limb_2 incorrect.
626 trace.set(C::memory_limb_2_, 0, UINT16_MAX + 1);
627 EXPECT_THROW_WITH_MESSAGE((check_interaction<MemoryTraceBuilder, lookup_memory_range_check_limb_2_settings>(trace)),
628 "Failed.*RANGE_CHECK_LIMB_2. Could not find tuple in destination.");
629}
630
631} // namespace
632} // namespace bb::avm2::constraining
#define EXPECT_THROW_WITH_MESSAGE(code, expectedMessageRegex)
Definition assert.hpp:224
static TaggedValue from_tag(ValueTag tag, FF value)
static constexpr size_t SR_TAG_IS_FF
Definition memory.hpp:50
static constexpr size_t SR_READ_WRITE_CONSISTENCY_TAG
Definition memory.hpp:49
static constexpr size_t SR_DIFF
Definition memory.hpp:44
static constexpr size_t SR_LAST_ACCESS
Definition memory.hpp:43
static constexpr size_t SR_READ_WRITE_CONSISTENCY_VALUE
Definition memory.hpp:48
static constexpr size_t SR_MEMORY_INIT_TAG
Definition memory.hpp:47
static std::string get_subrelation_label(size_t index)
Definition memory.hpp:53
static constexpr size_t SR_MEMORY_INIT_VALUE
Definition memory.hpp:46
static constexpr size_t SR_SEL_RNG_WRITE
Definition memory.hpp:51
static constexpr size_t SR_DIFF_DECOMP
Definition memory.hpp:45
static constexpr size_t SR_MEM_CONTINUITY
Definition memory.hpp:41
static constexpr size_t SR_SEL_RNG_CHK
Definition memory.hpp:42
const FF & get(Column col, uint32_t row) const
void set(Column col, uint32_t row, const FF &value, bool use_atomic_limbs=false)
void visit_column(Column col, const std::function< void(uint32_t, const FF &)> &visitor) const
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.
TestTraceContainer empty_trace()
Definition fixtures.cpp:156
lookup_settings< lookup_memory_range_check_limb_0_settings_ > lookup_memory_range_check_limb_0_settings
lookup_settings< lookup_memory_range_check_limb_1_settings_ > lookup_memory_range_check_limb_1_settings
AvmFlavorSettings::FF FF
Definition field.hpp:10
lookup_settings< lookup_memory_range_check_limb_2_settings_ > lookup_memory_range_check_limb_2_settings
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
MemoryStore memory
static constexpr uint256_t modulus