Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
eccvm_prover.cpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: Planned, auditors: [], commit: }
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
7#include "eccvm_prover.hpp"
20
21#include <iterator>
22
23namespace bb {
24
25ECCVMProver::ECCVMProver(CircuitBuilder& builder, const std::shared_ptr<Transcript>& transcript)
26 : transcript(transcript)
27{
28 BB_BENCH_NAME("ECCVMProver(CircuitBuilder&)");
29
30 // TODO(https://github.com/AztecProtocol/barretenberg/issues/939): Remove redundancy between
31 // ProvingKey/ProverPolynomials and update the model to reflect what's done in all other proving systems.
32
33 // Construct the proving key; populates all polynomials except for witness polys
35
36 key->commitment_key = CommitmentKey(key->circuit_size);
37
39 for (auto [commitment, vk_commitment] : zip_view(commitments.get_precomputed(), vk.get_all())) {
40 commitment = vk_commitment;
41 }
42}
43
49{
51
52 // Fiat-Shamir the vk hash
54 typename Flavor::BF vk_hash = vk.get_hash();
55 transcript->add_to_hash_buffer("vk_hash", vk_hash);
56 vinfo("ECCVM vk hash in prover: ", vk_hash);
57}
58
64{
65 BB_BENCH_NAME("ECCVMProver::execute_wire_commitments_round");
66
67 const size_t circuit_size = key->circuit_size;
68
69 // Create and commit to Gemini masking polynomial (for ZK-PCS)
70 key->polynomials.gemini_masking_poly = Polynomial::random(circuit_size);
71 auto masking_commitment = key->commitment_key.commit(key->polynomials.gemini_masking_poly);
72 commitments.gemini_masking_poly = masking_commitment;
73 transcript->send_to_verifier("Gemini:masking_poly_comm", masking_commitment);
74
75 auto batch = key->commitment_key.start_batch();
76 for (const auto& [wire, label] : zip_view(key->polynomials.get_wires(), commitment_labels.get_wires())) {
77 batch.add_to_batch(wire, label, Flavor::CommitmentLabels::wire_has_high_duplicate_density(label));
78 }
79 auto wire_commitments = batch.commit_and_send_to_verifier(transcript);
80 for (auto [commitment, computed_commitment] : zip_view(commitments.get_wires(), wire_commitments)) {
81 commitment = computed_commitment;
82 }
83}
84
90{
91 BB_BENCH_NAME("ECCVMProver::execute_log_derivative_commitments_round");
92
93 // Compute and add beta to relation parameters
94 auto [beta, gamma] = transcript->template get_challenges<FF>(std::array<std::string, 2>{ "beta", "gamma" });
95
96 // TODO(#583)(@zac-williamson): fix Transcript to be able to generate more than 2 challenges per round! oof.
97 auto beta_sqr = beta * beta;
98 auto beta_quartic = beta_sqr * beta_sqr;
101 relation_parameters.beta_sqr = beta_sqr;
102 relation_parameters.beta_cube = beta_sqr * beta;
103 relation_parameters.beta_quartic = beta_quartic;
104 // `eccvm_set_permutation_delta` is used in the set membership gadget in eccvm/ecc_set_relation.hpp, specifically to
105 // constrain (pc, round, wnaf_slice) to match between the MSM table and the Precomputed table. The number of rows we
106 // add per short scalar `mul` is slightly less in the Precomputed table as in the MSM table, so to get the
107 // permutation argument to work out, when `precompute_select == 0`, we must implicitly _remove_ (0, 0, 0) as a tuple
108 // on the wNAF side. This corresponds to dividing by
109 // (γ+t·β⁴)·(γ+β²+t·β⁴)·(γ+2β²+t·β⁴)·(γ+3β²+t·β⁴), where t = FIRST_TERM_TAG.
110 auto first_term_tag = beta_quartic; // FIRST_TERM_TAG (= 1) * beta_quartic
111 relation_parameters.eccvm_set_permutation_delta = (gamma + first_term_tag) * (gamma + beta_sqr + first_term_tag) *
112 (gamma + beta_sqr + beta_sqr + first_term_tag) *
113 (gamma + beta_sqr + beta_sqr + beta_sqr + first_term_tag);
115 // Compute inverse polynomial for our logarithmic-derivative lookup method
116 // Skip the disabled head region to preserve masking values
118 typename Flavor::LookupRelation,
120 true>(key->polynomials, relation_parameters, Flavor::TRACE_OFFSET);
121 auto& li = key->polynomials.lookup_inverses;
122 commitments.lookup_inverses = key->commitment_key.commit(li);
123 transcript->send_to_verifier(commitment_labels.lookup_inverses, commitments.lookup_inverses);
124}
125
131{
132 BB_BENCH_NAME("ECCVMProver::execute_grand_product_computation_round");
133 // Compute permutation grand product (starts after disabled head region via gp_start)
134 compute_grand_products<Flavor>(key->polynomials, relation_parameters);
135 auto& zp = key->polynomials.z_perm;
136 // set has_duplicates_hint for Z_PERM (empty row = duplicate Z value)
137 commitments.z_perm = key->commitment_key.commit(zp, /*has_duplicates_hint=*/true);
138 transcript->send_to_verifier(commitment_labels.z_perm, commitments.z_perm);
139}
140
146{
147 BB_BENCH_NAME("ECCVMProver::execute_relation_check_rounds");
148 using Sumcheck = SumcheckProver<Flavor>;
149
150 // Each linearly independent subrelation contribution is multiplied by `alpha^i`, where
151 // i = 0, ..., NUM_SUBRELATIONS- 1.
152 FF alpha = transcript->template get_challenge<FF>("Sumcheck:alpha");
153
154 std::vector<FF> gate_challenges =
155 transcript->template get_dyadic_powers_of_challenge<FF>("Sumcheck:gate_challenge", CONST_ECCVM_LOG_N);
156
157 Sumcheck sumcheck(key->circuit_size,
158 key->polynomials,
160 alpha,
161 gate_challenges,
163 CONST_ECCVM_LOG_N);
164
165 zk_sumcheck_data = ZKData(key->log_circuit_size, transcript, key->commitment_key);
166
167 sumcheck_output = sumcheck.prove(zk_sumcheck_data);
168}
169
174{
175 using Curve = typename Flavor::Curve;
176
177 SmallSubgroupIPA small_subgroup_ipa_prover(zk_sumcheck_data,
178 sumcheck_output.challenge,
179 sumcheck_output.claimed_libra_evaluation,
181 key->commitment_key);
182 small_subgroup_ipa_prover.prove();
183
184 const FF libra_evaluation_challenge =
185 transcript->template get_challenge<FF>("Libra:small_ipa_evaluation_challenge");
186 auto libra_opening_claims = make_small_ipa_prover_opening_claims<Curve>(
187 small_subgroup_ipa_prover.get_witness_polynomials(), libra_evaluation_challenge, "Libra:", transcript);
188 const auto libra_commitments = small_subgroup_ipa_prover.get_witness_commitments();
189
190 for (size_t idx = 0; idx < libra_opening_claims.size(); ++idx) {
191 univariate_claims.add(std::move(libra_opening_claims[idx]),
192 libra_commitments[SMALL_IPA_CLAIMS[idx].commitment_index]);
193 }
194}
195
201{
203 static constexpr size_t NUM_SUMCHECK_CLAIMS_PER_ROUND = 3;
204
205 auto sumcheck_round_claims = Shplemini::compute_sumcheck_round_claims(key->circuit_size,
206 sumcheck_output.challenge,
207 sumcheck_output.round_univariates,
208 sumcheck_output.round_univariate_evaluations);
209
210 for (size_t idx = 0; idx < sumcheck_output.round_univariate_commitments.size(); ++idx) {
211 for (size_t eval_idx = 0; eval_idx < NUM_SUMCHECK_CLAIMS_PER_ROUND; ++eval_idx) {
212 const size_t claim_idx = idx * NUM_SUMCHECK_CLAIMS_PER_ROUND + eval_idx;
213 univariate_claims.add(std::move(sumcheck_round_claims[claim_idx]),
214 sumcheck_output.round_univariate_commitments[idx]);
215 }
216 }
217}
218
227{
228 static constexpr size_t POW_MASK_SIZE = 8;
229 Polynomial mask = Polynomial::random(POW_MASK_SIZE, key->circuit_size, /*start_index=*/0);
230 Commitment mask_commitment = key->commitment_key.commit(mask);
231 transcript->send_to_verifier("TripleIPA:pow_mask_commitment", mask_commitment);
232 const FF mask_challenge = transcript->template get_challenge<FF>("TripleIPA:pow_mask_challenge");
233 const FF mask_evaluation = mask.evaluate(mask_challenge);
234 transcript->send_to_verifier("TripleIPA:pow_mask_evaluation", mask_evaluation);
235 univariate_claims.add({ std::move(mask), { mask_challenge, mask_evaluation } }, mask_commitment);
236}
237
241void ECCVMProver::prove_triple_ipa(const OpeningClaim& prover_opening, const VerifierOpeningClaim& verifier_opening)
242{
244 typename TripleIPA::TripleIpaInput input;
245
246 const FF rho = transcript->template get_challenge<FF>("TripleIPA:rho");
248 sumcheck_output.claimed_evaluations.get_unshifted(),
249 commitments.get_to_be_shifted(),
250 sumcheck_output.claimed_evaluations.get_to_be_shifted(),
251 sumcheck_output.claimed_evaluations.get_shifted(),
252 sumcheck_output.challenge,
253 rho,
254 verifier_opening);
255
256 // Prover-only: share the witness polynomials backing the opening — the unshifted set, the to-be-shifted sources
257 // (for the shift claim's batched witness), and the reduced univariate.
258 auto unshifted_polynomials = key->polynomials.get_unshifted();
259 input.unshifted_polynomials.reserve(unshifted_polynomials.size());
260 for (auto& polynomial : unshifted_polynomials) {
261 input.unshifted_polynomials.emplace_back(polynomial.share());
262 }
263 auto shifted_polynomials = key->polynomials.get_to_be_shifted();
264 input.shifted_polynomials.reserve(shifted_polynomials.size());
265 for (auto& polynomial : shifted_polynomials) {
266 input.shifted_polynomials.emplace_back(polynomial.share());
267 }
268 input.univariate_polynomial = prover_opening.polynomial.share();
269
270 auto ipa_transcript = std::make_shared<Transcript>();
271 TripleIPA::compute_opening_proof(key->commitment_key, input, ipa_transcript);
272 ipa_proof = ipa_transcript->export_proof();
273}
274
282{
283 using ShplonkProver = ShplonkProver_<Flavor::Curve>;
284 using ShplonkVerifier = ShplonkVerifier_<Flavor::Curve>;
285
286 const auto shplonk_output = ShplonkProver::compute_partially_evaluated_quotient(
287 key->commitment_key, univariate_claims.prover_claims, transcript);
288 const auto verifier_opening = ShplonkVerifier::compute_partially_evaluated_quotient_claim(
289 key->commitment_key.get_monomial_points()[0],
290 univariate_claims.verifier_claims,
291 shplonk_output.quotient_commitment,
292 shplonk_output.batching_challenge,
293 shplonk_output.opening_claim.opening_pair.challenge);
294 BB_ASSERT(verifier_opening.opening_pair == shplonk_output.opening_claim.opening_pair);
295
296 return { shplonk_output.opening_claim, verifier_opening };
297}
298
300{
301 return { transcript->export_proof() };
302}
303
305{
306 BB_BENCH_NAME("ECCVMProver::construct_proof");
307
312 execute_relation_check_rounds(); // sumcheck
313
314 // Gather every univariate opening claim into `univariate_claims`. Libra (sumcheck ZK masking) is produced first
315 // since its commitments enter the transcript before translation's; the committed sumcheck round claims follow.
316 // A final random masking claim blinds the TripleIPA pow tensor (see append_pow_masking_opening_claim).
321
322 // A single Shplonk reduces them to one opening; the TripleIPA opens the sumcheck multilinears with it.
323 auto [prover_opening, verifier_opening] = reduce_univariate_opening_claims();
324 prove_triple_ipa(prover_opening, verifier_opening);
325
326 return export_proof();
327}
328
357{
358 // Used to capture the batched evaluation of unmasked `translation_polynomials` while preserving ZK
360 using Curve = Flavor::Curve;
361
362 RefArray translation_polynomials{ key->polynomials.transcript_op,
363 key->polynomials.transcript_Px,
364 key->polynomials.transcript_Py,
365 key->polynomials.transcript_z1,
366 key->polynomials.transcript_z2 };
367
368 // Extract the masking terms of `translation_polynomials`, concatenate them in the Lagrange basis over SmallSubgroup
369 // H, mask the resulting polynomial, and commit to it
370 TranslationData<Transcript> translation_data(translation_polynomials, transcript, key->commitment_key);
371
372 // Get a challenge to evaluate the `translation_polynomials` as univariates
373 evaluation_challenge_x = transcript->template get_challenge<FF>("Translation:evaluation_challenge_x");
374
375 // Evaluate `translation_polynomial` as univariates and add their evaluations at x to the transcript
376 for (auto [eval, poly, label] :
378 eval = poly.evaluate(evaluation_challenge_x);
379 transcript->send_to_verifier(label, eval);
380 }
381
382 // Get another challenge to batch the evaluations of the transcript polynomials
383 batching_challenge_v = transcript->template get_challenge<FF>("Translation:batching_challenge_v");
384
385 SmallIPA translation_masking_term_prover(
386 translation_data, evaluation_challenge_x, batching_challenge_v, transcript, key->commitment_key);
387 translation_masking_term_prover.prove();
388
389 // Get the challenge to check evaluations of the SmallSubgroupIPA witness polynomials
390 FF small_ipa_evaluation_challenge =
391 transcript->template get_challenge<FF>("Translation:small_ipa_evaluation_challenge");
392
393 // Populate the five SmallSubgroupIPA opening claims via the shared helper, which evaluates witness polynomials,
394 // sends transmitted slots to the transcript, and fills boundary slots with 0.
395 const auto small_ipa_claims =
396 make_small_ipa_prover_opening_claims<Curve>(translation_masking_term_prover.get_witness_polynomials(),
397 small_ipa_evaluation_challenge,
398 "Translation:",
399 transcript);
400 const auto small_ipa_commitments = translation_masking_term_prover.get_witness_commitments();
401
402 for (size_t idx = 0; idx < NUM_SMALL_IPA_OPENING_CLAIMS; ++idx) {
403 univariate_claims.add(small_ipa_claims[idx], small_ipa_commitments[SMALL_IPA_CLAIMS[idx].commitment_index]);
404 }
405
406 // Compute the opening claim for the masked evaluations of `op`, `Px`, `Py`, `z1`, and `z2` at
407 // `evaluation_challenge_x` batched by the powers of `batching_challenge_v`.
408 const std::vector<FF> batching_challenges = batching_scalars(batching_challenge_v, NUM_TRANSLATION_EVALUATIONS);
409 std::vector<PolynomialSpan<const FF>> translation_spans;
410 translation_spans.reserve(NUM_TRANSLATION_EVALUATIONS);
411 for (const auto& polynomial : translation_polynomials) {
412 translation_spans.push_back(static_cast<PolynomialSpan<const FF>>(polynomial));
413 }
414 Polynomial batched_translation_univariate{ key->circuit_size };
415 add_scaled_batch(batched_translation_univariate,
416 std::span<const PolynomialSpan<const FF>>(translation_spans),
417 std::span<const FF>(batching_challenges));
418
419 std::vector<FF> translation_evaluation_values;
420 translation_evaluation_values.reserve(NUM_TRANSLATION_EVALUATIONS);
421 for (const auto& eval : translation_evaluations.get_all()) {
422 translation_evaluation_values.emplace_back(eval);
423 }
424 const FF batched_translation_evaluation = batch_evaluations<Curve>(
425 std::span<const FF>(translation_evaluation_values), std::span<const FF>(batching_challenges));
426
427 std::vector<Commitment> translation_commitments = { commitments.transcript_op,
428 commitments.transcript_Px,
429 commitments.transcript_Py,
430 commitments.transcript_z1,
431 commitments.transcript_z2 };
432
433 // Add the batched translation univariate claim after the SmallSubgroupIPA opening claims.
435 { batched_translation_univariate, { evaluation_challenge_x, batched_translation_evaluation } },
436 batch_commitments<Curve>(std::span<const Commitment>(translation_commitments),
437 std::span<const FF>(batching_challenges)));
438}
439
440} // namespace bb
#define BB_ASSERT(expression,...)
Definition assert.hpp:70
#define BB_BENCH_NAME(name)
Definition bb_bench.hpp:264
A container for the prover polynomials.
typename Curve::BaseField BF
FixedVKAndHash_< PrecomputedEntities< Commitment >, BF, ECCVMHardcodedVKAndHash > VerificationKey
The verification key stores commitments to the precomputed polynomials used by the verifier.
static constexpr size_t TRACE_OFFSET
void prove_triple_ipa(const OpeningClaim &prover_opening, const VerifierOpeningClaim &verifier_opening)
Open the sumcheck multilinears together with the single reduced univariate claim via the TripleIPA.
Flavor::Commitment Commitment
SumcheckOutput< Flavor > sumcheck_output
BB_PROFILE void execute_log_derivative_commitments_round()
Compute sorted witness-table accumulator.
ECCVMProver(CircuitBuilder &builder, const std::shared_ptr< Transcript > &transcript)
void append_libra_opening_claims()
Add the Libra (sumcheck ZK masking) univariate opening claims, produced via the SmallSubgroupIPA prov...
ZKSumcheckData< Flavor > ZKData
std::shared_ptr< Transcript > transcript
CommitmentLabels commitment_labels
TranslationEvaluations translation_evaluations
void append_translation_opening_claims()
To link the ECCVM Transcript wires op, Px, Py, z1, and z2 to the accumulator computed by the translat...
Commitments commitments
std::shared_ptr< ProvingKey > key
void append_pow_masking_opening_claim()
Add a small random univariate opening claim that masks the TripleIPA pow tensor.
BB_PROFILE void execute_preamble_round()
Fiat-Shamir the VK.
BB_PROFILE void execute_wire_commitments_round()
Compute commitments to the first three wires.
Flavor::CommitmentKey CommitmentKey
std::pair< OpeningClaim, VerifierOpeningClaim > reduce_univariate_opening_claims()
Reduce all univariate opening claims to a single opening claim via one Shplonk.
ProverOpeningClaimBatcher< Flavor::Curve > univariate_claims
BB_PROFILE void execute_grand_product_computation_round()
Compute permutation and lookup grand product polynomials and commitments.
BB_PROFILE void execute_relation_check_rounds()
Run Sumcheck resulting in u = (u_1,...,u_d) challenges and all evaluations at u being calculated.
bb::RelationParameters< FF > relation_parameters
void append_sumcheck_round_opening_claims()
Add the committed-sumcheck round univariate opening claims (3 per round: evaluations at 0,...
ECCVMLookupShortRelation< FF > LookupRelation
Simple verification key class for fixed-size circuits (ECCVM, Translator, AVM).
Definition flavor.hpp:104
HashType get_hash() const
Definition flavor.hpp:119
Unverified claim (C,r,v) for some witness polynomial p(X) such that.
Definition claim.hpp:55
static Polynomial random(size_t size, size_t start_index=0)
Fr evaluate(const Fr &z) const
Polynomial share() const
Polynomial p and an opening pair (r,v) such that p(r) = v.
Definition claim.hpp:36
Polynomial polynomial
Definition claim.hpp:41
A template class for a reference array. Behaves as if std::array<T&, N> was possible.
Definition ref_array.hpp:23
Shplonk Prover.
Definition shplonk.hpp:38
Shplonk Verifier.
Definition shplonk.hpp:367
A Curve-agnostic ZK protocol to prove inner products of small vectors.
std::array< bb::Polynomial< FF >, NUM_SMALL_IPA_COMMITMENTS > get_witness_polynomials() const
std::array< Commitment, NUM_SMALL_IPA_COMMITMENTS > get_witness_commitments() const
void prove()
Compute the derived witnesses and and commit to them.
The implementation of the sumcheck Prover for statements of the form for multilinear polynomials .
Definition sumcheck.hpp:304
A class designed to accept the ECCVM Transcript Polynomials, concatenate their masking terms in Lagra...
static void compute_opening_proof(const CK &ck, const TripleIpaInput &input, const std::shared_ptr< Transcript > &transcript)
#define vinfo(...)
Definition log.hpp:94
AluTraceBuilder builder
Definition alu.test.cpp:124
std::string label
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
void compute_logderivative_inverse(Polynomials &polynomials, auto &relation_parameters, const size_t start_index=0)
Compute the inverse polynomial I(X) required for logderivative lookups.
void add_scaled_batch(Polynomial< Fr > &dst, std::span< const PolynomialSpan< const Fr > > sources, std::span< const Fr > scalars)
Fused parallel batched add: dst += sum_i scalars[i] * sources[i].
constexpr auto SMALL_IPA_CLAIMS
The five SmallSubgroupIPA opening claims, in transcript order.
std::vector< Fr > batching_scalars(const Fr &challenge, const size_t count)
constexpr size_t NUM_SMALL_IPA_OPENING_CLAIMS
VerifierCommitmentKey< Curve > vk
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
RefArray< BF, NUM_TRANSLATION_EVALUATIONS > get_all()
std::array< std::string, NUM_TRANSLATION_EVALUATIONS > labels
static TripleIpaClaimData create(const CommitmentRange &unshifted_commitments, const EvaluationRange &unshifted_evaluations, const ShiftedCommitmentRange &shifted_source_commitments, const ShiftedSourceEvaluationRange &shifted_source_evaluations, const ShiftedEvaluationRange &shifted_evaluations, std::span< const Fr > multilinear_challenge, const Fr &rho, const OpeningClaim< Curve > &univariate)
Build the claim data shared by the ECCVM prover and verifier.
Prover-side TripleIPA input: claim data plus the witness polynomials needed to build the proof.
std::vector< Polynomial > shifted_polynomials
std::vector< Polynomial > unshifted_polynomials
TripleIpaClaimData< Curve > claim_data
constexpr field invert() const noexcept