Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
range_check.test.cpp
Go to the documentation of this file.
1#include <gmock/gmock.h>
2#include <gtest/gtest.h>
3
4#include <cmath>
5#include <cstdint>
6
14
15namespace bb::avm2::constraining {
16namespace {
17
18using tracegen::RangeCheckTraceBuilder;
19using tracegen::TestTraceContainer;
21using C = Column;
23
24TEST(RangeCheckConstrainingTest, EmptyRow)
25{
26 check_relation<range_check>(testing::empty_trace());
27}
28
29TEST(RangeCheckConstrainingTest, IsLteMutuallyExclusive)
30{
31 TestTraceContainer trace({
32 { { C::range_check_sel, 1 }, { C::range_check_is_lte_u32, 1 } },
33 });
34
35 check_relation<range_check>(trace, range_check::SR_IS_LTE_MUTUALLY_EXCLUSIVE);
36}
37
38TEST(RangeCheckConstrainingTest, NegativeIsLteMutuallyExclusive)
39{
40 TestTraceContainer trace({
41 // Negative test, only one is_lte flag should be high
42 { { C::range_check_sel, 1 }, { C::range_check_is_lte_u32, 1 }, { C::range_check_is_lte_u112, 1 } },
43 });
44
46 "IS_LTE_MUTUALLY_EXCLUSIVE");
47}
48
49TEST(RangeCheckConstrainingTest, CheckRecomposition)
50{
51 uint128_t value = 0x3FFFFFFFD;
53
54 uint16_t u16_r0 = 0xFFFD; // value & 0xFFFF;
55 uint16_t u16_r1 = 0xFFFF; // (value >> 16) & 0xFFFF;
56 uint16_t dynamic_slice_register = 0x0003; // (value >> 32) & 0xFFFF;
57
58 TestTraceContainer trace({ {
59 { C::range_check_sel, 1 },
60 { C::range_check_value, value_u256 },
61 { C::range_check_is_lte_u48, 1 },
62 { C::range_check_u16_r0, u16_r0 },
63 { C::range_check_u16_r1, u16_r1 },
64 { C::range_check_u16_r7, dynamic_slice_register },
65 } });
66
67 check_relation<range_check>(trace, range_check::SR_CHECK_RECOMPOSITION);
68}
69
70TEST(RangeCheckConstrainingTest, NegativeCheckRecomposition)
71{
72 uint128_t value = 0x3FFFFFFFD;
73 // Add 1 to the value to create a "bad" value that doesn't match recomposition
75
76 uint16_t u16_r0 = value & 0xFFFF;
77 uint16_t u16_r1 = (value >> 16) & 0xFFFF;
78 uint16_t dynamic_slice_register = (value >> 32) & 0xFFFF;
79
80 TestTraceContainer trace({ {
81 { C::range_check_sel, 1 },
82 { C::range_check_value, bad_value },
83 { C::range_check_is_lte_u48, 1 },
84 { C::range_check_u16_r0, u16_r0 },
85 { C::range_check_u16_r1, u16_r1 },
86 { C::range_check_u16_r7, dynamic_slice_register },
87 } });
88
90 "CHECK_RECOMPOSITION");
91}
92
93TEST(RangeCheckConstrainingTest, Full)
94{
95 uint8_t num_bits = 34;
96 uint8_t non_dynamic_bits = 32;
97 uint8_t dynamic_bits = num_bits - non_dynamic_bits;
98
99 // Choose a value that has num_bits
100 uint128_t value = (static_cast<uint128_t>(1) << num_bits) - 3;
102
103 uint16_t u16_r0 = value & 0xFFFF;
104 uint16_t u16_r1 = (value >> 16) & 0xFFFF;
105 uint16_t dynamic_slice_register = (value >> 32) & 0xFFFF;
106
107 uint16_t dynamic_bits_pow_2 = static_cast<uint16_t>(1 << dynamic_bits);
108 uint16_t dynamic_diff = static_cast<uint16_t>(dynamic_bits_pow_2 - dynamic_slice_register - 1);
109
110 TestTraceContainer trace({ {
111 { C::range_check_sel, 1 },
112 { C::range_check_value, value_u256 },
113 { C::range_check_rng_chk_bits, num_bits },
114 { C::range_check_is_lte_u48, 1 },
115 { C::range_check_u16_r0, u16_r0 },
116 { C::range_check_u16_r1, u16_r1 },
117 { C::range_check_u16_r7, dynamic_slice_register },
118 { C::range_check_dyn_rng_chk_bits, dynamic_bits },
119 { C::range_check_dyn_rng_chk_pow_2, dynamic_bits_pow_2 },
120 { C::range_check_dyn_diff, dynamic_diff },
121 // Enable 16 bit range lookup for each regular (non-dynamic) register being used.
122 { C::range_check_sel_r0_16_bit_rng_lookup, 1 },
123 { C::range_check_sel_r1_16_bit_rng_lookup, 1 },
124 } });
125
126 check_relation<range_check>(trace);
127}
128
129TEST(RangeCheckConstrainingTest, NegativeMissingLookup)
130{
131 uint8_t num_bits = 34;
132 uint8_t non_dynamic_bits = 32;
133 uint8_t dynamic_bits = num_bits - non_dynamic_bits;
134
135 // Choose a value that has num_bits
136 uint128_t value = (static_cast<uint128_t>(1) << num_bits) - 3;
138
139 uint16_t u16_r0 = value & 0xFFFF;
140 uint16_t u16_r1 = (value >> 16) & 0xFFFF;
141 uint16_t dynamic_slice_register = (value >> 32) & 0xFFFF;
142
143 uint16_t dynamic_bits_pow_2 = static_cast<uint16_t>(1 << dynamic_bits);
144 uint16_t dynamic_diff = static_cast<uint16_t>(dynamic_bits_pow_2 - dynamic_slice_register - 1);
145
146 TestTraceContainer trace({ {
147 { C::range_check_sel, 1 },
148 { C::range_check_value, value_u256 },
149 { C::range_check_rng_chk_bits, num_bits },
150 { C::range_check_is_lte_u48, 1 },
151 { C::range_check_u16_r0, u16_r0 },
152 { C::range_check_u16_r1, u16_r1 },
153 { C::range_check_u16_r7, dynamic_slice_register },
154 { C::range_check_dyn_rng_chk_bits, dynamic_bits },
155 { C::range_check_dyn_rng_chk_pow_2, dynamic_bits_pow_2 },
156 { C::range_check_dyn_diff, dynamic_diff },
157 // Enable 16 bit range lookup for each regular (non-dynamic) register being used.
158 { C::range_check_sel_r0_16_bit_rng_lookup, 1 },
159 { C::range_check_sel_r1_16_bit_rng_lookup, 0 }, // BAD! SHOULD BE 1
160 } });
161
162 EXPECT_THROW_WITH_MESSAGE(check_relation<range_check>(trace), "Relation range_check");
163}
164
165TEST(RangeCheckConstrainingTest, WithTracegen)
166{
167 TestTraceContainer trace;
168 RangeCheckTraceBuilder builder;
169
170 builder.process(
171 {
172 { .value = 0, .num_bits = 0 },
173 { .value = 0, .num_bits = 1 },
174 { .value = 0, .num_bits = 16 },
175 { .value = 2, .num_bits = 2 },
176 { .value = 255, .num_bits = 8 },
177 { .value = 1 << 16, .num_bits = 17 },
178 { .value = 1 << 18, .num_bits = 32 },
179 { .value = static_cast<uint128_t>(1) << 66, .num_bits = 67 },
180 { .value = 1024, .num_bits = 109 },
181 { .value = 1, .num_bits = 128 },
182 { .value = 0xFFFFFFFFFFFFFFFF, .num_bits = 128 },
183 { .value = 0x1FFF, .num_bits = 13 },
184 },
185 trace);
186
187 check_relation<range_check>(trace);
188}
189
190TEST(RangeCheckConstrainingTest, NegativeWithTracegen)
191{
192 TestTraceContainer trace;
193 RangeCheckTraceBuilder builder;
194
195 builder.process(
196 {
197 { .value = 1, .num_bits = 0 },
198 { .value = 2, .num_bits = 1 },
199 { .value = 255, .num_bits = 7 },
200 { .value = 1 << 16, .num_bits = 16 },
201 { .value = 1 << 18, .num_bits = 18 },
202 { .value = static_cast<uint128_t>(1) << 66, .num_bits = 66 },
203 { .value = 1024, .num_bits = 9 },
204 { .value = 1, .num_bits = 0 },
205 { .value = 0xFFFFFFFFFFFFFFFF, .num_bits = 127 },
206 { .value = 0x1FFF, .num_bits = 12 },
207 },
208 trace);
209
210 EXPECT_THROW_WITH_MESSAGE(check_relation<range_check>(trace), "Relation range_check");
211}
212
213} // namespace
214} // namespace bb::avm2::constraining
static constexpr size_t SR_IS_LTE_MUTUALLY_EXCLUSIVE
static constexpr size_t SR_CHECK_RECOMPOSITION
static constexpr uint256_t from_uint128(const uint128_t a) noexcept
Definition uint256.hpp:94
AluTraceBuilder builder
Definition alu.test.cpp:123
RangeCheck range_check
TestTraceContainer trace
#define EXPECT_THROW_WITH_MESSAGE(code, expectedMessage)
Definition macros.hpp:7
TEST(TxExecutionConstrainingTest, WriteTreeValue)
Definition tx.test.cpp:508
TestTraceContainer empty_trace()
Definition fixtures.cpp:153
typename Flavor::FF FF
unsigned __int128 uint128_t
Definition serialize.hpp:44