Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
recursive_verifier.cpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: Planned, auditors: [Federico], commit: }
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
8
9#include <algorithm>
10#include <cstddef>
11#include <memory>
12#include <numeric>
13
24
25namespace bb::avm2 {
26
27AvmRecursiveVerifier::AvmRecursiveVerifier(Builder& builder, const std::shared_ptr<Transcript>& transcript)
29 , transcript(transcript)
30{
32
34 key->fix_witness();
35
36 auto native_vk_hash = native_vk->hash();
37 vk_hash = FF::from_witness(&builder, native_vk_hash);
38 vk_hash.fix_witness();
39}
40
41// Evaluate the given public input column over the multivariate challenge points
43 const std::vector<FF>& challenges)
44{
45 auto coefficients = SharedShiftedVirtualZeroesArray<FF>{
46 .start_ = 0,
47 .end_ = points.size(),
48 .virtual_size_ = MAX_AVM_TRACE_SIZE,
49 .backing_memory_ = BackingMemory<FF>::allocate(points.size()),
50 };
51
52 memcpy(
53 static_cast<void*>(coefficients.data()), static_cast<const void*>(points.data()), sizeof(FF) * points.size());
54
55 return generic_evaluate_mle<FF>(challenges, coefficients);
56}
57
59 const HonkProof& proof, const std::vector<std::vector<fr>>& public_inputs_vec_nt)
60{
61 StdlibProof stdlib_proof(builder, proof);
62
63 std::vector<std::vector<FF>> public_inputs_ct;
64 public_inputs_ct.reserve(public_inputs_vec_nt.size());
65
66 for (const auto& vec : public_inputs_vec_nt) {
67 std::vector<FF> vec_ct;
68 vec_ct.reserve(vec.size());
69 for (const auto& el : vec) {
70 vec_ct.push_back(stdlib::witness_t<Builder>(&builder, el));
71 }
72 public_inputs_ct.push_back(vec_ct);
73 }
74
75 return verify_proof(stdlib_proof, public_inputs_ct);
76}
77
78// TODO(#991): (see https://github.com/AztecProtocol/barretenberg/issues/991)
80 const stdlib::Proof<Builder>& stdlib_proof, const std::vector<std::vector<FF>>& public_inputs)
81{
82 using Curve = typename Flavor::Curve;
83 using PCS = typename Flavor::PCS;
85 using RelationParams = RelationParameters<typename Flavor::FF>;
87 using ClaimBatcher = ClaimBatcher_<Curve>;
88 using ClaimBatch = ClaimBatcher::Batch;
89
90 if (public_inputs.size() != AVM_NUM_PUBLIC_INPUT_COLUMNS) {
91 throw_or_abort("AvmRecursiveVerifier::verify_proof: public inputs size mismatch");
92 }
93 for (const auto& public_input : public_inputs) {
94 if (public_input.size() != AVM_PUBLIC_INPUTS_COLUMNS_MAX_LENGTH) {
95 throw_or_abort("AvmRecursiveVerifier::verify_proof: public input size mismatch");
96 }
97 }
98
99 transcript->load_proof(stdlib_proof);
100
101 transcript->add_to_hash_buffer("avm_vk_hash", vk_hash);
102
103 info("AVM vk hash in recursive verifier: ", vk_hash.get_value());
104
105 RelationParams relation_parameters;
106 VerifierCommitments commitments{ key };
107
108 // Add public inputs to transcript for Fiat-Shamir
109 for (size_t i = 0; i < AVM_NUM_PUBLIC_INPUT_COLUMNS; i++) {
110 for (size_t j = 0; j < public_inputs[i].size(); j++) {
111 transcript->add_to_hash_buffer("public_input_" + std::to_string(i) + "_" + std::to_string(j),
112 public_inputs[i][j]);
113 }
114 }
115 // Get commitments to VM wires
116 for (auto [comm, label] : zip_view(commitments.get_wires(), commitments.get_wires_labels())) {
117 comm = transcript->template receive_from_prover<Commitment>(label);
118 }
119
120 auto [beta, gamma] = transcript->template get_challenges<FF>(std::array<std::string, 2>{ "beta", "gamma" });
121 relation_parameters.beta = beta;
122 relation_parameters.gamma = gamma;
123
124 // Get commitments to inverses
125 for (auto [label, commitment] : zip_view(commitments.get_derived_labels(), commitments.get_derived())) {
126 commitment = transcript->template receive_from_prover<Commitment>(label);
127 }
128
129 std::vector<FF> padding_indicator_array(MAX_AVM_TRACE_LOG_SIZE, FF(1));
130
131 // Multiply each linearly independent subrelation contribution by `alpha^i` for i = 0, ..., NUM_SUBRELATIONS - 1.
132 const FF alpha = transcript->template get_challenge<FF>("Sumcheck:alpha");
133
134 SumcheckVerifier<Flavor> sumcheck(transcript, alpha, MAX_AVM_TRACE_LOG_SIZE);
135
136 std::vector<FF> gate_challenges =
137 transcript->template get_dyadic_powers_of_challenge<FF>("Sumcheck:gate_challenge", MAX_AVM_TRACE_LOG_SIZE);
138
139 // No need to constrain that sumcheck_verified is true as this is guaranteed by the implementation of
140 // when called over a "circuit field" types.
141 SumcheckOutput<Flavor> output = sumcheck.verify(relation_parameters, gate_challenges, padding_indicator_array);
142 vinfo("verified sumcheck: ", (output.verified));
143
144 using C = ColumnAndShifts;
146 output.claimed_evaluations.get(C::public_inputs_cols_0_),
147 output.claimed_evaluations.get(C::public_inputs_cols_1_),
148 output.claimed_evaluations.get(C::public_inputs_cols_2_),
149 output.claimed_evaluations.get(C::public_inputs_cols_3_),
150 };
151
152 // Validate public inputs match the claimed evaluations
153 for (size_t i = 0; i < AVM_NUM_PUBLIC_INPUT_COLUMNS; i++) {
154 FF public_input_evaluation = evaluate_public_input_column(public_inputs[i], output.challenge);
155 public_input_evaluation.assert_equal(claimed_evaluations[i],
156 format("public_input_evaluation failed at column ", i));
157 }
158
159 // Batch commitments and evaluations using short scalars to reduce ECCVM circuit size
160 auto unshifted_comms = commitments.get_unshifted();
161 auto unshifted_evals = output.claimed_evaluations.get_unshifted();
162 auto shifted_comms = commitments.get_to_be_shifted();
163 auto shifted_evals = output.claimed_evaluations.get_shifted();
164
165 // Generate batching challenge labels
166 // Note: We get N-1 challenges for N unshifted commitments (first commitment has implicit coefficient 1)
167 std::vector<std::string> unshifted_batching_challenge_labels;
168 unshifted_batching_challenge_labels.reserve(unshifted_comms.size() - 1);
169 for (size_t idx = 0; idx < unshifted_comms.size() - 1; idx++) {
170 unshifted_batching_challenge_labels.push_back("rho_" + std::to_string(idx));
171 }
172 std::vector<std::string> shifted_batching_challenge_labels;
173 shifted_batching_challenge_labels.reserve(shifted_comms.size());
174 for (size_t idx = 0; idx < shifted_comms.size(); idx++) {
175 shifted_batching_challenge_labels.push_back("rho_" + std::to_string(unshifted_comms.size() - 1 + idx));
176 }
177
178 // Get short (128-bit) batching challenges from transcript
179 auto unshifted_challenges = transcript->template get_challenges<FF>(unshifted_batching_challenge_labels);
180 auto shifted_challenges = transcript->template get_challenges<FF>(shifted_batching_challenge_labels);
181
182 // Batch commitments: first commitment has coefficient 1, rest are batched with challenges
183 Commitment squashed_unshifted =
184 unshifted_comms[0] +
185 Commitment::batch_mul(
186 std::vector<Commitment>(unshifted_comms.begin() + 1, unshifted_comms.end()), unshifted_challenges, 128);
187
188 Commitment squashed_shifted = Commitment::batch_mul(
189 std::vector<Commitment>(shifted_comms.begin(), shifted_comms.end()), shifted_challenges, 128);
190
191 // Batch evaluations: compute inner product with first eval as initial value for unshifted
192 FF squashed_unshifted_eval = std::inner_product(
193 unshifted_challenges.begin(), unshifted_challenges.end(), unshifted_evals.begin() + 1, unshifted_evals[0]);
194
195 FF squashed_shifted_eval =
196 std::inner_product(shifted_challenges.begin(), shifted_challenges.end(), shifted_evals.begin(), FF(0));
197
198 // Execute Shplemini rounds with squashed claims
199 ClaimBatcher squashed_claim_batcher{ .unshifted = ClaimBatch{ .commitments = RefVector(squashed_unshifted),
200 .evaluations = RefVector(squashed_unshifted_eval) },
201 .shifted = ClaimBatch{ .commitments = RefVector(squashed_shifted),
202 .evaluations = RefVector(squashed_shifted_eval) } };
203 auto opening_claim =
204 Shplemini::compute_batch_opening_claim(
205 padding_indicator_array, squashed_claim_batcher, output.challenge, Commitment::one(&builder), transcript)
206 .batch_opening_claim;
207
208 PairingPoints pairing_points(PCS::reduce_verify_batch_opening_claim(std::move(opening_claim), transcript));
209
210 if (builder.failed()) {
211 info("AVM Recursive verifier builder failed with error: ", builder.err());
212 }
213
215
216 return pairing_points;
217}
218
220{
221 BB_ASSERT(is_verification_complete, "Transcript can only be hashed after verification is complete");
222 return Transcript::hash_avm_transcript(transcript, stdlib_proof);
223};
224
225} // namespace bb::avm2
#define BB_ASSERT(expression,...)
Definition assert.hpp:70
#define AVM_NUM_PUBLIC_INPUT_COLUMNS
#define AVM_PUBLIC_INPUTS_COLUMNS_MAX_LENGTH
IPA (inner product argument) commitment scheme class.
Definition ipa.hpp:92
static stdlib::field_t< Builder > hash_avm_transcript(Builder &builder, const stdlib::Proof< Builder > &stdlib_proof, const std::vector< std::vector< stdlib::field_t< Builder > > > &public_inputs)
Construct a transcript replicating the operations performed on the AVM transcript during proof verifi...
NativeFlavor::VerifierCommitments_< Commitment, VerificationKey > VerifierCommitments
AvmRecursiveFlavorSettings::Curve Curve
AvmRecursiveFlavorSettings::PCS PCS
AvmRecursiveVerifier(Builder &builder, const std::shared_ptr< Transcript > &transcript=std::make_shared< Transcript >())
std::shared_ptr< Transcript > transcript
typename Flavor::VerifierCommitments VerifierCommitments
FF hash_avm_transcript(const StdlibProof &stdlib_proof)
Hash the transcript after verification is complete to produce a hash of the public inputs and proofs ...
std::shared_ptr< VerificationKey > key
stdlib::recursion::PairingPoints< Curve > PairingPoints
FF evaluate_public_input_column(const std::vector< FF > &points, const std::vector< FF > &challenges)
PairingPoints verify_proof(const HonkProof &proof, const std::vector< std::vector< fr > > &public_inputs_vec_nt)
typename Flavor::CircuitBuilder Builder
typename Flavor::Commitment Commitment
static constexpr std::array< Commitment, VerificationKey::NUM_PRECOMPUTED_COMMITMENTS > get_all()
A simple wrapper around a vector of stdlib field elements representing a proof.
Definition proof.hpp:19
std::string format(Args... args)
Definition log.hpp:23
#define info(...)
Definition log.hpp:93
#define vinfo(...)
Definition log.hpp:94
AluTraceBuilder builder
Definition alu.test.cpp:124
constexpr std::size_t MAX_AVM_TRACE_SIZE
Definition constants.hpp:13
constexpr std::size_t MAX_AVM_TRACE_LOG_SIZE
Definition constants.hpp:12
ColumnAndShifts
Definition columns.hpp:34
std::vector< fr > HonkProof
Definition proof.hpp:15
RefVector(T &, Ts &...) -> RefVector< T >
Deduction guide for the RefVector class. Allows for RefVector {a, b, c} without explicit template par...
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_...
static BackingMemory allocate(size_t size)
A shared pointer array template that represents a virtual array filled with zeros up to virtual_size_...
size_t start_
The starting index of the memory-backed range.
Logic to support batching opening claims for unshifted, shifted and interleaved polynomials in Shplem...
Container for parameters used by the grand product (permutation, lookup) Honk relations.
An object storing two EC points that represent the inputs to a pairing check.
void throw_or_abort(std::string const &err)