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: 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
10#include <array>
11
12namespace bb {
13
20template <typename T> struct is_field_type {
21 static constexpr bool value = false;
22};
23
24template <typename Params> struct is_field_type<bb::field<Params>> {
25 static constexpr bool value = true;
26};
27
28template <typename T> inline constexpr bool is_field_type_v = is_field_type<T>::value;
29
41template <class Fr, size_t domain_end, size_t num_evals> class BarycentricDataFunctions {
42 public:
43 static constexpr size_t domain_size = domain_end;
44 static constexpr size_t big_domain_size = std::max(domain_size, num_evals);
45
46 static_assert(domain_size > 0, "BarycentricData requires domain_size > 0");
47 static_assert(num_evals > 0, "BarycentricData requires num_evals > 0");
48 static_assert(num_evals >= domain_end || (!is_field_type_v<Fr> && num_evals == 1),
49 "Expected num_evals >= domain_size (or stdlib num_evals==1 special case)");
50
55 // build big_domain, currently the set of x_i in {0, ..., big_domain_size - 1 }
57 {
59 for (size_t i = 0; i < big_domain_size; ++i) {
60 result[i] = static_cast<Fr>(i);
61 }
62 return result;
63 }
64
65 // build set of lagrange_denominators d_i = \prod_{j!=i} x_i - x_j
66 static constexpr std::array<Fr, domain_size> construct_lagrange_denominators(const auto& big_domain)
67 {
69 for (size_t i = 0; i != domain_size; ++i) {
70 result[i] = 1;
71 for (size_t j = 0; j != domain_size; ++j) {
72 if (j != i) {
73 result[i] *= big_domain[i] - big_domain[j];
74 }
75 }
76 }
77 return result;
78 }
79
80 // Non-constexpr helper so we can use BB_ASSERT inside the constexpr batch_invert.
81 static void assert_constant(const Fr& val)
82 {
83 if constexpr (!is_field_type_v<Fr>) {
84 BB_ASSERT(val.is_constant(), "barycentric coeffs must be constants, not witnesses");
85 }
86 }
87
90 {
91 constexpr size_t n = domain_size * num_evals;
92 std::array<Fr, n> temporaries{};
93 std::array<bool, n> skipped{};
94 Fr accumulator = 1;
95 for (size_t i = 0; i < n; ++i) {
96 temporaries[i] = accumulator;
97 // For native field types, == 0 is a plain constexpr comparison. For stdlib field_t,
98 // operator== would create circuit constraints and return bool_t, so we use get_value()
99 // to extract the underlying native value for a plain comparison instead. Note that coeffs[] are derived
100 // from constants (big_domain[i] = Fr(i)) and products/differences thereof, so they are constants. This
101 // makes the get_value() based zero check safe.
102 bool is_zero = false;
103 if constexpr (is_field_type_v<Fr>) {
104 is_zero = (coeffs[i] == 0);
105 } else {
106 assert_constant(coeffs[i]);
107 is_zero = (coeffs[i].get_value() == 0);
108 }
109 if (is_zero) {
110 skipped[i] = true;
111 } else {
112 skipped[i] = false;
113 accumulator *= coeffs[i];
114 }
115 }
116 accumulator = Fr(1) / accumulator;
117 std::array<Fr, n> result{};
118 Fr T0;
119 for (size_t i = n - 1; i < n; --i) {
120 if (!skipped[i]) {
121 T0 = accumulator * temporaries[i];
122 accumulator *= coeffs[i];
123 result[i] = T0;
124 }
125 }
126 return result;
127 }
128
129 // for each x_k in the big domain, build set of domain size-many denominator inverses
130 // 1/(d_i*(x_k - x_j)). will multiply against each of these (rather than to divide by something)
131 // for each barycentric evaluation
132 // special case for stdlib path: if num_evals == 1, we output the barycentric weights result[j] = 1 / d_j.
133 // This case does not arise on the native (compile-time) path.
135 const auto& big_domain, const auto& lagrange_denominators)
136 {
137 std::array<Fr, domain_size * num_evals> result{}; // default init to 0 since below does not init all elements
138 if constexpr (!is_field_type_v<Fr> && num_evals == 1) {
139 result = lagrange_denominators;
140 } else {
141 // Used in Univariate's `extend_to` method to extend univariates given by > 4 evaluations ( deg>3 ) to a
142 // bigger evaluation domain.
143 for (size_t k = domain_size; k < num_evals; ++k) {
144 for (size_t j = 0; j < domain_size; ++j) {
145 Fr inv = lagrange_denominators[j];
146 inv *= (big_domain[k] - big_domain[j]);
147 result[(k * domain_size) + j] = inv;
148 }
149 }
150 }
151 return batch_invert(result);
152 }
153
154 // get full numerator values
155 // full numerator is M(x) = \prod_{i} (x-x_i)
156 // these will be zero for i < domain_size, but that's ok because
157 // at such entries we will already have the evaluations of the polynomial
158 static constexpr std::array<Fr, num_evals> construct_full_numerator_values(const auto& big_domain)
159 {
161 for (size_t i = 0; i != num_evals; ++i) {
162 result[i] = 1;
163 Fr v_i = i;
164 for (size_t j = 0; j != domain_size; ++j) {
165 result[i] *= v_i - big_domain[j];
166 }
167 }
168 return result;
169 }
170};
171
176template <class Fr, size_t domain_end, size_t num_evals>
190
195template <class Fr, size_t domain_end, size_t num_evals>
209
217template <class Fr, size_t domain_end, size_t num_evals>
221
222} // 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