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: Planned, auditors: [], commit: }
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
7#pragma once
10#include <array>
11
12/* Future improvements (see https://github.com/AztecProtocol/barretenberg/issues/10): The code works for its intended
13 * use but could be improved: Precomputing for all possible size pairs is
14 * probably feasible and might be a better solution than instantiating many instances separately. Then perhaps we could
15 * infer input type to `extend`.
16 */
17namespace bb {
18
25template <typename T> struct is_field_type {
26 static constexpr bool value = false;
27};
28
29template <typename Params> struct is_field_type<bb::field<Params>> {
30 static constexpr bool value = true;
31};
32
33template <typename T> inline constexpr bool is_field_type_v = is_field_type<T>::value;
34
46template <class Fr, size_t domain_end, size_t num_evals> class BarycentricDataFunctions {
47 public:
48 static constexpr size_t domain_size = domain_end;
49 static constexpr size_t big_domain_size = std::max(domain_size, num_evals);
50
51 static_assert(domain_size > 0, "BarycentricData requires domain_size > 0");
52 static_assert(num_evals > 0, "BarycentricData requires num_evals > 0");
53 static_assert(num_evals >= domain_end || (!is_field_type_v<Fr> && num_evals == 1),
54 "Expected num_evals >= domain_size (or stdlib num_evals==1 special case)");
55
60 // build big_domain, currently the set of x_i in {0, ..., big_domain_size - 1 }
62 {
64 for (size_t i = 0; i < big_domain_size; ++i) {
65 result[i] = static_cast<Fr>(i);
66 }
67 return result;
68 }
69
70 // build set of lagrange_denominators d_i = \prod_{j!=i} x_i - x_j
71 static constexpr std::array<Fr, domain_size> construct_lagrange_denominators(const auto& big_domain)
72 {
74 for (size_t i = 0; i != domain_size; ++i) {
75 result[i] = 1;
76 for (size_t j = 0; j != domain_size; ++j) {
77 if (j != i) {
78 result[i] *= big_domain[i] - big_domain[j];
79 }
80 }
81 }
82 return result;
83 }
84
85 // Non-constexpr helper so we can use BB_ASSERT inside the constexpr batch_invert.
86 static void assert_constant(const Fr& val)
87 {
88 if constexpr (!is_field_type_v<Fr>) {
89 BB_ASSERT(val.is_constant(), "barycentric coeffs must be constants, not witnesses");
90 }
91 }
92
95 {
96 constexpr size_t n = domain_size * num_evals;
97 std::array<Fr, n> temporaries{};
98 std::array<bool, n> skipped{};
99 Fr accumulator = 1;
100 for (size_t i = 0; i < n; ++i) {
101 temporaries[i] = accumulator;
102 // For native field types, == 0 is a plain constexpr comparison. For stdlib field_t,
103 // operator== would create circuit constraints and return bool_t, so we use get_value()
104 // to extract the underlying native value for a plain comparison instead. Note that coeffs[] are derived
105 // from constants (big_domain[i] = Fr(i)) and products/differences thereof, so they are constants. This
106 // makes the get_value() based zero check safe.
107 bool is_zero = false;
108 if constexpr (is_field_type_v<Fr>) {
109 is_zero = (coeffs[i] == 0);
110 } else {
111 assert_constant(coeffs[i]);
112 is_zero = (coeffs[i].get_value() == 0);
113 }
114 if (is_zero) {
115 skipped[i] = true;
116 } else {
117 skipped[i] = false;
118 accumulator *= coeffs[i];
119 }
120 }
121 accumulator = Fr(1) / accumulator;
122 std::array<Fr, n> result{};
123 Fr T0;
124 for (size_t i = n - 1; i < n; --i) {
125 if (!skipped[i]) {
126 T0 = accumulator * temporaries[i];
127 accumulator *= coeffs[i];
128 result[i] = T0;
129 }
130 }
131 return result;
132 }
133
134 // for each x_k in the big domain, build set of domain size-many denominator inverses
135 // 1/(d_i*(x_k - x_j)). will multiply against each of these (rather than to divide by something)
136 // for each barycentric evaluation
137 // special case for stdlib path: if num_evals == 1, we output the barycentric weights result[j] = 1 / d_j.
138 // This case does not arise on the native (compile-time) path.
140 const auto& big_domain, const auto& lagrange_denominators)
141 {
142 std::array<Fr, domain_size * num_evals> result{}; // default init to 0 since below does not init all elements
143 if constexpr (!is_field_type_v<Fr> && num_evals == 1) {
144 result = lagrange_denominators;
145 } else {
146 // Used in Univariate's `extend_to` method to extend univariates given by > 4 evaluations ( deg>3 ) to a
147 // bigger evaluation domain.
148 for (size_t k = domain_size; k < num_evals; ++k) {
149 for (size_t j = 0; j < domain_size; ++j) {
150 Fr inv = lagrange_denominators[j];
151 inv *= (big_domain[k] - big_domain[j]);
152 result[(k * domain_size) + j] = inv;
153 }
154 }
155 }
156 return batch_invert(result);
157 }
158
159 // get full numerator values
160 // full numerator is M(x) = \prod_{i} (x-x_i)
161 // these will be zero for i < domain_size, but that's ok because
162 // at such entries we will already have the evaluations of the polynomial
163 static constexpr std::array<Fr, num_evals> construct_full_numerator_values(const auto& big_domain)
164 {
166 for (size_t i = 0; i != num_evals; ++i) {
167 result[i] = 1;
168 Fr v_i = i;
169 for (size_t j = 0; j != domain_size; ++j) {
170 result[i] *= v_i - big_domain[j];
171 }
172 }
173 return result;
174 }
175};
176
181template <class Fr, size_t domain_end, size_t num_evals>
195
200template <class Fr, size_t domain_end, size_t num_evals>
214
222template <class Fr, size_t domain_end, size_t num_evals>
226
227} // namespace bb
#define BB_ASSERT(expression,...)
Definition assert.hpp:70
Compile-time variant: precomputed arrays are static constexpr.
static constexpr auto lagrange_denominators
static constexpr auto big_domain
static constexpr auto precomputed_denominator_inverses
static constexpr auto full_numerator_values
Shared computation logic for barycentric extension and evaluation data.
static constexpr std::array< Fr, domain_size *num_evals > construct_denominator_inverses(const auto &big_domain, const auto &lagrange_denominators)
static constexpr std::array< Fr, num_evals > construct_full_numerator_values(const auto &big_domain)
static constexpr size_t domain_size
static constexpr size_t big_domain_size
static constexpr std::array< Fr, domain_size > construct_lagrange_denominators(const auto &big_domain)
static constexpr std::array< Fr, big_domain_size > construct_big_domain()
static void assert_constant(const Fr &val)
static constexpr std::array< Fr, domain_size *num_evals > batch_invert(const std::array< Fr, domain_size *num_evals > &coeffs)
Run-time variant: precomputed arrays are inline static const.
static const auto lagrange_denominators
static const auto full_numerator_values
static const auto precomputed_denominator_inverses
static const auto big_domain
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
constexpr bool is_field_type_v
std::conditional_t< is_field_type_v< Fr >, BarycentricDataCompileTime< Fr, domain_end, num_evals >, BarycentricDataRunTime< Fr, domain_end, num_evals > > 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
General class for prime fields see Prime field documentation["field documentation"] for general imple...
Helper to determine whether input is bb::field type.
static constexpr bool value