barretenberg
Loading...
Searching...
No Matches
protogalaxy_prover.hpp
1#pragma once
2#include "barretenberg/common/thread.hpp"
3#include "barretenberg/ecc/curves/bn254/fr.hpp"
5#include "barretenberg/flavor/goblin_ultra.hpp"
6#include "barretenberg/flavor/ultra.hpp"
7#include "barretenberg/polynomials/pow.hpp"
8#include "barretenberg/polynomials/univariate.hpp"
9#include "barretenberg/protogalaxy/folding_result.hpp"
10#include "barretenberg/relations/relation_parameters.hpp"
11#include "barretenberg/relations/utils.hpp"
12#include "barretenberg/sumcheck/instance/instances.hpp"
13
14namespace proof_system::honk {
15template <class ProverInstances_> class ProtoGalaxyProver_ {
16 public:
18 using Flavor = typename ProverInstances::Flavor;
19 using Transcript = typename Flavor::Transcript;
20 using FF = typename Flavor::FF;
21 using Instance = typename ProverInstances::Instance;
23 using RowEvaluations = typename Flavor::AllValues;
24 using ProverPolynomials = typename Flavor::ProverPolynomials;
25 using Relations = typename Flavor::Relations;
26 using AlphaType = typename ProverInstances::AlphaType;
27 using VerificationKey = typename Flavor::VerificationKey;
28 using CommitmentKey = typename Flavor::CommitmentKey;
29 using WitnessCommitments = typename Flavor::WitnessCommitments;
30 using Commitment = typename Flavor::Commitment;
31
33 // The length of ExtendedUnivariate is the largest length (==max_relation_degree + 1) of a univariate polynomial
34 // obtained by composing a relation with folded instance + relation parameters .
35 using ExtendedUnivariate = Univariate<FF, (Flavor::MAX_TOTAL_RELATION_LENGTH - 1) * (ProverInstances::NUM - 1) + 1>;
36 // Represents the total length of the combiner univariate, obtained by combining the already folded relations with
37 // the folded relation batching challenge.
39 Univariate<FF,
40 (Flavor::MAX_TOTAL_RELATION_LENGTH - 1 + ProverInstances::NUM - 1) * (ProverInstances::NUM - 1) + 1>;
41
42 using ExtendedUnivariates = typename Flavor::template ProverUnivariates<ExtendedUnivariate::LENGTH>;
43
44 using TupleOfTuplesOfUnivariates =
45 typename Flavor::template ProtogalaxyTupleOfTuplesOfUnivariates<ProverInstances::NUM>;
46 using RelationEvaluations = typename Flavor::TupleOfArraysOfValues;
47
48 ProverInstances instances;
49 std::shared_ptr<Transcript> transcript = std::make_shared<Transcript>();
50
51 std::shared_ptr<CommitmentKey> commitment_key;
52
53 ProtoGalaxyProver_() = default;
54 ProtoGalaxyProver_(const std::vector<std::shared_ptr<Instance>>& insts,
55 const std::shared_ptr<CommitmentKey>& commitment_key)
56 : instances(ProverInstances(insts))
57 , commitment_key(std::move(commitment_key)){};
58 ~ProtoGalaxyProver_() = default;
59
67
74 void send_accumulator(std::shared_ptr<Instance>, const std::string& domain_separator);
75
84 void finalise_and_send_instance(std::shared_ptr<Instance>, const std::string& domain_separator);
85
96 static std::vector<FF> compute_pow_polynomial_at_values(const std::vector<FF>& betas, const size_t instance_size)
97 {
98 std::vector<FF> pow_betas(instance_size);
99 for (size_t i = 0; i < instance_size; i++) {
100 auto res = FF(1);
101 for (size_t j = i, beta_idx = 0; j > 0; j >>= 1, beta_idx++) {
102 if ((j & 1) == 1) {
103 res *= betas[beta_idx];
104 }
105 }
106 pow_betas[i] = res;
107 }
108 return pow_betas;
109 }
110
115 static std::vector<FF> compute_round_challenge_pows(const size_t log_instance_size, const FF& round_challenge)
116 {
117 std::vector<FF> pows(log_instance_size);
118 pows[0] = round_challenge;
119 for (size_t i = 1; i < log_instance_size; i++) {
120 pows[i] = pows[i - 1].sqr();
121 }
122 return pows;
123 }
124
125 static std::vector<FF> update_gate_challenges(const FF perturbator_challenge,
126 const std::vector<FF>& gate_challenges,
127 const std::vector<FF>& round_challenges)
128 {
129 auto log_instance_size = gate_challenges.size();
130 std::vector<FF> next_gate_challenges(log_instance_size);
131 next_gate_challenges[0] = 1;
132
133 for (size_t idx = 1; idx < log_instance_size; idx++) {
134 next_gate_challenges[idx] = gate_challenges[idx] + perturbator_challenge * round_challenges[idx - 1];
135 }
136 return next_gate_challenges;
137 }
138
139 // Returns the accumulator, which is the first element in ProverInstances. The accumulator is assumed to have the
140 // FoldingParameters set and be the result of a previous round of folding.
141 // TODO(https://github.com/AztecProtocol/barretenberg/issues/740): handle the case when the accumulator is empty
142 // (i.e. we are in the first round of folding)/
143 std::shared_ptr<Instance> get_accumulator() { return instances[0]; }
144
150 static std::vector<FF> compute_full_honk_evaluations(const ProverPolynomials& instance_polynomials,
151 const FF& alpha,
152 const RelationParameters<FF>& relation_parameters)
153 {
154 auto instance_size = instance_polynomials.get_polynomial_size();
155
156 std::vector<FF> full_honk_evaluations(instance_size);
157 for (size_t row = 0; row < instance_size; row++) {
158 auto row_evaluations = instance_polynomials.get_row(row);
159 RelationEvaluations relation_evaluations;
160 Utils::zero_elements(relation_evaluations);
161
162 // Note that the evaluations are accumulated with the gate separation challenge being 1 at this stage, as
163 // this specific randomness is added later through the power polynomial univariate specific to ProtoGalaxy
164 Utils::template accumulate_relation_evaluations<>(
165 row_evaluations, relation_evaluations, relation_parameters, FF(1));
166
167 auto running_challenge = FF(1);
168 auto output = FF(0);
169 Utils::scale_and_batch_elements(relation_evaluations, alpha, running_challenge, output);
170 full_honk_evaluations[row] = output;
171 }
172 return full_honk_evaluations;
173 }
174
180 static std::vector<FF> construct_coefficients_tree(const std::vector<FF>& betas,
181 const std::vector<FF>& deltas,
182 const std::vector<std::vector<FF>>& prev_level_coeffs,
183 size_t level = 1)
184 {
185 // if we are at level t in the tree, where t = logn and n is the instance size, we have reached the root which
186 // contains the coefficients of the perturbator polynomial
187 if (level == betas.size()) {
188 return prev_level_coeffs[0];
189 }
190
191 auto degree = level + 1;
192 auto prev_level_width = prev_level_coeffs.size();
193 // we need degree + 1 terms to represent the intermediate polynomials
194 std::vector<std::vector<FF>> level_coeffs(prev_level_width >> 1, std::vector<FF>(degree + 1, 0));
195 for (size_t node = 0; node < prev_level_width; node += 2) {
196 auto parent = node >> 1;
197 std::copy(prev_level_coeffs[node].begin(), prev_level_coeffs[node].end(), level_coeffs[parent].begin());
198 for (size_t d = 0; d < degree; d++) {
199 level_coeffs[parent][d] += prev_level_coeffs[node + 1][d] * betas[level];
200 level_coeffs[parent][d + 1] += prev_level_coeffs[node + 1][d] * deltas[level];
201 }
202 }
203 return construct_coefficients_tree(betas, deltas, level_coeffs, level + 1);
204 }
205
216 static std::vector<FF> construct_perturbator_coefficients(const std::vector<FF>& betas,
217 const std::vector<FF>& deltas,
218 const std::vector<FF>& full_honk_evaluations)
219 {
220 auto width = full_honk_evaluations.size();
221 std::vector<std::vector<FF>> first_level_coeffs(width >> 1, std::vector<FF>(2, 0));
222 for (size_t node = 0; node < width; node += 2) {
223 auto parent = node >> 1;
224 first_level_coeffs[parent][0] = full_honk_evaluations[node] + full_honk_evaluations[node + 1] * betas[0];
225 first_level_coeffs[parent][1] = full_honk_evaluations[node + 1] * deltas[0];
226 }
227 return construct_coefficients_tree(betas, deltas, first_level_coeffs);
228 }
229
236 static Polynomial<FF> compute_perturbator(const std::shared_ptr<Instance> accumulator,
237 const std::vector<FF>& deltas)
238 {
239 auto full_honk_evaluations = compute_full_honk_evaluations(
240 accumulator->prover_polynomials, accumulator->alpha, accumulator->relation_parameters);
241 const auto betas = accumulator->folding_parameters.gate_challenges;
242 assert(betas.size() == deltas.size());
243 auto coeffs = construct_perturbator_coefficients(betas, deltas, full_honk_evaluations);
244 return Polynomial<FF>(coeffs);
245 }
246
247 TupleOfTuplesOfUnivariates univariate_accumulators;
248
257 void extend_univariates(ExtendedUnivariates& extended_univariates,
258 const ProverInstances& instances,
259 const size_t row_idx)
260 {
261 auto base_univariates = instances.row_to_univariates(row_idx);
262 for (auto [extended_univariate, base_univariate] : zip_view(extended_univariates.get_all(), base_univariates)) {
263 extended_univariate = base_univariate.template extend_to<ExtendedUnivariate::LENGTH>();
264 }
265 }
266
267 template <typename Parameters, size_t relation_idx = 0>
268 void accumulate_relation_univariates(TupleOfTuplesOfUnivariates& univariate_accumulators,
269 const ExtendedUnivariates& extended_univariates,
270 const Parameters& relation_parameters,
271 const FF& scaling_factor)
272 {
273 using Relation = std::tuple_element_t<relation_idx, Relations>;
274 Relation::accumulate(
275 std::get<relation_idx>(univariate_accumulators), extended_univariates, relation_parameters, scaling_factor);
276
277 // Repeat for the next relation.
278 if constexpr (relation_idx + 1 < Flavor::NUM_RELATIONS) {
279 accumulate_relation_univariates<Parameters, relation_idx + 1>(
280 univariate_accumulators, extended_univariates, relation_parameters, scaling_factor);
281 }
282 }
283
289 const std::vector<FF>& pow_betas_star)
290 {
291 size_t common_instance_size = instances[0]->instance_size;
292
293 // Determine number of threads for multithreading.
294 // Note: Multithreading is "on" for every round but we reduce the number of threads from the max available based
295 // on a specified minimum number of iterations per thread. This eventually leads to the use of a single thread.
296 // For now we use a power of 2 number of threads simply to ensure the round size is evenly divided.
297 size_t max_num_threads = get_num_cpus_pow2(); // number of available threads (power of 2)
298 size_t min_iterations_per_thread = 1 << 6; // min number of iterations for which we'll spin up a unique thread
299 size_t desired_num_threads = common_instance_size / min_iterations_per_thread;
300 size_t num_threads = std::min(desired_num_threads, max_num_threads); // fewer than max if justified
301 num_threads = num_threads > 0 ? num_threads : 1; // ensure num threads is >= 1
302 size_t iterations_per_thread = common_instance_size / num_threads; // actual iterations per thread
303
304 // Construct univariate accumulator containers; one per thread
305 std::vector<TupleOfTuplesOfUnivariates> thread_univariate_accumulators(num_threads);
306 for (auto& accum : thread_univariate_accumulators) {
307 // just normal relation lengths
309 }
310
311 // Construct extended univariates containers; one per thread
312 std::vector<ExtendedUnivariates> extended_univariates;
313 extended_univariates.resize(num_threads);
314
315 // Accumulate the contribution from each sub-relation
316 parallel_for(num_threads, [&](size_t thread_idx) {
317 size_t start = thread_idx * iterations_per_thread;
318 size_t end = (thread_idx + 1) * iterations_per_thread;
319
320 for (size_t idx = start; idx < end; idx++) {
321 extend_univariates(extended_univariates[thread_idx], instances, idx);
322
323 FF pow_challenge = pow_betas_star[idx];
324
325 // Accumulate the i-th row's univariate contribution. Note that the relation parameters passed to this
326 // function have already been folded
327 accumulate_relation_univariates(
328 thread_univariate_accumulators[thread_idx],
329 extended_univariates[thread_idx],
330 instances.relation_parameters, // these parameters have already been folded
331 pow_challenge);
332 }
333 });
334
335 // Accumulate the per-thread univariate accumulators into a single set of accumulators
336 for (auto& accumulators : thread_univariate_accumulators) {
337 Utils::add_nested_tuples(univariate_accumulators, accumulators);
338 }
339 // Batch the univariate contributions from each sub-relation to obtain the round univariate
340 return batch_over_relations(univariate_accumulators, instances.alpha);
341 }
342 static ExtendedUnivariateWithRandomization batch_over_relations(TupleOfTuplesOfUnivariates univariate_accumulators,
343 AlphaType alpha)
344 {
345
346 // First relation does not get multiplied by a batching challenge
347 auto result = std::get<0>(std::get<0>(univariate_accumulators))
348 .template extend_to<ProverInstances::BATCHED_EXTENDED_LENGTH>();
349 auto scale_and_sum = [&]<size_t outer_idx, size_t>(auto& element) {
350 auto extended = element.template extend_to<ProverInstances::BATCHED_EXTENDED_LENGTH>();
351 extended *= alpha;
352 result += extended;
353 };
354
355 Utils::template apply_to_tuple_of_tuples<0, 1>(univariate_accumulators, scale_and_sum);
356 Utils::zero_univariates(univariate_accumulators);
357
358 return result;
359 }
360
369 FF compressed_perturbator, ExtendedUnivariateWithRandomization combiner)
370 {
371 std::array<FF, ProverInstances::BATCHED_EXTENDED_LENGTH - ProverInstances::NUM> combiner_quotient_evals = {};
372
373 // Compute the combiner quotient polynomial as evaluations on points that are not in the vanishing set.
374 //
375 for (size_t point = ProverInstances::NUM; point < combiner.size(); point++) {
376 auto idx = point - ProverInstances::NUM;
377 auto lagrange_0 = FF(1) - FF(point);
378 auto vanishing_polynomial = FF(point) * (FF(point) - 1);
379
380 combiner_quotient_evals[idx] =
381 (combiner.value_at(point) - compressed_perturbator * lagrange_0) * vanishing_polynomial.invert();
382 }
383
385 combiner_quotient_evals);
386 return combiner_quotient;
387 }
388
397 {
398 // array of parameters to be computed
399 size_t param_idx = 0;
400 for (auto& folded_parameter : instances.relation_parameters.to_fold) {
402 size_t instance_idx = 0;
403 for (auto& instance : instances) {
404 tmp.value_at(instance_idx) = instance->relation_parameters.to_fold[param_idx].get();
405 instance_idx++;
406 }
407 folded_parameter.get() = tmp.template extend_to<ProverInstances::EXTENDED_LENGTH>();
408 param_idx++;
409 }
410 }
411
417 // TODO(https://github.com/AztecProtocol/barretenberg/issues/772): At the moment we have a single α per Instance, we
418 // fold them and then we use the unique folded_α for each folded subrelation that is batched in the combiner. This
419 // is obviously insecure. We need to generate α_i for each subrelation_i, fold them and then use folded_α_i when
420 // batching the i-th folded subrelation in the combiner.
421 static void combine_alpha(ProverInstances& instances)
422 {
423 Univariate<FF, ProverInstances::NUM> accumulated_alpha;
424 size_t instance_idx = 0;
425 for (auto& instance : instances) {
426 accumulated_alpha.value_at(instance_idx) = instance->alpha;
427 instance_idx++;
428 }
429 instances.alpha = accumulated_alpha.template extend_to<ProverInstances::BATCHED_EXTENDED_LENGTH>();
430 }
431
444 std::shared_ptr<Instance> compute_next_accumulator(
445 ProverInstances& instances,
447 const FF& challenge,
448 const FF& compressed_perturbator);
449};
450
451extern template class ProtoGalaxyProver_<ProverInstances_<honk::flavor::Ultra, 2>>;
452extern template class ProtoGalaxyProver_<ProverInstances_<honk::flavor::GoblinUltra, 2>>;
453} // namespace proof_system::honk
Definition: utils.hpp:7
static void zero_elements(auto &tuple)
Set each element in a tuple of arrays to zero.
Definition: utils.hpp:154
static void zero_univariates(auto &tuple)
Set all coefficients of Univariates to zero.
Definition: utils.hpp:53
static void scale_and_batch_elements(auto &tuple, const FF &challenge, FF current_scalar, FF &result)
Scale elements by consecutive powers of the challenge then sum.
Definition: utils.hpp:164
static constexpr void add_nested_tuples(Tuple &tuple_1, const Tuple &tuple_2)
Componentwise addition of nested tuples (tuples of tuples)
Definition: utils.hpp:109
The templates defined herein facilitate sharing the relation arithmetic between the prover and the ve...
Definition: relation_types.hpp:121
Common transcript class for both parties. Stores the data for the current round, as well as the manif...
Definition: transcript.hpp:62
Definition: protogalaxy_prover.hpp:15
static void combine_relation_parameters(ProverInstances &instances)
Combine each relation parameter, in part, from all the instances into univariates,...
Definition: protogalaxy_prover.hpp:396
std::shared_ptr< Instance > compute_next_accumulator(ProverInstances &instances, Univariate< FF, ProverInstances::BATCHED_EXTENDED_LENGTH, ProverInstances::NUM > &combiner_quotient, const FF &challenge, const FF &compressed_perturbator)
Compute the next accumulator (ϕ*, ω*\vec{\beta*}, e*), send the public data ϕ* and the folding parame...
Definition: protogalaxy_prover.cpp:176
void prepare_for_folding()
Prior to folding, we need to finalize the given instances and add all their public data ϕ to the tran...
Definition: protogalaxy_prover.cpp:113
void finalise_and_send_instance(std::shared_ptr< Instance >, const std::string &domain_separator)
For each instance produced by a circuit, prior to folding, we need to complete the computation of its...
Definition: protogalaxy_prover.cpp:5
void extend_univariates(ExtendedUnivariates &extended_univariates, const ProverInstances &instances, const size_t row_idx)
Prepare a univariate polynomial for relation execution in one step of the main loop in folded instanc...
Definition: protogalaxy_prover.hpp:257
static Univariate< FF, ProverInstances::BATCHED_EXTENDED_LENGTH, ProverInstances::NUM > compute_combiner_quotient(FF compressed_perturbator, ExtendedUnivariateWithRandomization combiner)
Compute the combiner quotient defined as $K$ polynomial in the paper.
Definition: protogalaxy_prover.hpp:368
static void combine_alpha(ProverInstances &instances)
Combine the relation batching parameter (named alpha) from each instance into a univariate,...
Definition: protogalaxy_prover.hpp:421
static Polynomial< FF > compute_perturbator(const std::shared_ptr< Instance > accumulator, const std::vector< FF > &deltas)
Construct the power perturbator polynomial F(X) in coefficient form from the accumulator,...
Definition: protogalaxy_prover.hpp:236
void send_accumulator(std::shared_ptr< Instance >, const std::string &domain_separator)
Send the public data of an accumulator, i.e. a relaxed instance, to the verifier (ϕ in the paper).
Definition: protogalaxy_prover.cpp:70
FoldingResult< Flavor > fold_instances()
Run the folding prover protocol to produce a new accumulator and a folding proof to be verified by th...
Definition: protogalaxy_prover.cpp:135
static std::vector< FF > compute_pow_polynomial_at_values(const std::vector< FF > &betas, const size_t instance_size)
Given a vector \vec{\beta} of values, compute the pow polynomial on these values as defined in the pa...
Definition: protogalaxy_prover.hpp:96
static std::vector< FF > compute_full_honk_evaluations(const ProverPolynomials &instance_polynomials, const FF &alpha, const RelationParameters< FF > &relation_parameters)
Compute the values of the full Honk relation at each row in the execution trace, f_i(ω) in the ProtoG...
Definition: protogalaxy_prover.hpp:150
ExtendedUnivariateWithRandomization compute_combiner(const ProverInstances &instances, const std::vector< FF > &pow_betas_star)
Compute the combiner polynomial $G$ in the Protogalaxy paper.
Definition: protogalaxy_prover.hpp:288
static std::vector< FF > construct_coefficients_tree(const std::vector< FF > &betas, const std::vector< FF > &deltas, const std::vector< std::vector< FF > > &prev_level_coeffs, size_t level=1)
Recursively compute the parent nodes of each level in there, starting from the leaves....
Definition: protogalaxy_prover.hpp:180
static std::vector< FF > construct_perturbator_coefficients(const std::vector< FF > &betas, const std::vector< FF > &deltas, const std::vector< FF > &full_honk_evaluations)
We construct the coefficients of the perturbator polynomial in O(n) time following the technique in C...
Definition: protogalaxy_prover.hpp:216
static std::vector< FF > compute_round_challenge_pows(const size_t log_instance_size, const FF &round_challenge)
For a new round challenge δ at each iteration of the ProtoGalaxy protocol, compute the vector [δ,...
Definition: protogalaxy_prover.hpp:115
An Instance is normally constructed from a finalized circuit and it's role is to compute all the poly...
Definition: prover_instance.hpp:20
A field element for each entity of the flavor. These entities represent the prover polynomials evalua...
Definition: goblin_translator.hpp:947
A container for the prover polynomials handles.
Definition: goblin_translator.hpp:955
VerificationKey_< PrecomputedEntities< Commitment > > VerificationKey
The verification key is responsible for storing the the commitments to the precomputed (non-witnessk)...
Definition: goblin_translator.hpp:941
CommitmentKey object over a pairing group 𝔾₁.
Definition: commitment_key.hpp:35
Definition: zip_view.hpp:159
Base class templates for structures that contain data parameterized by the fundamental polynomials of...
Defines particular circuit builder types expected to be used for circuit construction in stdlib and c...
Definition: claim.hpp:6
Container for parameters used by the grand product (permutation, lookup) Honk relations.
Definition: relation_parameters.hpp:12
The result of running the Protogalaxy prover containing a new accumulator (relaxed instance) as well ...
Definition: folding_result.hpp:12
Definition: instances.hpp:7