Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
sumcheck_round.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
16#include "zk_sumcheck_data.hpp"
17
18namespace bb {
19
20// To know if a flavor is AVM, without including the flavor.
21template <typename Flavor>
22concept isAvmFlavor = std::convertible_to<decltype(Flavor::IS_AVM), bool>;
23
44template <typename Flavor> class SumcheckProverRound {
45
47 using Relations = typename Flavor::Relations;
48 using SumcheckTupleOfTuplesOfUnivariates = decltype(create_sumcheck_tuple_of_tuples_of_univariates<Relations>());
50
51 public:
52 using FF = typename Flavor::FF;
54 typename Flavor::template ProverUnivariates<2>,
55 typename Flavor::ExtendedEdges>;
60 size_t round_size;
65 static constexpr size_t NUM_RELATIONS = Flavor::NUM_RELATIONS;
78 // Note: since this is not initialized with {}, the univariates contain garbage.
80
81 // The length of the polynomials used to mask the Sumcheck Round Univariates.
82 static constexpr size_t LIBRA_UNIVARIATES_LENGTH = Flavor::Curve::LIBRA_UNIVARIATES_LENGTH;
83
84 // Prover constructor
85 SumcheckProverRound(size_t initial_round_size)
86 : round_size(initial_round_size)
87 {
88 BB_BENCH_NAME("SumcheckProverRound constructor");
89
90 // Initialize univariate accumulators to 0
92 }
93
122 template <typename ProverPolynomialsOrPartiallyEvaluatedMultivariates>
123 void extend_edges(ExtendedEdges& extended_edges,
124 const ProverPolynomialsOrPartiallyEvaluatedMultivariates& multivariates,
125 const size_t edge_idx)
126 {
127 for (auto [extended_edge, multivariate] : zip_view(extended_edges.get_all(), multivariates.get_all())) {
128 if constexpr (Flavor::USE_SHORT_MONOMIALS) {
129 extended_edge = bb::Univariate<FF, 2>({ multivariate[edge_idx], multivariate[edge_idx + 1] });
130 } else {
131 if (multivariate.end_index() < edge_idx) {
132 static const auto zero_univariate = bb::Univariate<FF, MAX_PARTIAL_RELATION_LENGTH>::zero();
133 extended_edge = zero_univariate;
134 } else {
135 extended_edge = bb::Univariate<FF, 2>({ multivariate[edge_idx], multivariate[edge_idx + 1] })
136 .template extend_to<MAX_PARTIAL_RELATION_LENGTH>();
137 }
138 }
139 }
140 }
141
146 template <typename ProverPolynomialsOrPartiallyEvaluatedMultivariates>
147 SumcheckRoundUnivariate compute_univariate(ProverPolynomialsOrPartiallyEvaluatedMultivariates& polynomials,
148 const bb::RelationParameters<FF>& relation_parameters,
149 const bb::GateSeparatorPolynomial<FF>& gate_separators,
150 const SubrelationSeparators& alphas)
151 {
152 if constexpr (isAvmFlavor<Flavor>) {
153 return compute_univariate_avm(polynomials, relation_parameters, gate_separators, alphas);
154 } else {
155 return compute_univariate_with_row_skipping(polynomials, relation_parameters, gate_separators, alphas);
156 }
157 }
158
159 // TODO(https://github.com/AztecProtocol/barretenberg/issues/1484): should we more intelligently incorporate the two
160 // `compute_univariate` types of functions?
167 template <typename ProverPolynomialsOrPartiallyEvaluatedMultivariates>
168 SumcheckRoundUnivariate compute_univariate_avm(ProverPolynomialsOrPartiallyEvaluatedMultivariates& polynomials,
169 const bb::RelationParameters<FF>& relation_parameters,
170 const bb::GateSeparatorPolynomial<FF>& gate_separators,
171 const SubrelationSeparators& alphas)
172 {
173 BB_BENCH_NAME("compute_univariate_avm");
174
175 // Determine number of threads for multithreading.
176 // Note: Multithreading is "on" for every round but we reduce the number of threads from the max available based
177 // on a specified minimum number of iterations per thread. This eventually leads to the use of a single thread.
178 // For now we use a power of 2 number of threads simply to ensure the round size is evenly divided.
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(round_size, min_iterations_per_thread);
181
182 // In the AVM, the trace is more dense at the top and therefore it is worth to split the work per thread
183 // in a more distributed way over the edges. To achieve this, we split the trace into chunks and each chunk is
184 // evenly divided among the threads. Below we name a portion in the chunk being processed by any given thread
185 // a "chunk thread portion".
186 // We have: round_size = num_of_chunks * chunk_size and chunk_size = num_threads * chunk_thread_portion_size
187 // Important invariant: round_size = num_of_chunks * num_threads * chunk_thread_portion_size
188 // All the involved values are power of 2. We also require chunk_thread_portion_size >= 2
189 // because a "work unit" cannot be smaller than 2 as extended_edges() process 2 edges at a time.
190 //
191 // Example: round_size = 4096, num_threads = 16, chunk_thread_portion_size = 8
192 // - chunk_size = 16 * 8 = 128
193 // - num_of_chunks = 4096/128 = 32
194 //
195 // For each chunk with index chunk_idx, the thread with index thread_idx will process the edges
196 // in range starting at index: chunk_idx * chunk_size + thread_idx * chunk_thread_portion_size
197 // up to index (not included): chunk_idx * chunk_size + (thread_idx + 1) * chunk_thread_portion_size
198 //
199 // Pattern over edges is now:
200 //
201 // chunk_0 | chunk_1 | chunk_2 ....
202 // thread_0 | thread_1 ... | thread_0 | thread_1 ... | thread_0 | thread_1 ...
203 //
204 // Any thread now processes edges which are distributed at different locations in the trace contrary
205 // to the "standard" method where thread_0 processes all the low indices and the last thread processes
206 // all the high indices.
207 //
208 // MAX_CHUNK_THREAD_PORTION_SIZE is defined in the flavor.
209 // The MAX_CHUNK_THREAD_PORTION_SIZE defines the maximum value for chunk_thread_portion_size. Whenever the
210 // round_size is large enough, we set chunk_thread_portion_size = MAX_CHUNK_THREAD_PORTION_SIZE. When it is not
211 // possible we use a smaller value but must be at least 2 as mentioned above. If chunk_thread_portion_size is
212 // not at least 2, we fallback to using a single chunk. Note that chunk_size and num_of_chunks are not constant
213 // but are derived by round_size, num_threads and the chunk_thread_portion_size which needs to satisfy: 1) 2 <=
214 // chunk_thread_portion_size <= MAX_CHUNK_THREAD_PORTION_SIZE 2) chunk_thread_portion_size * num_threads <=
215 // round_size For the non-AVM flavors, we use a single chunk.
216
217 // Non AVM flavors
218 size_t num_of_chunks = 1;
219 size_t chunk_thread_portion_size = round_size / num_threads;
220
221 // This constant is assumed to be a power of 2 greater or equal to 2.
222 static_assert(Flavor::MAX_CHUNK_THREAD_PORTION_SIZE >= 2);
223 static_assert((Flavor::MAX_CHUNK_THREAD_PORTION_SIZE & (Flavor::MAX_CHUNK_THREAD_PORTION_SIZE - 1)) == 0);
224
225 // When the number of edges is so small that the chunk portion size per thread is lower than 2,
226 // we fall back to a single chunk, i.e., we keep the "non-AVM" values.
227 if (round_size / num_threads >= 2) {
228 chunk_thread_portion_size = std::min(round_size / num_threads, Flavor::MAX_CHUNK_THREAD_PORTION_SIZE);
229 num_of_chunks = round_size / (chunk_thread_portion_size * num_threads);
230 // We show that chunk_thread_portion_size satisfies 1) and 2) defined above.
231 // From "std::min()": chunk_thread_portion_size <= round_size/num_threads implying 2)
232 // From static_assert above, and "if condition", we know that both values in "std::min()"
233 // are >= 2 and therefore: chunk_thread_portion_size >= 2
234 // Finally, "std::min()" guarantees that: chunk_thread_portion_size <= MAX_CHUNK_THREAD_PORTION_SIZE
235 // which completes 1).
236 }
237
238 size_t chunk_size = round_size / num_of_chunks;
239 // Construct univariate accumulator containers; one per thread
240 // Note: std::vector will trigger {}-initialization of the contents. Therefore no need to zero the univariates.
241 std::vector<SumcheckTupleOfTuplesOfUnivariates> thread_univariate_accumulators(num_threads);
242
243 // Accumulate the contribution from each sub-relation accross each edge of the hyper-cube
244 parallel_for(num_threads, [&](size_t thread_idx) {
245 // Construct extended univariates containers; one per thread
246 ExtendedEdges lazy_extended_edges(polynomials);
247
248 for (size_t chunk_idx = 0; chunk_idx < num_of_chunks; chunk_idx++) {
249 size_t start = (chunk_idx * chunk_size) + (thread_idx * chunk_thread_portion_size);
250 size_t end = (chunk_idx * chunk_size) + ((thread_idx + 1) * chunk_thread_portion_size);
251 for (size_t edge_idx = start; edge_idx < end; edge_idx += 2) {
252 lazy_extended_edges.set_current_edge(edge_idx);
253 // Compute the \f$ \ell \f$-th edge's univariate contribution,
254 // scale it by the corresponding \f$ pow_{\beta} \f$ contribution and add it to the accumulators for
255 // \f$ \tilde{S}^i(X_i) \f$. If \f$ \ell \f$'s binary representation is given by \f$
256 // (\ell_{i+1},\ldots, \ell_{d-1})\f$, the \f$ pow_{\beta}\f$-contribution is
257 // \f$\beta_{i+1}^{\ell_{i+1}} \cdot \ldots \cdot \beta_{d-1}^{\ell_{d-1}}\f$.
258 accumulate_relation_univariates(thread_univariate_accumulators[thread_idx],
259 lazy_extended_edges,
260 relation_parameters,
261 gate_separators[(edge_idx >> 1) * gate_separators.periodicity]);
262 }
263 }
264 });
265
266 // Accumulate the per-thread univariate accumulators into a single set of accumulators
267 for (auto& accumulators : thread_univariate_accumulators) {
269 }
270
271 // Batch the univariate contributions from each sub-relation to obtain the round univariate
272 return batch_over_relations<SumcheckRoundUnivariate>(univariate_accumulators, alphas, gate_separators);
273 }
274
280 size_t size;
281 };
282
287 struct RowIterator {
291 RowIterator(const std::vector<BlockOfContiguousRows>& _blocks, size_t starting_index = 0)
292 : blocks(&_blocks)
293 {
294 size_t count = 0;
295 for (size_t i = 0; i < blocks->size(); ++i) {
296 const BlockOfContiguousRows block = blocks->at(i);
297 if (count + (block.size / 2) > starting_index) {
299 current_block_count = (starting_index - count) * 2;
300 break;
301 }
302 count += (block.size / 2);
303 }
304 }
305
307 {
309 size_t edge = block.starting_edge_idx + current_block_count;
310 if (current_block_count + 2 >= block.size) {
313 } else {
315 }
316 return edge;
317 }
318 };
319
333 template <typename ProverPolynomialsOrPartiallyEvaluatedMultivariates>
335 ProverPolynomialsOrPartiallyEvaluatedMultivariates& polynomials)
336 {
337 const size_t min_iterations_per_thread = 1 << 10; // min number of iterations for which we'll spin up a unique
338 const size_t num_threads = bb::calculate_num_threads_pow2(round_size, min_iterations_per_thread);
339 const size_t iterations_per_thread = round_size / num_threads; // actual iterations per thread
340
342 constexpr bool can_skip_rows = (isRowSkippable<Flavor, decltype(polynomials), size_t>);
343
344 if constexpr (can_skip_rows) {
345 std::vector<std::vector<BlockOfContiguousRows>> all_thread_blocks(num_threads);
346 parallel_for(num_threads, [&](size_t thread_idx) {
347 size_t current_block_size = 0;
348 size_t start = thread_idx * iterations_per_thread;
349 size_t end = (thread_idx + 1) * iterations_per_thread;
351 for (size_t edge_idx = start; edge_idx < end; edge_idx += 2) {
352 if (!Flavor::skip_entire_row(polynomials, edge_idx)) {
353 current_block_size += 2;
354 } else {
355 if (current_block_size > 0) {
356 thread_blocks.push_back(BlockOfContiguousRows{
357 .starting_edge_idx = edge_idx - current_block_size, .size = current_block_size });
358 current_block_size = 0;
359 }
360 }
361 }
362 if (current_block_size > 0) {
363 thread_blocks.push_back(BlockOfContiguousRows{ .starting_edge_idx = end - current_block_size,
364 .size = current_block_size });
365 }
366 all_thread_blocks[thread_idx] = thread_blocks;
367 });
368
369 for (const auto& thread_blocks : all_thread_blocks) {
370 for (const auto block : thread_blocks) {
371 result.push_back(block);
372 }
373 }
374 } else {
375 result.push_back(BlockOfContiguousRows{ .starting_edge_idx = 0, .size = round_size });
376 }
377 return result;
378 }
379
401 template <typename ProverPolynomialsOrPartiallyEvaluatedMultivariates>
403 ProverPolynomialsOrPartiallyEvaluatedMultivariates& polynomials,
404 const bb::RelationParameters<FF>& relation_parameters,
405 const bb::GateSeparatorPolynomial<FF>& gate_separators,
406 const SubrelationSeparators alphas)
407 {
408 BB_BENCH_NAME("compute_univariate_with_row_skipping");
409
411 // Compute how many nonzero rows we have
412 size_t num_valid_rows = 0;
413 for (const BlockOfContiguousRows block : round_manifest) {
414 num_valid_rows += block.size;
415 }
416 size_t num_valid_iterations = num_valid_rows / 2;
417
418 // Determine number of threads for multithreading.
419 // Note: Multithreading is "on" for every round but we reduce the number of threads from the max available based
420 // on a specified minimum number of iterations per thread. This eventually leads to the use of a single thread.
421 // For now we use a power of 2 number of threads simply to ensure the round size is evenly divided.
422 size_t min_iterations_per_thread = 1 << 6; // min number of iterations for which we'll spin up a unique thread
423 size_t num_threads = bb::calculate_num_threads(num_valid_iterations, min_iterations_per_thread);
424 size_t iterations_per_thread = num_valid_iterations / num_threads; // actual iterations per thread
425 size_t iterations_for_last_thread = num_valid_iterations - (iterations_per_thread * (num_threads - 1));
426 // Construct univariate accumulator containers; one per thread
427 // Note: std::vector will trigger {}-initialization of the contents. Therefore no need to zero the univariates.
428 std::vector<SumcheckTupleOfTuplesOfUnivariates> thread_univariate_accumulators(num_threads);
429
430 parallel_for(num_threads, [&](size_t thread_idx) {
431 const size_t start = thread_idx * iterations_per_thread;
432 const size_t end = (thread_idx == num_threads - 1) ? start + iterations_for_last_thread
433 : (thread_idx + 1) * iterations_per_thread;
434
435 RowIterator edge_iterator(round_manifest, start);
436 // Construct extended univariates containers; one per thread
437 ExtendedEdges extended_edges;
438 for (size_t i = start; i < end; ++i) {
439 size_t edge_idx = edge_iterator.get_next_edge();
440 extend_edges(extended_edges, polynomials, edge_idx);
441 // Compute the \f$ \ell \f$-th edge's univariate contribution,
442 // scale it by the corresponding \f$ pow_{\beta} \f$ contribution and add it to the accumulators for \f$
443 // \tilde{S}^i(X_i) \f$. If \f$ \ell \f$'s binary representation is given by \f$ (\ell_{i+1},\ldots,
444 // \ell_{d-1})\f$, the \f$ pow_{\beta}\f$-contribution is \f$\beta_{i+1}^{\ell_{i+1}} \cdot \ldots \cdot
445 // \beta_{d-1}^{\ell_{d-1}}\f$.
446 accumulate_relation_univariates(thread_univariate_accumulators[thread_idx],
447 extended_edges,
448 relation_parameters,
449 gate_separators[(edge_idx >> 1) * gate_separators.periodicity]);
450 }
451 });
452
453 // Accumulate the per-thread univariate accumulators into a single set of accumulators
454 for (auto& accumulators : thread_univariate_accumulators) {
456 }
457 // Batch the univariate contributions from each sub-relation to obtain the round univariate
458 // these are unmasked; we will mask in sumcheck.
459 const auto round_univariate =
460 batch_over_relations<SumcheckRoundUnivariate>(univariate_accumulators, alphas, gate_separators);
461 // define eval at 0 from target sum/or previous round univariate
462
463 return round_univariate;
464 };
465 template <typename ProverPolynomialsOrPartiallyEvaluatedMultivariates>
467 const size_t round_idx,
468 const ProverPolynomialsOrPartiallyEvaluatedMultivariates& polynomials,
469 const bb::RelationParameters<FF>& relation_parameters,
470 const bb::GateSeparatorPolynomial<FF>& gate_separators,
471 const SubrelationSeparators& alpha,
472 const ZKData& zk_sumcheck_data,
473 const RowDisablingPolynomial<FF> row_disabling_polynomial)
474 requires Flavor::HasZK
475 {
476 auto hiding_univariate = compute_libra_univariate(zk_sumcheck_data, round_idx);
477 if constexpr (UseRowDisablingPolynomial<Flavor>) {
478 hiding_univariate -= compute_disabled_contribution(
479 polynomials, relation_parameters, gate_separators, alpha, round_idx, row_disabling_polynomial);
480 }
481 return hiding_univariate;
482 }
483
490 template <typename ProverPolynomialsOrPartiallyEvaluatedMultivariates>
491 SumcheckRoundUnivariate compute_disabled_contribution(
492 ProverPolynomialsOrPartiallyEvaluatedMultivariates& polynomials,
493 const bb::RelationParameters<FF>& relation_parameters,
494 const bb::GateSeparatorPolynomial<FF>& gate_separators,
495 const SubrelationSeparators& alphas,
496 const size_t round_idx,
497 const RowDisablingPolynomial<FF> row_disabling_polynomial)
499 {
500 // Note: {} is required to initialize the tuple contents. Otherwise the univariates contain garbage.
501 SumcheckTupleOfTuplesOfUnivariates univariate_accumulator{};
502 ExtendedEdges extended_edges;
504
505 // In Round 0, we have to compute the contribution from 2 edges: (1, 1,..., 1) and (0, 1, ..., 1) (as points on
506 // (d-1) - dimensional Boolean hypercube).
507 size_t start_edge_idx = (round_idx == 0) ? round_size - 4 : round_size - 2;
508
509 for (size_t edge_idx = start_edge_idx; edge_idx < round_size; edge_idx += 2) {
510 extend_edges(extended_edges, polynomials, edge_idx);
511 accumulate_relation_univariates(univariate_accumulator,
512 extended_edges,
513 relation_parameters,
514 gate_separators[(edge_idx >> 1) * gate_separators.periodicity]);
515 }
516 result = batch_over_relations<SumcheckRoundUnivariate>(univariate_accumulator, alphas, gate_separators);
517 bb::Univariate<FF, 2> row_disabling_factor =
518 bb::Univariate<FF, 2>({ row_disabling_polynomial.eval_at_0, row_disabling_polynomial.eval_at_1 });
519 SumcheckRoundUnivariate row_disabling_factor_extended =
520 row_disabling_factor.template extend_to<SumcheckRoundUnivariate::LENGTH>();
521 result *= row_disabling_factor_extended;
522
523 return result;
524 }
525
526 template <typename ProverPolynomialsOrPartiallyEvaluatedMultivariates>
527 SumcheckRoundUnivariate compute_virtual_contribution(
528 ProverPolynomialsOrPartiallyEvaluatedMultivariates& polynomials,
529 const bb::RelationParameters<FF>& relation_parameters,
530 const GateSeparatorPolynomial<FF>& gate_separator,
531 const SubrelationSeparators& alphas)
532 {
533 // Note: {} is required to initialize the tuple contents. Otherwise the univariates contain garbage.
534 SumcheckTupleOfTuplesOfUnivariates univariate_accumulator{};
535
536 // For a given prover polynomial P_i(X_0, ..., X_{d-1}) extended by zero, i.e. multiplied by
537 // \tau(X_d, ..., X_{virtual_log_n - 1}) = \prod (1 - X_k)
538 // for k = d, ..., virtual_log_n - 1, the computation of the virtual sumcheck round univariate reduces to the
539 // edge (0, ...,0).
540 const size_t virtual_contribution_edge_idx = 0;
541
542 // Perform the usual sumcheck accumulation, but for a single edge.
543 // Note: we use a combination of `auto`, constexpr and a lambda to construct different types.
544 auto extended_edges = [&]() {
545 if constexpr (isAvmFlavor<Flavor>) {
546 auto lazy_extended_edges = ExtendedEdges(polynomials);
547 lazy_extended_edges.set_current_edge(virtual_contribution_edge_idx);
548 return lazy_extended_edges;
549 } else {
550 ExtendedEdges extended_edges;
551 extend_edges(extended_edges, polynomials, virtual_contribution_edge_idx);
552 return extended_edges;
553 }
554 }();
555
556 // The tail of G(X) = \prod_{k} (1 + X_k(\beta_k - 1) ) evaluated at the edge (0, ..., 0).
557 const FF gate_separator_tail{ 1 };
559 univariate_accumulator, extended_edges, relation_parameters, gate_separator_tail);
560
561 return batch_over_relations<SumcheckRoundUnivariate>(univariate_accumulator, alphas, gate_separator);
562 };
579 template <typename ExtendedUnivariate, typename ContainerOverSubrelations>
580 static ExtendedUnivariate batch_over_relations(ContainerOverSubrelations& univariate_accumulators,
581 const SubrelationSeparators& challenge,
582 const bb::GateSeparatorPolynomial<FF>& gate_separators)
583 {
585
586 auto result = ExtendedUnivariate(0);
588
589 // Reset all univariate accumulators to 0 before beginning accumulation in the next round
591 return result;
592 }
593
607 template <typename ExtendedUnivariate, typename TupleOfTuplesOfUnivariates>
608 static void extend_and_batch_univariates(const TupleOfTuplesOfUnivariates& tuple,
609 ExtendedUnivariate& result,
610 const bb::GateSeparatorPolynomial<FF>& gate_separators)
611 {
612 ExtendedUnivariate extended_random_polynomial;
613 // Pow-Factor \f$ (1-X) + X\beta_i \f$
614 auto random_polynomial = bb::Univariate<FF, 2>({ 1, gate_separators.current_element() });
615 extended_random_polynomial = random_polynomial.template extend_to<ExtendedUnivariate::LENGTH>();
616
617 auto extend_and_sum = [&]<size_t relation_idx, size_t subrelation_idx, typename Element>(Element& element) {
618 auto extended = element.template extend_to<ExtendedUnivariate::LENGTH>();
619
621 const bool is_subrelation_linearly_independent =
622 bb::subrelation_is_linearly_independent<Relation, subrelation_idx>();
623 // Except from the log derivative subrelation, each other subrelation in part is required to be 0 hence we
624 // multiply by the power polynomial. As the sumcheck prover is required to send a univariate to the
625 // verifier, we additionally need a univariate contribution from the pow polynomial which is the
626 // extended_random_polynomial which is the
627 if (!is_subrelation_linearly_independent) {
628 result += extended;
629 } else {
630 // Multiply by the pow polynomial univariate contribution and the partial
631 // evaluation result c_i (i.e. \f$ pow(u_0,...,u_{l-1})) \f$ where \f$(u_0,...,u_{i-1})\f$ are the
632 // verifier challenges from previous rounds.
633 result += extended * extended_random_polynomial * gate_separators.partial_evaluation_result;
634 }
635 };
636 Utils::apply_to_tuple_of_tuples(tuple, extend_and_sum);
637 }
638
651 static SumcheckRoundUnivariate compute_libra_univariate(const ZKData& zk_sumcheck_data, size_t round_idx)
652 {
654 // select the i'th column of Libra book-keeping table
655 const auto& current_column = zk_sumcheck_data.libra_univariates[round_idx];
656 // the evaluation of Libra round univariate at k=0...D are equal to \f$\texttt{libra_univariates}_{i}(k)\f$
657 // corrected by the Libra running sum
658 for (size_t idx = 0; idx < LIBRA_UNIVARIATES_LENGTH; ++idx) {
659 libra_round_univariate.value_at(idx) =
660 current_column.evaluate(FF(idx)) + zk_sumcheck_data.libra_running_sum;
661 };
663 return libra_round_univariate;
664 } else {
665 return libra_round_univariate.template extend_to<SumcheckRoundUnivariate::LENGTH>();
666 }
667 }
668
669 private:
698 const auto& extended_edges,
699 const bb::RelationParameters<FF>& relation_parameters,
700 const FF& scaling_factor)
701 {
702 constexpr_for<0, NUM_RELATIONS, 1>([&]<size_t relation_idx>() {
704 // Check if the relation is skippable to speed up accumulation
705 if constexpr (!isSkippable<Relation, decltype(extended_edges)>) {
706 // If not, accumulate normally
708 extended_edges,
709 relation_parameters,
710 scaling_factor);
711 } else {
712 // If so, only compute the contribution if the relation is active
713 if (!Relation::skip(extended_edges)) {
715 extended_edges,
716 relation_parameters,
717 scaling_factor);
718 }
719 }
720 });
721 }
722};
723
736template <typename Flavor> class SumcheckVerifierRound {
738 using Relations = typename Flavor::Relations;
739 using TupleOfArraysOfValues = decltype(create_tuple_of_arrays_of_values<typename Flavor::Relations>());
741
742 public:
743 using FF = typename Flavor::FF;
745 using ClaimedLibraEvaluations = typename std::vector<FF>;
746
747 bool round_failed = false;
752 static constexpr size_t NUM_RELATIONS = Flavor::NUM_RELATIONS;
759
761
763 // Verifier constructor
769
779 {
780 FF total_sum =
781 (FF(1) - indicator) * target_total_sum + indicator * (univariate.value_at(0) + univariate.value_at(1));
782 bool sumcheck_round_failed(false);
783 if constexpr (IsRecursiveFlavor<Flavor>) {
784 // This bool is only needed for debugging
785 if (indicator.get_value() == FF{ 1 }.get_value()) {
786 sumcheck_round_failed = (target_total_sum.get_value() != total_sum.get_value());
787 }
788
789 target_total_sum.assert_equal(total_sum);
790 } else {
791 sumcheck_round_failed = (target_total_sum != total_sum);
792 }
793
794 round_failed = round_failed || sumcheck_round_failed;
795 return !sumcheck_round_failed;
796 };
797
807 FF& round_challenge,
808 const FF& indicator)
809 {
810 // Evaluate \f$\tilde{S}^{i}(u_{i}) \f$
811 target_total_sum = (FF(1) - indicator) * target_total_sum + indicator * univariate.evaluate(round_challenge);
812 }
813
821 const bb::RelationParameters<FF>& relation_parameters,
822 const bb::GateSeparatorPolynomial<FF>& gate_separators,
823 const SubrelationSeparators& alphas)
824 {
825 // The verifier should never skip computation of contributions from any relation
826 Utils::template accumulate_relation_evaluations_without_skipping<>(purported_evaluations,
828 relation_parameters,
829 gate_separators.partial_evaluation_result);
830
832 }
833};
834} // namespace bb
#define BB_BENCH_NAME(name)
Definition bb_bench.hpp:218
static bool skip_entire_row(const ProverPolynomialsOrPartiallyEvaluatedMultivariates &polynomials, const EdgeType edge_idx)
When evaluating the sumcheck protocol - can we skip evaluation of all relations for a given row?...
A base class labelling all entities (for instance, all of the polynomials used by the prover during s...
A field element for each entity of the flavor. These entities represent the prover polynomials evalua...
Curve::ScalarField FF
std::array< FF, NUM_SUBRELATIONS - 1 > SubrelationSeparators
static constexpr size_t NUM_RELATIONS
static constexpr bool HasZK
static constexpr size_t MAX_PARTIAL_RELATION_LENGTH
Relations_< FF > Relations
static constexpr bool USE_SHORT_MONOMIALS
static constexpr size_t BATCHED_RELATION_PARTIAL_LENGTH
A wrapper for Relations to expose methods used by the Sumcheck prover or verifier to add the contribu...
static void scale_univariates(auto &tuple, const SubrelationSeparators &subrelation_separators)
Scale Univariates, each representing a subrelation, by different challenges.
Definition utils.hpp:76
static void zero_elements(auto &tuple)
Set each element in a tuple of arrays to zero.
Definition utils.hpp:202
static void zero_univariates(auto &tuple)
Set all coefficients of Univariates to zero.
Definition utils.hpp:61
static constexpr void add_nested_tuples(Tuple &tuple_1, const Tuple &tuple_2)
Componentwise addition of nested tuples (tuples of tuples)
Definition utils.hpp:117
static void apply_to_tuple_of_tuples(auto &tuple, Operation &&operation)
General purpose method for applying an operation to a tuple of tuples of Univariates.
Definition utils.hpp:43
static FF scale_and_batch_elements(auto &tuple, const SubrelationSeparators &subrelation_separators)
Scale elements, representing evaluations of subrelations, by separate challenges then sum them.
Definition utils.hpp:214
Imlementation of the Sumcheck prover round.
decltype(create_sumcheck_tuple_of_tuples_of_univariates< Relations >()) SumcheckTupleOfTuplesOfUnivariates
static constexpr size_t LIBRA_UNIVARIATES_LENGTH
static constexpr size_t BATCHED_RELATION_PARTIAL_LENGTH
The total algebraic degree of the Sumcheck relation as a polynomial in Prover Polynomials incremen...
std::conditional_t< Flavor::USE_SHORT_MONOMIALS, typename Flavor::template ProverUnivariates< 2 >, typename Flavor::ExtendedEdges > ExtendedEdges
static constexpr size_t MAX_PARTIAL_RELATION_LENGTH
The total algebraic degree of the Sumcheck relation as a polynomial in Prover Polynomials .
static void extend_and_batch_univariates(const TupleOfTuplesOfUnivariates &tuple, ExtendedUnivariate &result, const bb::GateSeparatorPolynomial< FF > &gate_separators)
Extend Univariates then sum them multiplying by the current -contributions.
static ExtendedUnivariate batch_over_relations(ContainerOverSubrelations &univariate_accumulators, const SubrelationSeparators &challenge, const bb::GateSeparatorPolynomial< FF > &gate_separators)
Given a tuple of tuples of extended per-relation contributions, and a challenge ,...
typename Flavor::SubrelationSeparators SubrelationSeparators
SumcheckRoundUnivariate compute_univariate_with_row_skipping(ProverPolynomialsOrPartiallyEvaluatedMultivariates &polynomials, const bb::RelationParameters< FF > &relation_parameters, const bb::GateSeparatorPolynomial< FF > &gate_separators, const SubrelationSeparators alphas)
Return the evaluations of the univariate round polynomials at . Most likely, is around ....
SumcheckProverRound(size_t initial_round_size)
SumcheckRoundUnivariate compute_univariate_avm(ProverPolynomialsOrPartiallyEvaluatedMultivariates &polynomials, const bb::RelationParameters< FF > &relation_parameters, const bb::GateSeparatorPolynomial< FF > &gate_separators, const SubrelationSeparators &alphas)
A version of compute_univariate that is better optimized for the AVM.
SumcheckTupleOfTuplesOfUnivariates univariate_accumulators
bb::Univariate< FF, BATCHED_RELATION_PARTIAL_LENGTH > SumcheckRoundUnivariate
SumcheckRoundUnivariate compute_univariate(ProverPolynomialsOrPartiallyEvaluatedMultivariates &polynomials, const bb::RelationParameters< FF > &relation_parameters, const bb::GateSeparatorPolynomial< FF > &gate_separators, const SubrelationSeparators &alphas)
Return the evaluations of the univariate round polynomials. Toggles between chunked computation (desi...
void extend_edges(ExtendedEdges &extended_edges, const ProverPolynomialsOrPartiallyEvaluatedMultivariates &multivariates, const size_t edge_idx)
To compute the round univariate in Round , the prover first computes the values of Honk polynomials ...
void accumulate_relation_univariates(SumcheckTupleOfTuplesOfUnivariates &univariate_accumulators, const auto &extended_edges, const bb::RelationParameters< FF > &relation_parameters, const FF &scaling_factor)
In Round , for a given point , calculate the contribution of each sub-relation to .
static SumcheckRoundUnivariate compute_libra_univariate(const ZKData &zk_sumcheck_data, size_t round_idx)
Compute Libra round univariate expressed given by the formula.
typename Flavor::FF FF
static constexpr size_t NUM_RELATIONS
Number of batched sub-relations in specified by Flavor.
std::vector< BlockOfContiguousRows > compute_contiguous_round_size(ProverPolynomialsOrPartiallyEvaluatedMultivariates &polynomials)
Compute the number of unskippable rows we must iterate over.
SumcheckRoundUnivariate compute_hiding_univariate(const size_t round_idx, const ProverPolynomialsOrPartiallyEvaluatedMultivariates &polynomials, const bb::RelationParameters< FF > &relation_parameters, const bb::GateSeparatorPolynomial< FF > &gate_separators, const SubrelationSeparators &alpha, const ZKData &zk_sumcheck_data, const RowDisablingPolynomial< FF > row_disabling_polynomial)
For ZK Flavors: A method disabling the last 4 rows of the ProverPolynomials.
typename Flavor::Relations Relations
size_t round_size
In Round , equals .
Implementation of the Sumcheck Verifier Round.
typename Flavor::AllValues ClaimedEvaluations
TupleOfArraysOfValues relation_evaluations
decltype(create_tuple_of_arrays_of_values< typename Flavor::Relations >()) TupleOfArraysOfValues
typename Flavor::SubrelationSeparators SubrelationSeparators
SumcheckVerifierRound(FF target_total_sum=0)
static constexpr size_t NUM_RELATIONS
Number of batched sub-relations in specified by Flavor.
FF compute_full_relation_purported_value(const ClaimedEvaluations &purported_evaluations, const bb::RelationParameters< FF > &relation_parameters, const bb::GateSeparatorPolynomial< FF > &gate_separators, const SubrelationSeparators &alphas)
Given the evaluations of the ProverPolynomials at the challenge point stored in purported_evaluatio...
void compute_next_target_sum(bb::Univariate< FF, BATCHED_RELATION_PARTIAL_LENGTH > &univariate, FF &round_challenge, const FF &indicator)
After checking that the univariate is good for this round, compute the next target sum given by the e...
static constexpr size_t BATCHED_RELATION_PARTIAL_LENGTH
The partial algebraic degree of the relation , i.e. MAX_PARTIAL_RELATION_LENGTH + 1.
typename std::vector< FF > ClaimedLibraEvaluations
typename Flavor::Relations Relations
bool check_sum(bb::Univariate< FF, BATCHED_RELATION_PARTIAL_LENGTH > &univariate, const FF &indicator)
Check that the round target sum is correct.
Fr & value_at(size_t i)
Fr evaluate(const Fr &u) const
Evaluate a univariate at a point u not known at compile time and assumed not to be in the domain (els...
static Univariate zero()
Check if the flavor has a static skip method to determine if accumulation of all relations can be ski...
The templates defined herein facilitate sharing the relation arithmetic between the prover and the ve...
Base class templates for structures that contain data parameterized by the fundamental polynomials of...
Entry point for Barretenberg command-line interface.
MegaFlavor Flavor
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:238
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
Curve::Element Element
Implementation of the methods for the -polynomials used in in Sumcheck.
size_t periodicity
In Round of Sumcheck, the periodicity equals to and represents the fixed interval at which elements...
FF current_element() const
Computes the component at index current_element_idx in betas.
FF partial_evaluation_result
The value obtained by partially evaluating one variable in the power polynomial at each round....
Container for parameters used by the grand product (permutation, lookup) Honk relations.
Polynomial for Sumcheck with disabled Rows.
Helper struct that describes a block of non-zero unskippable rows.
Helper struct that will, given a vector of BlockOfContiguousRows, return the edge indices that corres...
RowIterator(const std::vector< BlockOfContiguousRows > &_blocks, size_t starting_index=0)
const std::vector< BlockOfContiguousRows > * blocks
This structure is created to contain various polynomials and constants required by ZK Sumcheck.
std::vector< Polynomial< FF > > libra_univariates