barretenberg
Loading...
Searching...
No Matches
shplonk.hpp
1#pragma once
2#include "barretenberg/commitment_schemes/claim.hpp"
3#include "barretenberg/commitment_schemes/commitment_key.hpp"
4#include "barretenberg/commitment_schemes/verification_key.hpp"
5#include "barretenberg/transcript/transcript.hpp"
6
22
29
36template <typename Curve> struct ProverOutput {
37 OpeningPair<Curve> opening_pair; // single opening pair (challenge, evaluation)
38 OutputWitness<Curve> witness; // single polynomial G(X)
39};
40
46template <typename Curve> class ShplonkProver_ {
47 using Fr = typename Curve::ScalarField;
49
50 public:
59 static Polynomial compute_batched_quotient(std::span<const OpeningPair<Curve>> opening_pairs,
60 std::span<const Polynomial> witness_polynomials,
61 const Fr& nu)
62 {
63 // Find n, the maximum size of all polynomials fⱼ(X)
64 size_t max_poly_size{ 0 };
65 for (const auto& poly : witness_polynomials) {
66 max_poly_size = std::max(max_poly_size, poly.size());
67 }
68 // Q(X) = ∑ⱼ ρʲ ⋅ ( fⱼ(X) − vⱼ) / ( X − xⱼ )
69 Polynomial Q(max_poly_size);
70 Polynomial tmp(max_poly_size);
71
72 Fr current_nu = Fr::one();
73 for (size_t j = 0; j < opening_pairs.size(); ++j) {
74 // (Cⱼ, xⱼ, vⱼ)
75 const auto& [challenge, evaluation] = opening_pairs[j];
76
77 // tmp = ρʲ ⋅ ( fⱼ(X) − vⱼ) / ( X − xⱼ )
78 tmp = witness_polynomials[j];
79 tmp[0] -= evaluation;
80 tmp.factor_roots(challenge);
81
82 Q.add_scaled(tmp, current_nu);
83 current_nu *= nu;
84 }
85
86 // Return batched quotient polynomial Q(X)
87 return Q;
88 };
89
101 std::span<const OpeningPair<Curve>> opening_pairs,
102 std::span<const Polynomial> witness_polynomials,
103 Polynomial&& batched_quotient_Q,
104 const Fr& nu_challenge,
105 const Fr& z_challenge)
106 {
107 const size_t num_opening_pairs = opening_pairs.size();
108
109 // {ẑⱼ(r)}ⱼ , where ẑⱼ(r) = 1/zⱼ(r) = 1/(r - xⱼ)
110 std::vector<Fr> inverse_vanishing_evals;
111 inverse_vanishing_evals.reserve(num_opening_pairs);
112 for (const auto& pair : opening_pairs) {
113 inverse_vanishing_evals.emplace_back(z_challenge - pair.challenge);
114 }
115 Fr::batch_invert(inverse_vanishing_evals);
116
117 // G(X) = Q(X) - Q_z(X) = Q(X) - ∑ⱼ ρʲ ⋅ ( fⱼ(X) − vⱼ) / ( r − xⱼ ),
118 // s.t. G(r) = 0
119 Polynomial G(std::move(batched_quotient_Q)); // G(X) = Q(X)
120
121 // G₀ = ∑ⱼ ρʲ ⋅ vⱼ / ( r − xⱼ )
122 Fr current_nu = Fr::one();
123 Polynomial tmp(G.size());
124 for (size_t j = 0; j < num_opening_pairs; ++j) {
125 // (Cⱼ, xⱼ, vⱼ)
126 const auto& [challenge, evaluation] = opening_pairs[j];
127
128 // tmp = ρʲ ⋅ ( fⱼ(X) − vⱼ) / ( r − xⱼ )
129 tmp = witness_polynomials[j];
130 tmp[0] -= evaluation;
131 Fr scaling_factor = current_nu * inverse_vanishing_evals[j]; // = ρʲ / ( r − xⱼ )
132
133 // G -= ρʲ ⋅ ( fⱼ(X) − vⱼ) / ( r − xⱼ )
134 G.add_scaled(tmp, -scaling_factor);
135
136 current_nu *= nu_challenge;
137 }
138
139 // Return opening pair (z, 0) and polynomial G(X) = Q(X) - Q_z(X)
140 return { .opening_pair = { .challenge = z_challenge, .evaluation = Fr::zero() }, .witness = std::move(G) };
141 };
142};
143
148template <typename Curve> class ShplonkVerifier_ {
149 using Fr = typename Curve::ScalarField;
150 using GroupElement = typename Curve::Element;
151 using Commitment = typename Curve::AffineElement;
153
154 public:
164 static OpeningClaim<Curve> reduce_verification(std::shared_ptr<VK> vk,
165 std::span<const OpeningClaim<Curve>> claims,
166 auto& transcript)
167 {
168
169 const size_t num_claims = claims.size();
170
171 const Fr nu = transcript->get_challenge("Shplonk:nu");
172
173 auto Q_commitment = transcript->template receive_from_prover<Commitment>("Shplonk:Q");
174
175 const Fr z_challenge = transcript->get_challenge("Shplonk:z");
176
177 // [G] = [Q] - ∑ⱼ ρʲ / ( r − xⱼ )⋅[fⱼ] + G₀⋅[1]
178 // = [Q] - [∑ⱼ ρʲ ⋅ ( fⱼ(X) − vⱼ) / ( r − xⱼ )]
179 GroupElement G_commitment;
180
181 // compute simulated commitment to [G] as a linear combination of
182 // [Q], { [fⱼ] }, [1]:
183 // [G] = [Q] - ∑ⱼ (1/zⱼ(r))[Bⱼ] + ( ∑ⱼ (1/zⱼ(r)) Tⱼ(r) )[1]
184 // = [Q] - ∑ⱼ (1/zⱼ(r))[Bⱼ] + G₀ [1]
185 // G₀ = ∑ⱼ ρʲ ⋅ vⱼ / ( r − xⱼ )
186 auto G_commitment_constant = Fr(0);
187
188 // TODO(#673): The recursive and non-recursive (native) logic is completely separated via the following
189 // conditional. Much of the logic could be shared, but I've chosen to do it this way since soon the "else"
190 // branch should be removed in its entirety, and "native" verification will utilize the recursive code paths
191 // using a builder Simulator.
192 if constexpr (Curve::is_stdlib_type) {
193 auto builder = nu.get_context();
194
195 // Containers for the inputs to the final batch mul
196 std::vector<Commitment> commitments;
197 std::vector<Fr> scalars;
198
199 // [G] = [Q] - ∑ⱼ ρʲ / ( r − xⱼ )⋅[fⱼ] + G₀⋅[1]
200 // = [Q] - [∑ⱼ ρʲ ⋅ ( fⱼ(X) − vⱼ) / ( r − xⱼ )]
201 commitments.emplace_back(Q_commitment);
202 scalars.emplace_back(Fr(builder, 1)); // Fr(1)
203
204 // Compute {ẑⱼ(r)}ⱼ , where ẑⱼ(r) = 1/zⱼ(r) = 1/(r - xⱼ)
205 std::vector<Fr> inverse_vanishing_evals;
206 inverse_vanishing_evals.reserve(num_claims);
207 for (const auto& claim : claims) {
208 // Note: no need for batch inversion; emulated inversion is cheap. (just show known inverse is valid)
209 inverse_vanishing_evals.emplace_back((z_challenge - claim.opening_pair.challenge).invert());
210 }
211
212 auto current_nu = Fr(1);
213 // Note: commitments and scalars vectors used only in recursion setting for batch mul
214 for (size_t j = 0; j < num_claims; ++j) {
215 // (Cⱼ, xⱼ, vⱼ)
216 const auto& [opening_pair, commitment] = claims[j];
217
218 Fr scaling_factor = current_nu * inverse_vanishing_evals[j]; // = ρʲ / ( r − xⱼ )
219
220 // G₀ += ρʲ / ( r − xⱼ ) ⋅ vⱼ
221 G_commitment_constant += scaling_factor * opening_pair.evaluation;
222
223 current_nu *= nu;
224
225 // Store MSM inputs for batch mul
226 commitments.emplace_back(commitment);
227 scalars.emplace_back(-scaling_factor);
228 }
229
230 commitments.emplace_back(GroupElement::one(builder));
231 scalars.emplace_back(G_commitment_constant);
232
233 // [G] += G₀⋅[1] = [G] + (∑ⱼ ρʲ ⋅ vⱼ / ( r − xⱼ ))⋅[1]
234 G_commitment = GroupElement::batch_mul(commitments, scalars);
235
236 } else {
237 // [G] = [Q] - ∑ⱼ ρʲ / ( r − xⱼ )⋅[fⱼ] + G₀⋅[1]
238 // = [Q] - [∑ⱼ ρʲ ⋅ ( fⱼ(X) − vⱼ) / ( r − xⱼ )]
239 G_commitment = Q_commitment;
240
241 // Compute {ẑⱼ(r)}ⱼ , where ẑⱼ(r) = 1/zⱼ(r) = 1/(r - xⱼ)
242 std::vector<Fr> inverse_vanishing_evals;
243 inverse_vanishing_evals.reserve(num_claims);
244 for (const auto& claim : claims) {
245 inverse_vanishing_evals.emplace_back(z_challenge - claim.opening_pair.challenge);
246 }
247 Fr::batch_invert(inverse_vanishing_evals);
248
249 auto current_nu = Fr(1);
250 // Note: commitments and scalars vectors used only in recursion setting for batch mul
251 for (size_t j = 0; j < num_claims; ++j) {
252 // (Cⱼ, xⱼ, vⱼ)
253 const auto& [opening_pair, commitment] = claims[j];
254
255 Fr scaling_factor = current_nu * inverse_vanishing_evals[j]; // = ρʲ / ( r − xⱼ )
256
257 // G₀ += ρʲ / ( r − xⱼ ) ⋅ vⱼ
258 G_commitment_constant += scaling_factor * opening_pair.evaluation;
259
260 // [G] -= ρʲ / ( r − xⱼ )⋅[fⱼ]
261 G_commitment -= commitment * scaling_factor;
262
263 current_nu *= nu;
264 }
265
266 // [G] += G₀⋅[1] = [G] + (∑ⱼ ρʲ ⋅ vⱼ / ( r − xⱼ ))⋅[1]
267 G_commitment += vk->srs->get_first_g1() * G_commitment_constant;
268 }
269
270 // Return opening pair (z, 0) and commitment [G]
271 return { { z_challenge, Fr(0) }, G_commitment };
272 };
273};
274} // namespace proof_system::honk::pcs::shplonk
Definition: polynomial.hpp:12
void factor_roots(std::span< const Fr > roots)
Divides p(X) by (X-r₁)⋯(X−rₘ) in-place. Assumes that p(rⱼ)=0 for all j.
Definition: polynomial.hpp:214
void add_scaled(std::span< const Fr > other, Fr scaling_factor)
adds the polynomial q(X) 'other', multiplied by a scaling factor.
Definition: polynomial.cpp:367
Unverified claim (C,r,v) for some witness polynomial p(X) such that.
Definition: claim.hpp:43
Opening pair (r,v) for some witness polynomial p(X) such that p(r) = v.
Definition: claim.hpp:12
Definition: verification_key.hpp:25
Shplonk Prover.
Definition: shplonk.hpp:46
static ProverOutput< Curve > compute_partially_evaluated_batched_quotient(std::span< const OpeningPair< Curve > > opening_pairs, std::span< const Polynomial > witness_polynomials, Polynomial &&batched_quotient_Q, const Fr &nu_challenge, const Fr &z_challenge)
Compute partially evaluated batched quotient polynomial difference Q(X) - Q_z(X)
Definition: shplonk.hpp:100
static Polynomial compute_batched_quotient(std::span< const OpeningPair< Curve > > opening_pairs, std::span< const Polynomial > witness_polynomials, const Fr &nu)
Compute batched quotient polynomial Q(X) = ∑ⱼ ρʲ ⋅ ( fⱼ(X) − vⱼ) / ( X − xⱼ )
Definition: shplonk.hpp:59
Shplonk Verifier.
Definition: shplonk.hpp:148
static OpeningClaim< Curve > reduce_verification(std::shared_ptr< VK > vk, std::span< const OpeningClaim< Curve > > claims, auto &transcript)
Recomputes the new claim commitment [G] given the proof and the challenge r. No verification happens ...
Definition: shplonk.hpp:164
Reduces multiple claims about commitments, each opened at a single point into a single claim for a si...
Definition: shplonk.hpp:21
Prover output (claim=([G], r, 0), witness = G(X), proof = [Q]) that can be passed on to a univariate ...
Definition: shplonk.hpp:36