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
29{
31
33 key->fix_witness();
34
35 auto native_vk_hash = native_vk->hash();
36 vk_hash = FF::from_witness(&builder, native_vk_hash);
37 vk_hash.fix_witness();
38}
39
40// Evaluate the given public input column over the multivariate challenge points
42 const std::vector<FF>& challenges)
43{
44 auto coefficients = SharedShiftedVirtualZeroesArray<FF>{
45 .start_ = 0,
46 .end_ = points.size(),
47 .virtual_size_ = MAX_AVM_TRACE_SIZE,
48 .backing_memory_ = BackingMemory<FF>::allocate(points.size()),
49 };
50
51 memcpy(
52 static_cast<void*>(coefficients.data()), static_cast<const void*>(points.data()), sizeof(FF) * points.size());
53
54 return generic_evaluate_mle<FF>(challenges, coefficients);
55}
56
58 const HonkProof& proof, const std::vector<std::vector<fr>>& public_inputs_vec_nt)
59{
60 StdlibProof stdlib_proof(builder, proof);
61
62 std::vector<std::vector<FF>> public_inputs_ct;
63 public_inputs_ct.reserve(public_inputs_vec_nt.size());
64
65 for (const auto& vec : public_inputs_vec_nt) {
66 std::vector<FF> vec_ct;
67 vec_ct.reserve(vec.size());
68 for (const auto& el : vec) {
69 vec_ct.push_back(stdlib::witness_t<Builder>(&builder, el));
70 }
71 public_inputs_ct.push_back(vec_ct);
72 }
73
74 return verify_proof(stdlib_proof, public_inputs_ct);
75}
76
77// TODO(#991): (see https://github.com/AztecProtocol/barretenberg/issues/991)
79 const stdlib::Proof<Builder>& stdlib_proof, const std::vector<std::vector<FF>>& public_inputs)
80{
81 using Curve = typename Flavor::Curve;
82 using PCS = typename Flavor::PCS;
84 using RelationParams = RelationParameters<typename Flavor::FF>;
86 using ClaimBatcher = ClaimBatcher_<Curve>;
87 using ClaimBatch = ClaimBatcher::Batch;
88
89 if (public_inputs.size() != AVM_NUM_PUBLIC_INPUT_COLUMNS) {
90 throw_or_abort("AvmRecursiveVerifier::verify_proof: public inputs size mismatch");
91 }
92 for (const auto& public_input : public_inputs) {
93 if (public_input.size() != AVM_PUBLIC_INPUTS_COLUMNS_MAX_LENGTH) {
94 throw_or_abort("AvmRecursiveVerifier::verify_proof: public input size mismatch");
95 }
96 }
97
98 transcript->load_proof(stdlib_proof);
99
100 transcript->add_to_hash_buffer("avm_vk_hash", vk_hash);
101
102 info("AVM vk hash in recursive verifier: ", vk_hash.get_value());
103
104 RelationParams relation_parameters;
105 VerifierCommitments commitments{ key };
106
107 // Add public inputs to transcript for Fiat-Shamir
108 for (size_t i = 0; i < AVM_NUM_PUBLIC_INPUT_COLUMNS; i++) {
109 for (size_t j = 0; j < public_inputs[i].size(); j++) {
110 transcript->add_to_hash_buffer("public_input_" + std::to_string(i) + "_" + std::to_string(j),
111 public_inputs[i][j]);
112 }
113 }
114 // Get commitments to VM wires
115 for (auto [comm, label] : zip_view(commitments.get_wires(), commitments.get_wires_labels())) {
116 comm = transcript->template receive_from_prover<Commitment>(label);
117 }
118
119 auto [beta, gamma] = transcript->template get_challenges<FF>(std::array<std::string, 2>{ "beta", "gamma" });
120 relation_parameters.beta = beta;
121 relation_parameters.gamma = gamma;
122
123 // Get commitments to inverses
124 for (auto [label, commitment] : zip_view(commitments.get_derived_labels(), commitments.get_derived())) {
125 commitment = transcript->template receive_from_prover<Commitment>(label);
126 }
127
128 FF one{ 1 };
129 one.convert_constant_to_fixed_witness(&builder);
130
131 std::vector<FF> padding_indicator_array(key->log_fixed_circuit_size);
132 std::ranges::fill(padding_indicator_array, one);
133
134 // Multiply each linearly independent subrelation contribution by `alpha^i` for i = 0, ..., NUM_SUBRELATIONS - 1.
135 const FF alpha = transcript->template get_challenge<FF>("Sumcheck:alpha");
136
137 SumcheckVerifier<Flavor> sumcheck(transcript, alpha, key->log_fixed_circuit_size);
138
139 std::vector<FF> gate_challenges =
140 transcript->template get_dyadic_powers_of_challenge<FF>("Sumcheck:gate_challenge", key->log_fixed_circuit_size);
141
142 // No need to constrain that sumcheck_verified is true as this is guaranteed by the implementation of
143 // when called over a "circuit field" types.
144 SumcheckOutput<Flavor> output = sumcheck.verify(relation_parameters, gate_challenges, padding_indicator_array);
145 vinfo("verified sumcheck: ", (output.verified));
146
147 using C = ColumnAndShifts;
149 output.claimed_evaluations.get(C::public_inputs_cols_0_),
150 output.claimed_evaluations.get(C::public_inputs_cols_1_),
151 output.claimed_evaluations.get(C::public_inputs_cols_2_),
152 output.claimed_evaluations.get(C::public_inputs_cols_3_),
153 };
154
155 // Validate public inputs match the claimed evaluations
156 for (size_t i = 0; i < AVM_NUM_PUBLIC_INPUT_COLUMNS; i++) {
157 FF public_input_evaluation = evaluate_public_input_column(public_inputs[i], output.challenge);
158 public_input_evaluation.assert_equal(claimed_evaluations[i],
159 format("public_input_evaluation failed at column ", i));
160 }
161
162 // Batch commitments and evaluations using short scalars to reduce ECCVM circuit size
163 auto unshifted_comms = commitments.get_unshifted();
164 auto unshifted_evals = output.claimed_evaluations.get_unshifted();
165 auto shifted_comms = commitments.get_to_be_shifted();
166 auto shifted_evals = output.claimed_evaluations.get_shifted();
167
168 // Generate batching challenge labels
169 // Note: We get N-1 challenges for N unshifted commitments (first commitment has implicit coefficient 1)
170 std::vector<std::string> unshifted_batching_challenge_labels;
171 unshifted_batching_challenge_labels.reserve(unshifted_comms.size() - 1);
172 for (size_t idx = 0; idx < unshifted_comms.size() - 1; idx++) {
173 unshifted_batching_challenge_labels.push_back("rho_" + std::to_string(idx));
174 }
175 std::vector<std::string> shifted_batching_challenge_labels;
176 shifted_batching_challenge_labels.reserve(shifted_comms.size());
177 for (size_t idx = 0; idx < shifted_comms.size(); idx++) {
178 shifted_batching_challenge_labels.push_back("rho_" + std::to_string(unshifted_comms.size() - 1 + idx));
179 }
180
181 // Get short (128-bit) batching challenges from transcript
182 auto unshifted_challenges = transcript->template get_challenges<FF>(unshifted_batching_challenge_labels);
183 auto shifted_challenges = transcript->template get_challenges<FF>(shifted_batching_challenge_labels);
184
185 // Batch commitments: first commitment has coefficient 1, rest are batched with challenges
186 Commitment squashed_unshifted =
187 unshifted_comms[0] +
188 Commitment::batch_mul(
189 std::vector<Commitment>(unshifted_comms.begin() + 1, unshifted_comms.end()), unshifted_challenges, 128);
190
191 Commitment squashed_shifted = Commitment::batch_mul(
192 std::vector<Commitment>(shifted_comms.begin(), shifted_comms.end()), shifted_challenges, 128);
193
194 // Batch evaluations: compute inner product with first eval as initial value for unshifted
195 FF squashed_unshifted_eval = std::inner_product(
196 unshifted_challenges.begin(), unshifted_challenges.end(), unshifted_evals.begin() + 1, unshifted_evals[0]);
197
198 FF squashed_shifted_eval =
199 std::inner_product(shifted_challenges.begin(), shifted_challenges.end(), shifted_evals.begin(), FF(0));
200
201 // Execute Shplemini rounds with squashed claims
202 ClaimBatcher squashed_claim_batcher{ .unshifted = ClaimBatch{ .commitments = RefVector(squashed_unshifted),
203 .evaluations = RefVector(squashed_unshifted_eval) },
204 .shifted = ClaimBatch{ .commitments = RefVector(squashed_shifted),
205 .evaluations = RefVector(squashed_shifted_eval) } };
206 auto opening_claim =
207 Shplemini::compute_batch_opening_claim(
208 padding_indicator_array, squashed_claim_batcher, output.challenge, Commitment::one(&builder), transcript)
209 .batch_opening_claim;
210
211 PairingPoints pairing_points(PCS::reduce_verify_batch_opening_claim(std::move(opening_claim), transcript));
212
213 if (builder.failed()) {
214 info("AVM Recursive verifier builder failed with error: ", builder.err());
215 }
216
217 return pairing_points;
218}
219
220} // namespace bb::avm2
#define AVM_NUM_PUBLIC_INPUT_COLUMNS
#define AVM_PUBLIC_INPUTS_COLUMNS_MAX_LENGTH
IPA (inner product argument) commitment scheme class.
Definition ipa.hpp:93
NativeFlavor::VerifierCommitments_< Commitment, VerificationKey > VerifierCommitments
AvmRecursiveFlavorSettings::Curve Curve
AvmRecursiveFlavorSettings::PCS PCS
std::shared_ptr< Transcript > transcript
typename Flavor::VerifierCommitments VerifierCommitments
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:24
#define vinfo(...)
Definition log.hpp:94
void info(Args... args)
Definition log.hpp:89
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, 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)