Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
protogalaxy_recursive_verifier.cpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: not started, auditors: [], date: YYYY-MM-DD }
3// external_1: { status: not started, auditors: [], date: YYYY-MM-DD }
4// external_2: { status: not started, auditors: [], date: YYYY-MM-DD }
5// =====================
6
12
14
15template <class VerifierInstance>
17 const std::vector<FF>& proof)
18{
19 transcript->load_proof(proof);
20 auto key = insts_to_fold[0];
21 auto domain_separator = std::to_string(0);
22
23 // If the first instance to be folded in pure we need to complete it and generate the gate challenges
24 if (!key->is_complete) {
25 bb::OinkVerifier<Flavor> oink_verifier{ key, transcript, domain_separator + '_' };
26 oink_verifier.verify();
27 key->target_sum = FF::from_witness_index(builder, builder->zero_idx());
28 // Get the gate challenges for sumcheck/combiner computation
29 key->gate_challenges =
30 transcript->template get_powers_of_challenge<FF>(domain_separator + "_gate_challenge", CONST_PG_LOG_N);
31 }
32
33 // Complete the second instance (Step 1 of the paper)
34 key = insts_to_fold[1];
35 domain_separator = std::to_string(1);
36 bb::OinkVerifier<Flavor> oink_verifier{ key, transcript, domain_separator + '_' };
37 oink_verifier.verify();
38}
39
40template <class VerifierInstance>
42 const stdlib::Proof<Builder>& proof)
43{
44 // The degree of the combiner quotient (K in the paper) is equal to deg(G) - deg(Z), where Z is the vanishing
45 // polynomial of the domain 0, .., NUM_INSTANCES-1. Hence, deg(K) = deg(G) - NUM_INSTANCES and we need
46 // deg(G) + 1 - NUM_INSTANCES = BATCHED_EXTENDED_LENGTH - NUM_INSTANCES evaluations to represent it
47 static constexpr size_t COMBINER_QUOTIENT_LENGTH = BATCHED_EXTENDED_LENGTH - NUM_INSTANCES;
48
49 // Step 1
50 run_oink_verifier_on_each_incomplete_instance(proof);
51
52 const std::shared_ptr<VerifierInstance>& accumulator = insts_to_fold[0];
53
54 // Step 2 - 3
55 const std::vector<FF> deltas = transcript->template get_powers_of_challenge<FF>("delta", CONST_PG_LOG_N);
56
57 // Step 5 - Receive non-constant coefficients of the perturbator
58 // As n = 2^CONST_PG_LOG_N, the perturbator has degree equal to log(n) = CONST_PG_LOG_N
59 std::vector<FF> perturbator_coeffs(CONST_PG_LOG_N + 1, 0);
60 perturbator_coeffs[0] = accumulator->target_sum;
61 for (size_t idx = 1; idx <= CONST_PG_LOG_N; idx++) {
62 perturbator_coeffs[idx] = transcript->template receive_from_prover<FF>("perturbator_" + std::to_string(idx));
63 }
64
65 // Step 6 - Compute perturbator challenge
66 const FF perturbator_challenge = transcript->template get_challenge<FF>("perturbator_challenge");
67
68 // Step 7 - Compute evaluation of the perturbator
69 const FF perturbator_evaluation = evaluate_perturbator(perturbator_coeffs, perturbator_challenge);
70
71 // Step 11 - Receive evaluations of the combiner quotient
72 std::array<FF, COMBINER_QUOTIENT_LENGTH> combiner_quotient_evals;
73 for (size_t idx = 0; idx < COMBINER_QUOTIENT_LENGTH; idx++) {
74 combiner_quotient_evals[idx] =
75 transcript->template receive_from_prover<FF>("combiner_quotient_" + std::to_string(idx + NUM_INSTANCES));
76 }
77
78 // Step 12 - Compute combiner quotient challenge \gamma (used to generate folding output)
79 const FF combiner_challenge = transcript->template get_challenge<FF>("combiner_quotient_challenge");
80
81 // Folding
82 // A VerifierInstance is made up of three components: the commitments to the prover polynomials, the relation
83 // parameters, and the batching challenges. We have to fold each of these components. The commitments require an
84 // MSM, relation parameters and batching challenges require only field operations.
85
86 // Compute K(\gamma)
87 const Univariate<FF, BATCHED_EXTENDED_LENGTH, NUM_INSTANCES> combiner_quotient(combiner_quotient_evals);
88 const FF combiner_quotient_at_challenge = combiner_quotient.evaluate(combiner_challenge);
89
90 // Compute Z(\gamma)
91 const FF vanishing_polynomial_at_challenge = combiner_challenge * (combiner_challenge - FF(1));
92
93 // Compute L_0(\gamma) and L_1(\gamma)
94 const std::vector<FF> lagranges = { FF(1) - combiner_challenge, combiner_challenge };
95
124 // New transcript for challenge generation
125 Transcript batch_mul_transcript = transcript->branch_transcript();
126
127 // Prepare accumulator and instance commitments for MSM calculation
128 std::vector<Commitment> accumulator_commitments;
129 std::vector<Commitment> instance_commitments;
130 for (const auto& precomputed : get_data_to_fold<FOLDING_DATA::PRECOMPUTED_COMMITMENTS>()) {
131 accumulator_commitments.emplace_back(precomputed[0]);
132 instance_commitments.emplace_back(precomputed[1]);
133 }
134 for (const auto& witness : get_data_to_fold<FOLDING_DATA::WITNESS_COMMITMENTS>()) {
135 accumulator_commitments.emplace_back(witness[0]);
136 instance_commitments.emplace_back(witness[1]);
137 }
138
139 // Construct witnesses holding the purported values of the folding
140 std::vector<Commitment> output_commitments;
141 for (size_t i = 0; i < accumulator_commitments.size(); ++i) {
142 // Out-of-circuit calculation to populate the witness values
143 const auto lhs_scalar = lagranges[0].get_value(); // L_0(\gamma)
144 const auto rhs_scalar = lagranges[1].get_value(); // L_1(\gamma)
145 const auto lhs = accumulator_commitments[i].get_value(); // [P_{0,i}]
146 const auto rhs = instance_commitments[i].get_value(); // [P_{1,i}]
147 const auto output =
148 lhs * lhs_scalar + rhs * rhs_scalar; // [Q_i] := L_0(\gamma) * [P_{0,i}] + L_1(\gamma) * [P_{1,i}]
149 // Add a new witness whose underlying value for an honest prover is [Q_i]
150 output_commitments.emplace_back(Commitment::from_witness(builder, output));
151 // Add the output commitment to the transcript to ensure they can't be spoofed
152 batch_mul_transcript.add_to_hash_buffer("new_accumulator_commitment_" + std::to_string(i),
153 output_commitments[i]);
154 }
155
156 // Generate the challenges c_i
158 for (size_t idx = 0; idx < Flavor::NUM_FOLDED_ENTITIES; ++idx) {
159 args[idx] = "accumulator_combination_challenges_" + std::to_string(idx);
160 }
162 batch_mul_transcript.template get_challenges<FF>(args);
163 std::vector<FF> scalars(folding_challenges.begin(), folding_challenges.end());
164
165 // MSMs: note that edge cases are handled in the MSM only when the builder is Ultra. When the builder is mega, edge
166 // cases are handled by the ECCVM
167
168 // Compute [A] = \sum_i c_i [P_{0,i}]
169 Commitment accumulator_sum = Commitment::batch_mul(accumulator_commitments,
170 scalars,
171 /*max_num_bits=*/0,
172 /*handle_edge_cases=*/IsUltraBuilder<Builder>);
173
174 // Compute [B] = \sum_i c_i [P_{1,i}]
175 Commitment instance_sum = Commitment::batch_mul(instance_commitments,
176 scalars,
177 /*max_num_bits=*/0,
178 /*handle_edge_cases=*/IsUltraBuilder<Builder>);
179
180 // Compute [C] = \sum_i c_i [Q_i]
181 Commitment output_sum = Commitment::batch_mul(output_commitments,
182 scalars,
183 /*max_num_bits=*/0,
184 /*handle_edge_cases=*/IsUltraBuilder<Builder>);
185 // Compute (1 - gamma) * [A] + gamma * [B]
186 Commitment folded_sum = Commitment::batch_mul({ accumulator_sum, instance_sum },
187 lagranges,
188 /*max_num_bits=*/0,
189 /*handle_edge_cases=*/IsUltraBuilder<Builder>);
190
191 // Enforce [C] = (1 - gamma) * [A] + gamma * [B]
192 output_sum.incomplete_assert_equal(folded_sum);
193
194 // Step 13. Update the target sum: e^{\ast} = F(\alpha) * L_0(\gamma) + Z(\gamma) * K(\gamma)
195 accumulator->target_sum =
196 perturbator_evaluation * lagranges[0] + vanishing_polynomial_at_challenge * combiner_quotient_at_challenge;
197
198 // Step 8. Update gate challenges: beta^{\ast} = \beta + \alpha * \deltas
199 accumulator->gate_challenges = update_gate_challenges(perturbator_challenge, accumulator->gate_challenges, deltas);
200
201 // Define a constant virtual log circuit size for the accumulator
202 // This is just a placeholder: the decider verifier (PG decider) uses a constant value as the maximum dyadic size of
203 // the circuits that have been folded using PG. The constant is Flavor::VIRTUAL_LOG_N, which is always bigger or
204 // equal than CONST_PG_LOG_N. See also https://github.com/AztecProtocol/barretenberg/issues/1545 for more details.
205 FF virtual_log_n = FF::from_witness(builder, CONST_PG_LOG_N);
206 virtual_log_n.fix_witness();
207 accumulator->vk_and_hash->vk->log_circuit_size = virtual_log_n;
208
209 // Fold the batching challenges (alphas)
210 for (auto [combination, to_combine] : zip_view(accumulator->alphas, get_data_to_fold<FOLDING_DATA::ALPHAS>())) {
211 combination = to_combine[0] + combiner_challenge * (to_combine[1] - to_combine[0]);
212 }
213
214 // Fold the relation parameters
215 for (auto [combination, to_combine] : zip_view(accumulator->relation_parameters.get_to_fold(),
216 get_data_to_fold<FOLDING_DATA::RELATION_PARAMETERS>())) {
217 combination = to_combine[0] + combiner_challenge * (to_combine[1] - to_combine[0]);
218 }
219
220 // Update the precomputed commitments of the accumulator
221 auto accumulator_vkey = accumulator->vk_and_hash->vk->get_all();
222 for (size_t i = 0; i < Flavor::NUM_PRECOMPUTED_ENTITIES; ++i) {
223 accumulator_vkey[i] = output_commitments[i];
224 }
225
226 // Update the witness commitments of the accumulator
227 auto accumulator_witnesses = accumulator->witness_commitments.get_all();
228 for (size_t i = 0; i < Flavor::NUM_WITNESS_ENTITIES; ++i) {
229 accumulator_witnesses[i] = output_commitments[i + accumulator_vkey.size()];
230 }
231
232 return accumulator;
233}
234
235// Instantiate the template with specific flavors and builders
237
238} // namespace bb::stdlib::recursion::honk
Common transcript class for both parties. Stores the data for the current round, as well as the manif...
void add_to_hash_buffer(const std::string &label, const T &element)
Adds an element to the transcript.
BaseTranscript branch_transcript()
Branch a transcript to perform verifier-only computations.
static constexpr size_t NUM_PRECOMPUTED_ENTITIES
static constexpr size_t NUM_WITNESS_ENTITIES
static constexpr size_t NUM_FOLDED_ENTITIES
Verifier class for all the presumcheck rounds, which are shared between the folding verifier and ultr...
A univariate polynomial represented by its values on {domain_start, domain_start + 1,...
Fr evaluate(const Fr &u) const
Evaluate a univariate at a point u not known at compile time and assumed not to be in the domain (els...
A simple wrapper around a vector of stdlib field elements representing a proof.
Definition proof.hpp:19
void run_oink_verifier_on_each_incomplete_instance(const std::vector< FF > &)
Process the public data for the verification keys to be folded.
std::shared_ptr< VerifierInstance > verify_folding_proof(const stdlib::Proof< Builder > &)
Run the folding protocol on the verifier side to establish whether the public data of the new accumu...
AluTraceBuilder builder
Definition alu.test.cpp:123
std::vector< FF > update_gate_challenges(const FF &perturbator_challenge, const std::vector< FF > &gate_challenges, const std::vector< FF > &init_challenges)
Compute the gate challenges used in the combiner calculation.
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
std::string to_string(bb::avm2::ValueTag tag)