Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
logderiv_lookup_relation.hpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: Complete, auditors: [Luke, Raju], commit: }
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
7#pragma once
8#include <array>
9#include <tuple>
10
16
17namespace bb {
18
95template <typename FF_> class LogDerivLookupRelationImpl {
96 public:
97 using FF = FF_;
98 static constexpr size_t TABLE_TERMS = 1; // the number of table terms in the lookup relation
99 // 1 + polynomial degree of this relation
100 static constexpr size_t INVERSE_SUBRELATION_LENGTH = 5; // both subrelations are degree 4
101 static constexpr size_t LOOKUP_SUBRELATION_LENGTH = 5; // both subrelations are degree 4
102 static constexpr size_t BOOLEAN_CHECK_SUBRELATION_LENGTH =
103 3; // deg + 1 of the relation checking that read_tag_m is a boolean value
104
105 static constexpr std::array<size_t, 3> SUBRELATION_PARTIAL_LENGTHS{
106 INVERSE_SUBRELATION_LENGTH, // inverse construction sub-relation
107 LOOKUP_SUBRELATION_LENGTH, // log derivative lookup argument sub-relation
108 BOOLEAN_CHECK_SUBRELATION_LENGTH // boolean check sub-relation
109 };
110
111 static constexpr std::array<bool, 3>
112 SUBRELATION_LINEARLY_INDEPENDENT = { true /*Inverse subrelation*/,
113 false /*Lookup subrelation*/,
114 true /*read_tag boolean check subrelation*/ };
115
116 template <typename AllEntities> inline static bool skip(const AllEntities& in)
117 {
118 // Ensure the input does not contain a lookup gate or data that is being read
119 return in.q_lookup.is_zero() && in.lookup_read_counts.is_zero();
120 }
121
133 template <typename AllValues> static bool operation_exists_at_row(const AllValues& row)
134 {
135 // is the row a lookup gate or does it contain table data that has been read at some point in this circuit
136 return (row.q_lookup == 1) || (row.lookup_read_tags == 1);
137 }
138
139 // Get the inverse polynomial for this relation
140 template <typename AllEntities> static auto& get_inverse_polynomial(AllEntities& in) { return in.lookup_inverses; }
141
157 template <typename Accumulator, typename AllEntities>
158 static Accumulator compute_inverse_exists(const AllEntities& in)
159 {
160 using CoefficientAccumulator = typename Accumulator::CoefficientAccumulator;
161
162 const auto row_has_write = CoefficientAccumulator(in.lookup_read_tags);
163 const auto row_has_read = CoefficientAccumulator(in.q_lookup);
164 // Relation checking: is_read_gate == 1 || read_tag == 1
165 // Important note: the relation written below assumes that is_read_gate and read_tag are boolean values, which
166 // is guaranteed by the boolean_check subrelation. If not, fixing one of the two, the return value is a linear
167 // function in the other variable and can be set to an arbitrary value independent of the fixed value. See the
168 // boolean_check subrelation for more explanation.
169 // 1 - (1 - row_has_write) * (1- row_has_read)
170 // degree 1 1 1 1 = 2
171 return Accumulator(-(row_has_write * row_has_read) + row_has_write + row_has_read);
172 }
173
188 // Compute table_1 + gamma + table_2 * eta + table_3 * eta_2 + table_4 * eta_3
189 // table_1,2,3 correspond to the (maximum) three columns of the lookup table and table_4 is the unique identifier
190 // of the lookup table table_index
191 template <typename Accumulator, typename AllEntities, typename Parameters>
192 static Accumulator compute_table_term(const AllEntities& in, const Parameters& params)
193 {
194 using ParameterCoefficientAccumulator = typename Parameters::DataType::CoefficientAccumulator;
195 using CoefficientAccumulator = typename Accumulator::CoefficientAccumulator;
196
197 const auto gamma = ParameterCoefficientAccumulator(params.gamma);
198 const auto beta = ParameterCoefficientAccumulator(params.beta);
199 const auto beta_sqr = ParameterCoefficientAccumulator(params.beta_sqr);
200 const auto beta_cube = ParameterCoefficientAccumulator(params.beta_cube);
201
202 auto table_1 = CoefficientAccumulator(in.table_1);
203 auto table_2 = CoefficientAccumulator(in.table_2);
204 auto table_3 = CoefficientAccumulator(in.table_3);
205 auto table_4 = CoefficientAccumulator(in.table_4);
206
207 // degree 1 0 1 0 1 0 = 1
208 auto result = (table_2 * beta) + (table_3 * beta_sqr) + (table_4 * beta_cube);
209 result += table_1;
210 result += gamma;
211 return Accumulator(result);
212 }
213
214 template <typename Accumulator, typename AllEntities, typename Parameters>
215 static Accumulator compute_lookup_term(const AllEntities& in, const Parameters& params)
216 {
217 using ParameterCoefficientAccumulator = typename Parameters::DataType::CoefficientAccumulator;
218 using CoefficientAccumulator = typename Accumulator::CoefficientAccumulator;
219
220 const auto gamma = ParameterCoefficientAccumulator(params.gamma);
221 const auto beta = ParameterCoefficientAccumulator(params.beta);
222 const auto beta_sqr = ParameterCoefficientAccumulator(params.beta_sqr);
223 const auto beta_cube = ParameterCoefficientAccumulator(params.beta_cube);
224
225 auto w_1 = CoefficientAccumulator(in.w_l);
226 auto w_2 = CoefficientAccumulator(in.w_r);
227 auto w_3 = CoefficientAccumulator(in.w_o);
228
229 auto w_1_shift = CoefficientAccumulator(in.w_l_shift);
230 auto w_2_shift = CoefficientAccumulator(in.w_r_shift);
231 auto w_3_shift = CoefficientAccumulator(in.w_o_shift);
232
233 auto table_index = CoefficientAccumulator(in.q_o);
234 auto negative_column_1_step_size = CoefficientAccumulator(in.q_r);
235 auto negative_column_2_step_size = CoefficientAccumulator(in.q_m);
236 auto negative_column_3_step_size = CoefficientAccumulator(in.q_c);
237
238 // The wire values for lookup gates are accumulators structured in such a way that the differences w_i -
239 // step_size*w_i_shift result in values present in column i of a corresponding table. See the documentation in
240 // method bb::plookup::get_lookup_accumulators() in for a detailed explanation.
241 // degree 1 1 1 0 = 2
242 auto derived_table_entry_1 = (negative_column_1_step_size * w_1_shift) + (w_1 + gamma);
243 // degree 1 1 1 = 2
244 auto derived_table_entry_2 = (negative_column_2_step_size * w_2_shift) + w_2;
245 // degree 1 1 1 = 2
246 auto derived_table_entry_3 = (negative_column_3_step_size * w_3_shift) + w_3;
247 // 1 0 = 1
248 auto table_index_entry = table_index * beta_cube;
249
250 // (w_1 + γ + q_2*w_1_shift) + β(w_2 + q_m*w_2_shift) + β²(w_3 + q_c*w_3_shift) + β³*q_index.
251 // deg 2 or 3
252 // degree 2 0 2 0 = 2
253 auto result = Accumulator(derived_table_entry_2) * beta + Accumulator(derived_table_entry_3) * beta_sqr;
254 result += Accumulator(derived_table_entry_1 + table_index_entry);
255 return result;
256 }
257
269 template <typename Polynomials>
270 static void compute_logderivative_inverse(Polynomials& polynomials,
271 auto& relation_parameters,
272 const size_t circuit_size)
273 {
274 BB_BENCH_NAME("Lookup::compute_logderivative_inverse");
275 auto& inverse_polynomial = get_inverse_polynomial(polynomials);
276
277 size_t min_iterations_per_thread = 1 << 6; // min number of iterations for which we'll spin up a unique thread
278 size_t num_threads = bb::calculate_num_threads(circuit_size, min_iterations_per_thread);
279
280 parallel_for(num_threads, [&](ThreadChunk chunk) {
281 for (size_t i : chunk.range(circuit_size)) {
282 // We only compute the inverse if this row contains a lookup gate or data that has been looked up
283 if (polynomials.q_lookup.get(i) == 1 || polynomials.lookup_read_tags.get(i) == 1) {
284 // TODO(https://github.com/AztecProtocol/barretenberg/issues/940): avoid get_row if possible.
285 auto row = polynomials.get_row(i); // Note: this is a copy. use sparingly!
286 auto value = compute_lookup_term<FF>(row, relation_parameters) *
287 compute_table_term<FF>(row, relation_parameters);
288 inverse_polynomial.at(i) = value;
289 }
290 }
291 });
292
293 // Compute inverse polynomial I in place by inverting the product at each row
294 FF::batch_invert(inverse_polynomial.coeffs());
295 };
296
306 template <typename ContainerOverSubrelations, typename AllEntities, typename Parameters>
307 static void accumulate(ContainerOverSubrelations& accumulator,
308 const AllEntities& in,
309 const Parameters& params,
310 const FF& scaling_factor)
311 {
312 // declare the accumulator of the maximum length, in non-ZK Flavors, they are of the same length,
313 // whereas in ZK Flavors, the accumulator corresponding log derivative lookup argument sub-relation is the
314 // longest
315 using ShortAccumulator = typename std::tuple_element_t<0, ContainerOverSubrelations>;
316 using BooleanCheckerAccumulator = typename std::tuple_element_t<2, ContainerOverSubrelations>;
317 using ShortView = typename ShortAccumulator::View;
318
319 using Accumulator = typename std::tuple_element_t<1, ContainerOverSubrelations>;
320 using CoefficientAccumulator = typename Accumulator::CoefficientAccumulator;
321
322 // allows to re-use the values accumulated by the accumulator of the size smaller than
323 // the size of Accumulator declared above
324
325 const auto inverses_m = CoefficientAccumulator(in.lookup_inverses); // Degree 1
326 const Accumulator inverses(inverses_m);
327 const auto read_counts_m = CoefficientAccumulator(in.lookup_read_counts); // Degree 1
328 const auto read_selector_m = CoefficientAccumulator(in.q_lookup); // Degree 1
329
330 const auto inverse_exists = compute_inverse_exists<Accumulator>(in); // Degree 2
331 const auto lookup_term = compute_lookup_term<Accumulator>(in, params); // Degree 2
332 const auto table_term = compute_table_term<Accumulator>(in, params); // Degree 1
333
334 // Establish the correctness of the polynomial of inverses I. Note: inverses is computed so that the value is 0
335 // if !inverse_exists.
336 // Degrees: 5 2 1 1 0
337 const Accumulator logderiv_first_term = (lookup_term * table_term * inverses - inverse_exists) * scaling_factor;
338 std::get<0>(accumulator) += ShortView(logderiv_first_term); // Deg 5
339
340 // Establish validity of the read. Note: no scaling factor here since this constraint is 'linearly dependent,
341 // i.e. enforced across the entire trace, not on a per-row basis.
342 // Degrees: 1 2 = 3
343 Accumulator tmp = Accumulator(read_selector_m) * table_term;
344 tmp -= (Accumulator(read_counts_m) * lookup_term);
345 tmp *= inverses; // degree 4(5)
346 std::get<1>(accumulator) += tmp; // Deg 4 (5)
347
348 // We should make sure that the read_tag is a boolean value
349 const auto read_tag_m = CoefficientAccumulator(in.lookup_read_tags);
350 const auto read_tag = BooleanCheckerAccumulator(read_tag_m);
351 // degree 1 1 0(1) = 2
352 std::get<2>(accumulator) += (read_tag * read_tag - read_tag) * scaling_factor;
353 }
354};
355
357
358} // namespace bb
#define BB_BENCH_NAME(name)
Definition bb_bench.hpp:225
Log-derivative lookup argument relation for establishing lookup reads from tables with 3 or fewer col...
static constexpr std::array< size_t, 3 > SUBRELATION_PARTIAL_LENGTHS
static bool operation_exists_at_row(const AllValues &row)
Does the provided row contain data relevant to table lookups.
static void compute_logderivative_inverse(Polynomials &polynomials, auto &relation_parameters, const size_t circuit_size)
Construct the polynomial whose components are the inverse of the product of the read and write terms...
static constexpr size_t LOOKUP_SUBRELATION_LENGTH
static void accumulate(ContainerOverSubrelations &accumulator, const AllEntities &in, const Parameters &params, const FF &scaling_factor)
Accumulate the subrelation contributions for reads from a lookup table.
static Accumulator compute_inverse_exists(const AllEntities &in)
Compute the Accumulator whose values indicate whether the inverse is computed or not.
static constexpr size_t INVERSE_SUBRELATION_LENGTH
static Accumulator compute_table_term(const AllEntities &in, const Parameters &params)
Compute the table term.
static constexpr std::array< bool, 3 > SUBRELATION_LINEARLY_INDEPENDENT
static bool skip(const AllEntities &in)
static Accumulator compute_lookup_term(const AllEntities &in, const Parameters &params)
static auto & get_inverse_polynomial(AllEntities &in)
static constexpr size_t BOOLEAN_CHECK_SUBRELATION_LENGTH
A wrapper for Relations to expose methods used by the Sumcheck prover or verifier to add the contribu...
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
size_t calculate_num_threads(size_t num_iterations, size_t min_iterations_per_thread)
calculates number of threads to create based on minimum iterations per thread
Definition thread.cpp:233
void parallel_for(size_t num_iterations, const std::function< void(size_t)> &func)
Definition thread.cpp:111
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
auto range(size_t size, size_t offset=0) const
Definition thread.hpp:152
static void batch_invert(C &coeffs) noexcept
Batch invert a collection of field elements using Montgomery's trick.