Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
barycentric.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
9#include <array>
10
11// TODO(#674): We need the functionality of BarycentricData for both field (native) and field_t (stdlib). The former is
12// is compatible with constexpr operations, and the former is not. The functions for computing the
13// pre-computable arrays in BarycentricData need to be constexpr and it takes some trickery to share these functions
14// with the non-constexpr setting. Right now everything is more or less duplicated across BarycentricDataCompileTime and
15// BarycentricDataRunTime. There should be a way to share more of the logic.
16
17/* TODO(https://github.com/AztecProtocol/barretenberg/issues/10): This could or should be improved in various ways. In
18 no particular order:
19 1) Edge cases are not considered. One non-use case situation (I forget which) leads to a segfault.
20
21 2) Precomputing for all possible size pairs is probably feasible and might be a better solution than instantiating
22 many instances separately. Then perhaps we could infer input type to `extend`.
23
24 3) There should be more thorough testing of this class in isolation.
25 */
26namespace bb {
27
34template <class Fr, size_t domain_end, size_t num_evals, size_t domain_start = 0> class BarycentricDataCompileTime {
35 public:
36 static constexpr size_t domain_size = domain_end - domain_start;
37 static constexpr size_t big_domain_size = std::max(domain_size, num_evals);
38
43 // build big_domain, currently the set of x_i in {domain_start, ..., big_domain_end - 1 }
45 {
47 for (size_t i = 0; i < big_domain_size; ++i) {
48 result[i] = static_cast<Fr>(i + domain_start);
49 }
50 return result;
51 }
52
53 // build set of lagrange_denominators d_i = \prod_{j!=i} x_i - x_j
55 {
57 for (size_t i = 0; i != domain_size; ++i) {
58 result[i] = 1;
59 for (size_t j = 0; j != domain_size; ++j) {
60 if (j != i) {
61 result[i] *= big_domain[i] - big_domain[j];
62 }
63 }
64 }
65 return result;
66 }
67
70 {
71 constexpr size_t n = domain_size * num_evals;
72 std::array<Fr, n> temporaries{};
73 std::array<bool, n> skipped{};
74 Fr accumulator = 1;
75 for (size_t i = 0; i < n; ++i) {
76 temporaries[i] = accumulator;
77 if (coeffs[i] == 0) {
78 skipped[i] = true;
79 } else {
80 skipped[i] = false;
81 accumulator *= coeffs[i];
82 }
83 }
84 accumulator = Fr(1) / accumulator;
85 std::array<Fr, n> result{};
86 Fr T0;
87 for (size_t i = n - 1; i < n; --i) {
88 if (!skipped[i]) {
89 T0 = accumulator * temporaries[i];
90 accumulator *= coeffs[i];
91 result[i] = T0;
92 }
93 }
94 return result;
95 }
96 // for each x_k in the big domain, build set of domain size-many denominator inverses
97 // 1/(d_i*(x_k - x_j)). will multiply against each of these (rather than to divide by something)
98 // for each barycentric evaluation
100 const auto& big_domain, const auto& lagrange_denominators)
101 {
102 std::array<Fr, domain_size * num_evals> result{}; // default init to 0 since below does not init all elements
103 for (size_t k = domain_size; k < num_evals; ++k) {
104 for (size_t j = 0; j < domain_size; ++j) {
105 Fr inv = lagrange_denominators[j];
106 inv *= (big_domain[k] - big_domain[j]);
107 result[k * domain_size + j] = inv;
108 }
109 }
110 return batch_invert(result);
111 }
112
113 // get full numerator values
114 // full numerator is M(x) = \prod_{i} (x-x_i)
115 // these will be zero for i < domain_size, but that's ok because
116 // at such entries we will already have the evaluations of the polynomial
118 {
120 for (size_t i = 0; i != num_evals; ++i) {
121 result[i] = 1;
122 Fr v_i = i + domain_start;
123 for (size_t j = 0; j != domain_size; ++j) {
124 result[i] *= v_i - big_domain[j];
125 }
126 }
127 return result;
128 }
129
130 static constexpr auto big_domain = construct_big_domain();
132 static constexpr auto precomputed_denominator_inverses =
135};
136
137template <class Fr, size_t domain_end, size_t num_evals, size_t domain_start = 0> class BarycentricDataRunTime {
138 public:
139 static constexpr size_t domain_size = domain_end - domain_start;
140 static constexpr size_t big_domain_size = std::max(domain_size, num_evals);
141
146 // build big_domain, currently the set of x_i in {domain_start, ..., big_domain_end - 1 }
148 {
150 for (size_t i = 0; i < big_domain_size; ++i) {
151 result[i] = static_cast<Fr>(i + domain_start);
152 }
153 return result;
154 }
155
156 // build set of lagrange_denominators d_i = \prod_{j!=i} x_i - x_j
158 {
160 for (size_t i = 0; i != domain_size; ++i) {
161 result[i] = 1;
162 for (size_t j = 0; j != domain_size; ++j) {
163 if (j != i) {
164 result[i] *= big_domain[i] - big_domain[j];
165 }
166 }
167 }
168 return result;
169 }
170
172 {
173 constexpr size_t n = domain_size * num_evals;
174 std::array<Fr, n> temporaries{};
175 std::array<bool, n> skipped{};
176 Fr accumulator = 1;
177 for (size_t i = 0; i < n; ++i) {
178 temporaries[i] = accumulator;
179 if (coeffs[i].get_value() == 0) {
180 skipped[i] = true;
181 } else {
182 skipped[i] = false;
183 accumulator *= coeffs[i];
184 }
185 }
186 accumulator = Fr(1) / accumulator;
187 std::array<Fr, n> result{};
188 Fr T0;
189 for (size_t i = n - 1; i < n; --i) {
190 if (!skipped[i]) {
191 T0 = accumulator * temporaries[i];
192 accumulator *= coeffs[i];
193 result[i] = T0;
194 }
195 }
196 return result;
197 }
198 // for each x_k in the big domain, build set of domain size-many denominator inverses
199 // 1/(d_i*(x_k - x_j)). will multiply against each of these (rather than to divide by something)
200 // for each barycentric evaluation
202 const auto& lagrange_denominators)
203 {
204 std::array<Fr, domain_size * num_evals> result{}; // default init to 0 since below does not init all elements
205 if constexpr (num_evals == 1) {
206 result = lagrange_denominators;
207 } else {
208 // Used in Univariate's `extend_to` method to extend univariates given by > 4 evaluations ( deg>3 ) to a
209 // bigger evaluation domains.
210 for (size_t k = domain_size; k < num_evals; ++k) {
211 for (size_t j = 0; j < domain_size; ++j) {
212 Fr inv = lagrange_denominators[j];
213 inv *= (big_domain[k] - big_domain[j]);
214 result[k * domain_size + j] = inv;
215 }
216 }
217 }
218 return batch_invert(result);
219 }
220
221 // get full numerator values
222 // full numerator is M(x) = \prod_{i} (x-x_i)
223 // these will be zero for i < domain_size, but that's ok because
224 // at such entries we will already have the evaluations of the polynomial
226 {
228 for (size_t i = 0; i != num_evals; ++i) {
229 result[i] = 1;
230 Fr v_i = i + domain_start;
231 for (size_t j = 0; j != domain_size; ++j) {
232 result[i] *= v_i - big_domain[j];
233 }
234 }
235 return result;
236 }
237
238 inline static const auto big_domain = construct_big_domain();
240 inline static const auto precomputed_denominator_inverses =
243};
244
250template <typename T> struct is_field_type {
251 static constexpr bool value = false;
252};
253
254template <typename Params> struct is_field_type<bb::field<Params>> {
255 static constexpr bool value = true;
256};
257
258template <typename T> inline constexpr bool is_field_type_v = is_field_type<T>::value;
259
267template <class Fr, size_t domain_end, size_t num_evals, size_t domain_start = 0>
271
272} // namespace bb
static constexpr size_t domain_size
static constexpr std::array< Fr, big_domain_size > construct_big_domain()
static constexpr std::array< Fr, domain_size *num_evals > batch_invert(const std::array< Fr, domain_size *num_evals > &coeffs)
static constexpr std::array< Fr, num_evals > construct_full_numerator_values(const auto &big_domain)
static constexpr auto lagrange_denominators
static constexpr size_t big_domain_size
static constexpr auto full_numerator_values
static constexpr auto big_domain
static constexpr std::array< Fr, domain_size > construct_lagrange_denominators(const auto &big_domain)
static constexpr auto precomputed_denominator_inverses
static constexpr std::array< Fr, domain_size *num_evals > construct_denominator_inverses(const auto &big_domain, const auto &lagrange_denominators)
static std::array< Fr, domain_size *num_evals > construct_denominator_inverses(const auto &big_domain, const auto &lagrange_denominators)
static std::array< Fr, domain_size > construct_lagrange_denominators(const auto &big_domain)
static constexpr size_t domain_size
static std::array< Fr, num_evals > construct_full_numerator_values(const auto &big_domain)
static const auto precomputed_denominator_inverses
static std::array< Fr, domain_size *num_evals > batch_invert(const std::array< Fr, domain_size *num_evals > &coeffs)
static const auto full_numerator_values
static std::array< Fr, big_domain_size > construct_big_domain()
static const auto big_domain
static const auto lagrange_denominators
static constexpr size_t big_domain_size
Entry point for Barretenberg command-line interface.
constexpr bool is_field_type_v
std::conditional_t< is_field_type_v< Fr >, BarycentricDataCompileTime< Fr, domain_end, num_evals, domain_start >, BarycentricDataRunTime< Fr, domain_end, num_evals, domain_start > > BarycentricData
Exposes BarycentricData with compile time arrays if the type is bberg::field and runtime arrays other...
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
Curve::ScalarField Fr
Helper to determine whether input is bberg::field type.
static constexpr bool value