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: not started, auditors: [], date: YYYY-MM-DD }
3// external_1: { status: not started, auditors: [], date: YYYY-MM-DD }
4// external_2: { status: not started, auditors: [], date: YYYY-MM-DD }
5// =====================
6
7#pragma once
8#include <array>
9#include <tuple>
10
16
17namespace bb {
18
19template <typename FF_> class LogDerivLookupRelationImpl {
20 public:
21 using FF = FF_;
22 static constexpr size_t WRITE_TERMS = 1; // the number of write terms in the lookup relation
23 // 1 + polynomial degree of this relation
24 static constexpr size_t INVERSE_SUBRELATION_LENGTH = 5; // both subrelations are degree 4
25 static constexpr size_t LOOKUP_SUBRELATION_LENGTH = 5; // both subrelations are degree 4
26 static constexpr size_t BOOLEAN_CHECK_SUBRELATION_LENGTH =
27 3; // deg + 1 of the relation checking that read_tag_m is a boolean value
28
29 static constexpr std::array<size_t, 3> SUBRELATION_PARTIAL_LENGTHS{
30 INVERSE_SUBRELATION_LENGTH, // inverse construction sub-relation
31 LOOKUP_SUBRELATION_LENGTH, // log derivative lookup argument sub-relation
32 BOOLEAN_CHECK_SUBRELATION_LENGTH // boolean check sub-relation
33 };
34
35 // Note: the required correction for the second sub-relation is technically +1 but the two corrections must agree
36 // due to the way the relation algebra is written so both are set to +2.
37 static constexpr std::array<size_t, 3> TOTAL_LENGTH_ADJUSTMENTS{
38 2, // inverse construction sub-relation
39 2, // log derivative lookup argument sub-relation
40 2, // read_tag boolean sub-relation check
41 };
42
43 static constexpr std::array<bool, 3> SUBRELATION_LINEARLY_INDEPENDENT = { true, false, true };
44
45 template <typename AllEntities> inline static bool skip(const AllEntities& in)
46 {
47 // Ensure the input does not contain a lookup gate or data that is being read
48 return in.q_lookup.is_zero() && in.lookup_read_counts.is_zero();
49 }
50
61 template <typename AllValues> static bool operation_exists_at_row(const AllValues& row)
62 {
63 // is the row a lookup gate or does it contain table data that has been read at some point in this circuit
64 return (row.q_lookup == 1) || (row.lookup_read_tags == 1);
65 }
66
67 // Get the inverse polynomial for this relation
68 template <typename AllEntities> static auto& get_inverse_polynomial(AllEntities& in) { return in.lookup_inverses; }
69
70 // Used in the inverse correctness subrelation; facilitates only computing inverses where necessary
71 template <typename Accumulator, typename AllEntities>
72 static Accumulator compute_inverse_exists(const AllEntities& in)
73 {
74 using CoefficientAccumulator = typename Accumulator::CoefficientAccumulator;
75
76 const auto row_has_write = CoefficientAccumulator(in.lookup_read_tags);
77 const auto row_has_read = CoefficientAccumulator(in.q_lookup);
78 // degree 1(1) 1(1) 1 1 = 2(2)
79 return Accumulator(-(row_has_write * row_has_read) + row_has_write + row_has_read);
80 }
81
82 template <typename Accumulator, size_t index, typename AllEntities>
83 static Accumulator lookup_read_counts(const AllEntities& in)
84 {
85 using CoefficientAccumulator = typename Accumulator::CoefficientAccumulator;
86 return Accumulator(CoefficientAccumulator(in.lookup_read_counts));
87 }
88
89 // Compute table_1 + gamma + table_2 * eta + table_3 * eta_2 + table_4 * eta_3
90 template <typename Accumulator, size_t write_index, typename AllEntities, typename Parameters>
91 static Accumulator compute_write_term(const AllEntities& in, const Parameters& params)
92 {
93 using View = typename Accumulator::View;
94 using ParameterView = GetParameterView<Parameters, View>;
95 using ParameterCoefficientAccumulator = typename ParameterView::CoefficientAccumulator;
96 using CoefficientAccumulator = typename Accumulator::CoefficientAccumulator;
97
98 static_assert(write_index < WRITE_TERMS);
99
100 const auto gamma = ParameterCoefficientAccumulator(params.gamma);
101 const auto eta = ParameterCoefficientAccumulator(params.eta);
102 const auto eta_two = ParameterCoefficientAccumulator(params.eta_two);
103 const auto eta_three = ParameterCoefficientAccumulator(params.eta_three);
104
105 auto table_1 = CoefficientAccumulator(in.table_1);
106 auto table_2 = CoefficientAccumulator(in.table_2);
107 auto table_3 = CoefficientAccumulator(in.table_3);
108 auto table_4 = CoefficientAccumulator(in.table_4);
109
110 // degree 1 0(1) 1 0(1) 1 0(1) = 1(2)
111 auto result = (table_2 * eta) + (table_3 * eta_two) + (table_4 * eta_three);
112 result += table_1;
113 result += gamma;
114 return Accumulator(result);
115 }
116
117 template <typename Accumulator, size_t read_index, typename AllEntities, typename Parameters>
118 static Accumulator compute_read_term(const AllEntities& in, const Parameters& params)
119 {
120 using View = typename Accumulator::View;
121 using ParameterView = GetParameterView<Parameters, View>;
122 using ParameterCoefficientAccumulator = typename ParameterView::CoefficientAccumulator;
123 using CoefficientAccumulator = typename Accumulator::CoefficientAccumulator;
124
125 const auto gamma = ParameterCoefficientAccumulator(params.gamma);
126 const auto eta = ParameterCoefficientAccumulator(params.eta);
127 const auto eta_two = ParameterCoefficientAccumulator(params.eta_two);
128 const auto eta_three = ParameterCoefficientAccumulator(params.eta_three);
129
130 auto w_1 = CoefficientAccumulator(in.w_l);
131 auto w_2 = CoefficientAccumulator(in.w_r);
132 auto w_3 = CoefficientAccumulator(in.w_o);
133
134 auto w_1_shift = CoefficientAccumulator(in.w_l_shift);
135 auto w_2_shift = CoefficientAccumulator(in.w_r_shift);
136 auto w_3_shift = CoefficientAccumulator(in.w_o_shift);
137
138 auto table_index = CoefficientAccumulator(in.q_o);
139 auto negative_column_1_step_size = CoefficientAccumulator(in.q_r);
140 auto negative_column_2_step_size = CoefficientAccumulator(in.q_m);
141 auto negative_column_3_step_size = CoefficientAccumulator(in.q_c);
142
143 // The wire values for lookup gates are accumulators structured in such a way that the differences w_i -
144 // step_size*w_i_shift result in values present in column i of a corresponding table. See the documentation in
145 // method get_lookup_accumulators() in for a detailed explanation.
146 // degree 1 1 1 0(1) = 2
147 auto derived_table_entry_1 = (negative_column_1_step_size * w_1_shift) + (w_1 + gamma);
148 // degree 1 1 1 = 2
149 auto derived_table_entry_2 = (negative_column_2_step_size * w_2_shift) + w_2;
150 // degree 1 1 1 = 2
151 auto derived_table_entry_3 = (negative_column_3_step_size * w_3_shift) + w_3;
152 // 1 0 (1) = 1 (2)
153 auto table_index_entry = table_index * eta_three;
154
155 // (w_1 + \gamma q_2*w_1_shift) + η(w_2 + q_m*w_2_shift) + η₂(w_3 + q_c*w_3_shift) + η₃q_index.
156 // deg 2 or 3
157 // degree 2 0(1) 2 0(1) = 2 (3)
158 auto result = Accumulator(derived_table_entry_2) * eta + Accumulator(derived_table_entry_3) * eta_two;
159 result += Accumulator(derived_table_entry_1 + table_index_entry);
160 return result;
161 }
162
171 template <typename Polynomials>
172 static void compute_logderivative_inverse(Polynomials& polynomials,
173 auto& relation_parameters,
174 const size_t circuit_size)
175 {
176 PROFILE_THIS_NAME("Lookup::compute_logderivative_inverse");
177 auto& inverse_polynomial = get_inverse_polynomial(polynomials);
178
179 size_t min_iterations_per_thread = 1 << 6; // min number of iterations for which we'll spin up a unique thread
180 size_t num_threads = bb::calculate_num_threads_pow2(circuit_size, min_iterations_per_thread);
181 size_t iterations_per_thread = circuit_size / num_threads; // actual iterations per thread
182
183 parallel_for(num_threads, [&](size_t thread_idx) {
184 size_t start = thread_idx * iterations_per_thread;
185 size_t end = (thread_idx + 1) * iterations_per_thread;
186 for (size_t i = start; i < end; ++i) {
187 // We only compute the inverse if this row contains a lookup gate or data that has been looked up
188 if (polynomials.q_lookup.get(i) == 1 || polynomials.lookup_read_tags.get(i) == 1) {
189 // TODO(https://github.com/AztecProtocol/barretenberg/issues/940): avoid get_row if possible.
190 auto row = polynomials.get_row(i); // Note: this is a copy. use sparingly!
191 auto value = compute_read_term<FF, 0>(row, relation_parameters) *
192 compute_write_term<FF, 0>(row, relation_parameters);
193 inverse_polynomial.at(i) = value;
194 }
195 }
196 });
197
198 // Compute inverse polynomial I in place by inverting the product at each row
199 FF::batch_invert(inverse_polynomial.coeffs());
200 };
201
250 template <typename ContainerOverSubrelations, typename AllEntities, typename Parameters>
251 static void accumulate(ContainerOverSubrelations& accumulator,
252 const AllEntities& in,
253 const Parameters& params,
254 const FF& scaling_factor)
255 {
256 // declare the accumulator of the maximum length, in non-ZK Flavors, they are of the same length,
257 // whereas in ZK Flavors, the accumulator corresponding log derivative lookup argument sub-relation is the
258 // longest
259 using ShortAccumulator = typename std::tuple_element_t<0, ContainerOverSubrelations>;
260 using BooleanCheckerAccumulator = typename std::tuple_element_t<2, ContainerOverSubrelations>;
261 using ShortView = typename ShortAccumulator::View;
262
263 using Accumulator = typename std::tuple_element_t<1, ContainerOverSubrelations>;
264 using CoefficientAccumulator = typename Accumulator::CoefficientAccumulator;
265
266 // allows to re-use the values accumulated by the accumulator of the size smaller than
267 // the size of Accumulator declared above
268
269 const auto inverses_m = CoefficientAccumulator(in.lookup_inverses); // Degree 1
270 const Accumulator inverses(inverses_m);
271 const auto read_counts_m = CoefficientAccumulator(in.lookup_read_counts); // Degree 1
272 const auto read_selector_m = CoefficientAccumulator(in.q_lookup); // Degree 1
273
274 const auto inverse_exists = compute_inverse_exists<Accumulator>(in); // Degree 2 (2)
275 const auto read_term = compute_read_term<Accumulator, 0>(in, params); // Degree 2 (3)
276 const auto write_term = compute_write_term<Accumulator, 0>(in, params); // Degree 1 (2)
277
278 // Establish the correctness of the polynomial of inverses I. Note: inverses is computed so that the value is 0
279 // if !inverse_exists.
280 // Degrees: 5(7) 2 (3) 1(2) 1 0(1)
281 const Accumulator logderiv_first_term = (read_term * write_term * inverses - inverse_exists) * scaling_factor;
282 std::get<0>(accumulator) += ShortView(logderiv_first_term); // Deg 5(7)
283
284 // Establish validity of the read. Note: no scaling factor here since this constraint is 'linearly dependent,
285 // i.e. enforced across the entire trace, not on a per-row basis.
286 // Degrees: 1 2 (3) = 3 (4)
287 Accumulator tmp = Accumulator(read_selector_m) * write_term;
288 tmp -= (Accumulator(read_counts_m) * read_term);
289 tmp *= inverses; // degree 4(5)
290 std::get<1>(accumulator) += tmp; // Deg 4 (5)
291
292 // we should make sure that the read_tag is a boolean value
293 const auto read_tag_m = CoefficientAccumulator(in.lookup_read_tags);
294 const auto read_tag = BooleanCheckerAccumulator(read_tag_m);
295 // degree 1 1 0(1) = 2(3)
296 std::get<2>(accumulator) += (read_tag * read_tag - read_tag) * scaling_factor;
297 }
298};
299
301
302} // namespace bb
static constexpr std::array< size_t, 3 > SUBRELATION_PARTIAL_LENGTHS
static Accumulator lookup_read_counts(const AllEntities &in)
static constexpr std::array< size_t, 3 > TOTAL_LENGTH_ADJUSTMENTS
static bool operation_exists_at_row(const AllValues &row)
Does the provided row contain data relevant to table lookups; Used to determine whether the polynomia...
static void compute_logderivative_inverse(Polynomials &polynomials, auto &relation_parameters, const size_t circuit_size)
Construct the polynomial I whose components are the inverse of the product of the read and write term...
static constexpr size_t LOOKUP_SUBRELATION_LENGTH
static void accumulate(ContainerOverSubrelations &accumulator, const AllEntities &in, const Parameters &params, const FF &scaling_factor)
Log-derivative style lookup argument for conventional lookups form tables with 3 or fewer columns.
static Accumulator compute_inverse_exists(const AllEntities &in)
static constexpr size_t INVERSE_SUBRELATION_LENGTH
static Accumulator compute_read_term(const AllEntities &in, const Parameters &params)
static Accumulator compute_write_term(const AllEntities &in, const Parameters &params)
static constexpr std::array< bool, 3 > SUBRELATION_LINEARLY_INDEPENDENT
static bool skip(const AllEntities &in)
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.
std::conditional_t< IsField< typename Params::DataType >, typename Params::DataType, View > GetParameterView
A type to optionally extract a view of a relation parameter in a relation.
size_t calculate_num_threads_pow2(size_t num_iterations, size_t min_iterations_per_thread)
calculates number of threads to create based on minimum iterations per thread, guaranteed power of 2
Definition thread.cpp:215
void parallel_for(size_t num_iterations, const std::function< void(size_t)> &func)
Definition thread.cpp:72
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
#define PROFILE_THIS_NAME(name)
Definition op_count.hpp:16
static void batch_invert(std::span< field > coeffs) noexcept