Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
recursive_verifier.cpp
Go to the documentation of this file.
2
3#include <algorithm>
4#include <cstddef>
5#include <memory>
6#include <numeric>
7
18
19namespace bb::avm2 {
20
21// TODO(#15892): Remove vk argument from all functions once its fixed.
22AvmRecursiveVerifier::AvmRecursiveVerifier(Builder& builder, const std::shared_ptr<VerificationKey>& vkey)
24 , key(vkey)
25{
26 // TODO(#15892): Uncomment this when we make the AVM vk and vk
27 // hash fixed.
28 // key->fix_witness();
29 // compute the vk hash from the native vk fields
30 // this->vk_hash.fix_witness();
31}
32
33// Evaluate the given public input column over the multivariate challenge points
35 const std::vector<FF>& challenges)
36{
37 auto coefficients = SharedShiftedVirtualZeroesArray<FF>{
38 .start_ = 0,
39 .end_ = points.size(),
40 .virtual_size_ = MAX_AVM_TRACE_SIZE,
41 .backing_memory_ = BackingMemory<FF>::allocate(points.size()),
42 };
43
44 memcpy(
45 static_cast<void*>(coefficients.data()), static_cast<const void*>(points.data()), sizeof(FF) * points.size());
46
47 return generic_evaluate_mle<FF>(challenges, coefficients);
48}
49
51 const HonkProof& proof, const std::vector<std::vector<fr>>& public_inputs_vec_nt)
52{
53 StdlibProof stdlib_proof(builder, proof);
54
55 std::vector<std::vector<FF>> public_inputs_ct;
56 public_inputs_ct.reserve(public_inputs_vec_nt.size());
57
58 for (const auto& vec : public_inputs_vec_nt) {
59 std::vector<FF> vec_ct;
60 vec_ct.reserve(vec.size());
61 for (const auto& el : vec) {
62 vec_ct.push_back(stdlib::witness_t<Builder>(&builder, el));
63 }
64 public_inputs_ct.push_back(vec_ct);
65 }
66
67 return verify_proof(stdlib_proof, public_inputs_ct);
68}
69
70// TODO(#991): (see https://github.com/AztecProtocol/barretenberg/issues/991)
71// TODO(#14234)[Unconditional PIs validation]: rename stdlib_proof_with_pi_flag to stdlib_proof
73 const stdlib::Proof<Builder>& stdlib_proof_with_pi_flag, const std::vector<std::vector<FF>>& public_inputs)
74{
75 using Curve = typename Flavor::Curve;
76 using PCS = typename Flavor::PCS;
78 using RelationParams = RelationParameters<typename Flavor::FF>;
79 using Shplemini = ShpleminiVerifier_<Curve>;
80 using ClaimBatcher = ClaimBatcher_<Curve>;
81 using ClaimBatch = ClaimBatcher::Batch;
82 using stdlib::bool_t;
83
84 // TODO(#14234)[Unconditional PIs validation]: Remove the next 3 lines
85 StdlibProof stdlib_proof = stdlib_proof_with_pi_flag;
86 bool_t<Builder> pi_validation = !bool_t<Builder>(stdlib_proof.at(0));
87 // TODO(https://github.com/AztecProtocol/aztec-packages/issues/16716) Origin Tag security mechanism is screaming
88 // that there is a free witness affecting proof verificaton. Because it is and this bool allows completely disabling
89 // public input logic. So this has to be removed in the future.
90 pi_validation.unset_free_witness_tag();
91 stdlib_proof.erase(stdlib_proof.begin());
92
93 if (public_inputs.size() != AVM_NUM_PUBLIC_INPUT_COLUMNS) {
94 throw_or_abort("AvmRecursiveVerifier::verify_proof: public inputs size mismatch");
95 }
96 for (const auto& public_input : public_inputs) {
97 if (public_input.size() != AVM_PUBLIC_INPUTS_COLUMNS_MAX_LENGTH) {
98 throw_or_abort("AvmRecursiveVerifier::verify_proof: public input size mismatch");
99 }
100 }
101
102 transcript->load_proof(stdlib_proof);
103
104 // TODO(#15892): Fiat-Shamir the vk hash by uncommenting the add_to_hash_buffer.
105 // transcript->add_to_hash_buffer("avm_vk_hash", vk_hash);
106 // TODO(https://github.com/AztecProtocol/aztec-packages/issues/16716) For now we are unsetting the free witness tags
107 // to stop triggering the Origin Tag security mechanism, but the problem is that the VK is not hashed.
108 for (auto& comm : key->get_all()) {
109 comm.unset_free_witness_tag();
110 }
111
112 info("AVM vk hash in recursive verifier: ", vk_hash);
113
114 RelationParams relation_parameters;
115 VerifierCommitments commitments{ key };
116
117 // TODO(https://github.com/AztecProtocol/aztec-packages/pull/17045): make the protocols secure at some point
118 // // Add public inputs to transcript
119 // for (size_t i = 0; i < AVM_NUM_PUBLIC_INPUT_COLUMNS; i++) {
120 // for (size_t j = 0; j < public_inputs[i].size(); j++) {
121 // transcript->add_to_hash_buffer("public_input_" + std::to_string(i) + "_" + std::to_string(j),
122 // public_inputs[i][j]);
123 // }
124 // }
125
126 for (size_t i = 0; i < AVM_NUM_PUBLIC_INPUT_COLUMNS; i++) {
127 for (size_t j = 0; j < public_inputs[i].size(); j++) {
128 // TODO(https://github.com/AztecProtocol/aztec-packages/pull/17045): make the protocols secure at some point
129 // transcript->add_to_hash_buffer("public_input_" + std::to_string(i) + "_" + std::to_string(j),
130 // public_inputs[i][j]);
131 public_inputs[i][j].unset_free_witness_tag();
132 }
133 }
134 // Get commitments to VM wires
135 for (auto [comm, label] : zip_view(commitments.get_wires(), commitments.get_wires_labels())) {
136 comm = transcript->template receive_from_prover<Commitment>(label);
137 }
138
139 auto [beta, gamma] = transcript->template get_challenges<FF>(std::array<std::string, 2>{ "beta", "gamma" });
140 relation_parameters.beta = beta;
141 relation_parameters.gamma = gamma;
142
143 // Get commitments to inverses
144 for (auto [label, commitment] : zip_view(commitments.get_derived_labels(), commitments.get_derived())) {
145 commitment = transcript->template receive_from_prover<Commitment>(label);
146 }
147
148 FF one{ 1 };
149 one.convert_constant_to_fixed_witness(&builder);
150
151 std::vector<FF> padding_indicator_array(key->log_fixed_circuit_size);
152 std::ranges::fill(padding_indicator_array, one);
153
154 // Multiply each linearly independent subrelation contribution by `alpha^i` for i = 0, ..., NUM_SUBRELATIONS - 1.
155 const FF alpha = transcript->template get_challenge<FF>("Sumcheck:alpha");
156
157 SumcheckVerifier<Flavor> sumcheck(transcript, alpha, key->log_fixed_circuit_size);
158
159 std::vector<FF> gate_challenges =
160 transcript->template get_dyadic_powers_of_challenge<FF>("Sumcheck:gate_challenge", key->log_fixed_circuit_size);
161
162 // No need to constrain that sumcheck_verified is true as this is guaranteed by the implementation of
163 // when called over a "circuit field" types.
164 SumcheckOutput<Flavor> output = sumcheck.verify(relation_parameters, gate_challenges, padding_indicator_array);
165 vinfo("verified sumcheck: ", (output.verified));
166
167 using C = ColumnAndShifts;
169 output.claimed_evaluations.get(C::public_inputs_cols_0_),
170 output.claimed_evaluations.get(C::public_inputs_cols_1_),
171 output.claimed_evaluations.get(C::public_inputs_cols_2_),
172 output.claimed_evaluations.get(C::public_inputs_cols_3_),
173 };
174
175 // TODO(#14234)[Unconditional PIs validation]: Inside of loop, replace pi_validation.must_imply() by
176 // public_input_evaluation.assert_equal(claimed_evaluations[i]
177 for (size_t i = 0; i < AVM_NUM_PUBLIC_INPUT_COLUMNS; i++) {
178 FF public_input_evaluation = evaluate_public_input_column(public_inputs[i], output.challenge);
179 pi_validation.must_imply(public_input_evaluation == claimed_evaluations[i],
180 format("public_input_evaluation failed at column ", i));
181 }
182
183 // Batch commitments and evaluations using short scalars to reduce ECCVM circuit size
184 auto unshifted_comms = commitments.get_unshifted();
185 auto unshifted_evals = output.claimed_evaluations.get_unshifted();
186 auto shifted_comms = commitments.get_to_be_shifted();
187 auto shifted_evals = output.claimed_evaluations.get_shifted();
188
189 // Generate batching challenge labels
190 // Note: We get N-1 challenges for N unshifted commitments (first commitment has implicit coefficient 1)
191 std::vector<std::string> unshifted_batching_challenge_labels;
192 unshifted_batching_challenge_labels.reserve(unshifted_comms.size() - 1);
193 for (size_t idx = 0; idx < unshifted_comms.size() - 1; idx++) {
194 unshifted_batching_challenge_labels.push_back("rho_" + std::to_string(idx));
195 }
196 std::vector<std::string> shifted_batching_challenge_labels;
197 shifted_batching_challenge_labels.reserve(shifted_comms.size());
198 for (size_t idx = 0; idx < shifted_comms.size(); idx++) {
199 shifted_batching_challenge_labels.push_back("rho_" + std::to_string(unshifted_comms.size() - 1 + idx));
200 }
201
202 // Get short (128-bit) batching challenges from transcript
203 auto unshifted_challenges = transcript->template get_challenges<FF>(unshifted_batching_challenge_labels);
204 auto shifted_challenges = transcript->template get_challenges<FF>(shifted_batching_challenge_labels);
205
206 // Batch commitments: first commitment has coefficient 1, rest are batched with challenges
207 Commitment squashed_unshifted =
208 unshifted_comms[0] +
209 Commitment::batch_mul(
210 std::vector<Commitment>(unshifted_comms.begin() + 1, unshifted_comms.end()), unshifted_challenges, 128);
211
212 Commitment squashed_shifted = Commitment::batch_mul(
213 std::vector<Commitment>(shifted_comms.begin(), shifted_comms.end()), shifted_challenges, 128);
214
215 // Batch evaluations: compute inner product with first eval as initial value for unshifted
216 FF squashed_unshifted_eval = std::inner_product(
217 unshifted_challenges.begin(), unshifted_challenges.end(), unshifted_evals.begin() + 1, unshifted_evals[0]);
218
219 FF squashed_shifted_eval =
220 std::inner_product(shifted_challenges.begin(), shifted_challenges.end(), shifted_evals.begin(), FF(0));
221
222 // Execute Shplemini rounds with squashed claims
223 ClaimBatcher squashed_claim_batcher{ .unshifted = ClaimBatch{ .commitments = RefVector(squashed_unshifted),
224 .evaluations = RefVector(squashed_unshifted_eval) },
225 .shifted = ClaimBatch{ .commitments = RefVector(squashed_shifted),
226 .evaluations = RefVector(squashed_shifted_eval) } };
227 auto opening_claim = Shplemini::compute_batch_opening_claim(
228 padding_indicator_array, squashed_claim_batcher, output.challenge, Commitment::one(&builder), transcript);
229
230 PairingPoints pairing_points(PCS::reduce_verify_batch_opening_claim(std::move(opening_claim), transcript));
231
232 if (builder.failed()) {
233 info("AVM Recursive verifier builder failed with error: ", builder.err());
234 }
235
236 return pairing_points;
237}
238
239} // namespace bb::avm2
#define AVM_NUM_PUBLIC_INPUT_COLUMNS
#define AVM_PUBLIC_INPUTS_COLUMNS_MAX_LENGTH
An efficient verifier for the evaluation proofs of multilinear polynomials and their shifts.
NativeFlavor::VerifierCommitments_< Commitment, VerificationKey > VerifierCommitments
AvmRecursiveFlavorSettings::Curve Curve
AvmRecursiveFlavorSettings::PCS PCS
std::shared_ptr< Transcript > transcript
typename Flavor::VerifierCommitments VerifierCommitments
stdlib::Proof< Builder > StdlibProof
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
AvmRecursiveVerifier(Builder &builder, const std::shared_ptr< VerificationKey > &vkey)
typename Flavor::Commitment Commitment
A simple wrapper around a vector of stdlib field elements representing a proof.
Definition proof.hpp:19
Implements boolean logic in-circuit.
Definition bool.hpp:59
std::string format(Args... args)
Definition log.hpp:22
#define vinfo(...)
Definition log.hpp:80
void info(Args... args)
Definition log.hpp:75
AluTraceBuilder builder
Definition alu.test.cpp:124
constexpr std::size_t MAX_AVM_TRACE_SIZE
Definition constants.hpp:13
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 and shifted polynomials in Shplemini.
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)