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
100template <typename FF_> class LogDerivLookupRelationImpl {
101 public:
102 using FF = FF_;
103 static constexpr bool HAS_LOGDERIVATIVE_INVERSE_COMPUTATION = true;
104 static constexpr size_t TABLE_TERMS = 1; // the number of table terms in the lookup relation
105 // 1 + polynomial degree of this relation
106 static constexpr size_t INVERSE_SUBRELATION_LENGTH = 5; // both subrelations are degree 4
107 static constexpr size_t LOOKUP_SUBRELATION_LENGTH = 5; // both subrelations are degree 4
108 static constexpr size_t BOOLEAN_CHECK_SUBRELATION_LENGTH =
109 3; // deg + 1 of the relation checking that read_tag_m is a boolean value
110
111 static constexpr std::array<size_t, 3> SUBRELATION_PARTIAL_LENGTHS{
112 INVERSE_SUBRELATION_LENGTH, // inverse construction sub-relation
113 LOOKUP_SUBRELATION_LENGTH, // log derivative lookup argument sub-relation
114 BOOLEAN_CHECK_SUBRELATION_LENGTH // boolean check sub-relation
115 };
116
117 static constexpr std::array<bool, 3>
118 SUBRELATION_LINEARLY_INDEPENDENT = { true /*Inverse subrelation*/,
119 false /*Lookup subrelation*/,
120 true /*read_tag boolean check subrelation*/ };
121
122 template <typename AllEntities> inline static bool skip(const AllEntities& in)
123 {
124 // Ensure the input does not contain a lookup gate or data that is being read
126 }
127
139 template <typename AllValues> static bool operation_exists_at_row(const AllValues& row)
140 {
141 // is the row a lookup gate or does it contain table data that has been read at some point in this circuit
142 return (row.q_lookup == 1) || (row.lookup_read_tags == 1);
143 }
144
145 // Get the inverse polynomial for this relation
146 template <typename AllEntities> static auto& get_inverse_polynomial(AllEntities& in)
147 {
149 }
150
166 template <typename Accumulator, typename AllEntities>
168 {
169 using CoefficientAccumulator = typename Accumulator::CoefficientAccumulator;
170
171 const auto row_has_write = CoefficientAccumulator(in[AllEntities::EntityId::lookup_read_tags]);
172 const auto row_has_read = CoefficientAccumulator(in[AllEntities::EntityId::q_lookup]);
173 // Relation checking: is_read_gate == 1 || read_tag == 1
174 // Important note: the relation written below assumes that is_read_gate and read_tag are boolean values, which
175 // is guaranteed by the boolean_check subrelation. If not, fixing one of the two, the return value is a linear
176 // function in the other variable and can be set to an arbitrary value independent of the fixed value. See the
177 // boolean_check subrelation for more explanation.
178 // 1 - (1 - row_has_write) * (1- row_has_read)
179 // degree 1 1 1 1 = 2
180 return Accumulator(-(row_has_write * row_has_read) + row_has_write + row_has_read);
181 }
182
197 // Compute table_1 + gamma + table_2 * eta + table_3 * eta_2 + table_4 * eta_3
198 // table_1,2,3 correspond to the (maximum) three columns of the lookup table and table_4 is the unique identifier
199 // of the lookup table table_index
200 template <typename Accumulator, typename AllEntities, typename Parameters>
201 static Accumulator compute_table_term(const AllEntities& in, const Parameters& params)
202 {
203 using ParameterCoefficientAccumulator = typename Parameters::DataType::CoefficientAccumulator;
204 using CoefficientAccumulator = typename Accumulator::CoefficientAccumulator;
205
206 const auto gamma = ParameterCoefficientAccumulator(params.gamma);
207 const auto beta = ParameterCoefficientAccumulator(params.beta);
208 const auto beta_sqr = ParameterCoefficientAccumulator(params.beta_sqr);
209 const auto beta_cube = ParameterCoefficientAccumulator(params.beta_cube);
210
211 auto table_1 = CoefficientAccumulator(in[AllEntities::EntityId::table_1]);
212 auto table_2 = CoefficientAccumulator(in[AllEntities::EntityId::table_2]);
213 auto table_3 = CoefficientAccumulator(in[AllEntities::EntityId::table_3]);
214 auto table_4 = CoefficientAccumulator(in[AllEntities::EntityId::table_4]);
215
216 // degree 1 0 1 0 1 0 = 1
217 auto result = (table_2 * beta) + (table_3 * beta_sqr) + (table_4 * beta_cube);
218 result += table_1;
219 result += gamma;
220 return Accumulator(result);
221 }
222
223 template <typename Accumulator, typename AllEntities, typename Parameters>
224 static Accumulator compute_lookup_term(const AllEntities& in, const Parameters& params)
225 {
226 using ParameterCoefficientAccumulator = typename Parameters::DataType::CoefficientAccumulator;
227 using CoefficientAccumulator = typename Accumulator::CoefficientAccumulator;
228
229 const auto gamma = ParameterCoefficientAccumulator(params.gamma);
230 const auto beta = ParameterCoefficientAccumulator(params.beta);
231 const auto beta_sqr = ParameterCoefficientAccumulator(params.beta_sqr);
232 const auto beta_cube = ParameterCoefficientAccumulator(params.beta_cube);
233
234 auto w_1 = CoefficientAccumulator(in[AllEntities::EntityId::w_l]);
235 auto w_2 = CoefficientAccumulator(in[AllEntities::EntityId::w_r]);
236 auto w_3 = CoefficientAccumulator(in[AllEntities::EntityId::w_o]);
237
238 auto w_1_shift = CoefficientAccumulator(in[AllEntities::EntityId::w_l_shift]);
239 auto w_2_shift = CoefficientAccumulator(in[AllEntities::EntityId::w_r_shift]);
240 auto w_3_shift = CoefficientAccumulator(in[AllEntities::EntityId::w_o_shift]);
241
242 auto table_index = CoefficientAccumulator(in[AllEntities::EntityId::q_o]);
243 auto negative_column_1_step_size = CoefficientAccumulator(in[AllEntities::EntityId::q_r]);
244 auto negative_column_2_step_size = CoefficientAccumulator(in[AllEntities::EntityId::q_m]);
245 auto negative_column_3_step_size = CoefficientAccumulator(in[AllEntities::EntityId::q_c]);
246
247 // The wire values for lookup gates are accumulators structured in such a way that the differences w_i -
248 // step_size*w_i_shift result in values present in column i of a corresponding table. See the documentation in
249 // method bb::plookup::get_lookup_accumulators() in for a detailed explanation.
250 // degree 1 1 1 0 = 2
251 auto derived_table_entry_1 = (negative_column_1_step_size * w_1_shift) + (w_1 + gamma);
252 // degree 1 1 1 = 2
253 auto derived_table_entry_2 = (negative_column_2_step_size * w_2_shift) + w_2;
254 // degree 1 1 1 = 2
255 auto derived_table_entry_3 = (negative_column_3_step_size * w_3_shift) + w_3;
256 // 1 0 = 1
257 auto table_index_entry = table_index * beta_cube;
258
259 // (w_1 + γ + q_2*w_1_shift) + β(w_2 + q_m*w_2_shift) + β²(w_3 + q_c*w_3_shift) + β³*q_index.
260 // deg 2 or 3
261 // degree 2 0 2 0 = 2
262 auto result = Accumulator(derived_table_entry_2) * beta + Accumulator(derived_table_entry_3) * beta_sqr;
263 result += Accumulator(derived_table_entry_1 + table_index_entry);
264 return result;
265 }
266
278 template <typename Polynomials>
279 static void compute_logderivative_inverse(Polynomials& polynomials,
280 auto& relation_parameters,
281 const size_t circuit_size,
282 const size_t start_index = 0)
283 {
284 BB_BENCH_NAME("Lookup::compute_logderivative_inverse");
285 auto& inverse_polynomial = get_inverse_polynomial(polynomials);
286
287 const size_t num_rows = circuit_size - start_index;
288 size_t min_iterations_per_thread = 1 << 6; // min number of iterations for which we'll spin up a unique thread
289 size_t num_threads = bb::calculate_num_threads(num_rows, min_iterations_per_thread);
290
291 parallel_for(num_threads, [&](ThreadChunk chunk) {
292 BB_BENCH_TRACY_NAME("Lookup::compute_inverses/chunk");
293 for (size_t j : chunk.range(num_rows)) {
294 size_t i = j + start_index;
295 // We only compute the inverse if this row contains a lookup gate or data that has been looked up
296 if (polynomials.q_lookup().get(i) == 1 || polynomials.lookup_read_tags().get(i) == 1) {
297 // TODO(https://github.com/AztecProtocol/barretenberg/issues/940): avoid get_row if possible.
298 auto row = polynomials.get_row(i); // Note: this is a copy. use sparingly!
299 auto value = compute_lookup_term<FF>(row, relation_parameters) *
300 compute_table_term<FF>(row, relation_parameters);
301 inverse_polynomial.at(i) = value;
302 }
303 }
304 });
305
306 // Compute inverse polynomial I in place by inverting the product at each row
307 FF::batch_invert(inverse_polynomial.coeffs());
308 };
309
319 template <typename ContainerOverSubrelations, typename AllEntities, typename Parameters>
320 static void accumulate(ContainerOverSubrelations& accumulator,
321 const AllEntities& in,
322 const Parameters& params,
323 const FF& scaling_factor)
324 {
325 // declare the accumulator of the maximum length, in non-ZK Flavors, they are of the same length,
326 // whereas in ZK Flavors, the accumulator corresponding log derivative lookup argument sub-relation is the
327 // longest
328 using ShortAccumulator = typename std::tuple_element_t<0, ContainerOverSubrelations>;
329 using BooleanCheckerAccumulator = typename std::tuple_element_t<2, ContainerOverSubrelations>;
330 using ShortView = typename ShortAccumulator::View;
331
333 using CoefficientAccumulator = typename Accumulator::CoefficientAccumulator;
334
335 // allows to re-use the values accumulated by the accumulator of the size smaller than
336 // the size of Accumulator declared above
337
338 const auto inverses_m = CoefficientAccumulator(in[AllEntities::EntityId::lookup_inverses]); // Degree 1
339 const Accumulator inverses(inverses_m);
340 const auto read_counts_m = CoefficientAccumulator(in[AllEntities::EntityId::lookup_read_counts]); // Degree 1
341 const auto read_selector_m = CoefficientAccumulator(in[AllEntities::EntityId::q_lookup]); // Degree 1
342
343 const auto inverse_exists = compute_inverse_exists<Accumulator>(in); // Degree 2
344 const auto lookup_term = compute_lookup_term<Accumulator>(in, params); // Degree 2
345 const auto table_term = compute_table_term<Accumulator>(in, params); // Degree 1
346
347 // Establish the correctness of the polynomial of inverses I. Note: inverses is computed so that the value is 0
348 // if !inverse_exists.
349 // Degrees: 5 2 1 1 0
350 const Accumulator logderiv_first_term = (lookup_term * table_term * inverses - inverse_exists) * scaling_factor;
351 std::get<0>(accumulator) += ShortView(logderiv_first_term); // Deg 5
352
353 // Establish validity of the read. Note: no scaling factor here since this constraint is 'linearly dependent,
354 // i.e. enforced across the entire trace, not on a per-row basis.
355 // Degrees: 1 2 = 3
356 Accumulator tmp = Accumulator(read_selector_m) * table_term;
357 tmp -= (Accumulator(read_counts_m) * lookup_term);
358 tmp *= inverses; // degree 4(5)
359 std::get<1>(accumulator) += tmp; // Deg 4 (5)
360
361 // We should make sure that the read_tag is a boolean value
362 const auto read_tag_m = CoefficientAccumulator(in[AllEntities::EntityId::lookup_read_tags]);
363 const auto read_tag = BooleanCheckerAccumulator(read_tag_m);
364 // degree 1 1 0(1) = 2
365 std::get<2>(accumulator) += (read_tag * read_tag - read_tag) * scaling_factor;
366 }
367};
368
370
371} // namespace bb
#define BB_BENCH_NAME(name)
Definition bb_bench.hpp:264
#define BB_BENCH_TRACY_NAME(name)
Definition bb_bench.hpp:256
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 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 void compute_logderivative_inverse(Polynomials &polynomials, auto &relation_parameters, const size_t circuit_size, const size_t start_index=0)
Construct the polynomial whose components are the inverse of the product of the read and write terms...
static constexpr bool HAS_LOGDERIVATIVE_INVERSE_COMPUTATION
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:112
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.
VectorField result