Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
databus_lookup_relation_consistency.test.cpp
Go to the documentation of this file.
1
19#include <gtest/gtest.h>
20
21using namespace bb;
22
23using FF = fr;
24
28
29// The kernel_calldata bus relation. App-calldata and return-data buses are shape-identical and
30// covered by symmetry — running the consistency suite once is enough.
32 EntityId::kernel_calldata,
33 EntityId::kernel_calldata_read_counts,
34 EntityId::kernel_calldata_inverses,
35 EntityId::kernel_calldata_indicator,
36 EntityId::q_l>;
37
38static DatabusInputElements get_random_databus_inputs()
39{
41 for (auto name : { EntityId::w_l,
42 EntityId::w_r,
43 EntityId::databus_id,
44 EntityId::q_busread,
45 EntityId::q_l,
46 EntityId::kernel_calldata,
47 EntityId::kernel_calldata_read_counts,
48 EntityId::kernel_calldata_inverses,
49 EntityId::kernel_calldata_indicator }) {
51 }
52 return result;
53}
54
55// A valid kernel_calldata read: read kernel_calldata[5] == 42 with q_l (the column's selector)
56// and read-counts enabled.
57static DatabusInputElements get_valid_calldata_read_inputs()
58{
60 result[EntityId::w_l] = FF(42);
61 result[EntityId::w_r] = FF(5);
62 result[EntityId::databus_id] = FF(5);
63 result[EntityId::kernel_calldata] = FF(42);
64 result[EntityId::q_busread] = FF(1);
65 result[EntityId::q_l] = FF(1);
66 result[EntityId::kernel_calldata_read_counts] = FF(1);
67 result[EntityId::kernel_calldata_indicator] = FF(1);
68 return result;
69}
70
71class DatabusLookupRelationConsistency : public testing::Test {
72 public:
74 static constexpr size_t NUM_SUBRELATIONS = 4;
75
77 const DatabusInputElements& input_elements,
78 const RelationParameters<FF>& parameters)
79 {
81 Relation::accumulate(accumulator, input_elements, parameters, FF(1));
82 EXPECT_EQ(accumulator, expected_values);
83 }
84};
85
87static std::array<FF, 4> compute_expected_values(const DatabusInputElements& in, const RelationParameters<FF>& params)
88{
89 const auto& beta = params.beta;
90 const auto& gamma = params.gamma;
91
92 const auto lookup_term = in[EntityId::w_l] + in[EntityId::w_r] * beta + gamma;
93 const auto column_selector = in[EntityId::q_l];
94 const auto bus_value = in[EntityId::kernel_calldata];
95 const auto read_counts = in[EntityId::kernel_calldata_read_counts];
96 const auto inverses = in[EntityId::kernel_calldata_inverses];
97 const auto indicator = in[EntityId::kernel_calldata_indicator];
98
99 const auto is_read = in[EntityId::q_busread] * column_selector;
100 const auto table_term = bus_value + in[EntityId::databus_id] * beta + gamma;
101 const auto common = lookup_term * table_term * inverses - FF(1);
102
103 return {
104 common * is_read, // (1a)
105 common * read_counts, // (1b)
106 (is_read * table_term - read_counts * lookup_term) * inverses, // (2) no scaling
107 read_counts - indicator * read_counts, // (3) (1 - ind) * count
108 };
109}
110
112{
113 const auto run_test = [](bool random_inputs) {
114 DatabusInputElements in = random_inputs ? get_random_databus_inputs() : get_valid_calldata_read_inputs();
115 const auto parameters = RelationParameters<FF>::get_random();
116 validate_relation_execution(compute_expected_values(in, parameters), in, parameters);
117 };
118
119 run_test(/*random_inputs=*/false);
120 run_test(/*random_inputs=*/true);
121}
122
125{
126 const auto parameters = RelationParameters<FF>::get_random();
127
129 in[EntityId::q_busread] = FF(0);
130 in[EntityId::q_l] = FF(0);
131 in[EntityId::kernel_calldata_read_counts] = FF(0);
132 // Set other values non-zero to confirm they don't leak into the subrelations.
133 in[EntityId::w_l] = FF(42);
134 in[EntityId::w_r] = FF(5);
135 in[EntityId::databus_id] = FF(5);
136 in[EntityId::kernel_calldata] = FF(42);
137 in[EntityId::kernel_calldata_inverses] = FF(0);
138
139 std::array<FF, 4> accumulator{};
140 Relation::accumulate(accumulator, in, parameters, FF(1));
141 for (size_t i = 0; i < 4; i++) {
142 EXPECT_EQ(accumulator[i], FF(0)) << "Subrelation " << i << " should be zero for inactive gates";
143 }
144}
145
149{
150 const auto parameters = RelationParameters<FF>::get_random();
151 const auto& beta = parameters.beta;
152 const auto& gamma = parameters.gamma;
153
155 in[EntityId::q_busread] = FF(1);
156 in[EntityId::q_l] = FF(1);
157
158 const FF value = FF(42);
159 const FF index = FF(5);
160 in[EntityId::w_l] = value;
161 in[EntityId::w_r] = index;
162 in[EntityId::databus_id] = index;
163 in[EntityId::kernel_calldata] = value;
164
165 const auto lookup_term = value + index * beta + gamma;
166 const auto table_term = value + index * beta + gamma; // same; L == T.
167 in[EntityId::kernel_calldata_inverses] = (lookup_term * table_term).invert();
168 in[EntityId::kernel_calldata_read_counts] = FF(1);
169 in[EntityId::kernel_calldata_indicator] = FF(1);
170 std::array<FF, 4> accumulator{};
171 Relation::accumulate(accumulator, in, parameters, FF(1));
172
173 EXPECT_EQ(accumulator[0], FF(0)); // (1a) (I·L·T − 1)·is_read = 0
174 EXPECT_EQ(accumulator[1], FF(0)); // (1b) (I·L·T − 1)·count = 0
175 EXPECT_EQ(accumulator[2], FF(0)); // (2) (T − L)·I = 0 since L == T
176 EXPECT_EQ(accumulator[3], FF(0)); // (3) (1 − indicator)·count = 0
177}
178
180TEST_F(DatabusLookupRelationConsistency, MismatchedReadWriteTerms)
181{
182 const auto parameters = RelationParameters<FF>::get_random();
183 const auto& beta = parameters.beta;
184 const auto& gamma = parameters.gamma;
185
187 in[EntityId::q_busread] = FF(1);
188 in[EntityId::q_l] = FF(1);
189
190 const FF read_value = FF(42);
191 const FF bus_value = FF(100); // intentional mismatch
192 const FF index = FF(5);
193 in[EntityId::w_l] = read_value;
194 in[EntityId::w_r] = index;
195 in[EntityId::databus_id] = index;
196 in[EntityId::kernel_calldata] = bus_value;
197
198 const auto lookup_term = read_value + index * beta + gamma;
199 const auto table_term = bus_value + index * beta + gamma;
200 const auto inverse = (lookup_term * table_term).invert();
201 in[EntityId::kernel_calldata_inverses] = inverse;
202 in[EntityId::kernel_calldata_read_counts] = FF(1);
203 in[EntityId::kernel_calldata_indicator] = FF(1);
204 std::array<FF, 4> accumulator{};
205 Relation::accumulate(accumulator, in, parameters, FF(1));
206
207 EXPECT_EQ(accumulator[0], FF(0)); // (1a) I correct
208 EXPECT_EQ(accumulator[1], FF(0)); // (1b) I correct
209 EXPECT_EQ(accumulator[2], (table_term - lookup_term) * inverse); // (2) L != T
210 EXPECT_EQ(accumulator[3], FF(0)); // (3) data row
211 EXPECT_NE(accumulator[2], FF(0));
212}
213
216TEST_F(DatabusLookupRelationConsistency, InverseUnconstrainedAtInactiveRows)
217{
218 const auto parameters = RelationParameters<FF>::get_random();
219
221 in[EntityId::q_busread] = FF(0);
222 in[EntityId::q_l] = FF(0);
223 in[EntityId::kernel_calldata_read_counts] = FF(0);
224 in[EntityId::kernel_calldata_inverses] = FF(999);
225 in[EntityId::w_l] = FF(42);
226 in[EntityId::w_r] = FF(5);
227 in[EntityId::databus_id] = FF(5);
228 in[EntityId::kernel_calldata] = FF(42);
229
230 std::array<FF, 4> accumulator{};
231 Relation::accumulate(accumulator, in, parameters, FF(1));
232 for (size_t i = 0; i < 4; i++) {
233 EXPECT_EQ(accumulator[i], FF(0)) << "Subrelation " << i << " should be unaffected by garbage inverse";
234 }
235}
236
238TEST_F(DatabusLookupRelationConsistency, ReadCountLocalityFailsOutsideDataRows)
239{
240 const auto parameters = RelationParameters<FF>::get_random();
241
243 in[EntityId::q_busread] = FF(0);
244 in[EntityId::q_l] = FF(0);
245 in[EntityId::kernel_calldata_read_counts] = FF(3);
246 in[EntityId::kernel_calldata_indicator] = FF(0);
247
248 std::array<FF, 4> accumulator{};
249 Relation::accumulate(accumulator, in, parameters, FF(1));
250
251 EXPECT_EQ(accumulator[3], FF(3)); // (1 - indicator) * count
252}
253
255TEST_F(DatabusLookupRelationConsistency, WrongInverseOnReadRowFails)
256{
257 const auto parameters = RelationParameters<FF>::get_random();
258 const auto& beta = parameters.beta;
259 const auto& gamma = parameters.gamma;
260
262 in[EntityId::q_busread] = FF(1);
263 in[EntityId::q_l] = FF(1);
264
265 const FF value = FF(42);
266 const FF index = FF(5);
267 in[EntityId::w_l] = value;
268 in[EntityId::w_r] = index;
269 in[EntityId::databus_id] = index;
270 in[EntityId::kernel_calldata] = value;
271 in[EntityId::kernel_calldata_inverses] = FF(777); // wrong
272 in[EntityId::kernel_calldata_read_counts] = FF(0);
273
274 const auto lookup_term = value + index * beta + gamma;
275 const auto table_term = value + index * beta + gamma;
276
277 std::array<FF, 4> accumulator{};
278 Relation::accumulate(accumulator, in, parameters, FF(1));
279
280 EXPECT_EQ(accumulator[0], (FF(777) * lookup_term * table_term - FF(1)) * FF(1));
281 EXPECT_NE(accumulator[0], FF(0));
282 EXPECT_EQ(accumulator[1], FF(0));
283}
284
286TEST_F(DatabusLookupRelationConsistency, WrongInverseOnWriteRowFails)
287{
288 const auto parameters = RelationParameters<FF>::get_random();
289 const auto& beta = parameters.beta;
290 const auto& gamma = parameters.gamma;
291
293 in[EntityId::q_busread] = FF(0);
294 in[EntityId::q_l] = FF(0);
295
296 const FF value = FF(42);
297 const FF index = FF(5);
298 in[EntityId::databus_id] = index;
299 in[EntityId::kernel_calldata] = value;
300 in[EntityId::w_l] = FF(0);
301 in[EntityId::w_r] = FF(0);
302 in[EntityId::kernel_calldata_read_counts] = FF(3);
303 in[EntityId::kernel_calldata_indicator] = FF(1);
304 in[EntityId::kernel_calldata_inverses] = FF(999); // wrong
305 const auto lookup_term = in[EntityId::w_l] + in[EntityId::w_r] * beta + gamma;
306 const auto table_term = value + index * beta + gamma;
307
308 std::array<FF, 4> accumulator{};
309 Relation::accumulate(accumulator, in, parameters, FF(1));
310
311 EXPECT_EQ(accumulator[0], FF(0));
312 EXPECT_EQ(accumulator[1], (FF(999) * lookup_term * table_term - FF(1)) * FF(3));
313 EXPECT_EQ(accumulator[3], FF(0));
314 EXPECT_NE(accumulator[1], FF(0));
315}
316
319TEST_F(DatabusLookupRelationConsistency, CorrectInverseOnWriteRow)
320{
321 const auto parameters = RelationParameters<FF>::get_random();
322 const auto& beta = parameters.beta;
323 const auto& gamma = parameters.gamma;
324
326 in[EntityId::q_busread] = FF(0);
327 in[EntityId::q_l] = FF(0);
328
329 const FF value = FF(42);
330 const FF index = FF(5);
331 in[EntityId::databus_id] = index;
332 in[EntityId::kernel_calldata] = value;
333 in[EntityId::w_l] = FF(0);
334 in[EntityId::w_r] = FF(0);
335
336 const auto lookup_term = in[EntityId::w_l] + in[EntityId::w_r] * beta + gamma;
337 const auto table_term = value + index * beta + gamma;
338 in[EntityId::kernel_calldata_inverses] = (lookup_term * table_term).invert();
339 in[EntityId::kernel_calldata_read_counts] = FF(3);
340 in[EntityId::kernel_calldata_indicator] = FF(1);
341 std::array<FF, 4> accumulator{};
342 Relation::accumulate(accumulator, in, parameters, FF(1));
343
344 EXPECT_EQ(accumulator[0], FF(0));
345 EXPECT_EQ(accumulator[1], FF(0));
346 EXPECT_EQ(accumulator[2], (FF(0) * table_term - FF(3) * lookup_term) * (lookup_term * table_term).invert());
347 EXPECT_EQ(accumulator[3], FF(0));
348 EXPECT_NE(accumulator[2], FF(0));
349}
static void validate_relation_execution(const std::array< FF, NUM_SUBRELATIONS > &expected_values, const DatabusInputElements &input_elements, const RelationParameters< FF > &parameters)
Log-derivative lookup argument for a single DataBus column.
static void accumulate(ContainerOverSubrelations &accumulator, const AllEntities &in, const Parameters &params, const FF &scaling_factor)
Accumulate this column's four subrelation contributions. (1a) (I*L*T - 1) * is_read = 0 (1b) (I*L*T -...
SingleBusLookupRelationImpl< FF, EntityId::kernel_calldata, EntityId::kernel_calldata_read_counts, EntityId::kernel_calldata_inverses, EntityId::kernel_calldata_indicator, EntityId::q_l > KernelCalldataRelation
MegaFlavor_Generated::AllEntities< FF > DatabusInputElements
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
TEST_F(IPATest, ChallengesAreZero)
Definition ipa.test.cpp:160
field< Bn254FrParams > fr
Definition fr.hpp:155
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
std::string name
Container for parameters used by the grand product (permutation, lookup) Honk relations.
static RelationParameters get_random()
static field random_element(numeric::RNG *engine=nullptr) noexcept
VectorField result