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
65template <typename FF_> class LogDerivLookupRelationImpl {
66 public:
67 using FF = FF_;
68 static constexpr size_t WRITE_TERMS = 1; // the number of write terms in the lookup relation
69 // 1 + polynomial degree of this relation
70 static constexpr size_t INVERSE_SUBRELATION_LENGTH = 5; // both subrelations are degree 4
71 static constexpr size_t LOOKUP_SUBRELATION_LENGTH = 5; // both subrelations are degree 4
72 static constexpr size_t BOOLEAN_CHECK_SUBRELATION_LENGTH =
73 3; // deg + 1 of the relation checking that read_tag_m is a boolean value
74
75 static constexpr std::array<size_t, 3> SUBRELATION_PARTIAL_LENGTHS{
76 INVERSE_SUBRELATION_LENGTH, // inverse construction sub-relation
77 LOOKUP_SUBRELATION_LENGTH, // log derivative lookup argument sub-relation
78 BOOLEAN_CHECK_SUBRELATION_LENGTH // boolean check sub-relation
79 };
80
81 static constexpr std::array<bool, 3>
82 SUBRELATION_LINEARLY_INDEPENDENT = { true /*Inverse subrelation*/,
83 false /*Lookup subrelation*/,
84 true /*read_tag boolean check subrelation*/ };
85
86 template <typename AllEntities> inline static bool skip(const AllEntities& in)
87 {
88 // Ensure the input does not contain a lookup gate or data that is being read
89 return in.q_lookup.is_zero() && in.lookup_read_counts.is_zero();
90 }
91
102 template <typename AllValues> static bool operation_exists_at_row(const AllValues& row)
103 {
104 // is the row a lookup gate or does it contain table data that has been read at some point in this circuit
105 return (row.q_lookup == 1) || (row.lookup_read_tags == 1);
106 }
107
108 // Get the inverse polynomial for this relation
109 template <typename AllEntities> static auto& get_inverse_polynomial(AllEntities& in) { return in.lookup_inverses; }
110
120 template <typename Accumulator, typename AllEntities>
121 static Accumulator compute_inverse_exists(const AllEntities& in)
122 {
123 using CoefficientAccumulator = typename Accumulator::CoefficientAccumulator;
124
125 const auto row_has_write = CoefficientAccumulator(in.lookup_read_tags);
126 const auto row_has_read = CoefficientAccumulator(in.q_lookup);
127 // Relation checking: is_read_gate == 1 || read_tag == 1
128 // Important note: the relation written below assumes that is_read_gate and read_tag are boolean values, which
129 // is guaranteed by the boolean_check subrelation. If not, fixing one of the two, the return value is a linear
130 // function in the other variable and can be set to an arbitrary value independent of the fixed value. See the
131 // boolean_check subrelation for more explanation.
132 // 1 - (1 - row_has_write) * (1- row_has_read)
133 // degree 1 1 1 1 = 2
134 return Accumulator(-(row_has_write * row_has_read) + row_has_write + row_has_read);
135 }
136
137 // Compute table_1 + gamma + table_2 * eta + table_3 * eta_2 + table_4 * eta_3
138 // table_1,2,3 correspond to the (maximum) three columns of the lookup table and table_4 is the unique identifier
139 // of the lookup table table_index
140 template <typename Accumulator, typename AllEntities, typename Parameters>
141 static Accumulator compute_write_term(const AllEntities& in, const Parameters& params)
142 {
143 using ParameterCoefficientAccumulator = typename Parameters::DataType::CoefficientAccumulator;
144 using CoefficientAccumulator = typename Accumulator::CoefficientAccumulator;
145
146 const auto gamma = ParameterCoefficientAccumulator(params.gamma);
147 const auto eta = ParameterCoefficientAccumulator(params.eta);
148 const auto eta_two = ParameterCoefficientAccumulator(params.eta_two);
149 const auto eta_three = ParameterCoefficientAccumulator(params.eta_three);
150
151 auto table_1 = CoefficientAccumulator(in.table_1);
152 auto table_2 = CoefficientAccumulator(in.table_2);
153 auto table_3 = CoefficientAccumulator(in.table_3);
154 auto table_4 = CoefficientAccumulator(in.table_4);
155
156 // degree 1 0 1 0 1 0 = 1
157 auto result = (table_2 * eta) + (table_3 * eta_two) + (table_4 * eta_three);
158 result += table_1;
159 result += gamma;
160 return Accumulator(result);
161 }
162
163 template <typename Accumulator, typename AllEntities, typename Parameters>
164 static Accumulator compute_read_term(const AllEntities& in, const Parameters& params)
165 {
166 using ParameterCoefficientAccumulator = typename Parameters::DataType::CoefficientAccumulator;
167 using CoefficientAccumulator = typename Accumulator::CoefficientAccumulator;
168
169 const auto gamma = ParameterCoefficientAccumulator(params.gamma);
170 const auto eta = ParameterCoefficientAccumulator(params.eta);
171 const auto eta_two = ParameterCoefficientAccumulator(params.eta_two);
172 const auto eta_three = ParameterCoefficientAccumulator(params.eta_three);
173
174 auto w_1 = CoefficientAccumulator(in.w_l);
175 auto w_2 = CoefficientAccumulator(in.w_r);
176 auto w_3 = CoefficientAccumulator(in.w_o);
177
178 auto w_1_shift = CoefficientAccumulator(in.w_l_shift);
179 auto w_2_shift = CoefficientAccumulator(in.w_r_shift);
180 auto w_3_shift = CoefficientAccumulator(in.w_o_shift);
181
182 auto table_index = CoefficientAccumulator(in.q_o);
183 auto negative_column_1_step_size = CoefficientAccumulator(in.q_r);
184 auto negative_column_2_step_size = CoefficientAccumulator(in.q_m);
185 auto negative_column_3_step_size = CoefficientAccumulator(in.q_c);
186
187 // The wire values for lookup gates are accumulators structured in such a way that the differences w_i -
188 // step_size*w_i_shift result in values present in column i of a corresponding table. See the documentation in
189 // method bb::plookup::get_lookup_accumulators() in for a detailed explanation.
190 // degree 1 1 1 0 = 2
191 auto derived_table_entry_1 = (negative_column_1_step_size * w_1_shift) + (w_1 + gamma);
192 // degree 1 1 1 = 2
193 auto derived_table_entry_2 = (negative_column_2_step_size * w_2_shift) + w_2;
194 // degree 1 1 1 = 2
195 auto derived_table_entry_3 = (negative_column_3_step_size * w_3_shift) + w_3;
196 // 1 0 = 1
197 auto table_index_entry = table_index * eta_three;
198
199 // (w_1 + \gamma q_2*w_1_shift) + η(w_2 + q_m*w_2_shift) + η₂(w_3 + q_c*w_3_shift) + η₃q_index.
200 // deg 2 or 3
201 // degree 2 0 2 0 = 2
202 auto result = Accumulator(derived_table_entry_2) * eta + Accumulator(derived_table_entry_3) * eta_two;
203 result += Accumulator(derived_table_entry_1 + table_index_entry);
204 return result;
205 }
206
215 template <typename Polynomials>
216 static void compute_logderivative_inverse(Polynomials& polynomials,
217 auto& relation_parameters,
218 const size_t circuit_size)
219 {
220 BB_BENCH_NAME("Lookup::compute_logderivative_inverse");
221 auto& inverse_polynomial = get_inverse_polynomial(polynomials);
222
223 size_t min_iterations_per_thread = 1 << 6; // min number of iterations for which we'll spin up a unique thread
224 size_t num_threads = bb::calculate_num_threads_pow2(circuit_size, min_iterations_per_thread);
225 size_t iterations_per_thread = circuit_size / num_threads; // actual iterations per thread
226
227 parallel_for(num_threads, [&](size_t thread_idx) {
228 size_t start = thread_idx * iterations_per_thread;
229 size_t end = (thread_idx + 1) * iterations_per_thread;
230 for (size_t i = start; i < end; ++i) {
231 // We only compute the inverse if this row contains a lookup gate or data that has been looked up
232 if (polynomials.q_lookup.get(i) == 1 || polynomials.lookup_read_tags.get(i) == 1) {
233 // TODO(https://github.com/AztecProtocol/barretenberg/issues/940): avoid get_row if possible.
234 auto row = polynomials.get_row(i); // Note: this is a copy. use sparingly!
235 auto value = compute_read_term<FF>(row, relation_parameters) *
236 compute_write_term<FF>(row, relation_parameters);
237 inverse_polynomial.at(i) = value;
238 }
239 }
240 });
241
242 // Compute inverse polynomial I in place by inverting the product at each row
243 FF::batch_invert(inverse_polynomial.coeffs());
244 };
245
255 template <typename ContainerOverSubrelations, typename AllEntities, typename Parameters>
256 static void accumulate(ContainerOverSubrelations& accumulator,
257 const AllEntities& in,
258 const Parameters& params,
259 const FF& scaling_factor)
260 {
261 // declare the accumulator of the maximum length, in non-ZK Flavors, they are of the same length,
262 // whereas in ZK Flavors, the accumulator corresponding log derivative lookup argument sub-relation is the
263 // longest
264 using ShortAccumulator = typename std::tuple_element_t<0, ContainerOverSubrelations>;
265 using BooleanCheckerAccumulator = typename std::tuple_element_t<2, ContainerOverSubrelations>;
266 using ShortView = typename ShortAccumulator::View;
267
268 using Accumulator = typename std::tuple_element_t<1, ContainerOverSubrelations>;
269 using CoefficientAccumulator = typename Accumulator::CoefficientAccumulator;
270
271 // allows to re-use the values accumulated by the accumulator of the size smaller than
272 // the size of Accumulator declared above
273
274 const auto inverses_m = CoefficientAccumulator(in.lookup_inverses); // Degree 1
275 const Accumulator inverses(inverses_m);
276 const auto read_counts_m = CoefficientAccumulator(in.lookup_read_counts); // Degree 1
277 const auto read_selector_m = CoefficientAccumulator(in.q_lookup); // Degree 1
278
279 const auto inverse_exists = compute_inverse_exists<Accumulator>(in); // Degree 2
280 const auto read_term = compute_read_term<Accumulator>(in, params); // Degree 2
281 const auto write_term = compute_write_term<Accumulator>(in, params); // Degree 1
282
283 // Establish the correctness of the polynomial of inverses I. Note: inverses is computed so that the value is 0
284 // if !inverse_exists.
285 // Degrees: 5 2 1 1 0
286 const Accumulator logderiv_first_term = (read_term * write_term * inverses - inverse_exists) * scaling_factor;
287 std::get<0>(accumulator) += ShortView(logderiv_first_term); // Deg 5
288
289 // Establish validity of the read. Note: no scaling factor here since this constraint is 'linearly dependent,
290 // i.e. enforced across the entire trace, not on a per-row basis.
291 // Degrees: 1 2 = 3
292 Accumulator tmp = Accumulator(read_selector_m) * write_term;
293 tmp -= (Accumulator(read_counts_m) * read_term);
294 tmp *= inverses; // degree 4(5)
295 std::get<1>(accumulator) += tmp; // Deg 4 (5)
296
297 // We should make sure that the read_tag is a boolean value
298 const auto read_tag_m = CoefficientAccumulator(in.lookup_read_tags);
299 const auto read_tag = BooleanCheckerAccumulator(read_tag_m);
300 // degree 1 1 0(1) = 2
301 std::get<2>(accumulator) += (read_tag * read_tag - read_tag) * scaling_factor;
302 }
303};
304
306
307} // namespace bb
#define BB_BENCH_NAME(name)
Definition bb_bench.hpp:219
Log-derivative lookup argument relation for establishing lookup reads from tables with 3 or fewer col...
static Accumulator compute_write_term(const AllEntities &in, const Parameters &params)
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; 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)
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_read_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.
Definition api.hpp:5
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:254
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
static void batch_invert(C &coeffs) noexcept