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),
235 EXPECT_THROW_WITH_MESSAGE(check_relation<ff_gt>(trace, ff_gt::SR_B_DECOMPOSITION),
237}
238
239TEST(FieldGreaterThanConstrainingTest, NegativeManipulatedComparisonsWithP)
240{
241 NiceMock<MockRangeCheck> range_check;
242 DeduplicatingEventEmitter<FieldGreaterThanEvent> event_emitter;
243 FieldGreaterThan field_gt_simulator(range_check, event_emitter);
244
245 field_gt_simulator.ff_gt(0, 0);
246
247 TestTraceContainer trace({
248 { { C::precomputed_first_row, 1 } },
249 });
250
251 FieldGreaterThanTraceBuilder builder;
252 builder.process(event_emitter.dump_events(), trace);
253 check_relation<ff_gt>(trace);
254
256 uint256_t p_lo = p_limbs.lo;
257 uint256_t p_hi = p_limbs.hi;
258
259 // Manipulate the decomposition in a way that passes the decomposition check due to overflow
260 trace.set(Column::ff_gt_a_lo, 1, p_lo);
261 trace.set(Column::ff_gt_a_hi, 1, p_hi);
262 trace.set(Column::ff_gt_b_lo, 1, p_lo);
263 trace.set(Column::ff_gt_b_hi, 1, p_hi);
264
265 trace.set(Column::ff_gt_p_sub_a_hi, 1, p_lo - 1);
266 trace.set(Column::ff_gt_p_sub_a_lo, 1, p_hi - 1);
267 trace.set(Column::ff_gt_p_sub_b_hi, 1, p_lo - 1);
268 trace.set(Column::ff_gt_p_sub_b_lo, 1, p_hi - 1);
269
270 EXPECT_THROW_WITH_MESSAGE(check_relation<ff_gt>(trace, ff_gt::SR_P_SUB_A_LO),
272 EXPECT_THROW_WITH_MESSAGE(check_relation<ff_gt>(trace, ff_gt::SR_P_SUB_A_HI),
274 EXPECT_THROW_WITH_MESSAGE(check_relation<ff_gt>(trace, ff_gt::SR_P_SUB_B_LO),
276 EXPECT_THROW_WITH_MESSAGE(check_relation<ff_gt>(trace, ff_gt::SR_P_SUB_B_HI),
278}
279
280TEST(FieldGreaterThanConstrainingTest, NegativeLessRangeChecks)
281{
282 NiceMock<MockRangeCheck> range_check;
283 DeduplicatingEventEmitter<FieldGreaterThanEvent> event_emitter;
284 FieldGreaterThan field_gt_simulator(range_check, event_emitter);
285
286 field_gt_simulator.ff_gt(0, 0);
287
288 TestTraceContainer trace({
289 { { C::precomputed_first_row, 1 } },
290 });
291
292 FieldGreaterThanTraceBuilder builder;
293 builder.process(event_emitter.dump_events(), trace);
294 check_relation<ff_gt>(trace);
295
296 trace.set(Column::ff_gt_cmp_rng_ctr, 1, 3);
297 trace.set(Column::ff_gt_cmp_rng_ctr, 2, 0);
298
299 EXPECT_THROW_WITH_MESSAGE(check_relation<ff_gt>(trace, ff_gt::SR_RNG_CTR_GT_INIT),
301 EXPECT_THROW_WITH_MESSAGE(check_relation<ff_gt>(trace, ff_gt::SR_RNG_CTR_DECREMENT),
303}
304
305TEST(FieldGreaterThanConstrainingTest, NegativeRangeCheckCtrInitInDec)
306{
307 NiceMock<MockRangeCheck> range_check;
308 DeduplicatingEventEmitter<FieldGreaterThanEvent> event_emitter;
309 FieldGreaterThan field_gt_simulator(range_check, event_emitter);
310
311 field_gt_simulator.canon_dec(0);
312
313 TestTraceContainer trace({
314 { { C::precomputed_first_row, 1 } },
315 });
316
317 FieldGreaterThanTraceBuilder builder;
318 builder.process(event_emitter.dump_events(), trace);
319 check_relation<ff_gt>(trace);
320
321 trace.set(Column::ff_gt_cmp_rng_ctr, 1, 4);
322 trace.set(Column::ff_gt_cmp_rng_ctr, 2, 2);
323
324 EXPECT_THROW_WITH_MESSAGE(check_relation<ff_gt>(trace, ff_gt::SR_RNG_CTR_DEC_INIT),
326 EXPECT_THROW_WITH_MESSAGE(check_relation<ff_gt>(trace, ff_gt::SR_RNG_CTR_DECREMENT),
328}
329
330TEST(FieldGreaterThanConstrainingTest, NegativeSelectorConsistency)
331{
332 NiceMock<MockRangeCheck> range_check;
333 DeduplicatingEventEmitter<FieldGreaterThanEvent> event_emitter;
334 FieldGreaterThan field_gt_simulator(range_check, event_emitter);
335
336 field_gt_simulator.ff_gt(0, 0);
337
338 TestTraceContainer trace({
339 { { C::precomputed_first_row, 1 } },
340 });
341
342 FieldGreaterThanTraceBuilder builder;
343 builder.process(event_emitter.dump_events(), trace);
344 check_relation<ff_gt>(trace);
345
346 // Disable the selector after the first row
347 trace.set(Column::ff_gt_sel, 2, 0);
348
349 EXPECT_THROW_WITH_MESSAGE(check_relation<ff_gt>(trace, ff_gt::SR_TRACE_CONTINUITY),
351}
352
353TEST(FieldGreaterThanConstrainingTest, NegativeEraseShift)
354{
355 NiceMock<MockRangeCheck> range_check;
356 DeduplicatingEventEmitter<FieldGreaterThanEvent> event_emitter;
357 FieldGreaterThan field_gt_simulator(range_check, event_emitter);
358
359 field_gt_simulator.ff_gt(42, 27);
360
361 TestTraceContainer trace({
362 { { C::precomputed_first_row, 1 } },
363 });
364
365 FieldGreaterThanTraceBuilder builder;
366 builder.process(event_emitter.dump_events(), trace);
367 check_relation<ff_gt>(trace);
368
369 trace.set(Column::ff_gt_a_lo, 2, 0);
370 trace.set(Column::ff_gt_a_hi, 2, 0);
371 trace.set(Column::ff_gt_p_sub_a_lo, 2, 0);
372 trace.set(Column::ff_gt_p_sub_a_hi, 2, 0);
373 trace.set(Column::ff_gt_b_lo, 2, 0);
374 trace.set(Column::ff_gt_b_hi, 2, 0);
375 trace.set(Column::ff_gt_p_sub_b_lo, 2, 0);
376 trace.set(Column::ff_gt_p_sub_b_hi, 2, 1);
377
394}
395
396} // namespace
397} // namespace bb::avm2::constraining
#define EXPECT_THROW_WITH_MESSAGE(code, expectedMessageRegex)
Definition assert.hpp:224
RangeCheck range_check
INSTANTIATE_TEST_SUITE_P(All, KernelIOTamperingTests, testing::Values(KernelIOField::PAIRING_INPUTS, KernelIOField::ACCUMULATOR_HASH, KernelIOField::KERNEL_RETURN_DATA, KernelIOField::APP_RETURN_DATA, KernelIOField::ECC_OP_HASH), [](const testing::TestParamInfo< KernelIOField > &info) { switch(info.param) { case KernelIOField::PAIRING_INPUTS:return "PairingInputs";case KernelIOField::ACCUMULATOR_HASH:return "AccumulatorHash";case KernelIOField::KERNEL_RETURN_DATA:return "KernelReturnData";case KernelIOField::APP_RETURN_DATA:return "AppReturnData";case KernelIOField::ECC_OP_HASH:return "EccOpHash";} return "Unknown";})
TEST_P(KernelIOTamperingTests, CausesVerificationFailure)
static constexpr size_t SR_P_SUB_B_LO
Definition ff_gt.hpp:46
static constexpr size_t SR_RNG_CTR_GT_INIT
Definition ff_gt.hpp:50
static constexpr size_t SR_RNG_CTR_DECREMENT
Definition ff_gt.hpp:52
static constexpr size_t SR_P_SUB_A_LO
Definition ff_gt.hpp:43
static constexpr size_t SR_B_DECOMPOSITION
Definition ff_gt.hpp:45
static constexpr size_t SR_SHIFT_RES_TO_P_SUB_B_LO
Definition ff_gt.hpp:60
static constexpr size_t SR_SHIFT_P_SUB_B_TO_B_LO
Definition ff_gt.hpp:58
static constexpr size_t SR_P_SUB_B_HI
Definition ff_gt.hpp:47
static constexpr size_t SR_SHIFT_B_TO_P_SUB_A_HI
Definition ff_gt.hpp:57
static constexpr size_t SR_SHIFT_P_SUB_B_TO_B_HI
Definition ff_gt.hpp:59
static constexpr size_t SR_SHIFT_P_SUB_A_TO_A_LO
Definition ff_gt.hpp:54
static constexpr size_t SR_SHIFT_B_TO_P_SUB_A_LO
Definition ff_gt.hpp:56
static constexpr size_t SR_P_SUB_A_HI
Definition ff_gt.hpp:44
static constexpr size_t SR_A_DECOMPOSITION
Definition ff_gt.hpp:42
static constexpr size_t SR_SHIFT_RES_TO_P_SUB_B_HI
Definition ff_gt.hpp:61
static constexpr size_t SR_TRACE_CONTINUITY
Definition ff_gt.hpp:40
static std::string get_subrelation_label(size_t index)
Definition ff_gt.hpp:63
static constexpr size_t SR_SHIFT_P_SUB_A_TO_A_HI
Definition ff_gt.hpp:55
static constexpr size_t SR_RNG_CTR_DEC_INIT
Definition ff_gt.hpp:51
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, bool use_atomic_limbs=false)
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
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:156
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