Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
batched_honk_translator_verifier.cpp
Go to the documentation of this file.
2
18
19namespace bb {
20
21template <typename Curve>
23 std::shared_ptr<MegaZKVKAndHash> mega_zk_vk_and_hash, std::shared_ptr<Transcript> transcript)
24 : mega_zk_vk_and_hash(std::move(mega_zk_vk_and_hash))
25 , transcript(std::move(transcript))
26{}
27
34template <typename Curve>
36 const Proof& mega_zk_proof)
37{
38 transcript->load_proof(mega_zk_proof);
39
40 if constexpr (IsRecursive) {
41 builder = mega_zk_proof.back().get_context();
42 }
43
44 mega_zk_verifier_instance = std::make_shared<MegaZKVerifierInstance>(mega_zk_vk_and_hash);
45
46 // Derive num_public_inputs from the Oink-only MegaZK proof.
47 const size_t num_public_inputs = mega_zk_proof.size() - ProofLength::Oink<MegaZKFlavorT>::LENGTH_WITHOUT_PUB_INPUTS;
48
49 OinkVerifier<MegaZKFlavorT> oink_verifier{ mega_zk_verifier_instance, transcript, num_public_inputs };
50 oink_verifier.verify(/*emit_alpha=*/false);
51
52 mega_zk_relation_parameters = mega_zk_verifier_instance->relation_parameters;
53
54 return OinkResult{
55 .public_inputs = mega_zk_verifier_instance->public_inputs,
56 .calldata_commitment = mega_zk_verifier_instance->witness_commitments.calldata,
57 .ecc_op_wires = mega_zk_verifier_instance->witness_commitments.get_ecc_op_wires().get_copy(),
58 };
59}
60
67template <typename Curve>
69 Curve>::verify_translator_oink(const Proof& joint_proof,
70 const TransBF& evaluation_input_x,
71 const TransBF& batching_challenge_v,
72 const TransBF& accumulated_result,
73 const std::array<Commitment, TranslatorFlavor::NUM_OP_QUEUE_WIRES>&
74 op_queue_wire_commitments)
75{
76 // Pass the full joint_proof to TranslatorVerifier. It calls
77 // transcript->load_proof(proof) in receive_pre_sumcheck(), loading everything
78 // (translator oink + joint sumcheck + joint PCS data) into the transcript buffer.
79 // The joint phases that follow will read the remaining data in order.
80 TranslatorVerifier_<TransFlavor> trans_verifier(transcript,
81 joint_proof,
82 evaluation_input_x,
83 batching_challenge_v,
84 accumulated_result,
85 op_queue_wire_commitments);
86 auto trans_commitments = trans_verifier.receive_pre_sumcheck();
87 translator_relation_parameters = trans_verifier.relation_parameters;
88 return trans_commitments;
89}
90
99{
100 static constexpr size_t JOINT_LOG_N = TranslatorFlavor::CONST_TRANSLATOR_LOG_N; // 17
101
102 // Draw joint alpha after all pre-sumcheck commitments from both circuits.
103 const FF alpha = transcript->template get_challenge<FF>("Sumcheck:alpha");
104
105 // Compute α^{K_H}.
106 FF alpha_power_KH = FF(1);
107 for (size_t i = 0; i < MegaZKFlavorT::NUM_SUBRELATIONS; i++) {
108 alpha_power_KH *= alpha;
109 }
110
111 // Subrelation separators.
112 auto mega_zk_alphas = initialize_relation_separator<FF, MegaZKFlavorT::NUM_SUBRELATIONS - 1>(alpha);
113 auto translator_alphas = initialize_relation_separator<FF, TransFlavor::NUM_SUBRELATIONS - 1>(alpha);
114
115 // Draw gate challenges.
116 std::vector<FF> gate_challenges(JOINT_LOG_N);
117 for (size_t i = 0; i < JOINT_LOG_N; i++) {
118 gate_challenges[i] = transcript->template get_challenge<FF>("Sumcheck:gate_challenge_" + std::to_string(i));
119 }
120
121 // Receive Libra masking commitments.
122 libra_commitments = {};
123 libra_commitments[0] = transcript->template receive_from_prover<Commitment>("Libra:concatenation_commitment");
124
125 // ZK correction: receive Libra:Sum and Libra:Challenge to set initial target sum.
126 FF libra_total_sum = transcript->template receive_from_prover<FF>("Libra:Sum");
127 libra_challenge = transcript->template get_challenge<FF>("Libra:Challenge");
128
129 // Initialise the joint sumcheck round verifier.
130 SumcheckVerifierRound<MegaZKFlavorT> joint_round(libra_total_sum * libra_challenge);
131
132 GateSeparatorPolynomial<FF> gate_sep(gate_challenges);
133
134 const size_t mega_zk_log_n = [&]() -> size_t {
135 if constexpr (IsRecursive) {
136 return static_cast<size_t>(static_cast<uint64_t>(mega_zk_vk_and_hash->vk->log_circuit_size.get_value()));
137 } else {
138 return static_cast<size_t>(mega_zk_vk_and_hash->vk->log_circuit_size);
139 }
140 }();
141
142 joint_challenge.clear();
143 joint_challenge.reserve(JOINT_LOG_N);
144
145 bool verified = true;
146
147 // ==================== Real rounds 0..mega_zk_log_n-1 ====================
148 for (size_t round_idx = 0; round_idx < mega_zk_log_n; round_idx++) {
149 joint_round.process_round(transcript, joint_challenge, gate_sep, FF(1), round_idx);
150 verified = verified && !joint_round.round_failed;
151
152 if (round_idx == TranslatorFlavor::LOG_MINI_CIRCUIT_SIZE - 1) {
153 TransFlavor::set_minicircuit_evaluations(
154 trans_evals,
155 transcript->template receive_from_prover<std::array<FF, TransFlavor::NUM_MINICIRCUIT_EVALUATIONS>>(
156 "Sumcheck:minicircuit_evaluations"));
157 }
158 }
159
160 // Receive MegaZK circuit evaluations: P_j(u_0,...,u_{d-1}) without the tau factor.
161 // These are obtained before virtual-round challenges are drawn, eliminating prover
162 // freedom in the zero-padded region.
163 {
164 auto transcript_evals =
165 transcript->template receive_from_prover<std::array<FF, MegaZKFlavorT::NUM_ALL_ENTITIES>>(
166 "Sumcheck:evaluations");
167 for (auto [eval, te] : zip_view(mega_zk_evals.get_all(), transcript_evals)) {
168 eval = te;
169 }
170 }
171
172 // ==================== Virtual rounds mega_zk_log_n..JOINT_LOG_N-1 ====================
173 for (size_t round_idx = mega_zk_log_n; round_idx < JOINT_LOG_N; round_idx++) {
174 joint_round.process_round(transcript, joint_challenge, gate_sep, FF(1), round_idx);
175 verified = verified && !joint_round.round_failed;
176
177 if (round_idx == TranslatorFlavor::LOG_MINI_CIRCUIT_SIZE - 1) {
178 TransFlavor::set_minicircuit_evaluations(
179 trans_evals,
180 transcript->template receive_from_prover<std::array<FF, TransFlavor::NUM_MINICIRCUIT_EVALUATIONS>>(
181 "Sumcheck:minicircuit_evaluations"));
182 }
183 }
184
185 // Extend MegaZK evaluations by zero: multiply each by τ = ∏_{k=d}^{N-1}(1-u_k).
186 // This is the verifier-determined zero-padding extension — the prover has no control over it.
187 {
188 FF tau = FF(1);
189 for (size_t k = mega_zk_log_n; k < JOINT_LOG_N; k++) {
190 tau *= (FF(1) - joint_challenge[k]);
191 }
192 for (auto& eval : mega_zk_evals.get_all()) {
193 eval *= tau;
194 }
195 }
196
197 // Receive translator evaluations (full-circuit subset, then complete from minicircuit + precomputed).
198 {
199 auto get_full_circuit_evals =
200 transcript->template receive_from_prover<std::array<FF, TransFlavor::NUM_FULL_CIRCUIT_EVALUATIONS>>(
201 "Sumcheck:evaluations_translator");
202 TransFlavor::complete_full_circuit_evaluations(
203 trans_evals, get_full_circuit_evals, std::span<const FF>(joint_challenge));
204 }
205
206 // Set OriginTag for recursive mode.
207 if constexpr (IsRecursive) {
208 const auto challenge_tag = joint_challenge.back().get_origin_tag();
209 for (auto& eval : mega_zk_evals.get_all()) {
210 eval.set_origin_tag(challenge_tag);
211 }
212 for (auto& eval : trans_evals.get_all()) {
213 eval.set_origin_tag(challenge_tag);
214 }
215 }
216
217 // -------------------------------------------------------------------------
218 // Compute joint full-relation purported value.
219 // -------------------------------------------------------------------------
220
221 GateSeparatorPolynomial<FF> final_gate_sep(gate_challenges, joint_challenge);
222
223 // MegaZK circuit FRV: evaluations now include the verifier-computed tau factor.
224 SumcheckVerifierRound<MegaZKFlavorT> mega_zk_frv_round;
225 FF frv_mega_zk = mega_zk_frv_round.compute_full_relation_purported_value(
226 mega_zk_evals, mega_zk_relation_parameters, final_gate_sep, mega_zk_alphas);
227
228 // Apply row-disabling polynomial: RDP_d = 1 - u_2·...·u_{d-1}.
229 FF rdp_d = [&]() {
230 if constexpr (IsRecursive) {
231 auto mega_zk_padding =
232 stdlib::compute_padding_indicator_array<Curve, JOINT_LOG_N>(mega_zk_vk_and_hash->vk->log_circuit_size);
233 return RowDisablingPolynomial<FF>::evaluate_at_challenge(joint_challenge, mega_zk_padding);
234 } else {
235 return RowDisablingPolynomial<FF>::evaluate_at_challenge(joint_challenge, mega_zk_log_n);
236 }
237 }();
238 frv_mega_zk *= rdp_d;
239
240 // Translator FRV (no row-disabling).
242 FF frv_translator = trans_frv_round.compute_full_relation_purported_value(
243 trans_evals, translator_relation_parameters, final_gate_sep, translator_alphas);
244
245 // Combine: FRV_joint = FRV_MZK + α^{K_H} · FRV_translator.
246 FF frv_joint = frv_mega_zk + alpha_power_KH * frv_translator;
247
248 // Receive and apply Libra correction.
249 libra_evaluation = transcript->template receive_from_prover<FF>("Libra:claimed_evaluation");
250
251 // Receive Libra grand-sum and quotient commitments.
252 libra_commitments[1] = transcript->template receive_from_prover<Commitment>("Libra:grand_sum_commitment");
253 libra_commitments[2] = transcript->template receive_from_prover<Commitment>("Libra:quotient_commitment");
254
255 if constexpr (IsRecursive) {
256 const auto challenge_tag = joint_challenge.back().get_origin_tag();
257 libra_evaluation.set_origin_tag(challenge_tag);
258 }
259
260 frv_joint += libra_evaluation * libra_challenge;
261
262 // Final sumcheck check.
263 bool final_check = joint_round.perform_final_verification(frv_joint);
264 return final_check && verified;
265}
266
272template <typename Curve>
274 bool sumcheck_verified, MegaZKVerifierCommitments& mega_zk_commitments, TransVerifierCommitments& trans_commitments)
275{
277 using ClaimBatcher = ClaimBatcher_<Curve>;
278 using ClaimBatch = typename ClaimBatcher::Batch;
279
280 static constexpr size_t JOINT_LOG_N = TranslatorFlavor::CONST_TRANSLATOR_LOG_N;
281
282 const Commitment one_commitment = [&]() {
283 if constexpr (IsRecursive) {
284 return Commitment::one(builder);
285 } else {
286 return Commitment::one();
287 }
288 }();
289
290 // Build joint claim batchers from both circuits' commitments and evaluations.
291 RefVector<Commitment> joint_unshifted_comms = mega_zk_commitments.get_unshifted();
292 RefVector<FF> joint_unshifted_evals = mega_zk_evals.get_unshifted();
293 RefVector<Commitment> joint_shifted_comms = mega_zk_commitments.get_to_be_shifted();
294 RefVector<FF> joint_shifted_evals = mega_zk_evals.get_shifted();
295
296 // Translator claim components.
298 trans_evals.get_groups_to_be_concatenated_shifted(), std::span<const FF>(joint_challenge));
299
300 auto trans_unshifted_comms = trans_commitments.get_pcs_unshifted();
301 auto trans_unshifted_evals = trans_evals.get_pcs_unshifted();
302 auto trans_shifted_comms = trans_commitments.get_pcs_to_be_shifted();
303 auto trans_pcs_shifted_evals = trans_evals.get_pcs_shifted();
304
305 // Extend joint RefVectors with translator entries.
306 for (auto& comm : trans_unshifted_comms) {
307 joint_unshifted_comms.push_back(comm);
308 }
309 for (auto& eval : trans_unshifted_evals) {
310 joint_unshifted_evals.push_back(eval);
311 }
312 for (auto& comm : trans_shifted_comms) {
313 joint_shifted_comms.push_back(comm);
314 }
315 for (auto& eval : trans_pcs_shifted_evals) {
316 joint_shifted_evals.push_back(eval);
317 }
318 for (auto& eval : concat_shift_evals) {
319 joint_shifted_evals.push_back(eval);
320 }
321
322 ClaimBatcher joint_claim_batcher{ .unshifted = ClaimBatch{ joint_unshifted_comms, joint_unshifted_evals },
323 .shifted = ClaimBatch{ joint_shifted_comms, joint_shifted_evals } };
324
325 // All-ones padding for the joint Shplemini call (row-disabling already applied in FRV).
326 std::vector<FF> joint_padding(JOINT_LOG_N, FF(1));
327
328 auto [opening_claim, consistency_checked] = MegaZKShplemini::compute_batch_opening_claim(joint_padding,
329 joint_claim_batcher,
330 joint_challenge,
331 one_commitment,
332 transcript,
333 REPEATED_COMMITMENTS,
334 libra_commitments,
335 libra_evaluation);
336
337 auto pairing_points = MegaZKFlavorT::PCS::reduce_verify_batch_opening_claim(std::move(opening_claim), transcript);
338
339 return { pairing_points, sumcheck_verified && consistency_checked };
340}
341
342template <typename Curve>
344 const Proof& joint_proof,
345 const TransBF& evaluation_input_x,
346 const TransBF& batching_challenge_v,
347 const TransBF& accumulated_result,
348 const std::array<Commitment, TranslatorFlavor::NUM_OP_QUEUE_WIRES>& op_queue_wire_commitments)
349{
350 // Reconstruct MegaZK commitments from the stored verifier instance.
351 MegaZKVerifierCommitments mega_zk_commitments{ mega_zk_verifier_instance->get_vk(),
352 mega_zk_verifier_instance->witness_commitments };
353 mega_zk_commitments.gemini_masking_poly = mega_zk_verifier_instance->gemini_masking_commitment;
354
355 auto trans_commitments = verify_translator_oink(
356 joint_proof, evaluation_input_x, batching_challenge_v, accumulated_result, op_queue_wire_commitments);
357 bool sumcheck_verified = verify_joint_sumcheck();
358 return verify_joint_pcs(sumcheck_verified, mega_zk_commitments, trans_commitments);
359}
360
361// Explicit instantiations.
364
365} // namespace bb
bb::field< bb::Bn254FrParams > FF
Definition field.cpp:24
Verifier for the batched MegaZK circuit + translator sumcheck and PCS.
std::conditional_t< IsRecursive, stdlib::Proof< UltraCircuitBuilder >, HonkProof > Proof
BatchedHonkTranslatorVerifier_(std::shared_ptr< MegaZKVKAndHash > mega_zk_vk_and_hash, std::shared_ptr< Transcript > transcript)
Construct the batched verifier with minimal state.
typename TransFlavor::VerifierCommitments TransVerifierCommitments
ReductionResult verify_joint_pcs(bool sumcheck_verified, MegaZKVerifierCommitments &mega_zk_commitments, TransVerifierCommitments &trans_commitments)
Execute the joint Shplemini / KZG PCS reduction.
ReductionResult verify(const Proof &joint_proof, const TransBF &evaluation_input_x, const TransBF &batching_challenge_v, const TransBF &accumulated_result, const std::array< Commitment, TranslatorFlavor::NUM_OP_QUEUE_WIRES > &op_queue_wire_commitments)
Phase 2: Verify translator Oink + joint sumcheck + joint PCS.
bool verify_joint_sumcheck()
Verify the joint 17-round sumcheck.
OinkResult verify_mega_zk_oink(const Proof &mega_zk_proof)
Phase 1: Verify the MegaZK Oink phase on the shared transcript.
typename MegaZKFlavorT::VerifierCommitments MegaZKVerifierCommitments
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.
A template class for a reference vector. Behaves as if std::vector<T&> was possible.
void push_back(T &element)
Implementation of the Sumcheck Verifier Round.
void process_round(const std::shared_ptr< Transcript > &transcript, std::vector< FF > &multivariate_challenge, bb::GateSeparatorPolynomial< FF > &gate_separators, const FF &padding_indicator, size_t round_idx)
Process a single sumcheck round: receive univariate from transcript, verify sum, generate challenge.
bool perform_final_verification(const FF &full_honk_purported_value)
Perform final verification: check that the computed target sum matches the full relation evaluation....
FF compute_full_relation_purported_value(const ClaimedEvaluations &purported_evaluations, const bb::RelationParameters< FF > &relation_parameters, const bb::GateSeparatorPolynomial< FF > &gate_separators, const SubrelationSeparators &alphas)
Compute the full relation purported value.
static constexpr size_t CONST_TRANSLATOR_LOG_N
static constexpr size_t LOG_MINI_CIRCUIT_SIZE
static std::array< FFType, NUM_CONCATENATED_POLYS > reconstruct_concatenated_evaluations(const std::vector< RefVector< FFType > > &groups, std::span< const FFType > challenge)
Reconstruct concatenated polynomial evaluations from individual wire evaluations using the Lagrange b...
Translator verifier class that verifies the proof of the Translator circuit.
VerifierCommitments receive_pre_sumcheck()
Load translator proof and run the pre-sumcheck (Oink-like) phase on the shared transcript.
AluTraceBuilder builder
Definition alu.test.cpp:124
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
std::array< FF, N > initialize_relation_separator(const FF &alpha)
Definition sumcheck.hpp:890
STL namespace.
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.
Implementation of the methods for the -polynomials used in in Sumcheck.
Computes Oink proof length from flavor traits.
static FF evaluate_at_challenge(std::vector< FF > multivariate_challenge, const size_t log_circuit_size)
Compute the evaluation of at the sumcheck challenge.