Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
ultra_verifier.cpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: Completed, auditors: [Sergei], commit: }
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
19
20namespace bb {
21
27template <typename Flavor, class IO> size_t UltraVerifier_<Flavor, IO>::compute_log_n() const
28{
29 if constexpr (Flavor::USE_PADDING) {
30 return static_cast<size_t>(Flavor::VIRTUAL_LOG_N);
31 } else {
32 // Non-padded: use actual circuit size from VK (native only)
33 return static_cast<size_t>(verifier_instance->get_vk()->log_circuit_size);
34 }
35}
36
44template <typename Flavor, class IO>
46{
47 // - Non-ZK flavors: all 1s (no masking needed)
48 // - ZK without padding: all 1s (log_n == log_circuit_size, no padded region)
49 // - ZK with padding: computed to mask padded rounds (1s for real, 0s for padding)
50 std::vector<FF> padding_indicator_array(log_n, FF{ 1 });
51 if constexpr (Flavor::HasZK && Flavor::USE_PADDING) {
52 auto vk_ptr = verifier_instance->get_vk();
53 if constexpr (IsRecursive) {
54 // Recursive: use in-circuit computation via Lagrange polynomials
55 // Note: Must be called after OinkVerifier so log_circuit_size is properly tagged
56 padding_indicator_array =
57 stdlib::compute_padding_indicator_array<Curve, Flavor::VIRTUAL_LOG_N>(vk_ptr->log_circuit_size);
58 } else {
59 // Native: simple loop comparison
60 const size_t log_circuit_size = static_cast<size_t>(vk_ptr->log_circuit_size);
61 for (size_t idx = 0; idx < log_n; idx++) {
62 padding_indicator_array[idx] = (idx < log_circuit_size) ? FF{ 1 } : FF{ 0 };
63 }
64 }
65 }
66
67 return padding_indicator_array;
68}
69
86template <typename Flavor, class IO>
88 Flavor,
89 IO>::split_rollup_proof(const Proof& combined_proof) const
90 requires(IO::HasIPA)
91{
92 // Validate combined proof is large enough to contain IPA proof
93 BB_ASSERT_GTE(combined_proof.size(),
94 IPA_PROOF_LENGTH,
95 "Combined rollup proof is too small to contain IPA proof. Expected at least " +
96 std::to_string(IPA_PROOF_LENGTH) + " elements, got " + std::to_string(combined_proof.size()));
97
98 // IPA proof is appended at the end (must match UltraProver_::export_proof())
99 const auto honk_proof_length = static_cast<std::ptrdiff_t>(combined_proof.size() - IPA_PROOF_LENGTH);
100
101 Proof honk_proof(combined_proof.begin(), combined_proof.begin() + honk_proof_length);
102 Proof ipa_proof(combined_proof.begin() + honk_proof_length, combined_proof.end());
103
104 return std::make_pair(honk_proof, ipa_proof);
105}
106
110template <typename Flavor, class IO>
111bool UltraVerifier_<Flavor, IO>::verify_ipa(const Proof& ipa_proof, const IPAClaim& ipa_claim)
112 requires(!IsRecursiveFlavor<Flavor> && IO::HasIPA)
113{
114 VerifierCommitmentKey<curve::Grumpkin> ipa_verification_key(1 << CONST_ECCVM_LOG_N);
115 ipa_transcript->load_proof(ipa_proof);
116 bool ipa_verified = IPA<curve::Grumpkin>::reduce_verify(ipa_verification_key, ipa_claim, ipa_transcript);
117 vinfo("UltraVerifier: IPA check: ", ipa_verified ? "true" : "false");
118
119 if (!ipa_verified) {
120 info("UltraVerifier: verification failed at IPA check");
121 }
122
123 return ipa_verified;
124}
125
131template <typename Flavor, class IO>
133 const typename UltraVerifier_<Flavor, IO>::Proof& proof)
134{
136 using ClaimBatcher = ClaimBatcher_<Curve>;
137 using ClaimBatch = ClaimBatcher::Batch;
138
139 transcript->load_proof(proof);
140
141 // Compute log_n first (needed for proof layout calculation)
142 const size_t log_n = compute_log_n();
143
144 // Guard against proof size underflow before deriving num_public_inputs
145 const size_t min_proof_size = ProofLength::Honk<Flavor>::LENGTH_WITHOUT_PUB_INPUTS(log_n);
146 BB_ASSERT_GTE(proof.size(),
147 min_proof_size,
148 "Proof size too small. Got " + std::to_string(proof.size()) + " field elements, but need at least " +
149 std::to_string(min_proof_size) + " (excluding public inputs) for log_n=" + std::to_string(log_n));
150
151 // Derive num_public_inputs from proof size using centralized proof layout
152 const size_t num_public_inputs = ProofLength::Honk<Flavor>::derive_num_public_inputs(proof.size(), log_n);
153
154 OinkVerifier<Flavor> oink_verifier{ verifier_instance, transcript, num_public_inputs };
155 oink_verifier.verify();
156
157 // Compute padding indicator array AFTER OinkVerifier so VK fields are properly tagged
158 auto padding_indicator_array = compute_padding_indicator_array(log_n);
159 verifier_instance->gate_challenges =
160 transcript->template get_dyadic_powers_of_challenge<FF>("Sumcheck:gate_challenge", log_n);
161
162 // Get the witness commitments that the verifier needs to verify
163 VerifierCommitments commitments{ verifier_instance->get_vk(), verifier_instance->witness_commitments };
164 // For ZK flavors: set gemini_masking_poly commitment from accumulator
165 if constexpr (Flavor::HasZK) {
166 commitments.gemini_masking_poly = verifier_instance->gemini_masking_commitment;
167 }
168
169 // Construct the sumcheck verifier
170 SumcheckVerifier<Flavor> sumcheck(transcript, verifier_instance->alpha, log_n);
171 // Receive commitments to Libra masking polynomials for ZKFlavors
172 std::array<Commitment, NUM_LIBRA_COMMITMENTS> libra_commitments = {};
173
174 if constexpr (Flavor::HasZK) {
175 libra_commitments[0] = transcript->template receive_from_prover<Commitment>("Libra:concatenation_commitment");
176 }
177 // Run the sumcheck verifier
178 SumcheckOutput<Flavor> sumcheck_output = sumcheck.verify(
179 verifier_instance->relation_parameters, verifier_instance->gate_challenges, padding_indicator_array);
180 // Get the claimed evaluation of the Libra polynomials for ZKFlavors
181 if constexpr (Flavor::HasZK) {
182 libra_commitments[1] = transcript->template receive_from_prover<Commitment>("Libra:grand_sum_commitment");
183 libra_commitments[2] = transcript->template receive_from_prover<Commitment>("Libra:quotient_commitment");
184 }
185
186 ClaimBatcher claim_batcher{
187 .unshifted = ClaimBatch{ commitments.get_unshifted(), sumcheck_output.claimed_evaluations.get_unshifted() },
188 .shifted = ClaimBatch{ commitments.get_to_be_shifted(), sumcheck_output.claimed_evaluations.get_shifted() }
189 };
190
191 const Commitment one_commitment = [&]() {
192 if constexpr (IsRecursive) {
193 return Commitment::one(builder);
194 } else {
195 return Commitment::one();
196 }
197 }();
198
199 auto shplemini_output = Shplemini::compute_batch_opening_claim(padding_indicator_array,
200 claim_batcher,
201 sumcheck_output.challenge,
202 one_commitment,
203 transcript,
205 libra_commitments,
206 sumcheck_output.claimed_libra_evaluation);
207
208 // Build reduction result
209 ReductionResult result;
210 result.pairing_points = PCS::reduce_verify_batch_opening_claim(
211 std::move(shplemini_output.batch_opening_claim), transcript, Flavor::FINAL_PCS_MSM_SIZE(log_n));
212
213 bool consistency_checked = true;
214 if constexpr (Flavor::HasZK) {
215 consistency_checked = shplemini_output.consistency_checked;
216 vinfo("Ultra Verifier (with ZK): Libra evals consistency checked ", consistency_checked ? "true" : "false");
217 }
218 vinfo("Ultra Verifier sumcheck_verified: ", sumcheck_output.verified ? "true" : "false");
219 result.reduction_succeeded = sumcheck_output.verified && consistency_checked;
220
221 return result;
222}
223
231template <typename Flavor, class IO>
233 const typename UltraVerifier_<Flavor, IO>::Proof& proof)
234{
235 BB_BENCH_NAME("UltraVerifier::verify_proof");
236 // Step 1: Split proof if needed
237 Proof honk_proof;
238 Proof ipa_proof;
239 if constexpr (IO::HasIPA) {
240 std::tie(honk_proof, ipa_proof) = split_rollup_proof(proof);
241 } else {
242 honk_proof = proof;
243 }
244
245 // Step 2: Reduce to pairing check
246 auto [pcs_pairing_points, reduction_succeeded] = reduce_to_pairing_check(honk_proof);
247 vinfo("UltraVerifier: reduced to pairing check: ", reduction_succeeded ? "true" : "false");
248
249 if constexpr (!IsRecursive) {
250 if (!reduction_succeeded) {
251 info("UltraVerifier: verification failed at reduction step");
252 return Output{};
253 }
254 }
255
256 // Step 3: Process the reduction result and public inputs
257 IO inputs;
258 inputs.reconstruct_from_public(verifier_instance->public_inputs);
259
260 // Aggregate pairing points
261 PairingPoints pi_pairing_points = inputs.pairing_inputs;
262 pi_pairing_points.aggregate(pcs_pairing_points);
263
264 // Construct output (common to both native and recursive)
265 Output output(inputs);
266
267 if constexpr (IsRecursive) {
268 // Recursive: populate output for deferred verification
269 output.points_accumulator = std::move(pi_pairing_points);
270 if constexpr (IO::HasIPA) {
271 output.ipa_proof = ipa_proof;
272 }
273 } else {
274 // Perform pairing check
275 bool pairing_verified = pi_pairing_points.check();
276 vinfo("UltraVerifier: pairing check: ", pairing_verified ? "true" : "false");
277
278 if (!pairing_verified) {
279 info("UltraVerifier: verification failed at pairing check");
280 return Output{};
281 }
282
283 // Perform IPA verification if IO requires it
284 if constexpr (IO::HasIPA) {
285 if (!verify_ipa(ipa_proof, inputs.ipa_claim)) {
286 return Output{};
287 }
288 }
289
290 output.result = true;
291 }
292
293 return output;
294}
295
296// ===== NATIVE FLAVOR INSTANTIATIONS =====
297
302template class UltraVerifier_<UltraFlavor, RollupIO>; // Rollup uses UltraFlavor + RollupIO
306
307#ifdef STARKNET_GARAGA_FLAVORS
310#endif
311
312// ===== RECURSIVE FLAVOR INSTANTIATIONS =====
313
314// UltraRecursiveFlavor with DefaultIO
319
320// UltraZKRecursiveFlavor with DefaultIO
325
326// UltraRecursiveFlavor with RollupIO (replaces UltraRollupRecursiveFlavor)
328
329// MegaRecursiveFlavor with DefaultIO
334
335// MegaZKRecursiveFlavor with DefaultIO
340
341// MegaZKRecursiveFlavor with HidingKernelIO (Chonk)
344
345// MegaRecursiveFlavor with GoblinAvmIO
348
349} // namespace bb
#define BB_ASSERT_GTE(left, right,...)
Definition assert.hpp:128
#define BB_BENCH_NAME(name)
Definition bb_bench.hpp:225
static constexpr bool HasZK
static constexpr bool USE_PADDING
static constexpr RepeatedCommitmentsData REPEATED_COMMITMENTS
IPA (inner product argument) commitment scheme class.
Definition ipa.hpp:86
Verifier counterpart to OinkProver: receives witness commitments, computes relation parameters,...
void verify(bool emit_alpha=true)
Receive witness commitments, compute relation parameters, and prepare for Sumcheck.
Unverified claim (C,r,v) for some witness polynomial p(X) such that.
Definition claim.hpp:55
Implementation of the sumcheck Verifier for statements of the form for multilinear polynomials .
Definition sumcheck.hpp:747
SumcheckOutput< Flavor > verify(const bb::RelationParameters< FF > &relation_parameters, const std::vector< FF > &gate_challenges, const std::vector< FF > &padding_indicator_array)
The Sumcheck verification method. First it extracts round univariate, checks sum (the sumcheck univar...
Definition sumcheck.hpp:803
bool verify_ipa(const Proof &ipa_proof, const IPAClaim &ipa_claim)
Verify IPA proof for rollup circuits (native verifier only)
ReductionResult reduce_to_pairing_check(const Proof &proof)
Reduce ultra proof to verification claims (works for both native and recursive)
typename Transcript::Proof Proof
std::conditional_t< IsRecursive, stdlib::recursion::PairingPoints< Curve >, bb::PairingPoints< Curve > > PairingPoints
size_t compute_log_n() const
Compute log_n based on flavor.
std::vector< FF > compute_padding_indicator_array(size_t log_n) const
Compute padding indicator array based on flavor configuration.
std::conditional_t< IsRecursive, stdlib::recursion::honk::UltraRecursiveVerifierOutput< Builder >, UltraVerifierOutput< Flavor > > Output
typename Flavor::VerifierCommitments VerifierCommitments
typename Flavor::Commitment Commitment
Output verify_proof(const Proof &proof)
Perform ultra verification.
typename Flavor::FF FF
Representation of the Grumpkin Verifier Commitment Key inside a bn254 circuit.
Manages the data that is propagated on the public inputs of an application/function circuit.
The data that is propagated on the public inputs of the inner GoblinAvmRecursiveVerifier circuit.
Manages the data that is propagated on the public inputs of a hiding kernel circuit.
The data that is propagated on the public inputs of a rollup circuit.
#define info(...)
Definition log.hpp:93
#define vinfo(...)
Definition log.hpp:94
AluTraceBuilder builder
Definition alu.test.cpp:124
ECCVMFlavor Flavor
AvmProvingInputs inputs
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
std::string to_string(bb::avm2::ValueTag tag)
For a small integer N = virtual_log_n and a given witness x = log_n, compute in-circuit an indicator_...
Logic to support batching opening claims for unshifted and shifted polynomials in Shplemini.
static constexpr size_t LENGTH_WITHOUT_PUB_INPUTS(size_t log_n)
static constexpr size_t derive_num_public_inputs(size_t proof_size, size_t log_n)
Derive num_public_inputs from proof size.
Contains the evaluations of multilinear polynomials at the challenge point . These are computed by S...
ClaimedEvaluations claimed_evaluations
std::vector< FF > challenge
Result of reducing ultra proof to pairing points check. Contains pairing points and the aggregate res...