Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
field_gt.test.cpp
Go to the documentation of this file.
1#include <gmock/gmock.h>
2#include <gtest/gtest.h>
3
20
21namespace bb::avm2::constraining {
22namespace {
23
24using ::testing::NiceMock;
25using ::testing::TestWithParam;
26
27using tracegen::FieldGreaterThanTraceBuilder;
28using tracegen::RangeCheckTraceBuilder;
29using tracegen::TestTraceContainer;
30
31using simulation::DeduplicatingEventEmitter;
32using simulation::EventEmitter;
33using simulation::FieldGreaterThan;
34using simulation::FieldGreaterThanEvent;
35using simulation::MockRangeCheck;
36using simulation::RangeCheck;
37using simulation::RangeCheckEvent;
38using simulation::U256Decomposition;
39
41using C = Column;
42using ff_gt = bb::avm2::ff_gt<FF>;
43
44const uint256_t TWO_POW_128 = uint256_t{ 1 } << 128;
45
46TEST(FieldGreaterThanConstrainingTest, EmptyRow)
47{
48 check_relation<ff_gt>(testing::empty_trace());
49}
50
51struct GtTestParams {
55};
56struct DecTestParams {
57 FF a;
58 U256Decomposition expected_result;
59};
60
61std::vector<GtTestParams> comparison_tests = {
62 // GT
63 GtTestParams{ 27, 0, true },
64 GtTestParams{ TWO_POW_128, 0, true },
65 GtTestParams{ -1, 0, true }, // p-1 > 0
66 // EQ
67 GtTestParams{ 27, 27, false },
68 GtTestParams{ TWO_POW_128, TWO_POW_128, false },
69 GtTestParams{ -1, -1, false }, // p-1 == p-1
70 // LT
71 GtTestParams{ 0, 1, false },
72 GtTestParams{ 0, TWO_POW_128, false },
73 GtTestParams{ 0, -1, false }, // 0 < p-1
74 // Edge cases: zero
75 GtTestParams{ 0, 0, false }, // 0 == 0
76 GtTestParams{ 1, 0, true }, // 1 > 0
77 // Edge cases: maximum field element (p-1)
78 GtTestParams{ -1, 1, true }, // p-1 > 1
79 GtTestParams{ -2, -1, false }, // p-2 < p-1
80 // Edge cases: boundary at 2^128
81 GtTestParams{ TWO_POW_128 - 1, TWO_POW_128, false }, // boundary at 2^128
82 GtTestParams{ TWO_POW_128, TWO_POW_128 - 1, true } // boundary at 2^128
83};
84
85std::vector<DecTestParams> decomposition_tests = {
86 // Basic cases
87 DecTestParams{ 0, { .lo = 0, .hi = 0 } },
88 DecTestParams{ 1, { .lo = 1, .hi = 0 } },
89 // Powers of 2 at 128-bit boundary
90 DecTestParams{ uint256_t(1) << 128, { .lo = 0, .hi = 1 } },
91 DecTestParams{ (uint256_t(1) << 128) - 1, { .lo = static_cast<uint128_t>((uint256_t(1) << 128) - 1), .hi = 0 } },
92 // Large values
93 DecTestParams{ (uint256_t(1) << 200) - 1,
94 { .lo = static_cast<uint128_t>((uint256_t(1) << 128) - 1), .hi = (uint128_t(1) << 72) - 1 } },
95 // Edge case: maximum field element (p-1)
96 // p-1 decomposes into its limbs (computed at runtime)
97 DecTestParams{ FF(-1), simulation::decompose_256(FF::modulus - 1) },
98};
99
100class GtBasicTest : public TestWithParam<GtTestParams> {};
101
102TEST_P(GtBasicTest, BasicComparison)
103{
104 const auto& param = GetParam();
105
106 NiceMock<MockRangeCheck> range_check;
107 DeduplicatingEventEmitter<FieldGreaterThanEvent> event_emitter;
108 FieldGreaterThan field_gt_simulator(range_check, event_emitter);
109
110 EXPECT_EQ(field_gt_simulator.ff_gt(param.a, param.b), param.expected_result);
111
112 TestTraceContainer trace({
113 { { C::precomputed_first_row, 1 } },
114 });
115
116 FieldGreaterThanTraceBuilder builder;
117 builder.process(event_emitter.dump_events(), trace);
118 EXPECT_EQ(trace.get_num_rows(), /*start_row=*/1 + 5);
119 check_relation<ff_gt>(trace);
120}
121
122INSTANTIATE_TEST_SUITE_P(FieldGreaterThanConstrainingTest, GtBasicTest, ::testing::ValuesIn(comparison_tests));
123
124class DecBasicTest : public TestWithParam<DecTestParams> {};
125
126TEST_P(DecBasicTest, BasicDecomposition)
127{
128 const auto& param = GetParam();
129
130 NiceMock<MockRangeCheck> range_check;
131 DeduplicatingEventEmitter<FieldGreaterThanEvent> event_emitter;
132 FieldGreaterThan field_gt_simulator(range_check, event_emitter);
133
134 EXPECT_EQ(field_gt_simulator.canon_dec(param.a), param.expected_result);
135
136 TestTraceContainer trace({
137 { { C::precomputed_first_row, 1 } },
138 });
139
140 FieldGreaterThanTraceBuilder builder;
141 builder.process(event_emitter.dump_events(), trace);
142 EXPECT_EQ(trace.get_num_rows(), /*start_row=*/1 + 2);
143 check_relation<ff_gt>(trace);
144}
145
146INSTANTIATE_TEST_SUITE_P(FieldGreaterThanConstrainingTest, DecBasicTest, ::testing::ValuesIn(decomposition_tests));
147
148class GtInteractionTests : public TestWithParam<GtTestParams> {};
149
150TEST_P(GtInteractionTests, InteractionsWithRangeCheck)
151{
152 const auto& param = GetParam();
153
154 EventEmitter<RangeCheckEvent> range_check_event_emitter;
156 DeduplicatingEventEmitter<FieldGreaterThanEvent> event_emitter;
157 FieldGreaterThan field_gt_simulator(range_check, event_emitter);
158
159 EXPECT_EQ(field_gt_simulator.ff_gt(param.a, param.b), param.expected_result);
160
161 TestTraceContainer trace({
162 { { C::precomputed_first_row, 1 } },
163 });
164
165 FieldGreaterThanTraceBuilder builder;
166 RangeCheckTraceBuilder range_check_builder;
167
168 builder.process(event_emitter.dump_events(), trace);
170
171 check_interaction<FieldGreaterThanTraceBuilder, //
174
175 check_relation<ff_gt>(trace);
176}
177
178INSTANTIATE_TEST_SUITE_P(FieldGreaterThanConstrainingTest, GtInteractionTests, ::testing::ValuesIn(comparison_tests));
179
180class DecInteractionTests : public TestWithParam<DecTestParams> {};
181
182TEST_P(DecInteractionTests, InteractionsWithRangeCheck)
183{
184 const auto& param = GetParam();
185
186 EventEmitter<RangeCheckEvent> range_check_event_emitter;
188 DeduplicatingEventEmitter<FieldGreaterThanEvent> event_emitter;
189 FieldGreaterThan field_gt_simulator(range_check, event_emitter);
190
191 EXPECT_EQ(field_gt_simulator.canon_dec(param.a), param.expected_result);
192
193 TestTraceContainer trace({
194 { { C::precomputed_first_row, 1 } },
195 });
196
197 FieldGreaterThanTraceBuilder builder;
198 RangeCheckTraceBuilder range_check_builder;
199
200 builder.process(event_emitter.dump_events(), trace);
202
203 check_interaction<FieldGreaterThanTraceBuilder, //
206
207 check_relation<ff_gt>(trace);
208}
209
210INSTANTIATE_TEST_SUITE_P(FieldGreaterThanConstrainingTest,
211 DecInteractionTests,
212 ::testing::ValuesIn(decomposition_tests));
213
214TEST(FieldGreaterThanConstrainingTest, NegativeManipulatedDecompositions)
215{
216 NiceMock<MockRangeCheck> range_check;
217 DeduplicatingEventEmitter<FieldGreaterThanEvent> event_emitter;
218 FieldGreaterThan field_gt_simulator(range_check, event_emitter);
219
220 field_gt_simulator.ff_gt(0, 0);
221
222 TestTraceContainer trace({
223 { { C::precomputed_first_row, 1 } },
224 });
225
226 FieldGreaterThanTraceBuilder builder;
227 builder.process(event_emitter.dump_events(), trace);
228 check_relation<ff_gt>(trace);
229
230 trace.set(Column::ff_gt_a_lo, 1, 1);
231 trace.set(Column::ff_gt_b_hi, 1, 1);
232
233 EXPECT_THROW_WITH_MESSAGE(check_relation<ff_gt>(trace, ff_gt::SR_A_DECOMPOSITION), "A_DECOMPOSITION");
234 EXPECT_THROW_WITH_MESSAGE(check_relation<ff_gt>(trace, ff_gt::SR_B_DECOMPOSITION), "B_DECOMPOSITION");
235}
236
237TEST(FieldGreaterThanConstrainingTest, NegativeManipulatedComparisonsWithP)
238{
239 NiceMock<MockRangeCheck> range_check;
240 DeduplicatingEventEmitter<FieldGreaterThanEvent> event_emitter;
241 FieldGreaterThan field_gt_simulator(range_check, event_emitter);
242
243 field_gt_simulator.ff_gt(0, 0);
244
245 TestTraceContainer trace({
246 { { C::precomputed_first_row, 1 } },
247 });
248
249 FieldGreaterThanTraceBuilder builder;
250 builder.process(event_emitter.dump_events(), trace);
251 check_relation<ff_gt>(trace);
252
254 uint256_t p_lo = p_limbs.lo;
255 uint256_t p_hi = p_limbs.hi;
256
257 // Manipulate the decomposition in a way that passes the decomposition check due to overflow
258 trace.set(Column::ff_gt_a_lo, 1, p_lo);
259 trace.set(Column::ff_gt_a_hi, 1, p_hi);
260 trace.set(Column::ff_gt_b_lo, 1, p_lo);
261 trace.set(Column::ff_gt_b_hi, 1, p_hi);
262
263 trace.set(Column::ff_gt_p_sub_a_hi, 1, p_lo - 1);
264 trace.set(Column::ff_gt_p_sub_a_lo, 1, p_hi - 1);
265 trace.set(Column::ff_gt_p_sub_b_hi, 1, p_lo - 1);
266 trace.set(Column::ff_gt_p_sub_b_lo, 1, p_hi - 1);
267
268 EXPECT_THROW_WITH_MESSAGE(check_relation<ff_gt>(trace, ff_gt::SR_P_SUB_A_LO), "P_SUB_A_LO");
269 EXPECT_THROW_WITH_MESSAGE(check_relation<ff_gt>(trace, ff_gt::SR_P_SUB_A_HI), "P_SUB_A_HI");
270 EXPECT_THROW_WITH_MESSAGE(check_relation<ff_gt>(trace, ff_gt::SR_P_SUB_B_LO), "P_SUB_B_LO");
271 EXPECT_THROW_WITH_MESSAGE(check_relation<ff_gt>(trace, ff_gt::SR_P_SUB_B_HI), "P_SUB_B_HI");
272}
273
274TEST(FieldGreaterThanConstrainingTest, NegativeLessRangeChecks)
275{
276 NiceMock<MockRangeCheck> range_check;
277 DeduplicatingEventEmitter<FieldGreaterThanEvent> event_emitter;
278 FieldGreaterThan field_gt_simulator(range_check, event_emitter);
279
280 field_gt_simulator.ff_gt(0, 0);
281
282 TestTraceContainer trace({
283 { { C::precomputed_first_row, 1 } },
284 });
285
286 FieldGreaterThanTraceBuilder builder;
287 builder.process(event_emitter.dump_events(), trace);
288 check_relation<ff_gt>(trace);
289
290 trace.set(Column::ff_gt_cmp_rng_ctr, 1, 3);
291 trace.set(Column::ff_gt_cmp_rng_ctr, 2, 0);
292
293 EXPECT_THROW_WITH_MESSAGE(check_relation<ff_gt>(trace, ff_gt::SR_RNG_CTR_GT_INIT), "RNG_CTR_GT_INIT");
294 EXPECT_THROW_WITH_MESSAGE(check_relation<ff_gt>(trace, ff_gt::SR_RNG_CTR_DECREMENT), "RNG_CTR_DECREMENT");
295}
296
297TEST(FieldGreaterThanConstrainingTest, NegativeRangeCheckCtrInitInDec)
298{
299 NiceMock<MockRangeCheck> range_check;
300 DeduplicatingEventEmitter<FieldGreaterThanEvent> event_emitter;
301 FieldGreaterThan field_gt_simulator(range_check, event_emitter);
302
303 field_gt_simulator.canon_dec(0);
304
305 TestTraceContainer trace({
306 { { C::precomputed_first_row, 1 } },
307 });
308
309 FieldGreaterThanTraceBuilder builder;
310 builder.process(event_emitter.dump_events(), trace);
311 check_relation<ff_gt>(trace);
312
313 trace.set(Column::ff_gt_cmp_rng_ctr, 1, 4);
314 trace.set(Column::ff_gt_cmp_rng_ctr, 2, 2);
315
316 EXPECT_THROW_WITH_MESSAGE(check_relation<ff_gt>(trace, ff_gt::SR_RNG_CTR_DEC_INIT), "RNG_CTR_DEC_INIT");
317 EXPECT_THROW_WITH_MESSAGE(check_relation<ff_gt>(trace, ff_gt::SR_RNG_CTR_DECREMENT), "RNG_CTR_DECREMENT");
318}
319
320TEST(FieldGreaterThanConstrainingTest, NegativeSelectorConsistency)
321{
322 NiceMock<MockRangeCheck> range_check;
323 DeduplicatingEventEmitter<FieldGreaterThanEvent> event_emitter;
324 FieldGreaterThan field_gt_simulator(range_check, event_emitter);
325
326 field_gt_simulator.ff_gt(0, 0);
327
328 TestTraceContainer trace({
329 { { C::precomputed_first_row, 1 } },
330 });
331
332 FieldGreaterThanTraceBuilder builder;
333 builder.process(event_emitter.dump_events(), trace);
334 check_relation<ff_gt>(trace);
335
336 // Disable the selector after the first row
337 trace.set(Column::ff_gt_sel, 2, 0);
338
339 EXPECT_THROW_WITH_MESSAGE(check_relation<ff_gt>(trace, ff_gt::SR_SEL_CONSISTENCY), "SEL_CONSISTENCY");
340}
341
342TEST(FieldGreaterThanConstrainingTest, NegativeEraseShift)
343{
344 NiceMock<MockRangeCheck> range_check;
345 DeduplicatingEventEmitter<FieldGreaterThanEvent> event_emitter;
346 FieldGreaterThan field_gt_simulator(range_check, event_emitter);
347
348 field_gt_simulator.ff_gt(42, 27);
349
350 TestTraceContainer trace({
351 { { C::precomputed_first_row, 1 } },
352 });
353
354 FieldGreaterThanTraceBuilder builder;
355 builder.process(event_emitter.dump_events(), trace);
356 check_relation<ff_gt>(trace);
357
358 trace.set(Column::ff_gt_a_lo, 2, 0);
359 trace.set(Column::ff_gt_a_hi, 2, 0);
360 trace.set(Column::ff_gt_p_sub_a_lo, 2, 0);
361 trace.set(Column::ff_gt_p_sub_a_hi, 2, 0);
362 trace.set(Column::ff_gt_b_lo, 2, 0);
363 trace.set(Column::ff_gt_b_hi, 2, 0);
364 trace.set(Column::ff_gt_p_sub_b_lo, 2, 0);
365 trace.set(Column::ff_gt_p_sub_b_hi, 2, 1);
366
367 EXPECT_THROW_WITH_MESSAGE(check_relation<ff_gt>(trace, ff_gt::SR_SHIFT_P_SUB_A_TO_A_LO), "SHIFT_P_SUB_A_TO_A_LO");
368 EXPECT_THROW_WITH_MESSAGE(check_relation<ff_gt>(trace, ff_gt::SR_SHIFT_P_SUB_A_TO_A_HI), "SHIFT_P_SUB_A_TO_A_HI");
369 EXPECT_THROW_WITH_MESSAGE(check_relation<ff_gt>(trace, ff_gt::SR_SHIFT_B_TO_P_SUB_A_LO), "SHIFT_B_TO_P_SUB_A_LO");
370 EXPECT_THROW_WITH_MESSAGE(check_relation<ff_gt>(trace, ff_gt::SR_SHIFT_B_TO_P_SUB_A_HI), "SHIFT_B_TO_P_SUB_A_HI");
371 EXPECT_THROW_WITH_MESSAGE(check_relation<ff_gt>(trace, ff_gt::SR_SHIFT_P_SUB_B_TO_B_LO), "SHIFT_P_SUB_B_TO_B_LO");
372 EXPECT_THROW_WITH_MESSAGE(check_relation<ff_gt>(trace, ff_gt::SR_SHIFT_P_SUB_B_TO_B_HI), "SHIFT_P_SUB_B_TO_B_HI");
374 "SHIFT_RES_TO_P_SUB_B_LO");
376 "SHIFT_RES_TO_P_SUB_B_HI");
377}
378
379} // namespace
380} // namespace bb::avm2::constraining
#define EXPECT_THROW_WITH_MESSAGE(code, expectedMessageRegex)
Definition assert.hpp:193
RangeCheck range_check
static constexpr size_t SR_P_SUB_B_LO
Definition ff_gt.hpp:44
static constexpr size_t SR_RNG_CTR_GT_INIT
Definition ff_gt.hpp:48
static constexpr size_t SR_SEL_CONSISTENCY
Definition ff_gt.hpp:60
static constexpr size_t SR_RNG_CTR_DECREMENT
Definition ff_gt.hpp:50
static constexpr size_t SR_P_SUB_A_LO
Definition ff_gt.hpp:41
static constexpr size_t SR_B_DECOMPOSITION
Definition ff_gt.hpp:43
static constexpr size_t SR_SHIFT_RES_TO_P_SUB_B_LO
Definition ff_gt.hpp:58
static constexpr size_t SR_SHIFT_P_SUB_B_TO_B_LO
Definition ff_gt.hpp:56
static constexpr size_t SR_P_SUB_B_HI
Definition ff_gt.hpp:45
static constexpr size_t SR_SHIFT_B_TO_P_SUB_A_HI
Definition ff_gt.hpp:55
static constexpr size_t SR_SHIFT_P_SUB_B_TO_B_HI
Definition ff_gt.hpp:57
static constexpr size_t SR_SHIFT_P_SUB_A_TO_A_LO
Definition ff_gt.hpp:52
static constexpr size_t SR_SHIFT_B_TO_P_SUB_A_LO
Definition ff_gt.hpp:54
static constexpr size_t SR_P_SUB_A_HI
Definition ff_gt.hpp:42
static constexpr size_t SR_A_DECOMPOSITION
Definition ff_gt.hpp:40
static constexpr size_t SR_SHIFT_RES_TO_P_SUB_B_HI
Definition ff_gt.hpp:59
static constexpr size_t SR_SHIFT_P_SUB_A_TO_A_HI
Definition ff_gt.hpp:53
static constexpr size_t SR_RNG_CTR_DEC_INIT
Definition ff_gt.hpp:49
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 process(const simulation::EventEmitterInterface< simulation::RangeCheckEvent >::Container &events, TraceContainer &trace)
Processes range check events and populates the trace with decomposed value columns.
void set(Column col, uint32_t row, const FF &value)
RangeCheckTraceBuilder range_check_builder
Definition alu.test.cpp:121
AluTraceBuilder builder
Definition alu.test.cpp:124
EventEmitter< RangeCheckEvent > range_check_event_emitter
EventEmitter< DataCopyEvent > event_emitter
TestTraceContainer trace
FF a
FF b
bool expected_result
TEST_P(AvmRecursiveTestsParameterized, TwoLayerAvmRecursion)
A test of the Two Layer AVM recursive verifier.
INSTANTIATE_TEST_SUITE_P(PaddingVariants, AvmRecursiveTestsParameterized, ::testing::Values(false, true), [](const auto &info) { return info.param ? "Padded" :"Unpadded";})
void check_interaction(tracegen::TestTraceContainer &trace)
TEST(AvmFixedVKTests, FixedVKCommitments)
Test that the fixed VK commitments agree with the ones computed from precomputed columns.
U256Decomposition decompose_256(const uint256_t &x)
TestTraceContainer empty_trace()
Definition fixtures.cpp:153
AvmFlavorSettings::FF FF
Definition field.hpp:10
lookup_settings< lookup_ff_gt_a_lo_range_settings_ > lookup_ff_gt_a_lo_range_settings
lookup_settings< lookup_ff_gt_a_hi_range_settings_ > lookup_ff_gt_a_hi_range_settings
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
unsigned __int128 uint128_t
Definition serialize.hpp:45
static constexpr uint256_t modulus