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: not started, auditors: [], date: YYYY-MM-DD }
3// external_1: { status: not started, auditors: [], date: YYYY-MM-DD }
4// external_2: { status: not started, auditors: [], date: YYYY-MM-DD }
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:
56 static Polynomial<FF> construct(std::span<const FF> challenges, size_t log_num_monomials)
57 {
58 // Compute scaling factor C = ∏_i (1 - r_i)
59 FF scaling_factor = compute_scaling_factor(challenges);
60
61 // In production, challenges are generated by hashing the transcript, hence with high probability
62 // none of them equals 1. If C = 0, at least one r_i = 1, so we must use the fallback method.
63 if (scaling_factor.is_zero()) {
64 return construct_eq_with_edge_cases(challenges, log_num_monomials);
65 }
66
67 // Optimal path: transform to γ_i = r_i / (1 - r_i) and delegate to pow_β algorithm
69 transform_challenge(challenges), log_num_monomials, scaling_factor);
70 };
71
81 {
82 FF out(1);
83 const FF one(1);
84 for (auto u_i : challenge) {
85 out *= (one - u_i);
86 }
87 return out;
88 }
89
101 static std::vector<FF> transform_challenge(std::span<const FF> challenges)
102 {
103 std::vector<FF> result;
104 std::vector<FF> denominators;
105 for (const auto& challenge : challenges) {
106 denominators.push_back((FF(1) - challenge));
107 }
108
109 FF::batch_invert(denominators);
110
111 for (const auto& [denom_inverted, challenge] : zip_view(denominators, challenges)) {
112 result.push_back(denom_inverted * challenge);
113 }
114
115 return result;
116 }
117
142 {
143 const size_t d = r.size();
144 BB_ASSERT_EQ(d, log_num_monomials, "expect log_num_monomials == r.size()");
145 const size_t N = 1UL << d;
146
147 // Precompute per-variable linear/constant coeffs:
148 // eq(X,r) = ∏_i ( b_i + a_i X_i ), a_i = 2r_i - 1, b_i = 1 - r_i
149 std::vector<FF> eq_linear_coeffs(d);
150 std::vector<FF> eq_constant_coeffs(d);
151 for (size_t i = 0; i < d; ++i) {
152 eq_linear_coeffs[i] = r[i] + r[i] - FF(1); // a_i
153 eq_constant_coeffs[i] = FF(1) - r[i]; // b_i
154 }
155
156 // Start with table size 1: [1]
157 Polynomial<FF> current(
158 /*size*/ 1, /*virtual_size*/ N, /*start_index*/ 0, Polynomial<FF>::DontZeroMemory::FLAG);
159 current.at(0) = FF(1);
160
161 // Grow one variable at a time: size doubles each round
162 for (size_t var_idx = 0; var_idx < d; ++var_idx) {
163 const FF a_i = eq_linear_coeffs[var_idx];
164 const FF b_i = eq_constant_coeffs.at(var_idx);
165
166 const size_t prev_size = current.size();
167 const size_t next_size = prev_size << 1;
168
169 Polynomial<FF> next(/*size*/ next_size,
170 /*virtual_size*/ N,
171 /*start_index*/ 0,
173
174 // Write lower and upper halves
175 const FF* src = current.data();
176 FF* dst = next.data();
177
178 for (size_t j = 0; j < prev_size; ++j) {
179 const FF v = src[j];
180 dst[j] = v * b_i; // bit_i = 0: multiply by b_i
181 dst[j + prev_size] = v * (b_i + a_i); // bit_i = 1: multiply by (b_i + a_i)
182 }
183
184 current = std::move(next);
185 }
186
187 // current now holds all 2^d coefficients, index = mask over {X_i}
188 return current;
189 }
190};
191
204template <typename FF> struct VerifierEqPolynomial {
205 // --- Instance data (fixed for a proof) ---
206 std::vector<FF> r; // instance challenges r_i
207 std::vector<FF> a; // a_i = 2 r_i - 1
208 std::vector<FF> b; // b_i = 1 - r_i
209
210 explicit VerifierEqPolynomial(const std::vector<FF>& r_in) { initialize(r_in); }
211
212 void initialize(const std::vector<FF>& r_in)
213 {
214 r = r_in;
215 a.resize(r.size());
216 b.resize(r.size());
217 for (size_t i = 0; i < r.size(); ++i) {
218 a[i] = r[i] + r[i] - FF(1); // 2 r_i - 1
219 b[i] = FF(1) - r[i]; // 1 - r_i
220 }
221 }
222
223 // ---- Evaluate eq(X, r) at u ----
225 {
226 assert(u.size() == r.size());
227 FF acc = FF(1);
228 for (size_t i = 0; i < u.size(); ++i) {
229 // term_i = b_i + u_i * a_i
230 acc *= (b[i] + u[i] * a[i]);
231 }
232 return acc;
233 }
234
235 // ---- Compute eq(r, u) without constructing the object ----
237 {
238 assert(r_in.size() == u.size());
239 FF acc = FF(1);
240 for (size_t i = 0; i < r_in.size(); ++i) {
241 const FF ai = r_in[i] + r_in[i] - FF(1);
242 const FF bi = FF(1) - r_in[i];
243 acc *= (bi + u[i] * ai);
244 }
245 return acc;
246 }
247};
248
249} // namespace bb
#define BB_ASSERT_EQ(actual, expected,...)
Definition assert.hpp:88
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.
typename Flavor::FF FF
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)
static void batch_invert(C &coeffs) noexcept