Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
univariate_coefficient_basis.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
11#include <span>
12
13namespace bb {
14
39template <class Fr, size_t domain_end, bool has_a0_plus_a1> class UnivariateCoefficientBasis {
40 public:
41 static constexpr size_t LENGTH = domain_end;
42 static_assert(LENGTH == 2 || LENGTH == 3);
43 using value_type = Fr; // used to get the type of the elements consistently with std::array
44
56 std::array<Fr, 3> coefficients;
57
59
61 requires(!has_a0_plus_a1)
62 {
63 coefficients[0] = other.coefficients[0];
64 coefficients[1] = other.coefficients[1];
65 if constexpr (domain_end == 3) {
66 coefficients[2] = other.coefficients[2];
67 }
68 }
69
75
76 template <size_t other_domain_end, bool other_has_a0_plus_a1 = true>
78 requires(domain_end > other_domain_end)
79 {
80 coefficients[0] = other.coefficients[0];
81 coefficients[1] = other.coefficients[1];
82 if constexpr (domain_end == 3) {
83 coefficients[2] = 0;
84 }
85 };
86
87 // operator== is deleted. If an equality is needed, care must be taken to define the semantics correctly. The
88 // semantic meaning of coefficients[2] depends on template parameters (unused for domain_end=2,
89 // has_a0_plus_a1=false; a0+a1 Karatsuba precomputation for has_a0_plus_a1=true; the x^2 coefficient for
90 // domain_end=3), so a defaulted comparison can produce false negatives between construction paths that represent
91 // the same polynomial.
92 bool operator==(const UnivariateCoefficientBasis& other) const = delete;
93
94 template <size_t other_domain_end, bool other_has_a0_plus_a1>
97 {
98 // if both operands are degree-1, then we do not update coefficients[2], which represents `a1 + a0`
99 // the output object therefore must have `other_has_a0_plus_a1` set to false.
100 // i.e. the input also requires `other_has_a0_plus_a1`, otherwise use `operator+
101 coefficients[0] += other.coefficients[0];
102 coefficients[1] += other.coefficients[1];
103 if constexpr (other_domain_end == 3 && domain_end == 3) {
104 coefficients[2] += other.coefficients[2];
105 }
106 return *this;
107 }
108
109 template <size_t other_domain_end, bool other_has_a0_plus_a1>
112 {
113 // if both operands are degree-1, then we do not update coefficients[2], which represents `a1 + a0`
114 // the output object therefore must have `other_has_a0_plus_a1` set to false.
115 // i.e. the input also requires `other_has_a0_plus_a1`, otherwise use `operator+
116 coefficients[0] -= other.coefficients[0];
117 coefficients[1] -= other.coefficients[1];
118 if constexpr (other_domain_end == 3 && domain_end == 3) {
119 coefficients[2] -= other.coefficients[2];
120 }
121 return *this;
122 }
123
124 template <bool other_has_a0_plus_a1>
127 requires(LENGTH == 2)
128 {
130 // result.coefficients[0] = a0 * b0;
131 // result.coefficients[2] = a1 * b1
132 result.coefficients[0] = coefficients[0] * other.coefficients[0];
133 result.coefficients[2] = coefficients[1] * other.coefficients[1];
134
135 // the reason we've been tracking this variable all this time.
136 // coefficients[1] = sum of X^2 and X coefficients
137 // (a0 + a1X) * (b0 + b1X) = a0b0 + (a0b1 + a1b0)X + a1b1XX
138 // coefficients[1] = a0b1 + a1b0 + a1b1
139 // which represented as (a0 + a1) * (b0 + b1) - a0b0
140 // if we have a1_plus_a0
141 if constexpr (has_a0_plus_a1 && other_has_a0_plus_a1) {
142 result.coefficients[1] = (coefficients[2] * other.coefficients[2] - result.coefficients[0]);
143 } else if constexpr (has_a0_plus_a1 && !other_has_a0_plus_a1) {
144 result.coefficients[1] =
145 coefficients[2] * (other.coefficients[0] + other.coefficients[1]) - result.coefficients[0];
146 } else if constexpr (!has_a0_plus_a1 && other_has_a0_plus_a1) {
147 result.coefficients[1] =
148 (coefficients[0] + coefficients[1]) * other.coefficients[2] - result.coefficients[0];
149 } else {
150 result.coefficients[1] =
151 (coefficients[0] + coefficients[1]) * (other.coefficients[0] + other.coefficients[1]) -
152 result.coefficients[0];
153 }
154 return result;
155 }
156
157 template <size_t other_domain_end, bool other_has_a0_plus_a1>
160 {
162 // if both operands are degree-1, then we do not update coefficients[2], which represents `a1 + a0`
163 // the output object therefore must have `other_has_a0_plus_a1` set to false.
164 // i.e. the input also requires `other_has_a0_plus_a1`, otherwise use `operator+
165 res.coefficients[0] += other.coefficients[0];
166 res.coefficients[1] += other.coefficients[1];
167 if constexpr (other_domain_end == 3 && domain_end == 3) {
168 res.coefficients[2] += other.coefficients[2];
169 }
170 return res;
171 }
172
173 template <size_t other_domain_end, bool other_has_a0_plus_a1>
176 {
178 // if both operands are degree-1, then we do not update coefficients[2], which represents `a1 + a0`
179 // the output object therefore must have `other_has_a0_plus_a1` set to false.
180 // i.e. the input also requires `other_has_a0_plus_a1`, otherwise use `operator+
181 res.coefficients[0] -= other.coefficients[0];
182 res.coefficients[1] -= other.coefficients[1];
183 if constexpr (other_domain_end == 3 && domain_end == 3) {
184 res.coefficients[2] -= other.coefficients[2];
185 }
186 return res;
187 }
188
190 {
192 res.coefficients[0] = -coefficients[0];
193 res.coefficients[1] = -coefficients[1];
194 if constexpr (domain_end == 3) {
195 res.coefficients[2] = -coefficients[2];
196 }
197
198 return res;
199 }
200
206 requires(LENGTH == 2)
207 {
209 result.coefficients[0] = coefficients[0].sqr();
210 result.coefficients[2] = coefficients[1].sqr();
211
212 // (a0 + a1.X)^2 = a0a0 + 2a0a1.X + a1a1.XX
213 // coefficients[0] = a0a0
214 // coefficients[1] = 2a0a1 + a1a1 = (a0 + a0 + a1).a1
215 // coefficients[2] = a1a1
216 // a0a0 a1a1 a0a1a1a0
217 if constexpr (has_a0_plus_a1) {
218 result.coefficients[1] = (coefficients[2] + coefficients[0]) * coefficients[1];
219 } else {
220 result.coefficients[1] = coefficients[0] * coefficients[1];
221 result.coefficients[1] += result.coefficients[1];
222 result.coefficients[1] += result.coefficients[2];
223 }
224 return result;
225 }
226
227 // True iff the represented polynomial is identically zero. Checks the genuine coefficients
228 // a0, a1 (and a2 for LENGTH 3); for has_a0_plus_a1 layouts coefficients[2] = a0 + a1 is then
229 // also zero, so it need not be checked separately.
230 bool is_zero() const
231 {
232 if (!coefficients[0].is_zero() || !coefficients[1].is_zero()) {
233 return false;
234 }
235 if constexpr (domain_end == 3) {
236 return coefficients[2].is_zero();
237 }
238 return true;
239 }
240
241 // Operations between Univariate and scalar
243 requires(!has_a0_plus_a1)
244 {
245 coefficients[0] += scalar;
246 return *this;
247 }
248
250 requires(!has_a0_plus_a1)
251 {
252 coefficients[0] -= scalar;
253 return *this;
254 }
256 requires(!has_a0_plus_a1)
257 {
258 coefficients[0] *= scalar;
259 coefficients[1] *= scalar;
260 if constexpr (domain_end == 3) {
261 coefficients[2] *= scalar;
262 }
263 return *this;
264 }
265
267 {
269 res += scalar;
270 return res;
271 }
272
274 {
276 res -= scalar;
277 return res;
278 }
279
281 {
283 res.coefficients[0] *= scalar;
284 res.coefficients[1] *= scalar;
285 if constexpr (domain_end == 3) {
286 res.coefficients[2] *= scalar;
287 }
288 return res;
289 }
290
291 // Output is immediately parsable as a list of integers by Python.
292 friend std::ostream& operator<<(std::ostream& os, const UnivariateCoefficientBasis& u)
293 {
294 os << "[";
295 os << u.coefficients[0] << "," << std::endl;
296 for (size_t i = 1; i < u.coefficients.size(); i++) {
297 os << " " << u.coefficients[i];
298 if (i + 1 < u.coefficients.size()) {
299 os << "," << std::endl;
300 } else {
301 os << "]";
302 };
303 }
304 return os;
305 }
306};
307
308template <typename B, class Fr, size_t domain_end, bool has_a0_plus_a1>
310{
311 using serialize::read;
312 read(it, univariate.coefficients);
313}
314
315template <typename B, class Fr, size_t domain_end, bool has_a0_plus_a1>
317{
318 using serialize::write;
319 write(it, univariate.coefficients);
320}
321
322} // namespace bb
323
324namespace std {
325template <typename T, size_t N, bool X>
326struct tuple_size<bb::UnivariateCoefficientBasis<T, N, X>> : std::integral_constant<std::size_t, N> {};
327
328} // namespace std
A view of a univariate, also used to truncate univariates.
friend std::ostream & operator<<(std::ostream &os, const UnivariateCoefficientBasis &u)
UnivariateCoefficientBasis & operator=(const UnivariateCoefficientBasis &other)=default
UnivariateCoefficientBasis< Fr, domain_end, false > operator-(const Fr &scalar) const
UnivariateCoefficientBasis(const UnivariateCoefficientBasis< Fr, other_domain_end, other_has_a0_plus_a1 > &other)
UnivariateCoefficientBasis< Fr, domain_end, false > & operator*=(const Fr &scalar)
UnivariateCoefficientBasis(UnivariateCoefficientBasis &&other) noexcept=default
UnivariateCoefficientBasis< Fr, 3, false > sqr() const
Square a degree-1 monomial to degree 2 in the coefficient basis.
bool operator==(const UnivariateCoefficientBasis &other) const =delete
UnivariateCoefficientBasis(const UnivariateCoefficientBasis< Fr, domain_end, true > &other)
UnivariateCoefficientBasis & operator+=(const Fr &scalar)
UnivariateCoefficientBasis< Fr, domain_end, false > operator+(const UnivariateCoefficientBasis< Fr, other_domain_end, other_has_a0_plus_a1 > &other) const
std::array< Fr, 3 > coefficients
Storage for polynomial coefficients (always 3 elements for uniform layout).
UnivariateCoefficientBasis< Fr, domain_end, false > & operator+=(const UnivariateCoefficientBasis< Fr, other_domain_end, other_has_a0_plus_a1 > &other)
UnivariateCoefficientBasis< Fr, domain_end, false > operator-() const
UnivariateCoefficientBasis & operator-=(const Fr &scalar)
UnivariateCoefficientBasis & operator=(UnivariateCoefficientBasis &&other) noexcept=default
UnivariateCoefficientBasis(const UnivariateCoefficientBasis &other)=default
UnivariateCoefficientBasis< Fr, domain_end, false > & operator-=(const UnivariateCoefficientBasis< Fr, other_domain_end, other_has_a0_plus_a1 > &other)
UnivariateCoefficientBasis< Fr, 3, false > operator*(const UnivariateCoefficientBasis< Fr, domain_end, other_has_a0_plus_a1 > &other) const
UnivariateCoefficientBasis< Fr, domain_end, false > operator*(const Fr &scalar) const
UnivariateCoefficientBasis< Fr, domain_end, false > operator-(const UnivariateCoefficientBasis< Fr, other_domain_end, other_has_a0_plus_a1 > &other) const
UnivariateCoefficientBasis< Fr, domain_end, false > operator+(const Fr &scalar) const
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
void read(B &it, field2< base_field, Params > &value)
void write(B &buf, field2< base_field, Params > const &value)
void read(auto &it, msgpack_concepts::HasMsgPack auto &obj)
Automatically derived read for any object that defines .msgpack() (implicitly defined by SERIALIZATIO...
void write(auto &buf, const msgpack_concepts::HasMsgPack auto &obj)
Automatically derived write for any object that defines .msgpack() (implicitly defined by SERIALIZATI...
STL namespace.
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
Curve::ScalarField Fr
VectorField result