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// Whether a Flavor specifies the max number of rows per thread in a chunk for univariate computation.
21// Used for the AVM.
22template <typename Flavor>
23concept specifiesUnivariateChunks = std::convertible_to<decltype(Flavor::MAX_CHUNK_THREAD_PORTION_SIZE), size_t>;
24
45template <typename Flavor> class SumcheckProverRound {
46
48 using Relations = typename Flavor::Relations;
49 using SumcheckTupleOfTuplesOfUnivariates = decltype(create_sumcheck_tuple_of_tuples_of_univariates<Relations>());
51
52 public:
53 using FF = typename Flavor::FF;
55 typename Flavor::template ProverUnivariates<2>,
56 typename Flavor::ExtendedEdges>;
61 size_t round_size;
66 static constexpr size_t NUM_RELATIONS = Flavor::NUM_RELATIONS;
79 // Note: since this is not initialized with {}, the univariates contain garbage.
81
82 // The length of the polynomials used to mask the Sumcheck Round Univariates.
83 static constexpr size_t LIBRA_UNIVARIATES_LENGTH = Flavor::Curve::LIBRA_UNIVARIATES_LENGTH;
84
85 // Prover constructor
86 SumcheckProverRound(size_t initial_round_size)
87 : round_size(initial_round_size)
88 {
89 PROFILE_THIS_NAME("SumcheckProverRound constructor");
90
91 // Initialize univariate accumulators to 0
93 }
94
123 template <typename ProverPolynomialsOrPartiallyEvaluatedMultivariates>
124 void extend_edges(ExtendedEdges& extended_edges,
125 const ProverPolynomialsOrPartiallyEvaluatedMultivariates& multivariates,
126 const size_t edge_idx)
127 {
128 for (auto [extended_edge, multivariate] : zip_view(extended_edges.get_all(), multivariates.get_all())) {
129 bb::Univariate<FF, 2> edge({ multivariate[edge_idx], multivariate[edge_idx + 1] });
130 if constexpr (Flavor::USE_SHORT_MONOMIALS) {
131 extended_edge = edge;
132 } else {
133 if (multivariate.end_index() < edge_idx) {
134 static const auto zero_univariate = bb::Univariate<FF, MAX_PARTIAL_RELATION_LENGTH>::zero();
135 extended_edge = zero_univariate;
136 } else {
137 extended_edge = edge.template extend_to<MAX_PARTIAL_RELATION_LENGTH>();
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 (specifiesUnivariateChunks<Flavor>) {
153 return compute_univariate_with_chunking(polynomials, relation_parameters, gate_separators, alphas);
154 }
155 return compute_univariate_with_row_skipping(polynomials, relation_parameters, gate_separators, alphas);
156 }
157 // TODO(https://github.com/AztecProtocol/barretenberg/issues/1484): should we more intelligently incorporate the two
158 // `compute_univariate` types of functions?
181 template <typename ProverPolynomialsOrPartiallyEvaluatedMultivariates>
183 ProverPolynomialsOrPartiallyEvaluatedMultivariates& polynomials,
184 const bb::RelationParameters<FF>& relation_parameters,
185 const bb::GateSeparatorPolynomial<FF>& gate_separators,
186 const SubrelationSeparators& alphas)
187 {
188 PROFILE_THIS_NAME("compute_univariate_with_chunking");
189
190 // Determine number of threads for multithreading.
191 // Note: Multithreading is "on" for every round but we reduce the number of threads from the max available based
192 // on a specified minimum number of iterations per thread. This eventually leads to the use of a single thread.
193 // For now we use a power of 2 number of threads simply to ensure the round size is evenly divided.
194 size_t min_iterations_per_thread = 1 << 6; // min number of iterations for which we'll spin up a unique thread
195 size_t num_threads = bb::calculate_num_threads_pow2(round_size, min_iterations_per_thread);
196
197 // In the AVM, the trace is more dense at the top and therefore it is worth to split the work per thread
198 // in a more distributed way over the edges. To achieve this, we split the trace into chunks and each chunk is
199 // evenly divided among the threads. Below we name a portion in the chunk being processed by any given thread
200 // a "chunk thread portion".
201 // We have: round_size = num_of_chunks * chunk_size and chunk_size = num_threads * chunk_thread_portion_size
202 // Important invariant: round_size = num_of_chunks * num_threads * chunk_thread_portion_size
203 // All the involved values are power of 2. We also require chunk_thread_portion_size >= 2
204 // because a "work unit" cannot be smaller than 2 as extended_edges() process 2 edges at a time.
205 //
206 // Example: round_size = 4096, num_threads = 16, chunk_thread_portion_size = 8
207 // - chunk_size = 16 * 8 = 128
208 // - num_of_chunks = 4096/128 = 32
209 //
210 // For each chunk with index chunk_idx, the thread with index thread_idx will process the edges
211 // in range starting at index: chunk_idx * chunk_size + thread_idx * chunk_thread_portion_size
212 // up to index (not included): chunk_idx * chunk_size + (thread_idx + 1) * chunk_thread_portion_size
213 //
214 // Pattern over edges is now:
215 //
216 // chunk_0 | chunk_1 | chunk_2 ....
217 // thread_0 | thread_1 ... | thread_0 | thread_1 ... | thread_0 | thread_1 ...
218 //
219 // Any thread now processes edges which are distributed at different locations in the trace contrary
220 // to the "standard" method where thread_0 processes all the low indices and the last thread processes
221 // all the high indices.
222 //
223 // This "chunk mechanism" is only enabled for the AVM at the time being and is guarded
224 // by a compile time routine (specifiesUnivariateChunks<Flavor>) checking whether the constant
225 // MAX_CHUNK_THREAD_PORTION_SIZE is defined in the flavor.
226 // This constant defines the maximum value for chunk_thread_portion_size. Whenever the round_size
227 // is large enough, we set chunk_thread_portion_size = MAX_CHUNK_THREAD_PORTION_SIZE. When it is
228 // not possible we use a smaller value but must be at least 2 as mentioned above. If chunk_thread_portion_size
229 // is not at least 2, we fallback to using a single chunk.
230 // Note that chunk_size and num_of_chunks are not constant but are derived by round_size, num_threads and
231 // the chunk_thread_portion_size which needs to satisfy:
232 // 1) 2 <= chunk_thread_portion_size <= MAX_CHUNK_THREAD_PORTION_SIZE
233 // 2) chunk_thread_portion_size * num_threads <= round_size
234 // For the non-AVM flavors, we use a single chunk.
235
236 // Non AVM flavors
237 size_t num_of_chunks = 1;
238 size_t chunk_thread_portion_size = round_size / num_threads;
239
240 // AVM flavor (guarded by defined constant MAX_CHUNK_THREAD_PORTION_SIZE in flavor)
241 if constexpr (specifiesUnivariateChunks<Flavor>) {
242 // This constant is assumed to be a power of 2 greater or equal to 2.
243 static_assert(Flavor::MAX_CHUNK_THREAD_PORTION_SIZE >= 2);
244 static_assert((Flavor::MAX_CHUNK_THREAD_PORTION_SIZE & (Flavor::MAX_CHUNK_THREAD_PORTION_SIZE - 1)) == 0);
245
246 // When the number of edges is so small that the chunk portion size per thread is lower than 2,
247 // we fall back to a single chunk, i.e., we keep the "non-AVM" values.
248 if (round_size / num_threads >= 2) {
249 chunk_thread_portion_size = std::min(round_size / num_threads, Flavor::MAX_CHUNK_THREAD_PORTION_SIZE);
250 num_of_chunks = round_size / (chunk_thread_portion_size * num_threads);
251 // We show that chunk_thread_portion_size satisfies 1) and 2) defined above.
252 // From "std::min()": chunk_thread_portion_size <= round_size/num_threads implying 2)
253 // From static_assert above, and "if condition", we know that both values in "std::min()"
254 // are >= 2 and therefore: chunk_thread_portion_size >= 2
255 // Finally, "std::min()" guarantees that: chunk_thread_portion_size <= MAX_CHUNK_THREAD_PORTION_SIZE
256 // which completes 1).
257 }
258 }
259
260 size_t chunk_size = round_size / num_of_chunks;
261 // Construct univariate accumulator containers; one per thread
262 // Note: std::vector will trigger {}-initialization of the contents. Therefore no need to zero the univariates.
263 std::vector<SumcheckTupleOfTuplesOfUnivariates> thread_univariate_accumulators(num_threads);
264
265 // Accumulate the contribution from each sub-relation accross each edge of the hyper-cube
266 parallel_for(num_threads, [&](size_t thread_idx) {
267 // Construct extended univariates containers; one per thread
268 ExtendedEdges extended_edges;
269 for (size_t chunk_idx = 0; chunk_idx < num_of_chunks; chunk_idx++) {
270 size_t start = chunk_idx * chunk_size + thread_idx * chunk_thread_portion_size;
271 size_t end = chunk_idx * chunk_size + (thread_idx + 1) * chunk_thread_portion_size;
272 for (size_t edge_idx = start; edge_idx < end; edge_idx += 2) {
273 extend_edges(extended_edges, polynomials, edge_idx);
274 // Compute the \f$ \ell \f$-th edge's univariate contribution,
275 // scale it by the corresponding \f$ pow_{\beta} \f$ contribution and add it to the accumulators for
276 // \f$ \tilde{S}^i(X_i) \f$. If \f$ \ell \f$'s binary representation is given by \f$
277 // (\ell_{i+1},\ldots, \ell_{d-1})\f$, the \f$ pow_{\beta}\f$-contribution is
278 // \f$\beta_{i+1}^{\ell_{i+1}} \cdot \ldots \cdot \beta_{d-1}^{\ell_{d-1}}\f$.
279 accumulate_relation_univariates(thread_univariate_accumulators[thread_idx],
280 extended_edges,
281 relation_parameters,
282 gate_separators[(edge_idx >> 1) * gate_separators.periodicity]);
283 }
284 }
285 });
286
287 // Accumulate the per-thread univariate accumulators into a single set of accumulators
288 for (auto& accumulators : thread_univariate_accumulators) {
290 }
291
292 // Batch the univariate contributions from each sub-relation to obtain the round univariate
293 return batch_over_relations<SumcheckRoundUnivariate>(univariate_accumulators, alphas, gate_separators);
294 }
295
301 size_t size;
302 };
303
308 struct RowIterator {
312 RowIterator(const std::vector<BlockOfContiguousRows>& _blocks, size_t starting_index = 0)
313 : blocks(&_blocks)
314 {
315 size_t count = 0;
316 for (size_t i = 0; i < blocks->size(); ++i) {
317 const BlockOfContiguousRows block = blocks->at(i);
318 if (count + (block.size / 2) > starting_index) {
320 current_block_count = (starting_index - count) * 2;
321 break;
322 }
323 count += (block.size / 2);
324 }
325 }
326
328 {
330 size_t edge = block.starting_edge_idx + current_block_count;
331 if (current_block_count + 2 >= block.size) {
334 } else {
336 }
337 return edge;
338 }
339 };
340
354 template <typename ProverPolynomialsOrPartiallyEvaluatedMultivariates>
356 ProverPolynomialsOrPartiallyEvaluatedMultivariates& polynomials)
357 {
358 const size_t min_iterations_per_thread = 1 << 10; // min number of iterations for which we'll spin up a unique
359 const size_t num_threads = bb::calculate_num_threads_pow2(round_size, min_iterations_per_thread);
360 const size_t iterations_per_thread = round_size / num_threads; // actual iterations per thread
361
363 constexpr bool can_skip_rows = (isRowSkippable<Flavor, decltype(polynomials), size_t>);
364
365 if constexpr (can_skip_rows) {
366 std::vector<std::vector<BlockOfContiguousRows>> all_thread_blocks(num_threads);
367 parallel_for(num_threads, [&](size_t thread_idx) {
368 size_t current_block_size = 0;
369 size_t start = thread_idx * iterations_per_thread;
370 size_t end = (thread_idx + 1) * iterations_per_thread;
372 for (size_t edge_idx = start; edge_idx < end; edge_idx += 2) {
373 if (!Flavor::skip_entire_row(polynomials, edge_idx)) {
374 current_block_size += 2;
375 } else {
376 if (current_block_size > 0) {
377 thread_blocks.push_back(BlockOfContiguousRows{
378 .starting_edge_idx = edge_idx - current_block_size, .size = current_block_size });
379 current_block_size = 0;
380 }
381 }
382 }
383 if (current_block_size > 0) {
384 thread_blocks.push_back(BlockOfContiguousRows{ .starting_edge_idx = end - current_block_size,
385 .size = current_block_size });
386 }
387 all_thread_blocks[thread_idx] = thread_blocks;
388 });
389
390 for (const auto& thread_blocks : all_thread_blocks) {
391 for (const auto block : thread_blocks) {
392 result.push_back(block);
393 }
394 }
395 } else {
396 result.push_back(BlockOfContiguousRows{ .starting_edge_idx = 0, .size = round_size });
397 }
398 return result;
399 }
400
405 template <typename ProverPolynomialsOrPartiallyEvaluatedMultivariates>
407 ProverPolynomialsOrPartiallyEvaluatedMultivariates& polynomials,
408 const bb::RelationParameters<FF>& relation_parameters,
409 const bb::GateSeparatorPolynomial<FF>& gate_separators,
410 const SubrelationSeparators alphas)
411 {
412 PROFILE_THIS_NAME("compute_univariate_with_row_skipping");
413
415 // Compute how many nonzero rows we have
416 size_t num_valid_rows = 0;
417 for (const BlockOfContiguousRows block : round_manifest) {
418 num_valid_rows += block.size;
419 }
420 size_t num_valid_iterations = num_valid_rows / 2;
421
422 // Determine number of threads for multithreading.
423 // Note: Multithreading is "on" for every round but we reduce the number of threads from the max available based
424 // on a specified minimum number of iterations per thread. This eventually leads to the use of a single thread.
425 // For now we use a power of 2 number of threads simply to ensure the round size is evenly divided.
426 size_t min_iterations_per_thread = 1 << 6; // min number of iterations for which we'll spin up a unique thread
427 size_t num_threads = bb::calculate_num_threads(num_valid_iterations, min_iterations_per_thread);
428 size_t iterations_per_thread = num_valid_iterations / num_threads; // actual iterations per thread
429 size_t iterations_for_last_thread = num_valid_iterations - (iterations_per_thread * (num_threads - 1));
430 // Construct univariate accumulator containers; one per thread
431 // Note: std::vector will trigger {}-initialization of the contents. Therefore no need to zero the univariates.
432 std::vector<SumcheckTupleOfTuplesOfUnivariates> thread_univariate_accumulators(num_threads);
433
434 parallel_for(num_threads, [&](size_t thread_idx) {
435 const size_t start = thread_idx * iterations_per_thread;
436 const size_t end = (thread_idx == num_threads - 1) ? start + iterations_for_last_thread
437 : (thread_idx + 1) * iterations_per_thread;
438
439 RowIterator edge_iterator(round_manifest, start);
440 // Construct extended univariates containers; one per thread
441 ExtendedEdges extended_edges;
442 for (size_t i = start; i < end; ++i) {
443 size_t edge_idx = edge_iterator.get_next_edge();
444 extend_edges(extended_edges, polynomials, edge_idx);
445 // Compute the \f$ \ell \f$-th edge's univariate contribution,
446 // scale it by the corresponding \f$ pow_{\beta} \f$ contribution and add it to the accumulators for \f$
447 // \tilde{S}^i(X_i) \f$. If \f$ \ell \f$'s binary representation is given by \f$ (\ell_{i+1},\ldots,
448 // \ell_{d-1})\f$, the \f$ pow_{\beta}\f$-contribution is \f$\beta_{i+1}^{\ell_{i+1}} \cdot \ldots \cdot
449 // \beta_{d-1}^{\ell_{d-1}}\f$.
450 accumulate_relation_univariates(thread_univariate_accumulators[thread_idx],
451 extended_edges,
452 relation_parameters,
453 gate_separators[(edge_idx >> 1) * gate_separators.periodicity]);
454 }
455 });
456
457 // Accumulate the per-thread univariate accumulators into a single set of accumulators
458 for (auto& accumulators : thread_univariate_accumulators) {
460 }
461 // Batch the univariate contributions from each sub-relation to obtain the round univariate
462 // these are unmasked; we will mask in sumcheck.
463 const auto round_univariate =
464 batch_over_relations<SumcheckRoundUnivariate>(univariate_accumulators, alphas, gate_separators);
465
466 return round_univariate;
467 };
468 template <typename ProverPolynomialsOrPartiallyEvaluatedMultivariates>
470 const size_t round_idx,
471 const ProverPolynomialsOrPartiallyEvaluatedMultivariates& polynomials,
472 const bb::RelationParameters<FF>& relation_parameters,
473 const bb::GateSeparatorPolynomial<FF>& gate_separators,
474 const SubrelationSeparators& alpha,
475 const ZKData& zk_sumcheck_data,
476 const RowDisablingPolynomial<FF> row_disabling_polynomial)
477 requires Flavor::HasZK
478 {
479 auto hiding_univariate = compute_libra_univariate(zk_sumcheck_data, round_idx);
480 if constexpr (UseRowDisablingPolynomial<Flavor>) {
481 hiding_univariate -= compute_disabled_contribution(
482 polynomials, relation_parameters, gate_separators, alpha, round_idx, row_disabling_polynomial);
483 }
484 return hiding_univariate;
485 }
486
493 template <typename ProverPolynomialsOrPartiallyEvaluatedMultivariates>
494 SumcheckRoundUnivariate compute_disabled_contribution(
495 ProverPolynomialsOrPartiallyEvaluatedMultivariates& polynomials,
496 const bb::RelationParameters<FF>& relation_parameters,
497 const bb::GateSeparatorPolynomial<FF>& gate_separators,
498 const SubrelationSeparators& alphas,
499 const size_t round_idx,
500 const RowDisablingPolynomial<FF> row_disabling_polynomial)
502 {
503 // Note: {} is required to initialize the tuple contents. Otherwise the univariates contain garbage.
504 SumcheckTupleOfTuplesOfUnivariates univariate_accumulator{};
505 ExtendedEdges extended_edges;
507
508 // In Round 0, we have to compute the contribution from 2 edges: (1, 1,..., 1) and (0, 1, ..., 1) (as points on
509 // (d-1) - dimensional Boolean hypercube).
510 size_t start_edge_idx = (round_idx == 0) ? round_size - 4 : round_size - 2;
511
512 for (size_t edge_idx = start_edge_idx; edge_idx < round_size; edge_idx += 2) {
513 extend_edges(extended_edges, polynomials, edge_idx);
514 accumulate_relation_univariates(univariate_accumulator,
515 extended_edges,
516 relation_parameters,
517 gate_separators[(edge_idx >> 1) * gate_separators.periodicity]);
518 }
519 result = batch_over_relations<SumcheckRoundUnivariate>(univariate_accumulator, alphas, gate_separators);
520 bb::Univariate<FF, 2> row_disabling_factor =
521 bb::Univariate<FF, 2>({ row_disabling_polynomial.eval_at_0, row_disabling_polynomial.eval_at_1 });
522 SumcheckRoundUnivariate row_disabling_factor_extended =
523 row_disabling_factor.template extend_to<SumcheckRoundUnivariate::LENGTH>();
524 result *= row_disabling_factor_extended;
525
526 return result;
527 }
528
529 template <typename ProverPolynomialsOrPartiallyEvaluatedMultivariates>
530 SumcheckRoundUnivariate compute_virtual_contribution(
531 ProverPolynomialsOrPartiallyEvaluatedMultivariates& polynomials,
532 const bb::RelationParameters<FF>& relation_parameters,
533 const GateSeparatorPolynomial<FF>& gate_separator,
534 const SubrelationSeparators& alphas)
535 {
536 // Note: {} is required to initialize the tuple contents. Otherwise the univariates contain garbage.
537 SumcheckTupleOfTuplesOfUnivariates univariate_accumulator{};
538 ExtendedEdges extended_edges;
539
540 // For a given prover polynomial P_i(X_0, ..., X_{d-1}) extended by zero, i.e. multiplied by
541 // \tau(X_d, ..., X_{virtual_log_n - 1}) = \prod (1 - X_k)
542 // for k = d, ..., virtual_log_n - 1, the computation of the virtual sumcheck round univariate reduces to the
543 // edge (0, ...,0).
544 const size_t virtual_contribution_edge_idx = 0;
545
546 // Perform the usual sumcheck accumulation, but for a single edge.
547 extend_edges(extended_edges, polynomials, virtual_contribution_edge_idx);
548 // The tail of G(X) = \prod_{k} (1 + X_k(\beta_k - 1) ) evaluated at the edge (0, ..., 0).
549 const FF gate_separator_tail{ 1 };
551 univariate_accumulator, extended_edges, relation_parameters, gate_separator_tail);
552
553 return batch_over_relations<SumcheckRoundUnivariate>(univariate_accumulator, alphas, gate_separator);
554 };
571 template <typename ExtendedUnivariate, typename ContainerOverSubrelations>
572 static ExtendedUnivariate batch_over_relations(ContainerOverSubrelations& univariate_accumulators,
573 const SubrelationSeparators& challenge,
574 const bb::GateSeparatorPolynomial<FF>& gate_separators)
575 {
577
578 auto result = ExtendedUnivariate(0);
580
581 // Reset all univariate accumulators to 0 before beginning accumulation in the next round
583 return result;
584 }
585
599 template <typename ExtendedUnivariate, typename TupleOfTuplesOfUnivariates>
600 static void extend_and_batch_univariates(const TupleOfTuplesOfUnivariates& tuple,
601 ExtendedUnivariate& result,
602 const bb::GateSeparatorPolynomial<FF>& gate_separators)
603 {
604 ExtendedUnivariate extended_random_polynomial;
605 // Pow-Factor \f$ (1-X) + X\beta_i \f$
606 auto random_polynomial = bb::Univariate<FF, 2>({ 1, gate_separators.current_element() });
607 extended_random_polynomial = random_polynomial.template extend_to<ExtendedUnivariate::LENGTH>();
608
609 auto extend_and_sum = [&]<size_t relation_idx, size_t subrelation_idx, typename Element>(Element& element) {
610 auto extended = element.template extend_to<ExtendedUnivariate::LENGTH>();
611
613 const bool is_subrelation_linearly_independent =
614 bb::subrelation_is_linearly_independent<Relation, subrelation_idx>();
615 // Except from the log derivative subrelation, each other subrelation in part is required to be 0 hence we
616 // multiply by the power polynomial. As the sumcheck prover is required to send a univariate to the
617 // verifier, we additionally need a univariate contribution from the pow polynomial which is the
618 // extended_random_polynomial which is the
619 if (!is_subrelation_linearly_independent) {
620 result += extended;
621 } else {
622 // Multiply by the pow polynomial univariate contribution and the partial
623 // evaluation result c_i (i.e. \f$ pow(u_0,...,u_{l-1})) \f$ where \f$(u_0,...,u_{i-1})\f$ are the
624 // verifier challenges from previous rounds.
625 result += extended * extended_random_polynomial * gate_separators.partial_evaluation_result;
626 }
627 };
628 Utils::apply_to_tuple_of_tuples(tuple, extend_and_sum);
629 }
630
643 static SumcheckRoundUnivariate compute_libra_univariate(const ZKData& zk_sumcheck_data, size_t round_idx)
644 {
646 // select the i'th column of Libra book-keeping table
647 const auto& current_column = zk_sumcheck_data.libra_univariates[round_idx];
648 // the evaluation of Libra round univariate at k=0...D are equal to \f$\texttt{libra_univariates}_{i}(k)\f$
649 // corrected by the Libra running sum
650 for (size_t idx = 0; idx < LIBRA_UNIVARIATES_LENGTH; ++idx) {
651 libra_round_univariate.value_at(idx) =
652 current_column.evaluate(FF(idx)) + zk_sumcheck_data.libra_running_sum;
653 };
655 return libra_round_univariate;
656 } else {
657 return libra_round_univariate.template extend_to<SumcheckRoundUnivariate::LENGTH>();
658 }
659 }
660
661 private:
690 const auto& extended_edges,
691 const bb::RelationParameters<FF>& relation_parameters,
692 const FF& scaling_factor)
693 {
694 constexpr_for<0, NUM_RELATIONS, 1>([&]<size_t relation_idx>() {
696 // Check if the relation is skippable to speed up accumulation
697 if constexpr (!isSkippable<Relation, decltype(extended_edges)>) {
698 // If not, accumulate normally
700 extended_edges,
701 relation_parameters,
702 scaling_factor);
703 } else {
704 // If so, only compute the contribution if the relation is active
705 if (!Relation::skip(extended_edges)) {
707 extended_edges,
708 relation_parameters,
709 scaling_factor);
710 }
711 }
712 });
713 }
714};
715
728template <typename Flavor> class SumcheckVerifierRound {
730 using Relations = typename Flavor::Relations;
731 using TupleOfArraysOfValues = decltype(create_tuple_of_arrays_of_values<typename Flavor::Relations>());
733
734 public:
735 using FF = typename Flavor::FF;
737 using ClaimedLibraEvaluations = typename std::vector<FF>;
738
739 bool round_failed = false;
744 static constexpr size_t NUM_RELATIONS = Flavor::NUM_RELATIONS;
751
753
755 // Verifier constructor
761
771 {
772 FF total_sum =
773 (FF(1) - indicator) * target_total_sum + indicator * (univariate.value_at(0) + univariate.value_at(1));
774 bool sumcheck_round_failed(false);
775 if constexpr (IsRecursiveFlavor<Flavor>) {
776 // This bool is only needed for debugging
777 if (indicator.get_value() == FF{ 1 }.get_value()) {
778 sumcheck_round_failed = (target_total_sum.get_value() != total_sum.get_value());
779 }
780
781 target_total_sum.assert_equal(total_sum);
782 } else {
783 sumcheck_round_failed = (target_total_sum != total_sum);
784 }
785
786 round_failed = round_failed || sumcheck_round_failed;
787 return !sumcheck_round_failed;
788 };
789
799 FF& round_challenge,
800 const FF& indicator)
801 {
802 // Evaluate \f$\tilde{S}^{i}(u_{i}) \f$
803 target_total_sum = (FF(1) - indicator) * target_total_sum + indicator * univariate.evaluate(round_challenge);
804 }
805
813 const bb::RelationParameters<FF>& relation_parameters,
814 const bb::GateSeparatorPolynomial<FF>& gate_separators,
815 const SubrelationSeparators& alphas)
816 {
817 // The verifier should never skip computation of contributions from any relation
818 Utils::template accumulate_relation_evaluations_without_skipping<>(purported_evaluations,
820 relation_parameters,
821 gate_separators.partial_evaluation_result);
822
824 }
825};
826} // namespace bb
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:203
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:215
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)
Version of compute_univariate that allows for row-skipping, as a prover-side optimization.
SumcheckProverRound(size_t initial_round_size)
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
SumcheckRoundUnivariate compute_univariate_with_chunking(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 ....
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:199
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
Curve::Element Element
Implementation of the methods for the -polynomials used in Protogalaxy and -polynomials used in Sumch...
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