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: 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
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
52 std::array<Fr, 3> coefficients;
53
55
57 requires(!has_a0_plus_a1)
58 {
59 coefficients[0] = other.coefficients[0];
60 coefficients[1] = other.coefficients[1];
61 if constexpr (domain_end == 3) {
62 coefficients[2] = other.coefficients[2];
63 }
64 }
65
71
72 template <size_t other_domain_end, bool other_has_a0_plus_a1 = true>
74 requires(domain_end > other_domain_end)
75 {
76 coefficients[0] = other.coefficients[0];
77 coefficients[1] = other.coefficients[1];
78 if constexpr (domain_end == 3) {
79 coefficients[2] = 0;
80 }
81 };
82
83 size_t size() { return coefficients.size(); };
84
85 // Check if the UnivariateCoefficientBasis is identically zero
86 bool is_zero() const
87 requires(LENGTH == 2)
88 {
89 return coefficients[0].is_zero() || coefficients[1].is_zero();
90 }
91
92 // Check if the UnivariateCoefficientBasis is identically zero
93 bool is_zero() const
94 requires(LENGTH == 3)
95 {
96 return coefficients[2].is_zero() || coefficients[0].is_zero() || coefficients[1].is_zero();
97 }
98
99 // Write the Univariate coefficients to a buffer
100 [[nodiscard]] std::vector<uint8_t> to_buffer() const { return ::to_buffer(coefficients); }
101
102 // Static method for creating a Univariate from a buffer
103 // IMPROVEMENT: Could be made to identically match equivalent methods in e.g. field.hpp. Currently bypasses
104 // unnecessary ::from_buffer call
106 {
109 return result;
110 }
111
113 {
115 for (size_t i = 0; i < LENGTH; ++i) {
116 output.value_at(i) = Fr::random_element();
117 }
118 return output;
119 };
120
122 {
124 for (size_t i = 0; i != LENGTH; ++i) {
125 output.coefficients[i] = Fr::zero();
126 }
127 return output;
128 }
129
131
132 // Operations between UnivariateCoefficientBasis and other UnivariateCoefficientBasis
133 bool operator==(const UnivariateCoefficientBasis& other) const = default;
134
135 template <size_t other_domain_end, bool other_has_a0_plus_a1>
138 {
139 // if both operands are degree-1, then we do not update coefficients[2], which represents `a1 + a0`
140 // the output object therefore must have `other_has_a0_plus_a1` set to false.
141 // i.e. the input also requires `other_has_a0_plus_a1`, otherwise use `operator+
142 coefficients[0] += other.coefficients[0];
143 coefficients[1] += other.coefficients[1];
144 if constexpr (other_domain_end == 3 && domain_end == 3) {
145 coefficients[2] += other.coefficients[2];
146 }
147 return *this;
148 }
149
150 template <size_t other_domain_end, bool other_has_a0_plus_a1>
153 {
154 // if both operands are degree-1, then we do not update coefficients[2], which represents `a1 + a0`
155 // the output object therefore must have `other_has_a0_plus_a1` set to false.
156 // i.e. the input also requires `other_has_a0_plus_a1`, otherwise use `operator+
157 coefficients[0] -= other.coefficients[0];
158 coefficients[1] -= other.coefficients[1];
159 if constexpr (other_domain_end == 3 && domain_end == 3) {
160 coefficients[2] -= other.coefficients[2];
161 }
162 return *this;
163 }
164
165 template <bool other_has_a0_plus_a1>
168 requires(LENGTH == 2)
169 {
171 // result.coefficients[0] = a0 * a0;
172 // result.coefficients[1] = a1 * a1
173 result.coefficients[0] = coefficients[0] * other.coefficients[0];
174 result.coefficients[2] = coefficients[1] * other.coefficients[1];
175
176 // the reason we've been tracking this variable all this time.
177 // coefficients[1] = sum of X^2 and X coefficients
178 // (a0 + a1X) * (b0 + b1X) = a0b0 + (a0b1 + a1b0)X + a1b1XX
179 // coefficients[1] = a0b1 + a1b0 + a1b1
180 // which represented as (a0 + a1) * (b0 + b1) - a0b0
181 // if we have a1_plus_a0
182 if constexpr (has_a0_plus_a1 && other_has_a0_plus_a1) {
183 result.coefficients[1] = (coefficients[2] * other.coefficients[2] - result.coefficients[0]);
184 } else if constexpr (has_a0_plus_a1 && !other_has_a0_plus_a1) {
185 result.coefficients[1] =
186 coefficients[2] * (other.coefficients[0] + other.coefficients[1]) - result.coefficients[0];
187 } else if constexpr (!has_a0_plus_a1 && other_has_a0_plus_a1) {
188 result.coefficients[1] =
189 (coefficients[0] + coefficients[1]) * other.coefficients[2] - result.coefficients[0];
190 } else {
191 result.coefficients[1] =
192 (coefficients[0] + coefficients[1]) * (other.coefficients[0] + other.coefficients[1]) -
193 result.coefficients[0];
194 }
195 return result;
196 }
197
198 template <size_t other_domain_end, bool other_has_a0_plus_a1>
201 {
203 // if both operands are degree-1, then we do not update coefficients[2], which represents `a1 + a0`
204 // the output object therefore must have `other_has_a0_plus_a1` set to false.
205 // i.e. the input also requires `other_has_a0_plus_a1`, otherwise use `operator+
206 res.coefficients[0] += other.coefficients[0];
207 res.coefficients[1] += other.coefficients[1];
208 if constexpr (other_domain_end == 3 && domain_end == 3) {
209 res.coefficients[2] += other.coefficients[2];
210 }
211 return res;
212 }
213
214 template <size_t other_domain_end, bool other_has_a0_plus_a1>
217 {
219 // if both operands are degree-1, then we do not update coefficients[2], which represents `a1 + a0`
220 // the output object therefore must have `other_has_a0_plus_a1` set to false.
221 // i.e. the input also requires `other_has_a0_plus_a1`, otherwise use `operator+
222 res.coefficients[0] -= other.coefficients[0];
223 res.coefficients[1] -= other.coefficients[1];
224 if constexpr (other_domain_end == 3 && domain_end == 3) {
225 res.coefficients[2] -= other.coefficients[2];
226 }
227 return res;
228 }
229
231 {
233 res.coefficients[0] = -coefficients[0];
234 res.coefficients[1] = -coefficients[1];
235 if constexpr (domain_end == 3) {
236 res.coefficients[2] = -coefficients[2];
237 }
238
239 return res;
240 }
241
243 requires(LENGTH == 2)
244 {
246 result.coefficients[0] = coefficients[0].sqr();
247 result.coefficients[2] = coefficients[1].sqr();
248
249 // (a0 + a1.X)^2 = a0a0 + 2a0a1.X + a1a1.XX
250 // coefficients[0] = a0a0
251 // coefficients[1] = 2a0a1 + a1a1 = (a0 + a0 + a1).a1
252 // coefficients[2] = a1a1
253 // a0a0 a1a1 a0a1a1a0
254 if constexpr (has_a0_plus_a1) {
255 result.coefficients[1] = (coefficients[2] + coefficients[0]) * coefficients[1];
256 } else {
257 result.coefficients[1] = coefficients[0] * coefficients[1];
258 result.coefficients[1] += result.coefficients[1];
259 result.coefficients[1] += result.coefficients[2];
260 }
261 return result;
262 }
263
264 // Operations between Univariate and scalar
266 requires(!has_a0_plus_a1)
267 {
268 coefficients[0] += scalar;
269 return *this;
270 }
271
273 requires(!has_a0_plus_a1)
274 {
275 coefficients[0] -= scalar;
276 return *this;
277 }
279 requires(!has_a0_plus_a1)
280 {
281 coefficients[0] *= scalar;
282 coefficients[1] *= scalar;
283 if constexpr (domain_end == 3) {
284 coefficients[2] *= scalar;
285 }
286 return *this;
287 }
288
290 {
292 res += scalar;
293 return res;
294 }
295
297 {
299 res -= scalar;
300 return res;
301 }
302
304 {
306 res.coefficients[0] *= scalar;
307 res.coefficients[1] *= scalar;
308 if constexpr (domain_end == 3) {
309 res.coefficients[2] *= scalar;
310 }
311 return res;
312 }
313
314 // Output is immediately parsable as a list of integers by Python.
315 friend std::ostream& operator<<(std::ostream& os, const UnivariateCoefficientBasis& u)
316 {
317 os << "[";
318 os << u.coefficients[0] << "," << std::endl;
319 for (size_t i = 1; i < u.coefficients.size(); i++) {
320 os << " " << u.coefficients[i];
321 if (i + 1 < u.coefficients.size()) {
322 os << "," << std::endl;
323 } else {
324 os << "]";
325 };
326 }
327 return os;
328 }
329
330 // Begin iterators
331 auto begin() { return coefficients.begin(); }
332 auto begin() const { return coefficients.begin(); }
333 // End iterators
334 auto end() { return coefficients.end(); }
335 auto end() const { return coefficients.end(); }
336};
337
338template <typename B, class Fr, size_t domain_end, bool has_a0_plus_a1>
340{
341 using serialize::read;
342 read(it, univariate.coefficients);
343}
344
345template <typename B, class Fr, size_t domain_end, bool has_a0_plus_a1>
347{
348 using serialize::write;
349 write(it, univariate.coefficients);
350}
351
352} // namespace bb
353
354namespace std {
355template <typename T, size_t N, bool X>
356struct tuple_size<bb::UnivariateCoefficientBasis<T, N, X>> : std::integral_constant<std::size_t, N> {};
357
358} // namespace std
A view of a univariate, also used to truncate univariates.
bool operator==(const UnivariateCoefficientBasis &other) const =default
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
UnivariateCoefficientBasis(const UnivariateCoefficientBasis< Fr, domain_end, true > &other)
UnivariateCoefficientBasis & operator+=(const Fr &scalar)
static UnivariateCoefficientBasis get_random()
UnivariateCoefficientBasis< Fr, domain_end, false > operator+(const UnivariateCoefficientBasis< Fr, other_domain_end, other_has_a0_plus_a1 > &other) const
std::array< Fr, 3 > coefficients
coefficients is a length-3 array with the following representation:
UnivariateCoefficientBasis< Fr, domain_end, false > & operator+=(const UnivariateCoefficientBasis< Fr, other_domain_end, other_has_a0_plus_a1 > &other)
static UnivariateCoefficientBasis serialize_from_buffer(uint8_t const *buffer)
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
static UnivariateCoefficientBasis zero()
static UnivariateCoefficientBasis random_element()
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
uint8_t buffer[RANDOM_BUFFER_SIZE]
Definition engine.cpp:34
Entry point for Barretenberg command-line interface.
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 MSGPACK_FIEL...
void write(auto &buf, const msgpack_concepts::HasMsgPack auto &obj)
Automatically derived write for any object that defines .msgpack() (implicitly defined by MSGPACK_FIE...
STL namespace.
void read(auto &buf, std::integral auto &value)
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
Curve::ScalarField Fr
static field random_element(numeric::RNG *engine=nullptr) noexcept
static constexpr field zero()