Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
merge_prover.cpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: Complete, auditors: [Sergei], commit: }
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
7#include "merge_prover.hpp"
11
12namespace bb {
13
19MergeProver::MergeProver(const std::shared_ptr<ECCOpQueue>& op_queue, std::shared_ptr<Transcript> transcript)
20 : transcript(std::move(transcript))
21 , op_queue(op_queue)
22{
23 // MergeProver is used only for the final merge, where the hiding kernel subtable is appended at a fixed offset.
24 const size_t append_offset = op_queue->get_append_offset();
26 op_queue->merge_fixed_append(append_offset);
27
29};
30
32 const std::array<Polynomial, NUM_WIRES>& left_table, const std::vector<FF>& degree_check_challenges) const
33{
34 // The left table has a fixed length, so we need to compute the reverse according to that length
35 Polynomial reversed_batched_left_tables(fixed_append_shift_size);
36 for (size_t idx = 0; idx < NUM_WIRES; idx++) {
37 reversed_batched_left_tables.add_scaled(left_table[idx], degree_check_challenges[idx]);
38 }
39 return reversed_batched_left_tables.reverse();
40}
41
43 const std::array<Polynomial, NUM_WIRES>& left_table,
44 const std::array<Polynomial, NUM_WIRES>& right_table,
45 const std::array<Polynomial, NUM_WIRES>& merged_table,
46 const std::vector<FF>& shplonk_batching_challenges,
47 const FF& kappa,
48 const FF& kappa_inv,
49 const Polynomial& reversed_batched_left_tables,
50 const std::vector<FF>& evals)
51{
52 // Q such that Q·(X - κ)·(X - κ⁻¹) =
53 // (X - κ⁻¹)·(Σᵢ βᵢ(Lᵢ - lᵢ) + Σᵢ βᵢ(Rᵢ - rᵢ) + Σᵢ βᵢ(Mᵢ - mᵢ)) + (X - κ)·β(G - g)
54 Polynomial shplonk_batched_quotient(merged_table[0].size());
55
56 // Handle polynomials opened at κ
57 for (size_t idx_table = 0; idx_table < 3; idx_table++) {
58 for (size_t idx = 0; idx < NUM_WIRES; idx++) {
59 FF challenge = shplonk_batching_challenges[(idx_table * NUM_WIRES) + idx];
60 FF eval = evals[(idx_table * NUM_WIRES) + idx];
61 if (idx_table == 0) {
62 // Q += Lᵢ·βᵢ
63 shplonk_batched_quotient.add_scaled(left_table[idx], challenge);
64 } else if (idx_table == 1) {
65 // Q += Rᵢ·βᵢ
66 shplonk_batched_quotient.add_scaled(right_table[idx], challenge);
67 } else {
68 // Q += Mᵢ·βᵢ
69 shplonk_batched_quotient.add_scaled(merged_table[idx], challenge);
70 }
71 // Q -= eval·βᵢ
72 if (!shplonk_batched_quotient.is_empty()) {
73 shplonk_batched_quotient.at(0) -= challenge * eval;
74 }
75 }
76 }
77 // Q /= (X - κ)
78 shplonk_batched_quotient.factor_roots(kappa);
79
80 // Q += (G - g)/(X - κ⁻¹)·β
81 Polynomial reversed_batched_left_tables_copy(reversed_batched_left_tables);
82 if (!reversed_batched_left_tables_copy.is_empty()) {
83 reversed_batched_left_tables_copy.at(0) -= evals.back();
84 }
85 reversed_batched_left_tables_copy.factor_roots(kappa_inv);
86 shplonk_batched_quotient.add_scaled(reversed_batched_left_tables_copy, shplonk_batching_challenges.back());
87
88 return shplonk_batched_quotient;
89}
90
92 Polynomial& shplonk_batched_quotient,
93 const FF& shplonk_opening_challenge,
94 const std::array<Polynomial, NUM_WIRES>& left_table,
95 const std::array<Polynomial, NUM_WIRES>& right_table,
96 const std::array<Polynomial, NUM_WIRES>& merged_table,
97 const std::vector<FF>& shplonk_batching_challenges,
98 const FF& kappa,
99 const FF& kappa_inv,
100 Polynomial& reversed_batched_left_tables,
101 const std::vector<FF>& evals)
102{
103 // Q' (partially evaluated batched quotient) =
104 // -Q·(z - κ) + Σᵢ βᵢ(Lᵢ - lᵢ) + Σᵢ βᵢ(Rᵢ - rᵢ) + Σᵢ βᵢ(Mᵢ - mᵢ) + (z - κ)/(z - κ⁻¹)·β(G - g)
105 Polynomial shplonk_partially_evaluated_batched_quotient(std::move(shplonk_batched_quotient));
106 shplonk_partially_evaluated_batched_quotient *= -(shplonk_opening_challenge - kappa);
107
108 // Handle polynomials opened at κ
109 for (size_t idx_table = 0; idx_table < 3; idx_table++) {
110 for (size_t idx = 0; idx < NUM_WIRES; idx++) {
111 FF challenge = shplonk_batching_challenges[(idx_table * NUM_WIRES) + idx];
112 FF eval = evals[(idx_table * NUM_WIRES) + idx];
113 if (idx_table == 0) {
114 // Q' += Lᵢ·βᵢ
115 shplonk_partially_evaluated_batched_quotient.add_scaled(left_table[idx], challenge);
116 } else if (idx_table == 1) {
117 // Q' += Rᵢ·βᵢ
118 shplonk_partially_evaluated_batched_quotient.add_scaled(right_table[idx], challenge);
119 } else {
120 // Q' += Mᵢ·βᵢ
121 shplonk_partially_evaluated_batched_quotient.add_scaled(merged_table[idx], challenge);
122 }
123 // Q' -= eval·βᵢ
124 if (!shplonk_partially_evaluated_batched_quotient.is_empty()) {
125 shplonk_partially_evaluated_batched_quotient.at(0) -= challenge * eval;
126 }
127 }
128 }
129
130 // Q' += (G - g)·(z - κ)/(z - κ⁻¹)·β
131 if (!reversed_batched_left_tables.is_empty()) {
132 reversed_batched_left_tables.at(0) -= evals.back();
133 }
134 shplonk_partially_evaluated_batched_quotient.add_scaled(reversed_batched_left_tables,
135 shplonk_batching_challenges.back() *
136 (shplonk_opening_challenge - kappa) *
137 (shplonk_opening_challenge - kappa_inv).invert());
138
139 OpeningClaim shplonk_opening_claim = { .polynomial = std::move(shplonk_partially_evaluated_batched_quotient),
140 .opening_pair = { shplonk_opening_challenge, FF(0) } };
141
142 return shplonk_opening_claim;
143}
144
157{
158 BB_BENCH_NAME("MergeProver::construct_proof");
161 std::array<Polynomial, NUM_WIRES> merged_table = op_queue->construct_ultra_ops_table_columns(); // T
162
163 left_table = op_queue->construct_table_columns_up_to_tail(); // T_tail
164 right_table = op_queue->construct_current_ultra_ops_subtable_columns(); // t (fixed append carries
165 // APPEND_TRACE_OFFSET leading zeros)
166
167 // Send shift_size to the verifier
168 transcript->send_to_verifier("shift_size", static_cast<uint32_t>(fixed_append_shift_size));
169
170 // Compute commitments [M_j] and send to the verifier
171 for (size_t idx = 0; idx < NUM_WIRES; ++idx) {
172 transcript->send_to_verifier("MERGED_TABLE_" + std::to_string(idx),
173 pcs_commitment_key.commit(merged_table[idx]));
174 }
175
176 // Generate degree check batching challenges, batch polynomials, compute reversed polynomial, send commitment to the
177 // verifier
178 std::vector<FF> degree_check_challenges = transcript->template get_challenges<FF>(labels_degree_check);
179 Polynomial reversed_batched_left_tables = compute_degree_check_polynomial(left_table, degree_check_challenges);
180 transcript->send_to_verifier("REVERSED_BATCHED_LEFT_TABLES",
181 pcs_commitment_key.commit(reversed_batched_left_tables));
182
183 // Compute batching challenges
184 std::vector<FF> shplonk_batching_challenges =
185 transcript->template get_challenges<FF>(labels_shplonk_batching_challenges);
186
187 // Compute evaluation challenge
188 const FF kappa = transcript->template get_challenge<FF>("kappa");
189 const FF kappa_inv = kappa.invert();
190
191 // Send evaluations of [Lᵢ], [Rᵢ], [Mᵢ] at κ
192 std::vector<FF> evals;
193 evals.reserve((3 * NUM_WIRES) + 1);
194 for (size_t idx = 0; idx < NUM_WIRES; ++idx) {
195 evals.emplace_back(left_table[idx].evaluate(kappa));
196 transcript->send_to_verifier("LEFT_TABLE_EVAL_" + std::to_string(idx), evals.back());
197 }
198 for (size_t idx = 0; idx < NUM_WIRES; ++idx) {
199 evals.emplace_back(right_table[idx].evaluate(kappa));
200 transcript->send_to_verifier("RIGHT_TABLE_EVAL_" + std::to_string(idx), evals.back());
201 }
202 for (size_t idx = 0; idx < NUM_WIRES; ++idx) {
203 evals.emplace_back(merged_table[idx].evaluate(kappa));
204 transcript->send_to_verifier("MERGED_TABLE_EVAL_" + std::to_string(idx), evals.back());
205 }
206
207 // Send evaluation of G at 1/κ
208 evals.emplace_back(reversed_batched_left_tables.evaluate(kappa_inv));
209 transcript->send_to_verifier("REVERSED_BATCHED_LEFT_TABLES_EVAL", evals.back());
210
211 // Compute Shplonk batched quotient
212 Polynomial shplonk_batched_quotient = compute_shplonk_batched_quotient(left_table,
213 right_table,
214 merged_table,
215 shplonk_batching_challenges,
216 kappa,
217 kappa_inv,
218 reversed_batched_left_tables,
219 evals);
220
221 transcript->send_to_verifier("SHPLONK_BATCHED_QUOTIENT", pcs_commitment_key.commit(shplonk_batched_quotient));
222
223 // Generate Shplonk opening challenge
224 FF shplonk_opening_challenge = transcript->template get_challenge<FF>("shplonk_opening_challenge");
225
226 // Compute Shplonk opening claim
227 OpeningClaim shplonk_opening_claim = compute_shplonk_opening_claim(shplonk_batched_quotient,
228 shplonk_opening_challenge,
229 left_table,
230 right_table,
231 merged_table,
232 shplonk_batching_challenges,
233 kappa,
234 kappa_inv,
235 reversed_batched_left_tables,
236 evals);
237
238 // KZG prover
240
241 return transcript->export_proof();
242}
243} // namespace bb
#define BB_BENCH_NAME(name)
Definition bb_bench.hpp:264
Commitment commit(PolynomialSpan< const Fr > polynomial) const
Uses the ProverSRS to create a commitment to p(X)
static void compute_opening_proof(const CK &ck, const ProverOpeningClaim< Curve > &opening_claim, const std::shared_ptr< Transcript > &prover_trancript)
Computes the KZG commitment to an opening proof polynomial at a single evaluation point.
Definition kzg.hpp:43
static constexpr size_t NUM_WIRES
Curve::ScalarField FF
std::shared_ptr< ECCOpQueue > op_queue
std::vector< FF > MergeProof
BB_PROFILE MergeProof construct_proof()
Prove proper construction of the aggregate Goblin ECC op queue polynomials T_j.
std::vector< std::string > labels_degree_check
Polynomial compute_degree_check_polynomial(const std::array< Polynomial, NUM_WIRES > &left_table, const std::vector< FF > &degree_check_challenges) const
Compute the batched polynomial for the degree check.
static OpeningClaim compute_shplonk_opening_claim(Polynomial &shplonk_batched_quotient, const FF &shplonk_opening_challenge, const std::array< Polynomial, NUM_WIRES > &left_table, const std::array< Polynomial, NUM_WIRES > &right_table, const std::array< Polynomial, NUM_WIRES > &merged_table, const std::vector< FF > &shplonk_batching_challenges, const FF &kappa, const FF &kappa_inv, Polynomial &reversed_batched_left_tables, const std::vector< FF > &evals)
Compute the partially evaluated Shplonk batched quotient and the resulting opening claim.
std::vector< std::string > labels_shplonk_batching_challenges
MergeProver(const std::shared_ptr< ECCOpQueue > &op_queue, std::shared_ptr< Transcript > transcript)
Create MergeProver.
std::shared_ptr< Transcript > transcript
CommitmentKey pcs_commitment_key
static Polynomial compute_shplonk_batched_quotient(const std::array< Polynomial, NUM_WIRES > &left_table, const std::array< Polynomial, NUM_WIRES > &right_table, const std::array< Polynomial, NUM_WIRES > &merged_table, const std::vector< FF > &shplonk_batching_challenges, const FF &kappa, const FF &kappa_inv, const Polynomial &reversed_batched_left_tables, const std::vector< FF > &evals)
Compute the batched Shplonk quotient polynomial.
size_t fixed_append_shift_size
bb::CommitmentKey< Curve > CommitmentKey
bool is_empty() const
void add_scaled(PolynomialSpan< const Fr > other, const Fr &scaling_factor)
adds the polynomial q(X) 'other', multiplied by a scaling factor.
Fr evaluate(const Fr &z) const
Polynomial reverse() const
Returns the polynomial equal to the reverse of self.
Fr & at(size_t index)
Our mutable accessor, unlike operator[]. We abuse precedent a bit to differentiate at() and operator[...
void factor_roots(const Fr &root)
Divides p(X) by (X-r) in-place. Assumes that p(rⱼ)=0 for all j.
Polynomial p and an opening pair (r,v) such that p(r) = v.
Definition claim.hpp:36
Polynomial polynomial
Definition claim.hpp:41
static constexpr size_t NUM_ROWS_PER_OP
static constexpr size_t ZK_ULTRA_OPS
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
STL namespace.
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
std::string to_string(bb::avm2::ValueTag tag)
constexpr field invert() const noexcept