Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
merge_verifier.cpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: Complete, auditors: [Sergei], commit: d1307bdee7f2ee0e737c19b77a26204a8dbafafc}
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
7#include "merge_verifier.hpp"
13
14namespace bb {
15
16template <typename Curve>
17bool MergeVerifier_<Curve>::check_concatenation_identities(std::vector<FF>& evals, const FF& pow_kappa) const
18{
19 bool concatenation_verified = true;
20 FF concatenation_diff(0);
21 for (size_t idx = 0; idx < NUM_WIRES; idx++) {
22 // Identity: L(κ) + κ^ℓ · R(κ) = M(κ)
23 concatenation_diff = evals[idx] + (pow_kappa * evals[idx + NUM_WIRES]) - evals[idx + (2 * NUM_WIRES)];
24 if constexpr (IsRecursive) {
25 concatenation_verified &= concatenation_diff.get_value() == 0;
26 concatenation_diff.assert_equal(FF(0),
27 "assert_equal: merge concatenation identity failed in Merge Verifier");
28 } else {
29 concatenation_verified &= concatenation_diff == 0;
30 }
31 }
32 return concatenation_verified;
33}
34
35template <typename Curve>
36bool MergeVerifier_<Curve>::check_degree_identity(const std::vector<FF>& evals,
37 const FF& pow_kappa_minus_one,
38 const std::vector<FF>& degree_check_challenges) const
39{
40 bool degree_check_verified = true;
41 FF degree_check_diff(0);
42 for (size_t idx = 0; idx < NUM_WIRES; ++idx) {
43 degree_check_diff += evals[idx] * degree_check_challenges[idx];
44 }
45 degree_check_diff -= evals.back() * pow_kappa_minus_one;
46 if constexpr (IsRecursive) {
47 degree_check_verified &= degree_check_diff.get_value() == 0;
48 degree_check_diff.assert_equal(FF(0), "assert_equal: merge degree identity failed in Merge Verifier");
49 } else {
50 degree_check_verified &= degree_check_diff == 0;
51 }
52
53 return degree_check_verified;
54}
55
56template <typename Curve>
58 const std::vector<Commitment>& table_commitments,
59 const Commitment& shplonk_batched_quotient,
60 const FF& shplonk_opening_challenge,
61 const std::vector<FF>& shplonk_batching_challenges,
62 const FF& kappa,
63 const FF& kappa_inv,
64 const std::vector<FF>& evals) const
65{
66 // Claim {Q', (z, 0)} where Q' = -Q·(z - κ) + Σᵢ βᵢLᵢ + Σᵢ βᵢRᵢ + Σᵢ βᵢMᵢ + (z - κ)/(z - κ⁻¹)·βG
67 // - Σᵢ βᵢlᵢ - Σᵢ βᵢrᵢ - Σᵢ βᵢmᵢ - (z - κ)/(z - κ⁻¹)·β·g
68 BatchOpeningClaim<Curve> batch_opening_claim;
69
70 // Commitment: [L_1], [L_2], ..., [L_n], [R_1], ..., [R_n], [M_1], ..., [M_n], [G], [1]
71 batch_opening_claim.commitments = { std::move(shplonk_batched_quotient) };
72 for (auto& commitment : table_commitments) {
73 batch_opening_claim.commitments.emplace_back(std::move(commitment));
74 }
75 if constexpr (IsRecursive) {
76 batch_opening_claim.commitments.emplace_back(Commitment::one(kappa.get_context()));
77 } else {
78 batch_opening_claim.commitments.emplace_back(Commitment::one());
79 }
80
81 // Scalars: -(z - κ), β₁...β₁₂, β₁₃·(z - κ)/(z - κ⁻¹), -(Σᵢ βᵢlᵢ + Σᵢ βᵢrᵢ + Σᵢ βᵢmᵢ + β₁₃·(z - κ)/(z - κ⁻¹)·g)
82 batch_opening_claim.scalars = { -(shplonk_opening_challenge - kappa) };
83 for (auto& scalar : shplonk_batching_challenges) {
84 batch_opening_claim.scalars.emplace_back(std::move(scalar));
85 }
86 batch_opening_claim.scalars.back() *=
87 (shplonk_opening_challenge - kappa) * (shplonk_opening_challenge - kappa_inv).invert();
88
89 batch_opening_claim.scalars.emplace_back(FF(0));
90 for (size_t idx = 0; idx < evals.size(); idx++) {
91 if (idx < evals.size() - 1) {
92 batch_opening_claim.scalars.back() -= evals[idx] * shplonk_batching_challenges[idx];
93 } else {
94 batch_opening_claim.scalars.back() -= shplonk_batching_challenges.back() * evals.back() *
95 (shplonk_opening_challenge - kappa) *
96 (shplonk_opening_challenge - kappa_inv).invert();
97 }
98 }
99
100 batch_opening_claim.evaluation_point = { shplonk_opening_challenge };
101
102 return batch_opening_claim;
103}
104
116template <typename Curve>
118 const Proof& proof, const InputCommitments& input_commitments)
119{
120 BB_BENCH_NAME("MergeVerifier::reduce");
121 transcript->load_proof(proof);
122
123 // Receive shift size from prover
124 // For native: shift_size is uint32_t
125 // For stdlib: shift_size is FF (we'll get the value later)
126 const FF shift_size = transcript->template receive_from_prover<FF>("shift_size");
127
128 // Store T_commitments of the verifier
129 TableCommitments merged_table_commitments;
130
131 // Vector of commitments
132 // The vector is composed of: [L_1], .., [L_4], [R_1], .., [R_4], [M_1], .., [M_4], [G]
133 std::vector<Commitment> table_commitments;
134 table_commitments.reserve((3 * NUM_WIRES) + 1);
135 table_commitments.insert(table_commitments.end(),
136 input_commitments.T_prev_commitments.begin(),
137 input_commitments.T_prev_commitments.end());
138 table_commitments.insert(
139 table_commitments.end(), input_commitments.t_commitments.begin(), input_commitments.t_commitments.end());
140 for (size_t idx = 0; idx < NUM_WIRES; ++idx) {
141 table_commitments.emplace_back(
142 transcript->template receive_from_prover<Commitment>("MERGED_TABLE_" + std::to_string(idx)));
143 merged_table_commitments[idx] = table_commitments.back();
144 }
145
146 // Generate degree check batching challenges
147 std::vector<FF> degree_check_challenges = transcript->template get_challenges<FF>(labels_degree_check);
148
149 // Receive commitment to reversed batched left table
150 table_commitments.emplace_back(
151 transcript->template receive_from_prover<Commitment>("REVERSED_BATCHED_LEFT_TABLES"));
152
153 // Compute batching challenges
154 std::vector<FF> shplonk_batching_challenges =
155 transcript->template get_challenges<FF>(labels_shplonk_batching_challenges);
156
157 // Evaluation challenge
158 const FF kappa = transcript->template get_challenge<FF>("kappa");
159 const FF kappa_inv = kappa.invert();
160 const FF pow_kappa = kappa.pow(shift_size);
161 const FF pow_kappa_minus_one = pow_kappa * kappa_inv;
162
163 // Receive evaluations of [Lᵢ], [Rᵢ], [Mᵢ] at κ
164 std::vector<FF> evals;
165 evals.reserve((3 * NUM_WIRES) + 1);
166 for (size_t idx = 0; idx < NUM_WIRES; ++idx) {
167 evals.emplace_back(transcript->template receive_from_prover<FF>("LEFT_TABLE_EVAL_" + std::to_string(idx)));
168 }
169 for (size_t idx = 0; idx < NUM_WIRES; ++idx) {
170 evals.emplace_back(transcript->template receive_from_prover<FF>("RIGHT_TABLE_EVAL_" + std::to_string(idx)));
171 }
172 for (size_t idx = 0; idx < NUM_WIRES; ++idx) {
173 evals.emplace_back(transcript->template receive_from_prover<FF>("MERGED_TABLE_EVAL_" + std::to_string(idx)));
174 }
175
176 // Receive evaluation of G at 1/κ
177 evals.emplace_back(transcript->template receive_from_prover<FF>("REVERSED_BATCHED_LEFT_TABLES_EVAL"));
178
179 // OriginTag false positive: The evaluations are PCS-bound - once the table commitments
180 // are fixed and kappa is derived, the correct evaluations are uniquely determined. Tag them
181 // with kappa to reflect this constraint. The last eval (G at 1/κ) is bound by degree_check_challenges.
182 if constexpr (IsRecursive) {
183 for (auto& eval : evals) {
184 eval.set_origin_tag(kappa.get_origin_tag());
185 }
186 evals.back().set_origin_tag(degree_check_challenges.back().get_origin_tag());
187 }
188
189 // Check concatenation identities
190 bool concatenation_verified = check_concatenation_identities(evals, pow_kappa);
191
192 // Check degree identity
193 bool degree_check_verified = check_degree_identity(evals, pow_kappa_minus_one, degree_check_challenges);
194
195 // Receive Shplonk batched quotient
196 Commitment shplonk_batched_quotient =
197 transcript->template receive_from_prover<Commitment>("SHPLONK_BATCHED_QUOTIENT");
198
199 // Generate Shplonk opening challenge
200 FF shplonk_opening_challenge = transcript->template get_challenge<FF>("shplonk_opening_challenge");
201
202 // Prepare batched opening claim to be passed to KZG
203 BatchOpeningClaim<Curve> batch_opening_claim = compute_shplonk_opening_claim(table_commitments,
204 shplonk_batched_quotient,
205 shplonk_opening_challenge,
206 shplonk_batching_challenges,
207 kappa,
208 kappa_inv,
209 evals);
210
211 BB_ASSERT(batch_opening_claim.commitments.size() == MERGE_BATCHED_CLAIM_SIZE);
212 BB_ASSERT(batch_opening_claim.scalars.size() == MERGE_BATCHED_CLAIM_SIZE);
213
214 // KZG verifier - returns PairingPoints directly
215 PairingPoints pairing_points = PCS::reduce_verify_batch_opening_claim(std::move(batch_opening_claim), transcript);
216
217 vinfo("Merge Verifier: degree check passed: ", degree_check_verified ? "true" : "false");
218 vinfo("Merge Verifier: concatenation check passed: ", concatenation_verified ? "true" : "false");
219
220 return { pairing_points, merged_table_commitments, degree_check_verified && concatenation_verified };
221}
222
223// Explicit template instantiations
224template class MergeVerifier_<curve::BN254>;
227
228} // namespace bb
#define BB_ASSERT(expression,...)
Definition assert.hpp:70
bb::field< bb::Bn254FrParams > FF
Definition field.cpp:24
#define BB_BENCH_NAME(name)
Definition bb_bench.hpp:264
Verifier for the single-step Goblin ECC op queue merge protocol.
typename Curve::AffineElement Commitment
typename Curve::ScalarField FF
BatchOpeningClaim< Curve > compute_shplonk_opening_claim(const std::vector< Commitment > &table_commitments, const Commitment &shplonk_batched_quotient, const FF &shplonk_opening_challenge, const std::vector< FF > &shplonk_batching_challenges, const FF &kappa, const FF &kappa_inv, const std::vector< FF > &evals) const
std::vector< FF > Proof
bool check_concatenation_identities(std::vector< FF > &evals, const FF &pow_kappa) const
std::conditional_t< Curve::is_stdlib_type, stdlib::recursion::PairingPoints< Curve >, bb::PairingPoints< Curve > > PairingPoints
ReductionResult reduce_to_pairing_check(const Proof &proof, const InputCommitments &input_commitments)
Reduce the merge proof to a pairing check.
std::array< Commitment, NUM_WIRES > TableCommitments
bool check_degree_identity(const std::vector< FF > &evals, const FF &pow_kappa_minus_one, const std::vector< FF > &degree_check_challenges) const
#define vinfo(...)
Definition log.hpp:94
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
std::string to_string(bb::avm2::ValueTag tag)
An accumulator consisting of the Shplonk evaluation challenge and vectors of commitments and scalars.
Definition claim.hpp:155
std::vector< Commitment > commitments
Definition claim.hpp:160
std::vector< Scalar > scalars
Definition claim.hpp:161
Result of merge verification.