Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
eq_polynomial.hpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: Complete, auditors: [Nishat], commit: 94f596f8b3bbbc216f9ad7dc33253256141156b2 }
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
7#pragma once
13#include "gate_separator.hpp"
14
15#include <cstddef>
16#include <vector>
17namespace bb {
18
42template <typename FF> class ProverEqPolynomial {
43
44 public:
61 static Polynomial<FF> construct(std::span<const FF> challenges, size_t log_num_monomials)
62 {
63 // Prevent OOB read: compute_beta_products below (and construct_eq_with_edge_cases on the fallback path) read
64 // challenges[0..log_num_monomials).
65 BB_ASSERT_GTE(challenges.size(),
66 log_num_monomials,
67 "ProverEqPolynomial::construct: challenges.size() must be >= log_num_monomials");
68
69 // eq over 0 variables is the empty product 1.
70 if (log_num_monomials == 0) {
71 Polynomial<FF> result(/*size=*/1, /*virtual_size=*/1);
72 result.at(0) = FF(1);
73 return result;
74 }
75
76 // Compute scaling factor C = ∏_i (1 - r_i)
77 FF scaling_factor = compute_scaling_factor(challenges);
78
79 // In production, challenges are generated by hashing the transcript, hence with high probability
80 // none of them equals 1. If C = 0, at least one r_i = 1, so we must use the fallback method.
81 if (scaling_factor.is_zero()) {
82 return construct_eq_with_edge_cases(challenges, log_num_monomials);
83 }
84
85 // Optimal path: transform to γ_i = r_i / (1 - r_i) and delegate to pow_β algorithm
87 transform_challenge(challenges), log_num_monomials, scaling_factor);
88 };
89
99 {
100 FF out(1);
101 const FF one(1);
102 for (auto u_i : challenge) {
103 out *= (one - u_i);
104 }
105 return out;
106 }
107
119 static std::vector<FF> transform_challenge(std::span<const FF> challenges)
120 {
121 std::vector<FF> result;
122 std::vector<FF> denominators;
123 for (const auto& challenge : challenges) {
124 denominators.push_back((FF(1) - challenge));
125 }
126
127 FF::batch_invert(denominators);
128
129 for (const auto& [denom_inverted, challenge] : zip_view(denominators, challenges)) {
130 result.push_back(denom_inverted * challenge);
131 }
132
133 return result;
134 }
135
160 {
161 const size_t d = r.size();
162 BB_ASSERT_EQ(d, log_num_monomials, "expect log_num_monomials == r.size()");
163 const size_t N = 1UL << d;
164
165 // Precompute per-variable linear/constant coeffs:
166 // eq(X,r) = ∏_i ( b_i + a_i X_i ), a_i = 2r_i - 1, b_i = 1 - r_i
167 std::vector<FF> eq_linear_coeffs(d);
168 std::vector<FF> eq_constant_coeffs(d);
169 for (size_t i = 0; i < d; ++i) {
170 eq_linear_coeffs[i] = r[i] + r[i] - FF(1); // a_i
171 eq_constant_coeffs[i] = FF(1) - r[i]; // b_i
172 }
173
174 // Start with table size 1: [1]
175 Polynomial<FF> current(
176 /*size*/ 1, /*virtual_size*/ N, /*start_index*/ 0, Polynomial<FF>::DontZeroMemory::FLAG);
177 current.at(0) = FF(1);
178
179 // Grow one variable at a time: size doubles each round
180 for (size_t var_idx = 0; var_idx < d; ++var_idx) {
181 const FF a_i = eq_linear_coeffs[var_idx];
182 const FF b_i = eq_constant_coeffs.at(var_idx);
183
184 const size_t prev_size = current.size();
185 const size_t next_size = prev_size << 1;
186
187 Polynomial<FF> next(/*size*/ next_size,
188 /*virtual_size*/ N,
189 /*start_index*/ 0,
191
192 // Write lower and upper halves
193 const FF* src = current.data();
194 FF* dst = next.data();
195
196 for (size_t j = 0; j < prev_size; ++j) {
197 const FF v = src[j];
198 dst[j] = v * b_i; // bit_i = 0: multiply by b_i
199 dst[j + prev_size] = v * (b_i + a_i); // bit_i = 1: multiply by (b_i + a_i)
200 }
201
202 current = std::move(next);
203 }
204
205 // current now holds all 2^d coefficients, index = mask over {X_i}
206 return current;
207 }
208};
209
222template <typename FF> struct VerifierEqPolynomial {
223 // --- Instance data (fixed for a proof) ---
224 std::vector<FF> r; // instance challenges r_i
225 std::vector<FF> a; // a_i = 2 r_i - 1
226 std::vector<FF> b; // b_i = 1 - r_i
227
228 explicit VerifierEqPolynomial(const std::vector<FF>& r_in) { initialize(r_in); }
229
230 void initialize(const std::vector<FF>& r_in)
231 {
232 r = r_in;
233 a.resize(r.size());
234 b.resize(r.size());
235 for (size_t i = 0; i < r.size(); ++i) {
236 a[i] = r[i] + r[i] - FF(1); // 2 r_i - 1
237 b[i] = FF(1) - r[i]; // 1 - r_i
238 }
239 }
240
241 // ---- Evaluate eq(X, r) at u ----
243 {
244 BB_ASSERT_EQ(u.size(), r.size(), "expect u.size() == r.size()");
245 FF acc = FF(1);
246 for (size_t i = 0; i < u.size(); ++i) {
247 // term_i = b_i + u_i * a_i
248 acc *= (b[i] + u[i] * a[i]);
249 }
250 return acc;
251 }
252
253 // ---- Compute eq(r, u) without constructing the object ----
255 {
256 BB_ASSERT_EQ(r_in.size(), u.size(), "expect r_in.size() == u.size()");
257 FF acc = FF(1);
258 for (size_t i = 0; i < r_in.size(); ++i) {
259 const FF ai = r_in[i] + r_in[i] - FF(1);
260 const FF bi = FF(1) - r_in[i];
261 acc *= (bi + u[i] * ai);
262 }
263 return acc;
264 }
265};
266
267} // namespace bb
#define BB_ASSERT_GTE(left, right,...)
Definition assert.hpp:128
#define BB_ASSERT_EQ(actual, expected,...)
Definition assert.hpp:83
bb::field< bb::Bn254FrParams > FF
Definition field.cpp:24
Structured polynomial class that represents the coefficients 'a' of a_0 + a_1 x .....
Fr & at(size_t index)
Our mutable accessor, unlike operator[]. We abuse precedent a bit to differentiate at() and operator[...
std::size_t size() const
Prover-side eq(X, r) polynomial over Boolean hypercube.
static FF compute_scaling_factor(std::span< const FF > challenge)
Compute the scaling factor C = ∏_i (1 - r_i) for coordinate transformation.
static std::vector< FF > transform_challenge(std::span< const FF > challenges)
Transform challenges r_i to γ_i = r_i / (1 - r_i) for optimal method.
static Polynomial< FF > construct(std::span< const FF > challenges, size_t log_num_monomials)
Construct eq(X, r) coefficient table over Boolean hypercube {0,1}^d.
static Polynomial< FF > construct_eq_with_edge_cases(std::span< const FF > r, size_t log_num_monomials)
Fallback method: direct construction of eq(X, r) coefficient table for edge cases.
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
static BB_PROFILE Polynomial< FF > compute_beta_products(const std::vector< FF > &betas, const size_t log_num_monomials, const FF &scaling_factor=FF(1))
Given compute for .
Verifier-side polynomial for division-free evaluation of eq(r, u).
void initialize(const std::vector< FF > &r_in)
FF evaluate(std::span< const FF > u) const
VerifierEqPolynomial(const std::vector< FF > &r_in)
static FF eval(std::span< const FF > r_in, std::span< const FF > u)
BB_INLINE constexpr bool is_zero() const noexcept
static void batch_invert(C &coeffs) noexcept
Batch invert a collection of field elements using Montgomery's trick.