Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
batch_merge_prover.cpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: not started, auditors: [], commit: }
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
8
10#include <algorithm>
11
12namespace bb {
13
15 : transcript(std::make_shared<Transcript>())
16 , op_queue(op_queue)
17 , max_subtables(max_subtables)
18{
19 // The commitment key must be large enough for the full merged table (plus the zk offset).
21}
22
24 const std::vector<Polynomial>& flattened_columns,
25 const std::vector<FF>& degree_check_challenges,
26 const size_t max_size)
27{
28 // Zero initialization
29 Polynomial reversed_batched_poly(max_size);
30 std::vector<Polynomial> reversed_columns;
31 reversed_columns.reserve(flattened_columns.size());
32 for (const auto& poly : flattened_columns) {
33 reversed_columns.emplace_back(poly.reverse());
34 }
35
36 std::vector<PolynomialSpan<const FF>> reversed_column_spans;
37 std::vector<FF> scalars;
38 reversed_column_spans.reserve(flattened_columns.size());
39 scalars.reserve(flattened_columns.size());
40 for (size_t idx = 0; idx < flattened_columns.size(); ++idx) {
41 reversed_column_spans.emplace_back(reversed_columns[idx]);
42 scalars.push_back(degree_check_challenges[idx]);
43 }
44
45 add_scaled_batch(reversed_batched_poly,
46 std::span<const PolynomialSpan<const FF>>(reversed_column_spans),
47 std::span<const FF>(scalars));
48
49 return reversed_batched_poly;
50}
51
53{
54 BB_BENCH_NAME("BatchMergeProver::construct_proof");
55 const size_t M = max_subtables;
56
57 // -------------------------------------------------------------------------
58 // Step 1: Gather subtable column polynomials and their shift sizes
59 // -------------------------------------------------------------------------
60 std::vector<std::array<Polynomial, NUM_WIRES>> subtable_cols = op_queue->construct_subtable_columns();
61
62 size_t N = subtable_cols.size();
63 BB_ASSERT_LTE(N, M, "BatchMergeProver: more subtables than max_subtables");
64
65 std::vector<size_t> shift_sizes(N);
66 size_t max_shift_size = 0;
67 for (size_t i = 0; i < N; ++i) {
68 shift_sizes[i] = subtable_cols[i][0].size(); // number of rows per poly
69 max_shift_size = std::max(max_shift_size, shift_sizes[i]);
70 }
71
72 // -------------------------------------------------------------------------
73 // Step 2: Commit to columns to be merged
74 // -------------------------------------------------------------------------
75 for (size_t idx = 0; idx < N; ++idx) {
76 for (size_t col = 0; col < NUM_WIRES; ++col) {
77 transcript->send_to_verifier("COLUMN_" + std::to_string(col) + "_" + std::to_string(idx),
78 pcs_commitment_key.commit(subtable_cols[idx][col]));
79 }
80 // update hash after each subtable to match verifier's transcript
81 [[maybe_unused]] FF _ = transcript->template get_challenge<FF>("HASH_" + std::to_string(idx));
82 }
83
84 Commitment infinity = Commitment::infinity();
85 for (size_t idx = N; idx < M; ++idx) {
86 for (size_t col = 0; col < NUM_WIRES; ++col) {
87 transcript->send_to_verifier("COLUMN_" + std::to_string(col) + "_" + std::to_string(idx), infinity);
88 }
89 // update hash after each subtable to match verifier's transcript
90 [[maybe_unused]] FF _ = transcript->template get_challenge<FF>("HASH_" + std::to_string(idx));
91 }
92
93 // -------------------------------------------------------------------------
94 // Step 2.b: Send the masking table
95 // -------------------------------------------------------------------------
96 std::array<Polynomial, NUM_WIRES> zk_columns = op_queue->construct_zk_columns();
97 for (size_t col = 0; col < NUM_WIRES; ++col) {
98 transcript->send_to_verifier("ZK_COLUMN_" + std::to_string(col), pcs_commitment_key.commit(zk_columns[col]));
99 }
100 max_shift_size = std::max(max_shift_size, zk_columns[0].size());
101
102 // -------------------------------------------------------------------------
103 // Step 2.c: Flatten the columns for easier utilization
104 // -------------------------------------------------------------------------
105 std::vector<Polynomial> flattened_cols;
106 flattened_cols.reserve((subtable_cols.size() * NUM_WIRES) + NUM_WIRES);
107 for (size_t col = 0; col < NUM_WIRES; ++col) {
108 flattened_cols.push_back(std::move(zk_columns[col]));
109 }
110 for (auto& subtable_col : subtable_cols) {
111 for (size_t col = 0; col < NUM_WIRES; col++) {
112 flattened_cols.push_back(std::move(subtable_col[col]));
113 }
114 }
115
116 // -------------------------------------------------------------------------
117 // Step 3: Send N and shift sizes to the verifier
118 // -------------------------------------------------------------------------
119 transcript->send_to_verifier("NUM_SUBTABLES", static_cast<uint32_t>(N));
120 for (size_t i = 0; i < M; ++i) {
121 transcript->send_to_verifier("SHIFT_SIZE_" + std::to_string(i),
122 static_cast<uint32_t>(i < N ? shift_sizes[i] : 0));
123 }
124
125 // -------------------------------------------------------------------------
126 // Step 4: Construct and commit to T (full merged table)
127 // -------------------------------------------------------------------------
128 std::array<Polynomial, NUM_WIRES> merged_table(op_queue->construct_ultra_ops_table_columns());
129 for (size_t col = 0; col < NUM_WIRES; ++col) {
130 transcript->send_to_verifier("MERGED_COLUMN_" + std::to_string(col),
131 pcs_commitment_key.commit(merged_table[col]));
132 }
133
134 // -------------------------------------------------------------------------
135 // Step 5: Compute degree check batching challenges 1, α, α^2, .., α^{(M + 1) * NUM_WIRES -1}
136 // -------------------------------------------------------------------------
137 const FF degree_check_challenge = transcript->template get_challenge<FF>("DEGREE_CHECK_CHALLENGE");
138 const size_t num_degree_check_challenges = (M + 1) * NUM_WIRES;
139 std::vector<FF> degree_check_challenges = { FF(1), degree_check_challenge };
140 for (size_t idx = 2; idx < num_degree_check_challenges; idx++) {
141 degree_check_challenges.push_back(degree_check_challenges.back() * degree_check_challenge);
142 }
143
144 // -------------------------------------------------------------------------
145 // Step 6: Compute G = sum_i α_i * C_i(1 / X) * X^{shift_size_i - 1}, commit, send [G]
146 // -------------------------------------------------------------------------
147 Polynomial degree_check_poly =
148 compute_degree_check_polynomial(flattened_cols, degree_check_challenges, max_shift_size);
149 transcript->send_to_verifier("DEGREE_CHECK_POLY", pcs_commitment_key.commit(degree_check_poly));
150
151 // -------------------------------------------------------------------------
152 // Step 7: Evaluation challenge κ
153 // -------------------------------------------------------------------------
154 const FF kappa = transcript->template get_challenge<FF>("KAPPA");
155 const FF kappa_inv = kappa.invert();
156
157 // -------------------------------------------------------------------------
158 // Step 8: Compute and send evaluations C_i(κ), T(κ), G(κ^{-1})
159 // -------------------------------------------------------------------------
160 // C_i_col(κ)
161 std::vector<FF> evals;
162 const size_t num_actual_flattened_cols = (N * NUM_WIRES) + NUM_WIRES;
163 const size_t num_flattened_col_evals = (M * NUM_WIRES) + NUM_WIRES;
164 for (size_t col = 0; col < num_flattened_col_evals; ++col) {
165 evals.push_back(col < num_actual_flattened_cols ? flattened_cols[col].evaluate(kappa) : FF(0));
166 transcript->send_to_verifier("C_EVAL_" + std::to_string(col), evals.back());
167 }
168
169 // T_col(κ)
170 for (size_t col = 0; col < NUM_WIRES; ++col) {
171 evals.push_back(merged_table[col].evaluate(kappa));
172 transcript->send_to_verifier("MERGED_EVAL_" + std::to_string(col), evals.back());
173 }
174
175 // G_col(κ^{-1})
176 evals.push_back(degree_check_poly.evaluate(kappa_inv));
177 transcript->send_to_verifier("DEGREE_CHECK_EVAL", evals.back());
178
179 // -------------------------------------------------------------------------
180 // Step 9: Shplonk to open
181 // zk columns
182 // for C_i(κ)
183 // T(κ)
184 // for G(κ^{-1})
185 // -------------------------------------------------------------------------
186 const size_t num_opening_claims = ((M + 2) * NUM_WIRES) + 1;
187 std::vector<OpeningClaim> opening_claims;
188 opening_claims.reserve(num_opening_claims);
189 for (size_t idx = 0; idx < num_flattened_col_evals; ++idx) {
190 if (idx >= num_actual_flattened_cols || flattened_cols[idx].size() == 0) {
191 // We use Polynomial(1) to avoid failures in Shplonk due to accessing empty polynomials
192 opening_claims.push_back({ Polynomial(1), { kappa, FF(0) } });
193 } else {
194 opening_claims.push_back({ std::move(flattened_cols[idx]), { kappa, evals[idx] } });
195 }
196 }
197 for (size_t idx = 0; idx < NUM_WIRES; ++idx) {
198 opening_claims.push_back({ std::move(merged_table[idx]), { kappa, evals[((M + 1) * NUM_WIRES) + idx] } });
199 }
200 opening_claims.push_back({ std::move(degree_check_poly), { kappa_inv, evals.back() } });
201
202 auto shplonk_opening_claim = ShplonkProver::prove(pcs_commitment_key, opening_claims, transcript);
203
205
206 return transcript->export_proof();
207}
208
209} // namespace bb
#define BB_ASSERT_LTE(left, right,...)
Definition assert.hpp:158
#define BB_BENCH_NAME(name)
Definition bb_bench.hpp:264
Common transcript class for both parties. Stores the data for the current round, as well as the manif...
static constexpr size_t NUM_WIRES
BatchMergeProver(const std::shared_ptr< ECCOpQueue > &op_queue, size_t max_subtables)
std::shared_ptr< Transcript > transcript
std::shared_ptr< ECCOpQueue > op_queue
bb::CommitmentKey< Curve > CommitmentKey
std::vector< FF > MergeProof
bb::Polynomial< FF > Polynomial
Curve::AffineElement Commitment
MergeProof construct_proof()
Construct the batch merge proof.
static Polynomial compute_degree_check_polynomial(const std::vector< Polynomial > &flattened_columns, const std::vector< FF > &degree_check_challenges, const size_t max_size)
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
Fr evaluate(const Fr &z) const
static ProverOpeningClaim< Curve > prove(const CommitmentKey< Curve > &commitment_key, std::span< ProverOpeningClaim< Curve > > opening_claims, const std::shared_ptr< Transcript > &transcript, std::span< ProverOpeningClaim< Curve > > libra_opening_claims={}, std::span< ProverOpeningClaim< Curve > > sumcheck_round_claims={}, const size_t virtual_log_n=0)
Returns a batched opening claim equivalent to a set of opening claims consisting of polynomials,...
Definition shplonk.hpp:254
static constexpr size_t ZK_ULTRA_OPS
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
void add_scaled_batch(Polynomial< Fr > &dst, std::span< const PolynomialSpan< const Fr > > sources, std::span< const Fr > scalars)
Fused parallel batched add: dst += sum_i scalars[i] * sources[i].
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