Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
databus_lookup_relation.hpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: Complete, auditors: [Sergei], 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
61template <typename FF_> class DatabusLookupRelationImpl {
62 public:
63 using FF = FF_;
64
65 // Note: All three subrelations use length 6 to make efficient use of shared computation. Shortening (1b)/(2) to
66 // length 5 forces the shared factors (lookup_term, table_term, read_selector, inverses, `I*L*T - 1`) to be
67 // recomputed and is a net loss in performance.
68 static constexpr size_t INVERSE_READ_SUBREL_LENGTH = 6; // deg 5: (I*L*T - 1) * is_read
69 static constexpr size_t INVERSE_WRITE_SUBREL_LENGTH = 6; // deg 4: (I*L*T - 1) * count
70 static constexpr size_t LOOKUP_SUBREL_LENGTH = 6; // deg 4: (is_read*T - count*L) * I
71 static constexpr size_t NUM_SUB_RELATION_PER_IDX = 3; // the number of subrelations per bus column
72
73 // Per-bus subrelation layout: (1a) inverse-on-read, (1b) inverse-on-write, (2) lookup identity.
74 // The whole-relation arrays below repeat this layout once per bus column.
75 static constexpr std::array<size_t, NUM_SUB_RELATION_PER_IDX> PER_BUS_SUBREL_LENGTHS{
79 };
80 // (1a) and (1b) are per-row identities; (2) is a sum across the trace.
81 static constexpr std::array<bool, NUM_SUB_RELATION_PER_IDX> PER_BUS_LIN_INDEPENDENT{ true, true, false };
82
83 template <typename T, size_t N>
85 {
87 for (size_t bus = 0; bus < NUM_BUS_COLUMNS; ++bus) {
88 for (size_t i = 0; i < N; ++i) {
89 out[(bus * N) + i] = pattern[i];
90 }
91 }
92 return out;
93 }
94
95 static constexpr std::array<size_t, NUM_SUB_RELATION_PER_IDX * NUM_BUS_COLUMNS> SUBRELATION_PARTIAL_LENGTHS =
97 static constexpr std::array<bool, NUM_SUB_RELATION_PER_IDX * NUM_BUS_COLUMNS> SUBRELATION_LINEARLY_INDEPENDENT =
99
100 template <typename AllEntities> inline static bool skip([[maybe_unused]] const AllEntities& in)
101 {
102 // Ensure the input does not contain a read gate or data that is being read
103 if (!in.q_busread.is_zero()) {
104 return false;
105 }
106 bool all_counts_zero = true;
107 bb::constexpr_for<0, NUM_BUS_COLUMNS, 1>(
108 [&]<size_t bus_idx>() { all_counts_zero &= BusData<bus_idx, AllEntities>::read_counts(in).is_zero(); });
109 return all_counts_zero;
110 }
111
112 // Interface for easy access of databus components by column (bus_idx)
113 template <size_t bus_idx, typename AllEntities> struct BusData;
114
115 // Specialization for kernel_calldata (bus_idx = 0)
116 template <typename AllEntities> struct BusData</*bus_idx=*/0, AllEntities> {
117 static auto& values(const AllEntities& in) { return in.kernel_calldata; }
118 static auto& selector(const AllEntities& in) { return in.q_l; }
119 static auto& inverses(AllEntities& in) { return in.kernel_calldata_inverses; }
120 static auto& inverses(const AllEntities& in) { return in.kernel_calldata_inverses; } // const version
121 static auto& read_counts(const AllEntities& in) { return in.kernel_calldata_read_counts; }
122 };
123
124 // Specialization for first_app_calldata (bus_idx = 1)
125 template <typename AllEntities> struct BusData</*bus_idx=*/1, AllEntities> {
126 static auto& values(const AllEntities& in) { return in.first_app_calldata; }
127 static auto& selector(const AllEntities& in) { return in.q_r; }
128 static auto& inverses(AllEntities& in) { return in.first_app_calldata_inverses; }
129 static auto& inverses(const AllEntities& in) { return in.first_app_calldata_inverses; } // const version
130 static auto& read_counts(const AllEntities& in) { return in.first_app_calldata_read_counts; }
131 };
132
133 // Specialization for second_app_calldata (bus_idx = 2)
134 template <typename AllEntities> struct BusData</*bus_idx=*/2, AllEntities> {
135 static auto& values(const AllEntities& in) { return in.second_app_calldata; }
136 static auto& selector(const AllEntities& in) { return in.q_o; }
137 static auto& inverses(AllEntities& in) { return in.second_app_calldata_inverses; }
138 static auto& inverses(const AllEntities& in) { return in.second_app_calldata_inverses; } // const version
139 static auto& read_counts(const AllEntities& in) { return in.second_app_calldata_read_counts; }
140 };
141
142 // Specialization for third_app_calldata (bus_idx = 3)
143 template <typename AllEntities> struct BusData</*bus_idx=*/3, AllEntities> {
144 static auto& values(const AllEntities& in) { return in.third_app_calldata; }
145 static auto& selector(const AllEntities& in) { return in.q_4; }
146 static auto& inverses(AllEntities& in) { return in.third_app_calldata_inverses; }
147 static auto& inverses(const AllEntities& in) { return in.third_app_calldata_inverses; } // const version
148 static auto& read_counts(const AllEntities& in) { return in.third_app_calldata_read_counts; }
149 };
150
151 // Specialization for return data (bus_idx = 4)
152 template <typename AllEntities> struct BusData</*bus_idx=*/4, AllEntities> {
153 static auto& values(const AllEntities& in) { return in.return_data; }
154 static auto& selector(const AllEntities& in) { return in.q_m; }
155 static auto& inverses(AllEntities& in) { return in.return_data_inverses; }
156 static auto& inverses(const AllEntities& in) { return in.return_data_inverses; } // const version
157 static auto& read_counts(const AllEntities& in) { return in.return_data_read_counts; }
158 };
159
167 template <typename Accumulator, size_t bus_idx, typename AllEntities>
168 static Accumulator get_read_selector(const AllEntities& in)
169 {
170 using CoefficientAccumulator = typename Accumulator::CoefficientAccumulator;
171
172 auto q_busread = CoefficientAccumulator(in.q_busread);
173 auto column_selector = CoefficientAccumulator(BusData<bus_idx, AllEntities>::selector(in));
174
175 // degree 1 1 2 (2)
176 return Accumulator(q_busread * column_selector);
177 }
178
183 template <typename Accumulator, size_t bus_idx, typename AllEntities, typename Parameters>
184 static Accumulator compute_table_term(const AllEntities& in, const Parameters& params)
185 {
186 using CoefficientAccumulator = typename Accumulator::CoefficientAccumulator;
187 using ParameterCoefficientAccumulator = typename Parameters::DataType::CoefficientAccumulator;
188
189 const auto& id = CoefficientAccumulator(in.databus_id);
190 const auto& value = CoefficientAccumulator(BusData<bus_idx, AllEntities>::values(in));
191 const auto& gamma = ParameterCoefficientAccumulator(params.gamma);
192 const auto& beta = ParameterCoefficientAccumulator(params.beta);
193
194 // Construct value_i + idx_i*\beta + \gamma
195 // degrees 1(0) 0(1) 1(1) 0(1)
196 return Accumulator(id * beta + value + gamma); // degree 1 (1)
197 }
198
204 template <typename Accumulator, typename AllEntities, typename Parameters>
205 static Accumulator compute_lookup_term(const AllEntities& in, const Parameters& params)
206 {
207 using CoefficientAccumulator = typename Accumulator::CoefficientAccumulator;
208 using ParameterCoefficientAccumulator = typename Parameters::DataType::CoefficientAccumulator;
209
210 // Bus value stored in w_1, index into bus column stored in w_2
211 const auto& w_1 = CoefficientAccumulator(in.w_l);
212 const auto& w_2 = CoefficientAccumulator(in.w_r);
213 const auto& gamma = ParameterCoefficientAccumulator(params.gamma);
214 const auto& beta = ParameterCoefficientAccumulator(params.beta);
215
216 // Construct value + index*\beta + \gamma
217 return Accumulator((w_2 * beta) + w_1 + gamma); // degree 1 (2)
218 }
219
231 template <size_t bus_idx, typename Polynomials>
232 static void compute_logderivative_inverse(Polynomials& polynomials,
233 auto& relation_parameters,
234 const size_t circuit_size,
235 const size_t start_index = 0)
236 {
237 BB_BENCH_NAME("Databus::compute_logderivative_inverse");
238 auto& inverse_polynomial = BusData<bus_idx, Polynomials>::inverses(polynomials);
239 const auto& column_selector = BusData<bus_idx, Polynomials>::selector(polynomials);
240 const auto& read_counts = BusData<bus_idx, Polynomials>::read_counts(polynomials);
241
242 const size_t num_rows = circuit_size - start_index;
243 size_t min_iterations_per_thread = 1 << 6; // min number of iterations for which we'll spin up a unique thread
244 size_t num_threads = bb::calculate_num_threads(num_rows, min_iterations_per_thread);
245
246 parallel_for(num_threads, [&](ThreadChunk chunk) {
247 BB_BENCH_TRACY_NAME("Databus::compute_inverses/chunk");
248 for (size_t j : chunk.range(num_rows)) {
249 size_t i = j + start_index;
250 // Determine if the present row contains a databus operation
251 const bool is_read = polynomials.q_busread[i] == 1 && column_selector[i] == 1;
252 const bool nonzero_read_count = read_counts[i] > 0;
253 // We only compute the inverse if this row contains a read gate or data that has been read
254 if (is_read || nonzero_read_count) {
255 // TODO(https://github.com/AztecProtocol/barretenberg/issues/940): avoid get_row if possible.
256 auto row = polynomials.get_row(i); // Note: this is a copy. use sparingly!
257 auto value = compute_lookup_term<FF>(row, relation_parameters) *
258 compute_table_term<FF, bus_idx>(row, relation_parameters);
259 inverse_polynomial.at(i) = value;
260 }
261 }
262 });
263
264 // Compute inverse polynomial I in place by inverting the product at each row
265 // Note: zeroes are ignored as they are not used anyway
266 FF::batch_invert(inverse_polynomial.coeffs());
267 };
268
276 template <typename FF,
277 size_t bus_idx,
278 typename ContainerOverSubrelations,
279 typename AllEntities,
280 typename Parameters>
281 static void accumulate_subrelation_contributions(ContainerOverSubrelations& accumulator,
282 const AllEntities& in,
283 const Parameters& params,
284 const FF& scaling_factor)
285 {
286 // Subrelation indices for this bus column
287 constexpr size_t subrel_idx_inv_read = NUM_SUB_RELATION_PER_IDX * bus_idx; // (1a)
288 constexpr size_t subrel_idx_inv_write = NUM_SUB_RELATION_PER_IDX * bus_idx + 1; // (1b)
289 constexpr size_t subrel_idx_lookup = NUM_SUB_RELATION_PER_IDX * bus_idx + 2; // (2)
290
292 using CoefficientAccumulator = typename Accumulator::CoefficientAccumulator;
293
294 const auto inverses_m = CoefficientAccumulator(BusData<bus_idx, AllEntities>::inverses(in));
295 const auto read_counts_m = CoefficientAccumulator(BusData<bus_idx, AllEntities>::read_counts(in));
296
297 const Accumulator inverses(inverses_m);
298 const Accumulator read_counts(read_counts_m);
299 const auto lookup_term = compute_lookup_term<Accumulator>(in, params);
300 const auto table_term = compute_table_term<Accumulator, bus_idx>(in, params);
301 const auto read_selector = get_read_selector<Accumulator, bus_idx>(in);
302
303 // Shared factor in (1a) and (1b): I*L*T - 1
304 const auto common = lookup_term * table_term * inverses - FF(1);
305
306 // (1a) Inverse correctness on read rows: (I*L*T - 1) * is_read = 0
307 std::get<subrel_idx_inv_read>(accumulator) += (common * read_selector) * scaling_factor;
308
309 // (1b) Inverse correctness on write rows: (I*L*T - 1) * count = 0
310 std::get<subrel_idx_inv_write>(accumulator) += (common * read_counts) * scaling_factor;
311
312 // (2) Lookup identity: (is_read*T - count*L) * I = 0.
313 // No scaling factor here since this constraint is enforced across the entire trace, not per-row.
314 Accumulator tmp = read_selector * table_term;
315 tmp -= read_counts * lookup_term;
316 tmp *= inverses;
317 std::get<subrel_idx_lookup>(accumulator) += tmp;
318 }
319
327 template <typename ContainerOverSubrelations, typename AllEntities, typename Parameters>
328 static void accumulate(ContainerOverSubrelations& accumulator,
329 const AllEntities& in,
330 const Parameters& params,
331 const FF& scaling_factor)
332 {
333 // Accumulate the subrelation contributions for each column of the databus
334 bb::constexpr_for<0, NUM_BUS_COLUMNS, 1>([&]<size_t bus_idx>() {
335 accumulate_subrelation_contributions<FF, bus_idx>(accumulator, in, params, scaling_factor);
336 });
337 }
338};
339
341
342} // 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 DataBus reads.
static constexpr size_t INVERSE_WRITE_SUBREL_LENGTH
static constexpr std::array< T, N *NUM_BUS_COLUMNS > repeat_per_bus(const std::array< T, N > &pattern)
static constexpr size_t NUM_SUB_RELATION_PER_IDX
static bool skip(const AllEntities &in)
static void accumulate_subrelation_contributions(ContainerOverSubrelations &accumulator, const AllEntities &in, const Parameters &params, const FF &scaling_factor)
Accumulate the subrelation contributions for reads from a single databus column.
static constexpr std::array< size_t, NUM_SUB_RELATION_PER_IDX *NUM_BUS_COLUMNS > SUBRELATION_PARTIAL_LENGTHS
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 size_t INVERSE_READ_SUBREL_LENGTH
static constexpr size_t LOOKUP_SUBREL_LENGTH
static constexpr std::array< bool, NUM_SUB_RELATION_PER_IDX *NUM_BUS_COLUMNS > SUBRELATION_LINEARLY_INDEPENDENT
static constexpr std::array< bool, NUM_SUB_RELATION_PER_IDX > PER_BUS_LIN_INDEPENDENT
static Accumulator compute_lookup_term(const AllEntities &in, const Parameters &params)
Compute read term denominator in log derivative lookup argument.
static Accumulator get_read_selector(const AllEntities &in)
Compute scalar for read term in log derivative lookup argument.
static Accumulator compute_table_term(const AllEntities &in, const Parameters &params)
Compute write term denominator in log derivative lookup argument.
static constexpr std::array< size_t, NUM_SUB_RELATION_PER_IDX > PER_BUS_SUBREL_LENGTHS
static void accumulate(ContainerOverSubrelations &accumulator, const AllEntities &in, const Parameters &params, const FF &scaling_factor)
Accumulate the log derivative databus lookup argument subrelation contributions for each databus colu...
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
constexpr size_t NUM_BUS_COLUMNS
The DataBus; facilitates storage of public circuit input/output.
Definition databus.hpp:72
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:232
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.