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 const size_t log_circuit_size = static_cast<size_t>(verifier_instance->get_vk()->log_circuit_size);
34 log_circuit_size, static_cast<size_t>(1), "VK log_circuit_size is 0, which is invalid for any circuit");
35 return log_circuit_size;
36 }
37}
38
55template <typename Flavor, class IO>
57 Flavor,
58 IO>::split_rollup_proof(const Proof& combined_proof) const
59 requires(IO::HasIPA)
60{
61 // Validate combined proof is large enough to contain IPA proof
62 BB_ASSERT_GTE(combined_proof.size(),
63 IPA_PROOF_LENGTH,
64 "Combined rollup proof is too small to contain IPA proof. Expected at least " +
65 std::to_string(IPA_PROOF_LENGTH) + " elements, got " + std::to_string(combined_proof.size()));
66
67 // IPA proof is appended at the end (must match UltraProver_::export_proof())
68 const auto honk_proof_length = static_cast<std::ptrdiff_t>(combined_proof.size() - IPA_PROOF_LENGTH);
69
70 Proof honk_proof(combined_proof.begin(), combined_proof.begin() + honk_proof_length);
71 Proof ipa_proof(combined_proof.begin() + honk_proof_length, combined_proof.end());
72
73 return std::make_pair(honk_proof, ipa_proof);
74}
75
79template <typename Flavor, class IO>
80bool UltraVerifier_<Flavor, IO>::verify_ipa(const Proof& ipa_proof, const IPAClaim& ipa_claim)
81 requires(!IsRecursiveFlavor<Flavor> && IO::HasIPA)
82{
83 VerifierCommitmentKey<curve::Grumpkin> ipa_verification_key(1 << CONST_ECCVM_LOG_N);
84 ipa_transcript->load_proof(ipa_proof);
85 bool ipa_verified = IPA<curve::Grumpkin>::reduce_verify(ipa_verification_key, ipa_claim, ipa_transcript);
86 vinfo("UltraVerifier: IPA check: ", ipa_verified ? "true" : "false");
87
88 if (!ipa_verified) {
89 info("UltraVerifier: verification failed at IPA check");
90 }
91
92 return ipa_verified;
93}
94
100template <typename Flavor, class IO>
102 const typename UltraVerifier_<Flavor, IO>::Proof& proof)
103{
105 using ClaimBatcher = ClaimBatcher_<Curve>;
106 using ClaimBatch = ClaimBatcher::Batch;
107
108 transcript->load_proof(proof);
109
110 // Compute log_n first (needed for proof layout calculation)
111 const size_t log_n = compute_log_n();
112
113 // Guard against proof size underflow before deriving num_public_inputs
114 const size_t min_proof_size = ProofLength::Honk<Flavor>::LENGTH_WITHOUT_PUB_INPUTS(log_n);
115 BB_ASSERT_GTE(proof.size(),
116 min_proof_size,
117 "Proof size too small. Got " + std::to_string(proof.size()) + " field elements, but need at least " +
118 std::to_string(min_proof_size) + " (excluding public inputs) for log_n=" + std::to_string(log_n));
119
120 // Derive num_public_inputs from proof size using centralized proof layout
121 const size_t num_public_inputs = ProofLength::Honk<Flavor>::derive_num_public_inputs(proof.size(), log_n);
122
123 OinkVerifier<Flavor> oink_verifier{ verifier_instance, transcript, num_public_inputs };
124 oink_verifier.verify();
125
126 verifier_instance->gate_challenges =
127 transcript->template get_dyadic_powers_of_challenge<FF>("Sumcheck:gate_challenge", log_n);
128
129 // Get the witness commitments that the verifier needs to verify
130 VerifierCommitments commitments{ verifier_instance->get_vk(), verifier_instance->witness_commitments };
131 // For ZK flavors with Gemini masking: set gemini_masking_poly commitment from accumulator
132 if constexpr (flavor_has_gemini_masking<Flavor>()) {
133 commitments.gemini_masking_poly = verifier_instance->gemini_masking_commitment;
134 }
135
136 // Construct the sumcheck verifier
137 SumcheckVerifier<Flavor> sumcheck(transcript, verifier_instance->alpha, log_n);
138 // Receive commitments to Libra masking polynomials for ZKFlavors
139 std::array<Commitment, NUM_LIBRA_COMMITMENTS> libra_commitments = {};
140
141 if constexpr (Flavor::HasZK) {
142 libra_commitments[0] = transcript->template receive_from_prover<Commitment>("Libra:concatenation_commitment");
143 }
144 // Run the sumcheck verifier
145 SumcheckOutput<Flavor> sumcheck_output =
146 sumcheck.verify(verifier_instance->relation_parameters, verifier_instance->gate_challenges);
147 // Get the claimed evaluation of the Libra polynomials for ZKFlavors
148 if constexpr (Flavor::HasZK) {
149 libra_commitments[1] = transcript->template receive_from_prover<Commitment>("Libra:grand_sum_commitment");
150 libra_commitments[2] = transcript->template receive_from_prover<Commitment>("Libra:quotient_commitment");
151 }
152
153 ClaimBatcher claim_batcher{
154 .unshifted = ClaimBatch{ commitments.get_unshifted(), sumcheck_output.claimed_evaluations.get_unshifted() },
155 .shifted = ClaimBatch{ commitments.get_to_be_shifted(), sumcheck_output.claimed_evaluations.get_shifted() }
156 };
157
158 const Commitment one_commitment = [&]() {
159 if constexpr (IsRecursive) {
160 return Commitment::one(builder);
161 } else {
162 return Commitment::one();
163 }
164 }();
165
166 auto shplemini_output = Shplemini::compute_batch_opening_claim(claim_batcher,
167 sumcheck_output.challenge,
168 one_commitment,
169 transcript,
171 libra_commitments,
172 sumcheck_output.claimed_libra_evaluation);
173
174 // Build reduction result
175 ReductionResult result;
176 result.pairing_points = PCS::reduce_verify_batch_opening_claim(
177 std::move(shplemini_output.batch_opening_claim), transcript, Flavor::FINAL_PCS_MSM_SIZE(log_n));
178
179 bool consistency_checked = true;
180 if constexpr (Flavor::HasZK) {
181 consistency_checked = shplemini_output.consistency_checked;
182 vinfo("Ultra Verifier (with ZK): Libra evals consistency checked ", consistency_checked ? "true" : "false");
183 }
184 vinfo("Ultra Verifier sumcheck_verified: ", sumcheck_output.verified ? "true" : "false");
185 result.reduction_succeeded = sumcheck_output.verified && consistency_checked;
186
187 return result;
188}
189
197template <typename Flavor, class IO>
199 const typename UltraVerifier_<Flavor, IO>::Proof& proof)
200{
201 BB_BENCH_NAME("UltraVerifier::verify_proof");
202 // Step 1: Split proof if needed
203 Proof honk_proof;
204 Proof ipa_proof;
205 if constexpr (IO::HasIPA) {
206 std::tie(honk_proof, ipa_proof) = split_rollup_proof(proof);
207 } else {
208 honk_proof = proof;
209 }
210
211 // Step 2: Reduce to pairing check
212 auto [pcs_pairing_points, reduction_succeeded] = reduce_to_pairing_check(honk_proof);
213 vinfo("UltraVerifier: reduced to pairing check: ", reduction_succeeded ? "true" : "false");
214
215 if constexpr (!IsRecursive) {
216 if (!reduction_succeeded) {
217 info("UltraVerifier: verification failed at reduction step");
218 return Output{};
219 }
220 }
221
222 // Step 3: Process the reduction result and public inputs
223 IO inputs;
224 inputs.reconstruct_from_public(verifier_instance->public_inputs);
225
226 // Aggregate pairing points
227 PairingPoints pi_pairing_points = inputs.pairing_inputs;
228 pi_pairing_points.aggregate(pcs_pairing_points);
229
230 // Construct output (common to both native and recursive)
231 Output output(inputs);
232
233 if constexpr (IsRecursive) {
234 // Recursive: populate output for deferred verification
235 output.points_accumulator = std::move(pi_pairing_points);
236 if constexpr (IO::HasIPA) {
237 output.ipa_proof = ipa_proof;
238 }
239 } else {
240 // Perform pairing check
241 bool pairing_verified = pi_pairing_points.check();
242 vinfo("UltraVerifier: pairing check: ", pairing_verified ? "true" : "false");
243
244 if (!pairing_verified) {
245 info("UltraVerifier: verification failed at pairing check");
246 return Output{};
247 }
248
249 // Perform IPA verification if IO requires it
250 if constexpr (IO::HasIPA) {
251 if (!verify_ipa(ipa_proof, inputs.ipa_claim)) {
252 return Output{};
253 }
254 }
255
256 output.result = true;
257 }
258
259 return output;
260}
261
262// ===== NATIVE FLAVOR INSTANTIATIONS =====
263
268template class UltraVerifier_<UltraFlavor, RollupIO>; // Rollup uses UltraFlavor + RollupIO
272
273#ifdef STARKNET_GARAGA_FLAVORS
276#endif
277
278// ===== RECURSIVE FLAVOR INSTANTIATIONS =====
279
280// UltraRecursiveFlavor with DefaultIO
285
286// UltraZKRecursiveFlavor with DefaultIO
291
292// UltraRecursiveFlavor with RollupIO (replaces UltraRollupRecursiveFlavor)
294
295// MegaRecursiveFlavor with DefaultIO
300
301// MegaZKRecursiveFlavor with DefaultIO
306
307// MegaZKRecursiveFlavor with HidingKernelIO (Chonk)
310
311// MegaRecursiveFlavor with GoblinAvmIO
314
315} // namespace bb
#define BB_ASSERT_GTE(left, right,...)
Definition assert.hpp:128
#define BB_BENCH_NAME(name)
Definition bb_bench.hpp:264
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:804
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
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::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.
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)
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 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...