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
18
19namespace bb {
20
26template <typename Flavor, class IO> size_t UltraVerifier_<Flavor, IO>::compute_log_n() const
27{
28 if constexpr (Flavor::USE_PADDING) {
29 return static_cast<size_t>(Flavor::VIRTUAL_LOG_N);
30 } else {
31 // Non-padded: use actual circuit size from VK (native only)
32 return static_cast<size_t>(verifier_instance->get_vk()->log_circuit_size);
33 }
34}
35
43template <typename Flavor, class IO>
45{
46 // - Non-ZK flavors: all 1s (no masking needed)
47 // - ZK without padding: all 1s (log_n == log_circuit_size, no padded region)
48 // - ZK with padding: computed to mask padded rounds (1s for real, 0s for padding)
49 std::vector<FF> padding_indicator_array(log_n, FF{ 1 });
50 if constexpr (Flavor::HasZK && Flavor::USE_PADDING) {
51 auto vk_ptr = verifier_instance->get_vk();
52 if constexpr (IsRecursive) {
53 // Recursive: use in-circuit computation via Lagrange polynomials
54 // Note: Must be called after OinkVerifier so log_circuit_size is properly tagged
55 padding_indicator_array =
56 stdlib::compute_padding_indicator_array<Curve, Flavor::VIRTUAL_LOG_N>(vk_ptr->log_circuit_size);
57 } else {
58 // Native: simple loop comparison
59 const size_t log_circuit_size = static_cast<size_t>(vk_ptr->log_circuit_size);
60 for (size_t idx = 0; idx < log_n; idx++) {
61 padding_indicator_array[idx] = (idx < log_circuit_size) ? FF{ 1 } : FF{ 0 };
62 }
63 }
64 }
65
66 return padding_indicator_array;
67}
68
85template <typename Flavor, class IO>
87 Flavor,
88 IO>::split_rollup_proof(const Proof& combined_proof) const
89 requires(IO::HasIPA)
90{
91 // Validate combined proof is large enough to contain IPA proof
92 BB_ASSERT_GTE(combined_proof.size(),
93 IPA_PROOF_LENGTH,
94 "Combined rollup proof is too small to contain IPA proof. Expected at least " +
95 std::to_string(IPA_PROOF_LENGTH) + " elements, got " + std::to_string(combined_proof.size()));
96
97 // IPA proof is appended at the end (must match UltraProver_::export_proof())
98 const auto honk_proof_length = static_cast<std::ptrdiff_t>(combined_proof.size() - IPA_PROOF_LENGTH);
99
100 Proof honk_proof(combined_proof.begin(), combined_proof.begin() + honk_proof_length);
101 Proof ipa_proof(combined_proof.begin() + honk_proof_length, combined_proof.end());
102
103 return std::make_pair(honk_proof, ipa_proof);
104}
105
109template <typename Flavor, class IO>
110bool UltraVerifier_<Flavor, IO>::verify_ipa(const Proof& ipa_proof, const IPAClaim& ipa_claim)
111 requires(!IsRecursiveFlavor<Flavor> && IO::HasIPA)
112{
113 VerifierCommitmentKey<curve::Grumpkin> ipa_verification_key(1 << CONST_ECCVM_LOG_N);
114 ipa_transcript->load_proof(ipa_proof);
115 bool ipa_verified = IPA<curve::Grumpkin>::reduce_verify(ipa_verification_key, ipa_claim, ipa_transcript);
116 vinfo("UltraVerifier: IPA check: ", ipa_verified ? "true" : "false");
117
118 if (!ipa_verified) {
119 info("UltraVerifier: verification failed at IPA check");
120 }
121
122 return ipa_verified;
123}
124
130template <typename Flavor, class IO>
132 const typename UltraVerifier_<Flavor, IO>::Proof& proof)
133{
135 using ClaimBatcher = ClaimBatcher_<Curve>;
136 using ClaimBatch = ClaimBatcher::Batch;
137
138 transcript->load_proof(proof);
139
140 // Compute log_n first (needed for proof layout calculation)
141 const size_t log_n = compute_log_n();
142
143 // Guard against proof size underflow before deriving num_public_inputs
144 const size_t min_proof_size = ProofLength::Honk<Flavor>::LENGTH_WITHOUT_PUB_INPUTS(log_n);
145 BB_ASSERT_GTE(proof.size(),
146 min_proof_size,
147 "Proof size too small. Got " + std::to_string(proof.size()) + " field elements, but need at least " +
148 std::to_string(min_proof_size) + " (excluding public inputs) for log_n=" + std::to_string(log_n));
149
150 // Derive num_public_inputs from proof size using centralized proof layout
151 const size_t num_public_inputs = ProofLength::Honk<Flavor>::derive_num_public_inputs(proof.size(), log_n);
152
153 OinkVerifier<Flavor> oink_verifier{ verifier_instance, transcript, num_public_inputs };
154 oink_verifier.verify();
155
156 // Compute padding indicator array AFTER OinkVerifier so VK fields are properly tagged
157 auto padding_indicator_array = compute_padding_indicator_array(log_n);
158 verifier_instance->gate_challenges =
159 transcript->template get_dyadic_powers_of_challenge<FF>("Sumcheck:gate_challenge", log_n);
160
161 // Get the witness commitments that the verifier needs to verify
162 VerifierCommitments commitments{ verifier_instance->get_vk(), verifier_instance->witness_commitments };
163 // For ZK flavors: set gemini_masking_poly commitment from accumulator
164 if constexpr (Flavor::HasZK) {
165 commitments.gemini_masking_poly = verifier_instance->gemini_masking_commitment;
166 }
167
168 // Construct the sumcheck verifier
169 SumcheckVerifier<Flavor> sumcheck(transcript, verifier_instance->alpha, log_n);
170 // Receive commitments to Libra masking polynomials for ZKFlavors
172
173 if constexpr (Flavor::HasZK) {
174 libra_commitments[0] = transcript->template receive_from_prover<Commitment>("Libra:concatenation_commitment");
175 }
176 // Run the sumcheck verifier
177 SumcheckOutput<Flavor> sumcheck_output = sumcheck.verify(
178 verifier_instance->relation_parameters, verifier_instance->gate_challenges, padding_indicator_array);
179 // Get the claimed evaluation of the Libra polynomials for ZKFlavors
180 if constexpr (Flavor::HasZK) {
181 libra_commitments[1] = transcript->template receive_from_prover<Commitment>("Libra:grand_sum_commitment");
182 libra_commitments[2] = transcript->template receive_from_prover<Commitment>("Libra:quotient_commitment");
183 }
184
185 ClaimBatcher claim_batcher{
186 .unshifted = ClaimBatch{ commitments.get_unshifted(), sumcheck_output.claimed_evaluations.get_unshifted() },
187 .shifted = ClaimBatch{ commitments.get_to_be_shifted(), sumcheck_output.claimed_evaluations.get_shifted() }
188 };
189
190 const Commitment one_commitment = [&]() {
191 if constexpr (IsRecursive) {
192 return Commitment::one(builder);
193 } else {
194 return Commitment::one();
195 }
196 }();
197
198 auto shplemini_output = Shplemini::compute_batch_opening_claim(padding_indicator_array,
199 claim_batcher,
200 sumcheck_output.challenge,
201 one_commitment,
202 transcript,
204 libra_commitments,
205 sumcheck_output.claimed_libra_evaluation);
206
207 // Build reduction result
208 ReductionResult result;
209 result.pairing_points = PCS::reduce_verify_batch_opening_claim(
210 std::move(shplemini_output.batch_opening_claim), transcript, Flavor::FINAL_PCS_MSM_SIZE(log_n));
211
212 bool consistency_checked = true;
213 if constexpr (Flavor::HasZK) {
214 consistency_checked = shplemini_output.consistency_checked;
215 vinfo("Ultra Verifier (with ZK): Libra evals consistency checked ", consistency_checked ? "true" : "false");
216 }
217 vinfo("Ultra Verifier sumcheck_verified: ", sumcheck_output.verified ? "true" : "false");
218 result.reduction_succeeded = sumcheck_output.verified && consistency_checked;
219
220 return result;
221}
222
230template <typename Flavor, class IO>
232 const typename UltraVerifier_<Flavor, IO>::Proof& proof)
233{
234 // Step 1: Split proof if needed
235 Proof honk_proof;
236 Proof ipa_proof;
237 if constexpr (IO::HasIPA) {
238 std::tie(honk_proof, ipa_proof) = split_rollup_proof(proof);
239 } else {
240 honk_proof = proof;
241 }
242
243 // Step 2: Reduce to pairing check
244 auto [pcs_pairing_points, reduction_succeeded] = reduce_to_pairing_check(honk_proof);
245 vinfo("UltraVerifier: reduced to pairing check: ", reduction_succeeded ? "true" : "false");
246
247 if constexpr (!IsRecursive) {
248 if (!reduction_succeeded) {
249 info("UltraVerifier: verification failed at reduction step");
250 return Output{};
251 }
252 }
253
254 // Step 3: Process the reduction result and public inputs
255 IO inputs;
256 inputs.reconstruct_from_public(verifier_instance->public_inputs);
257
258 // Aggregate pairing points
259 PairingPoints pi_pairing_points = inputs.pairing_inputs;
260 pi_pairing_points.aggregate(pcs_pairing_points);
261
262 // Construct output (common to both native and recursive)
263 Output output(inputs);
264
265 if constexpr (IsRecursive) {
266 // Recursive: populate output for deferred verification
267 output.points_accumulator = std::move(pi_pairing_points);
268 if constexpr (IO::HasIPA) {
269 output.ipa_proof = ipa_proof;
270 }
271 } else {
272 // Perform pairing check
273 bool pairing_verified = pi_pairing_points.check();
274 vinfo("UltraVerifier: pairing check: ", pairing_verified ? "true" : "false");
275
276 if (!pairing_verified) {
277 info("UltraVerifier: verification failed at pairing check");
278 return Output{};
279 }
280
281 // Perform IPA verification if IO requires it
282 if constexpr (IO::HasIPA) {
283 if (!verify_ipa(ipa_proof, inputs.ipa_claim)) {
284 return Output{};
285 }
286 }
287
288 output.result = true;
289 }
290
291 return output;
292}
293
294// ===== NATIVE FLAVOR INSTANTIATIONS =====
295
300template class UltraVerifier_<UltraFlavor, RollupIO>; // Rollup uses UltraFlavor + RollupIO
304
305#ifdef STARKNET_GARAGA_FLAVORS
308#endif
309
310// ===== RECURSIVE FLAVOR INSTANTIATIONS =====
311
312// UltraRecursiveFlavor with DefaultIO
317
318// UltraZKRecursiveFlavor with DefaultIO
323
324// UltraRecursiveFlavor with RollupIO (replaces UltraRollupRecursiveFlavor)
326
327// MegaRecursiveFlavor with DefaultIO
332
333// MegaZKRecursiveFlavor with DefaultIO
338
339// MegaZKRecursiveFlavor with HidingKernelIO (Chonk)
342
343// MegaRecursiveFlavor with GoblinAvmIO
346
347} // namespace bb
#define BB_ASSERT_GTE(left, right,...)
Definition assert.hpp:128
static constexpr bool HasZK
static constexpr bool USE_PADDING
static constexpr RepeatedCommitmentsData REPEATED_COMMITMENTS
IPA (inner product argument) commitment scheme class.
Definition ipa.hpp:85
Verifier counterpart to OinkProver: receives witness commitments, computes relation parameters,...
void verify()
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...