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"
13
14namespace bb {
15
21MergeProver::MergeProver(const std::shared_ptr<ECCOpQueue>& op_queue, std::shared_ptr<Transcript> transcript)
22 : transcript(std::move(transcript))
23 , op_queue(op_queue)
24{
25 // MergeProver is used only for the final merge, where the hiding kernel subtable is appended at a fixed offset.
26 // The verifier hard-codes the shift size from HIDING_KERNEL_ULTRA_OPS, so the prover's subtable must match.
27 BB_ASSERT_EQ(op_queue->get_current_subtable_size(),
28 HIDING_KERNEL_ULTRA_OPS,
29 "Number of ultra ops in the hiding kernel doesn't match the expected value.");
30 const size_t append_offset = op_queue->get_append_offset_for_prover();
32 op_queue->merge_fixed_append(append_offset);
33
35};
36
38 const std::array<Polynomial, NUM_WIRES>& left_table, const std::vector<FF>& degree_check_challenges) const
39{
40 // The left table has a fixed length, so we need to compute the reverse according to that length
41 Polynomial reversed_batched_left_tables(fixed_append_shift_size);
42 for (size_t idx = 0; idx < NUM_WIRES; idx++) {
43 reversed_batched_left_tables.add_scaled(left_table[idx], degree_check_challenges[idx]);
44 }
45 return reversed_batched_left_tables.reverse();
46}
47
49 const std::array<Polynomial, NUM_WIRES>& left_table,
50 const std::array<Polynomial, NUM_WIRES>& right_table,
51 const std::array<Polynomial, NUM_WIRES>& merged_table,
52 const std::vector<FF>& shplonk_batching_challenges,
53 const FF& kappa,
54 const FF& kappa_inv,
55 const Polynomial& reversed_batched_left_tables,
56 const std::vector<FF>& evals)
57{
58 // Q such that Q·(X - κ)·(X - κ⁻¹) =
59 // (X - κ⁻¹)·(Σᵢ βᵢ(Lᵢ - lᵢ) + Σᵢ βᵢ(Rᵢ - rᵢ) + Σᵢ βᵢ(Mᵢ - mᵢ)) + (X - κ)·β(G - g)
60 Polynomial shplonk_batched_quotient(merged_table[0].size());
61
62 // Handle polynomials opened at κ
63 for (size_t idx_table = 0; idx_table < 3; idx_table++) {
64 for (size_t idx = 0; idx < NUM_WIRES; idx++) {
65 FF challenge = shplonk_batching_challenges[(idx_table * NUM_WIRES) + idx];
66 FF eval = evals[(idx_table * NUM_WIRES) + idx];
67 if (idx_table == 0) {
68 // Q += Lᵢ·βᵢ
69 shplonk_batched_quotient.add_scaled(left_table[idx], challenge);
70 } else if (idx_table == 1) {
71 // Q += Rᵢ·βᵢ
72 shplonk_batched_quotient.add_scaled(right_table[idx], challenge);
73 } else {
74 // Q += Mᵢ·βᵢ
75 shplonk_batched_quotient.add_scaled(merged_table[idx], challenge);
76 }
77 // Q -= eval·βᵢ
78 if (!shplonk_batched_quotient.is_empty()) {
79 shplonk_batched_quotient.at(0) -= challenge * eval;
80 }
81 }
82 }
83 // Q /= (X - κ)
84 shplonk_batched_quotient.factor_roots(kappa);
85
86 // Q += (G - g)/(X - κ⁻¹)·β
87 Polynomial reversed_batched_left_tables_copy(reversed_batched_left_tables);
88 if (!reversed_batched_left_tables_copy.is_empty()) {
89 reversed_batched_left_tables_copy.at(0) -= evals.back();
90 }
91 reversed_batched_left_tables_copy.factor_roots(kappa_inv);
92 shplonk_batched_quotient.add_scaled(reversed_batched_left_tables_copy, shplonk_batching_challenges.back());
93
94 return shplonk_batched_quotient;
95}
96
98 Polynomial& shplonk_batched_quotient,
99 const FF& shplonk_opening_challenge,
100 const std::array<Polynomial, NUM_WIRES>& left_table,
101 const std::array<Polynomial, NUM_WIRES>& right_table,
102 const std::array<Polynomial, NUM_WIRES>& merged_table,
103 const std::vector<FF>& shplonk_batching_challenges,
104 const FF& kappa,
105 const FF& kappa_inv,
106 Polynomial& reversed_batched_left_tables,
107 const std::vector<FF>& evals)
108{
109 // Q' (partially evaluated batched quotient) =
110 // -Q·(z - κ) + Σᵢ βᵢ(Lᵢ - lᵢ) + Σᵢ βᵢ(Rᵢ - rᵢ) + Σᵢ βᵢ(Mᵢ - mᵢ) + (z - κ)/(z - κ⁻¹)·β(G - g)
111 Polynomial shplonk_partially_evaluated_batched_quotient(std::move(shplonk_batched_quotient));
112 shplonk_partially_evaluated_batched_quotient *= -(shplonk_opening_challenge - kappa);
113
114 // Handle polynomials opened at κ
115 for (size_t idx_table = 0; idx_table < 3; idx_table++) {
116 for (size_t idx = 0; idx < NUM_WIRES; idx++) {
117 FF challenge = shplonk_batching_challenges[(idx_table * NUM_WIRES) + idx];
118 FF eval = evals[(idx_table * NUM_WIRES) + idx];
119 if (idx_table == 0) {
120 // Q' += Lᵢ·βᵢ
121 shplonk_partially_evaluated_batched_quotient.add_scaled(left_table[idx], challenge);
122 } else if (idx_table == 1) {
123 // Q' += Rᵢ·βᵢ
124 shplonk_partially_evaluated_batched_quotient.add_scaled(right_table[idx], challenge);
125 } else {
126 // Q' += Mᵢ·βᵢ
127 shplonk_partially_evaluated_batched_quotient.add_scaled(merged_table[idx], challenge);
128 }
129 // Q' -= eval·βᵢ
130 if (!shplonk_partially_evaluated_batched_quotient.is_empty()) {
131 shplonk_partially_evaluated_batched_quotient.at(0) -= challenge * eval;
132 }
133 }
134 }
135
136 // Q' += (G - g)·(z - κ)/(z - κ⁻¹)·β
137 if (!reversed_batched_left_tables.is_empty()) {
138 reversed_batched_left_tables.at(0) -= evals.back();
139 }
140 shplonk_partially_evaluated_batched_quotient.add_scaled(reversed_batched_left_tables,
141 shplonk_batching_challenges.back() *
142 (shplonk_opening_challenge - kappa) *
143 (shplonk_opening_challenge - kappa_inv).invert());
144
145 OpeningClaim shplonk_opening_claim = { .polynomial = std::move(shplonk_partially_evaluated_batched_quotient),
146 .opening_pair = { shplonk_opening_challenge, FF(0) } };
147
148 return shplonk_opening_claim;
149}
150
163{
164 BB_BENCH_NAME("MergeProver::construct_proof");
167 std::array<Polynomial, NUM_WIRES> merged_table = op_queue->construct_ultra_ops_table_columns(); // T
168
169 left_table = op_queue->construct_table_columns_up_to_tail(); // T_tail
170 right_table = op_queue->construct_current_ultra_ops_subtable_columns(); // t (fixed append carries
171 // APPEND_TRACE_OFFSET leading zeros)
172
173 // Compute commitments [M_j] and send to the verifier
174 for (size_t idx = 0; idx < NUM_WIRES; ++idx) {
175 transcript->send_to_verifier("MERGED_TABLE_" + std::to_string(idx),
176 pcs_commitment_key.commit(merged_table[idx]));
177 }
178
179 // Generate degree check batching challenges, batch polynomials, compute reversed polynomial, send commitment to the
180 // verifier
181 std::vector<FF> degree_check_challenges = transcript->template get_challenges<FF>(labels_degree_check);
182 Polynomial reversed_batched_left_tables = compute_degree_check_polynomial(left_table, degree_check_challenges);
183 transcript->send_to_verifier("REVERSED_BATCHED_LEFT_TABLES",
184 pcs_commitment_key.commit(reversed_batched_left_tables));
185
186 // Compute evaluation challenge
187 const FF kappa = transcript->template get_challenge<FF>("kappa");
188 const FF kappa_inv = kappa.invert();
189
190 // Send evaluations of [Lᵢ], [Rᵢ], [Mᵢ] at κ
191 std::vector<FF> evals;
192 evals.reserve((3 * NUM_WIRES) + 1);
193 for (size_t idx = 0; idx < NUM_WIRES; ++idx) {
194 evals.emplace_back(left_table[idx].evaluate(kappa));
195 transcript->send_to_verifier("LEFT_TABLE_EVAL_" + std::to_string(idx), evals.back());
196 }
197 for (size_t idx = 0; idx < NUM_WIRES; ++idx) {
198 evals.emplace_back(right_table[idx].evaluate(kappa));
199 transcript->send_to_verifier("RIGHT_TABLE_EVAL_" + std::to_string(idx), evals.back());
200 }
201 for (size_t idx = 0; idx < NUM_WIRES; ++idx) {
202 evals.emplace_back(merged_table[idx].evaluate(kappa));
203 transcript->send_to_verifier("MERGED_TABLE_EVAL_" + std::to_string(idx), evals.back());
204 }
205
206 // Send evaluation of G at 1/κ
207 evals.emplace_back(reversed_batched_left_tables.evaluate(kappa_inv));
208 transcript->send_to_verifier("REVERSED_BATCHED_LEFT_TABLES_EVAL", evals.back());
209
210 // Compute batching challenges
211 std::vector<FF> shplonk_batching_challenges =
212 transcript->template get_short_challenges<FF>(labels_shplonk_batching_challenges);
213
214 // Compute Shplonk batched quotient
215 Polynomial shplonk_batched_quotient = compute_shplonk_batched_quotient(left_table,
216 right_table,
217 merged_table,
218 shplonk_batching_challenges,
219 kappa,
220 kappa_inv,
221 reversed_batched_left_tables,
222 evals);
223
224 transcript->send_to_verifier("SHPLONK_BATCHED_QUOTIENT", pcs_commitment_key.commit(shplonk_batched_quotient));
225
226 // Generate Shplonk opening challenge
227 FF shplonk_opening_challenge = transcript->template get_challenge<FF>("shplonk_opening_challenge");
228
229 // Compute Shplonk opening claim
230 OpeningClaim shplonk_opening_claim = compute_shplonk_opening_claim(shplonk_batched_quotient,
231 shplonk_opening_challenge,
232 left_table,
233 right_table,
234 merged_table,
235 shplonk_batching_challenges,
236 kappa,
237 kappa_inv,
238 reversed_batched_left_tables,
239 evals);
240
241 // KZG prover
243
244 return transcript->export_proof();
245}
246} // namespace bb
#define BB_ASSERT_EQ(actual, expected,...)
Definition assert.hpp:83
#define BB_BENCH_NAME(name)
Definition bb_bench.hpp:264
Commitment commit(PolynomialSpan< const Fr > polynomial, bool has_duplicates_hint=false) const
Uses the ProverSRS to create a commitment to p(X)
static constexpr size_t compute_fixed_append_offset(size_t append_offset, bool include_zk_prefix=true)
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:44
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 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