Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
eccvm_verifier.cpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: Complete, auditors: [Sergei], commit: }
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
16
17namespace bb {
18
23template <typename Flavor>
25{
26 BB_BENCH_NAME("ECCVMVerifier::reduce");
27 RelationParameters<FF> relation_parameters;
28 univariate_opening_claims.clear();
29
30 // Load proof into transcript
31 transcript->load_proof(proof);
32
33 // Fiat-Shamir the vk hash (computed in constructor)
34 transcript->add_to_hash_buffer("vk_hash", vk_hash);
35 vinfo("ECCVM vk hash: ", vk_hash);
36
37 VerifierCommitments commitments{ key };
38 CommitmentLabels commitment_labels;
39
40 // Receive Gemini masking polynomial commitment (for ZK-PCS)
41 commitments.gemini_masking_poly = transcript->template receive_from_prover<Commitment>("Gemini:masking_poly_comm");
42 for (auto [comm, label] : zip_view(commitments.get_wires(), commitment_labels.get_wires())) {
43 comm = transcript->template receive_from_prover<Commitment>(label);
44 }
45
46 // Get challenge for sorted list batching and wire four memory records
47 auto [beta, gamma] = transcript->template get_challenges<FF>(std::array<std::string, 2>{ "beta", "gamma" });
48
49 auto beta_sqr = beta * beta;
50 auto beta_quartic = beta_sqr * beta_sqr;
51 relation_parameters.gamma = gamma;
52 relation_parameters.beta = beta;
53 relation_parameters.beta_sqr = beta_sqr;
54 relation_parameters.beta_cube = beta_sqr * beta;
55 relation_parameters.beta_quartic = beta_quartic;
56 auto first_term_tag = beta_quartic; // FIRST_TERM_TAG (= 1) * beta_quartic
57 relation_parameters.eccvm_set_permutation_delta = (gamma + first_term_tag) * (gamma + beta_sqr + first_term_tag) *
58 (gamma + beta_sqr + beta_sqr + first_term_tag) *
59 (gamma + beta_sqr + beta_sqr + beta_sqr + first_term_tag);
60 relation_parameters.eccvm_set_permutation_delta = relation_parameters.eccvm_set_permutation_delta.invert();
61
62 // Get commitment to permutation and lookup grand products
63 commitments.lookup_inverses =
64 transcript->template receive_from_prover<Commitment>(commitment_labels.lookup_inverses);
65 commitments.z_perm = transcript->template receive_from_prover<Commitment>(commitment_labels.z_perm);
66
67 // Each linearly independent subrelation contribution is multiplied by `alpha^i`, where
68 // i = 0, ..., NUM_SUBRELATIONS- 1.
69 const FF alpha = transcript->template get_challenge<FF>("Sumcheck:alpha");
70
71 // Execute Sumcheck Verifier
72 SumcheckVerifier<Flavor> sumcheck(transcript, alpha, CONST_ECCVM_LOG_N);
73
74 std::vector<FF> gate_challenges =
75 transcript->template get_dyadic_powers_of_challenge<FF>("Sumcheck:gate_challenge", CONST_ECCVM_LOG_N);
76
77 // Receive commitments to Libra masking polynomials
78 std::array<Commitment, NUM_SMALL_IPA_COMMITMENTS> libra_commitments = {};
79
80 libra_commitments[0] = transcript->template receive_from_prover<Commitment>("Libra:concatenation_commitment");
81 auto sumcheck_output = sumcheck.verify(relation_parameters, gate_challenges);
82
83 libra_commitments[1] = transcript->template receive_from_prover<Commitment>("Libra:grand_sum_commitment");
84 libra_commitments[2] = transcript->template receive_from_prover<Commitment>("Libra:quotient_commitment");
85
86 const bool consistency_checked = append_libra_opening_claims(
87 libra_commitments, sumcheck_output.challenge, sumcheck_output.claimed_libra_evaluation);
88
89 std::vector<Commitment> translation_commitments = { commitments.transcript_op,
90 commitments.transcript_Px,
91 commitments.transcript_Py,
92 commitments.transcript_z1,
93 commitments.transcript_z2 };
94
95 // Collect every univariate opening claim in transcript order; a single Shplonk reduction turns them into the
96 // univariate input to the TripleIPA.
97 append_translation_opening_claims(translation_commitments);
98 append_sumcheck_round_opening_claims(sumcheck_output.round_univariate_commitments,
99 sumcheck_output.round_univariate_evaluations,
100 sumcheck_output.challenge);
101 append_pow_masking_opening_claim();
102
103 const OpeningClaim<Curve> univariate_opening_claim = reduce_univariate_opening_claims();
104 ReductionResult result{ .triple_ipa_claim =
105 compute_triple_ipa_claim(commitments, sumcheck_output, univariate_opening_claim) };
106
107 bool sumcheck_verified = sumcheck_output.verified;
108 vinfo("ECCVM Verifier: sumcheck verified: ", sumcheck_verified);
109 vinfo("ECCVM Verifier: consistency checked: ", consistency_checked);
110 vinfo("ECCVM Verifier: translation masking consistency checked: ", translation_masking_consistency_checked);
111
112 compute_accumulated_result();
113 result.reduction_succeeded = sumcheck_verified && consistency_checked && translation_masking_consistency_checked;
114 return result;
115}
116
117template <typename Flavor>
119 const std::array<Commitment, NUM_SMALL_IPA_COMMITMENTS>& libra_commitments,
120 const std::vector<FF>& multilinear_challenge,
121 const FF& claimed_libra_evaluation)
122{
123 const FF libra_evaluation_challenge =
124 transcript->template get_challenge<FF>("Libra:small_ipa_evaluation_challenge");
125 const auto libra_opening_claims = make_small_ipa_verifier_opening_claims<Curve>(
126 libra_commitments, libra_evaluation_challenge, "Libra:", transcript);
127
129 for (size_t idx = 0; idx < NUM_SMALL_IPA_OPENING_CLAIMS; ++idx) {
130 libra_evaluations[idx] = libra_opening_claims[idx].opening_pair.evaluation;
131 }
132
133 univariate_opening_claims.insert(
134 univariate_opening_claims.end(), libra_opening_claims.begin(), libra_opening_claims.end());
135
137 libra_evaluations, libra_evaluation_challenge, multilinear_challenge, claimed_libra_evaluation);
138}
139
149template <typename Flavor>
150void ECCVMVerifier_<Flavor>::append_translation_opening_claims(const std::vector<Commitment>& translation_commitments)
151{
152 // Used to capture the batched evaluation of unmasked `translation_polynomials` while preserving ZK
153 using SmallIPA = SmallSubgroupIPAVerifier<Curve>;
154
155 // Initialize SmallSubgroupIPA structures
156 SmallSubgroupIPACommitments<Commitment> small_ipa_commitments;
157
158 // Get a commitment to M + Z_H * R, where M is a concatenation of the masking terms of
159 // `translation_polynomials`, Z_H = X^{|H|} - 1, and R is a random degree 2 polynomial
160 small_ipa_commitments.concatenated =
161 transcript->template receive_from_prover<Commitment>("Translation:concatenated_masking_term_commitment");
162
163 // Get a challenge to evaluate `translation_polynomials` as univariates
164 evaluation_challenge_x = transcript->template get_challenge<FF>("Translation:evaluation_challenge_x");
165
166 // Populate the translation evaluations {`op(x)`, `Px(x)`, `Py(x)`, `z1(x)`, `z2(x)`} to be batched
167 for (auto [eval, label] : zip_view(translation_evaluations.get_all(), translation_evaluations.labels)) {
168 eval = transcript->template receive_from_prover<FF>(label);
169 }
170
171 // Get the batching challenge for commitments and evaluations
172 batching_challenge_v = transcript->template get_challenge<FF>("Translation:batching_challenge_v");
173
174 // Get the value ∑ mᵢ(x) ⋅ vⁱ
175 translation_masking_term_eval = transcript->template receive_from_prover<FF>("Translation:masking_term_eval");
176
177 // Receive commitments to the SmallSubgroupIPA witnesses that are computed once x and v are available
178 small_ipa_commitments.grand_sum =
179 transcript->template receive_from_prover<Commitment>("Translation:grand_sum_commitment");
180 small_ipa_commitments.quotient =
181 transcript->template receive_from_prover<Commitment>("Translation:quotient_commitment");
182
183 // Get a challenge for the evaluations of the concatenated masking term G, grand sum A, its shift, and grand sum
184 // identity quotient Q
185 const FF small_ipa_evaluation_challenge =
186 transcript->template get_challenge<FF>("Translation:small_ipa_evaluation_challenge");
187
188 // Build the five SmallSubgroupIPA verifier opening claims via the shared helper. The boundary slot pins A(1) = 0;
189 // soundness comes from the Shplonk batched opening rejecting any committed [A] that does not evaluate to 0 there.
190 const auto small_ipa_claims = make_small_ipa_verifier_opening_claims<Curve>(
191 small_ipa_commitments.as_array(), small_ipa_evaluation_challenge, "Translation:", transcript);
192
194 std::ranges::copy(small_ipa_claims, translation_claims.begin());
196 for (size_t idx = 0; idx < NUM_SMALL_IPA_OPENING_CLAIMS; idx++) {
197 small_ipa_evaluations[idx] = small_ipa_claims[idx].opening_pair.evaluation;
198 }
199
200 // Check Grand Sum Identity at r
201
202 translation_masking_consistency_checked =
203 SmallIPA::check_eccvm_evaluations_consistency(small_ipa_evaluations,
204 small_ipa_evaluation_challenge,
205 evaluation_challenge_x,
206 batching_challenge_v,
207 translation_masking_term_eval);
208
209 // Compute the batched commitment and batched evaluation for the univariate opening claim
210 const std::vector<FF> batching_challenges = batching_scalars(batching_challenge_v, NUM_TRANSLATION_EVALUATIONS);
211 std::vector<FF> translation_evaluation_values;
212 translation_evaluation_values.reserve(NUM_TRANSLATION_EVALUATIONS);
213 for (const auto& eval : translation_evaluations.get_all()) {
214 translation_evaluation_values.emplace_back(eval);
215 }
216 const FF batched_translation_evaluation = batch_evaluations<Curve>(
217 std::span<const FF>(translation_evaluation_values), std::span<const FF>(batching_challenges));
218 const Commitment batched_commitment = batch_commitments<Curve>(std::span<const Commitment>(translation_commitments),
219 std::span<const FF>(batching_challenges));
220
221 // Place the batched translation univariate claim after the SmallSubgroupIPA opening claims.
222 translation_claims[NUM_SMALL_IPA_OPENING_CLAIMS] = { { evaluation_challenge_x, batched_translation_evaluation },
223 batched_commitment };
224 univariate_opening_claims.insert(
225 univariate_opening_claims.end(), translation_claims.begin(), translation_claims.end());
226}
227
229{
230 const Commitment pow_mask_commitment =
231 transcript->template receive_from_prover<Commitment>("TripleIPA:pow_mask_commitment");
232 const FF pow_mask_challenge = transcript->template get_challenge<FF>("TripleIPA:pow_mask_challenge");
233 const FF pow_mask_evaluation = transcript->template receive_from_prover<FF>("TripleIPA:pow_mask_evaluation");
234 univariate_opening_claims.push_back({ { pow_mask_challenge, pow_mask_evaluation }, pow_mask_commitment });
235}
236
237template <typename Flavor>
239{
240 using Shplonk = ShplonkVerifier_<Curve>;
241 return Shplonk::reduce_verification(pcs_g1_identity, univariate_opening_claims, transcript);
242}
243
244template <typename Flavor>
246 VerifierCommitments& commitments,
247 SumcheckOutput<Flavor>& sumcheck_output,
248 const OpeningClaim<Curve>& univariate_opening_claim)
249{
250 const FF rho = transcript->template get_challenge<FF>("TripleIPA:rho");
251 const auto triple_ipa_data =
252 TripleIPA::TripleIpaClaimData::create(commitments.get_unshifted(),
253 sumcheck_output.claimed_evaluations.get_unshifted(),
254 commitments.get_to_be_shifted(),
255 sumcheck_output.claimed_evaluations.get_to_be_shifted(),
256 sumcheck_output.claimed_evaluations.get_shifted(),
257 sumcheck_output.challenge,
258 rho,
259 univariate_opening_claim);
260 return triple_ipa_data.batch();
261}
262
263// Compute the accumulated result from translation evaluations
264// This is the value that Translator will use in its relations
265// Formula: accumulated_result = (op + v*Px + v²*Py + v³*z1 + v⁴*z2 - masking_term) / x^5
266// Translation poly data starts at coefficient TRACE_OFFSET,
267// introducing an x^TRACE_OFFSET factor. The division by x^(1+TRACE_OFFSET) accounts for both the
268// shiftable offset (x) and the trace offset.
270{
271 FF v = batching_challenge_v;
272 FF v_squared = v * v;
273 FF v_cubed = v_squared * v;
274 FF v_fourth = v_cubed * v;
275
276 // OriginTag false positive: translation_masking_term_eval is bound by the masking term
277 // commitments (fixed before batching_challenge_v) and batching_challenge_v itself.
278 if constexpr (IsRecursive) {
279 translation_masking_term_eval.set_origin_tag(batching_challenge_v.get_origin_tag());
280 }
281
282 FF batched_eval_minus_masking = translation_evaluations.op + v * translation_evaluations.Px +
283 v_squared * translation_evaluations.Py + v_cubed * translation_evaluations.z1 +
284 v_fourth * translation_evaluations.z2 - translation_masking_term_eval;
285
286 // x^(1 + TRACE_OFFSET) accounts for the shiftable offset (x) and trace data offset (x^TRACE_OFFSET)
287 FF x_power = evaluation_challenge_x;
288 for (size_t i = 0; i < Flavor::TRACE_OFFSET; i++) {
289 x_power *= evaluation_challenge_x;
290 }
291 accumulated_result = batched_eval_minus_masking / x_power;
292}
293
294template <typename Flavor>
296 const std::vector<Commitment>& sumcheck_round_commitments,
297 const std::vector<std::array<FF, 3>>& sumcheck_round_evaluations,
298 const std::vector<FF>& multilinear_challenge)
299{
300 static constexpr size_t NUM_COMMITTED_SUMCHECK_CLAIMS_PER_ROUND = 3;
301 univariate_opening_claims.reserve(univariate_opening_claims.size() +
302 multilinear_challenge.size() * NUM_COMMITTED_SUMCHECK_CLAIMS_PER_ROUND);
303
304 for (size_t idx = 0; idx < multilinear_challenge.size(); ++idx) {
306 FF(1),
307 multilinear_challenge[idx] };
308 for (size_t eval_idx = 0; eval_idx < NUM_COMMITTED_SUMCHECK_CLAIMS_PER_ROUND; ++eval_idx) {
309 univariate_opening_claims.push_back(
310 { { evaluation_points[eval_idx], sumcheck_round_evaluations[idx][eval_idx] },
311 sumcheck_round_commitments[idx] });
312 }
313 }
314}
315
316// Explicit template instantiations
317template class ECCVMVerifier_<ECCVMFlavor>;
319
320} // namespace bb
bb::field< bb::Bn254FrParams > FF
Definition field.cpp:24
#define BB_BENCH_NAME(name)
Definition bb_bench.hpp:264
A container for commitment labels.
static constexpr size_t NUM_TRANSLATION_OPENING_CLAIMS
static constexpr size_t TRACE_OFFSET
Unified ECCVM verifier class for both native and recursive verification.
void append_pow_masking_opening_claim()
TripleIpaClaim compute_triple_ipa_claim(VerifierCommitments &commitments, SumcheckOutput< Flavor > &sumcheck_output, const OpeningClaim< Curve > &univariate_opening_claim)
ReductionResult reduce_to_triple_ipa_claim()
Reduce the ECCVM proof to a compact TripleIPA verifier claim.
typename TripleIPA::TripleIpaClaim TripleIpaClaim
void append_sumcheck_round_opening_claims(const std::vector< Commitment > &sumcheck_round_commitments, const std::vector< std::array< FF, 3 > > &sumcheck_round_evaluations, const std::vector< FF > &multilinear_challenge)
bool append_libra_opening_claims(const std::array< Commitment, NUM_SMALL_IPA_COMMITMENTS > &libra_commitments, const std::vector< FF > &multilinear_challenge, const FF &claimed_libra_evaluation)
OpeningClaim< Curve > reduce_univariate_opening_claims()
Flavor::Commitment Commitment
void append_translation_opening_claims(const std::vector< Commitment > &translation_commitments)
To link the ECCVM Transcript wires op, Px, Py, z1, and z2 to the accumulator computed by the translat...
Unverified claim (C,r,v) for some witness polynomial p(X) such that.
Definition claim.hpp:55
Shplonk Verifier.
Definition shplonk.hpp:367
Verifies the consistency of polynomial evaluations provided by the the prover.
static bool check_libra_evaluations_consistency(const std::array< FF, NUM_SMALL_IPA_OPENING_CLAIMS > &libra_evaluations, const FF &gemini_evaluation_challenge, const std::vector< FF > &multilinear_challenge, const FF &inner_product_eval_claim)
A method required by ZKSumcheck. The challenge polynomial is concatenated from the powers of the sumc...
Implementation of the sumcheck Verifier for statements of the form for multilinear polynomials .
Definition sumcheck.hpp:802
SumcheckOutput< Flavor > verify(const bb::RelationParameters< FF > &relation_parameters, const std::vector< FF > &gate_challenges)
The Sumcheck verification method. First it extracts round univariate, checks sum (the sumcheck univar...
Definition sumcheck.hpp:859
#define vinfo(...)
Definition log.hpp:94
std::string label
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
std::vector< Fr > batching_scalars(const Fr &challenge, const size_t count)
constexpr size_t NUM_SMALL_IPA_OPENING_CLAIMS
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
This file contains part of the logic for the Origin Tag mechanism that tracks the use of in-circuit p...
Result of reducing ECCVM proof to a compact TripleIPA claim.
Container for parameters used by the grand product (permutation, lookup) Honk relations.
Holds commitments to [G], [A], [Q]. Code that needs a per-claim commitment must index as_array() via ...
std::array< Commitment, NUM_SMALL_IPA_COMMITMENTS > as_array() const
Contains the evaluations of multilinear polynomials at the challenge point . These are computed by S...
ClaimedEvaluations claimed_evaluations
std::vector< FF > challenge
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.
VectorField result