Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
field.cpp
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#include "field.hpp"
8#include "../bool/bool.hpp"
9#include "../circuit_builders/circuit_builders.hpp"
12#include <functional>
13
14using namespace bb;
15
16namespace bb::stdlib {
17
18template <typename Builder>
20 : context(parent_context)
21 , additive_constant(bb::fr::zero())
22 , multiplicative_constant(bb::fr::one())
23 , witness_index(IS_CONSTANT)
24{}
25
26template <typename Builder>
29 , additive_constant(bb::fr::zero())
30 , multiplicative_constant(bb::fr::one())
31 , witness_index(value.witness_index)
32{}
33
34template <typename Builder>
36 : context(parent_context)
37 , additive_constant(value)
38 , multiplicative_constant(bb::fr::one())
39 , witness_index(IS_CONSTANT)
40{}
41
42template <typename Builder>
57
58template <typename Builder>
60{
61 field_t<Builder> result(ctx);
62 result.witness_index = witness_index;
63 return result;
64}
65
72template <typename Builder> field_t<Builder>::operator bool_t<Builder>() const
73{
74 // If `this` is a constant field_t element, the resulting bool is also constant.
75 // In this case, `additive_constant` uniquely determines the value of `this`.
76 // After ensuring that `additive_constant` \in {0, 1}, we set the `.witness_bool` field of `result` to match the
77 // value of `additive_constant`.
78 if (is_constant()) {
79 ASSERT(additive_constant == bb::fr::one() || additive_constant == bb::fr::zero());
81 result.witness_bool = (additive_constant == bb::fr::one());
82 result.set_origin_tag(tag);
83 return result;
84 }
85
86 const bool add_constant_check = (additive_constant == bb::fr::zero());
87 const bool mul_constant_check = (multiplicative_constant == bb::fr::one());
88 const bool inverted_check = (additive_constant == bb::fr::one()) && (multiplicative_constant == bb::fr::neg_one());
89 bool result_inverted = false;
90 // Process the elements of the form
91 // a = a.v * 1 + 0 and a = a.v * (-1) + 1
92 // They do not need to be normalized if `a.v` is constrained to be boolean. In the first case, we have
93 // a == a.v,
94 // and in the second case
95 // a == ¬(a.v).
96 // The distinction between the cases is tracked by the .witness_inverted field of bool_t.
97 uint32_t witness_idx = witness_index;
98 if ((add_constant_check && mul_constant_check) || inverted_check) {
99 result_inverted = inverted_check;
100 } else {
101 // In general, the witness has to be normalized.
102 witness_idx = get_normalized_witness_index();
103 }
104 // Get the normalized value of the witness
105 bb::fr witness = context->get_variable(witness_idx);
106 BB_ASSERT_EQ((witness == bb::fr::zero()) || (witness == bb::fr::one()),
107 true,
108 "Attempting to create a bool_t from a witness_t not satisfying x^2 - x = 0");
109 bool_t result(context, witness == bb::fr::one());
110 result.witness_inverted = result_inverted;
111 result.witness_index = witness_idx;
112 context->create_bool_gate(witness_idx);
113 result.set_origin_tag(tag);
114 return result;
115}
116
121template <typename Builder> field_t<Builder> field_t<Builder>::operator+(const field_t& other) const
122{
124 field_t<Builder> result(ctx);
125 // Ensure that non-constant circuit elements can not be added without context
126 ASSERT(ctx || (is_constant() && other.is_constant()));
127
128 if (witness_index == other.witness_index && !is_constant()) {
129 // If summands represent the same circuit variable, i.e. their witness indices coincide, we just need to update
130 // the scaling factors of this variable.
131 result.additive_constant = additive_constant + other.additive_constant;
132 result.multiplicative_constant = multiplicative_constant + other.multiplicative_constant;
133 result.witness_index = witness_index;
134 } else if (is_constant() && other.is_constant()) {
135 // both inputs are constant - don't add a gate
136 result.additive_constant = additive_constant + other.additive_constant;
137 } else if (!is_constant() && other.is_constant()) {
138 // one input is constant - don't add a gate, but update scaling factors
139 result.additive_constant = additive_constant + other.additive_constant;
140 result.multiplicative_constant = multiplicative_constant;
141 result.witness_index = witness_index;
142 } else if (is_constant() && !other.is_constant()) {
143 result.additive_constant = additive_constant + other.additive_constant;
145 result.witness_index = other.witness_index;
146 } else {
147 // The summands are distinct circuit variables, the result needs to be constrained.
148 // a + b = a.v * a.mul + b.v * b.mul + (a.add + b.add)
149 // which leads to the constraint
150 // a.v * q_l + b.v * q_r + result.v * q_o + q_c = 0,
151 // where q_l, q_r, q_0, and q_c are the selectors storing corresponding scaling factors.
152 bb::fr left = ctx->get_variable(witness_index); // =: a.v
153 bb::fr right = ctx->get_variable(other.witness_index); // =: b.v
154 bb::fr result_value = left * multiplicative_constant;
155 result_value += right * other.multiplicative_constant;
156 result_value += additive_constant;
157 result_value += other.additive_constant;
158 result.witness_index = ctx->add_variable(result_value);
159
160 ctx->create_add_gate({ .a = witness_index,
161 .b = other.witness_index,
162 .c = result.witness_index,
163 .a_scaling = multiplicative_constant,
164 .b_scaling = other.multiplicative_constant,
165 .c_scaling = bb::fr::neg_one(),
166 .const_scaling = (additive_constant + other.additive_constant) });
167 }
168 result.tag = OriginTag(tag, other.tag);
169 return result;
170}
174template <typename Builder> field_t<Builder> field_t<Builder>::operator-(const field_t& other) const
175{
176 field_t<Builder> rhs(other);
178 if (!rhs.is_constant()) {
179 // Negate the multiplicative constant of the rhs then feed to `+` operator
181 }
182 return operator+(rhs);
183}
184
189template <typename Builder> field_t<Builder> field_t<Builder>::operator*(const field_t& other) const
190{
192 field_t<Builder> result(ctx);
193 // Ensure that non-constant circuit elements can not be multiplied without context
194 ASSERT(ctx || (is_constant() && other.is_constant()));
195
196 if (is_constant() && other.is_constant()) {
197 // Both inputs are constant - don't add a gate.
198 // The value of a constant is tracked in `.additive_constant`.
199 result.additive_constant = additive_constant * other.additive_constant;
200 } else if (!is_constant() && other.is_constant()) {
201
202 // Here and in the next case, only one input is not constant: don't add a gate, but update scaling factors.
203 // More concretely, let:
204 // a := this;
205 // b := other;
206 // a.v := ctx->variables[a.witness_index], the value of a;
207 // b.v := ctx->variables[b.witness_index], the value of b;
208 // .mul = .multiplicative_constant
209 // .add = .additive_constant
210 // Value of this = a.v * a.mul + a.add;
211 // Value of other = b.add
212 // Value of result = a * b = a.v * [a.mul * b.add] + [a.add * b.add]
213 // ^ ^result.mul ^result.add
214 // ^result.v
215
216 result.additive_constant = additive_constant * other.additive_constant;
217 result.multiplicative_constant = multiplicative_constant * other.additive_constant;
218 // We simply updated the scaling factors of `*this`, so `witness_index` of `result` must be equal to
219 // `this->witness_index`.
220 result.witness_index = witness_index;
221 } else if (is_constant() && !other.is_constant()) {
222 // Only one input is not constant: don't add a gate, but update scaling factors
223 result.additive_constant = additive_constant * other.additive_constant;
224 result.multiplicative_constant = other.multiplicative_constant * additive_constant;
225 // We simply updated the scaling factors of `other`, so `witness_index` of `result` must be equal to
226 // `other->witness_index`.
227 result.witness_index = other.witness_index;
228 } else {
247 bb::fr T0;
248 bb::fr q_m;
253 // Compute selector values
254 q_c = additive_constant * other.additive_constant;
255 q_r = additive_constant * other.multiplicative_constant;
256 q_l = multiplicative_constant * other.additive_constant;
257 q_m = multiplicative_constant * other.multiplicative_constant;
258
259 bb::fr left = context->get_variable(witness_index); // =: a.v
260 bb::fr right = context->get_variable(other.witness_index); // =: b.v
261 bb::fr result_value;
263 result_value = left * right;
264 result_value *= q_m;
265 // Scale `b.v` by the constant `a_mul * b_add`
266 T0 = left * q_l;
267 result_value += T0;
268 // Scale `a.v` by the constant `a_add * b_mul`
269 T0 = right * q_r;
270 result_value += T0;
271 result_value += q_c;
272 result.witness_index = ctx->add_variable(result_value);
273 // Constrain
274 // a.v * b.v * q_m + a.v * q_l + b_v * q_r + q_c + result.v * q_o = 0
275 ctx->create_poly_gate({ .a = witness_index,
276 .b = other.witness_index,
277 .c = result.witness_index,
278 .q_m = q_m,
279 .q_l = q_l,
280 .q_r = q_r,
281 .q_o = bb::fr::neg_one(),
282 .q_c = q_c });
283 }
284 result.tag = OriginTag(tag, other.tag);
285 return result;
286}
287
299template <typename Builder> field_t<Builder> field_t<Builder>::operator/(const field_t& other) const
300{
301 // If the denominator is a constant 0, the division is aborted. Otherwise, it is constrained to be non-zero.
302 other.assert_is_not_zero("field_t::operator/ divisor is 0");
303 return divide_no_zero_check(other);
304}
305
309template <typename Builder> field_t<Builder> field_t<Builder>::divide_no_zero_check(const field_t& other) const
310{
311
312 // Let
313 // a := this;
314 // b := other;
315 // q := a / b;
317 field_t<Builder> result(ctx);
318 // Ensure that non-constant circuit elements can not be divided without context
319 ASSERT(ctx || (is_constant() && other.is_constant()));
320
321 bb::fr additive_multiplier = bb::fr::one();
322
323 if (is_constant() && other.is_constant()) {
324 // Both inputs are constant, the result is given by
325 // q = a.add / b.add, if b != 0.
326 // q = a.add , if b == 0
327 if (!(other.additive_constant == bb::fr::zero())) {
328 additive_multiplier = other.additive_constant.invert();
329 }
330 result.additive_constant = additive_constant * additive_multiplier;
331 } else if (!is_constant() && other.is_constant()) {
332 // The numerator is a circuit variable, the denominator is a constant.
333 // The result is obtained by updating the circuit variable `a`
334 // q = a.v * [a.mul / b.add] + a.add / b.add, if b != 0.
335 // q = a , if b == 0
336 // with q.witness_index = a.witness_index.
337 if (!(other.additive_constant == bb::fr::zero())) {
338 additive_multiplier = other.additive_constant.invert();
339 }
340 result.additive_constant = additive_constant * additive_multiplier;
341 result.multiplicative_constant = multiplicative_constant * additive_multiplier;
342 result.witness_index = witness_index;
343 } else if (is_constant() && !other.is_constant()) {
344 // The numerator is a constant, the denominator is a circuit variable.
345 // If a == 0, the result is a constant 0, otherwise the result is a new variable that has to be constrained.
346 if (get_value() == 0) {
348 result.multiplicative_constant = 1;
349 result.witness_index = IS_CONSTANT;
350 } else {
351 bb::fr numerator = get_value();
352 bb::fr denominator_inv = other.get_value();
353 denominator_inv = denominator_inv.is_zero() ? 0 : denominator_inv.invert();
354
355 bb::fr out(numerator * denominator_inv);
356 result.witness_index = ctx->add_variable(out);
357 // Define non-zero selector values for a `poly` gate
358 // q_m := b.mul
359 // q_l := b.add
360 // q_c := a (= a.add, since a is constant)
362 bb::fr q_l = other.additive_constant;
363 bb::fr q_c = -get_value();
364 // The value of the quotient q = a / b has to satisfy
365 // q * (b.v * b.mul + b.add) = a
366 // Create a `poly` gate to constrain the quotient.
367 // q * b.v * q_m + q * q_l + 0 * b + 0 * c + q_c = 0
368 ctx->create_poly_gate({ .a = result.witness_index,
369 .b = other.witness_index,
370 .c = result.witness_index,
371 .q_m = q_m,
372 .q_l = q_l,
373 .q_r = 0,
374 .q_o = 0,
375 .q_c = q_c });
377 } else {
378 // Both numerator and denominator are circuit variables. Create a new circuit variable with the value a / b.
379 bb::fr numerator = get_value();
380 bb::fr denominator_inv = other.get_value();
381 denominator_inv = denominator_inv.is_zero() ? 0 : denominator_inv.invert();
382
383 bb::fr out(numerator * denominator_inv);
384 result.witness_index = ctx->add_variable(out);
386 // The value of the quotient q = a / b has to satisfy
387 // q * (b.v * b.mul + b.add) = a.v * a.mul + a.add
388 // Create a `poly` gate to constrain the quotient
389 // q * b.v * q_m + q * q_l + 0 * c + a.v * q_o + q_c = 0,
390 // where the `poly_gate` selector values are defined as follows:
391 // q_m = b.mul;
392 // q_l = b.add;
393 // q_r = 0;
394 // q_o = - a.mul;
395 // q_c = - a.add.
399 bb::fr q_o = -multiplicative_constant;
400 bb::fr q_c = -additive_constant;
401
402 ctx->create_poly_gate({ .a = result.witness_index,
403 .b = other.witness_index,
404 .c = witness_index,
405 .q_m = q_m,
406 .q_l = q_l,
407 .q_r = q_r,
408 .q_o = q_o,
409 .q_c = q_c });
410 }
411 result.tag = OriginTag(tag, other.tag);
412 return result;
413}
414
419template <typename Builder> field_t<Builder> field_t<Builder>::pow(const uint32_t& exponent) const
420{
421 if (is_constant()) {
422 return field_t(get_value().pow(exponent));
423 }
424 if (exponent == 0) {
425 return field_t(bb::fr::one());
426 }
427
428 bool accumulator_initialized = false;
429 field_t<Builder> accumulator;
430 field_t<Builder> running_power = *this;
431 auto shifted_exponent = exponent;
432
433 // Square and multiply, there's no need to constrain the exponent bit decomposition, as it is an integer constant.
434 while (shifted_exponent != 0) {
435 if (shifted_exponent & 1) {
436 if (!accumulator_initialized) {
437 accumulator = running_power;
438 accumulator_initialized = true;
439 } else {
440 accumulator *= running_power;
441 }
442 }
443 if (shifted_exponent >= 2) {
444 // Don't update `running_power` if `shifted_exponent` = 1, as it won't be used anywhere.
445 running_power = running_power.sqr();
446 }
447 shifted_exponent >>= 1;
448 }
449 return accumulator;
450}
451
456template <typename Builder> field_t<Builder> field_t<Builder>::pow(const field_t& exponent) const
457{
458 uint256_t exponent_value = exponent.get_value();
459 BB_ASSERT_LT(exponent_value.get_msb(), 32U);
460
461 if (is_constant() && exponent.is_constant()) {
462 return field_t(get_value().pow(exponent_value));
463 }
464 // Use the constant version that perfoms only the necessary multiplications if the exponent is constant
465 if (exponent.is_constant()) {
466 return pow(static_cast<uint32_t>(exponent_value));
467 }
468
469 auto* ctx = validate_context(context, exponent.context);
470
471 std::array<bool_t<Builder>, 32> exponent_bits;
472 // Collect individual bits as bool_t's
473 for (size_t i = 0; i < exponent_bits.size(); ++i) {
474 uint256_t value_bit = exponent_value & 1;
475 bool_t<Builder> bit;
476 bit = bool_t<Builder>(witness_t<Builder>(ctx, value_bit.data[0]));
477 bit.set_origin_tag(exponent.tag);
478 exponent_bits[31 - i] = bit;
479 exponent_value >>= 1;
480 }
481
482 field_t<Builder> exponent_accumulator(bb::fr::zero());
483 for (const auto& bit : exponent_bits) {
484 exponent_accumulator += exponent_accumulator;
485 exponent_accumulator += bit;
486 }
487 // Constrain the sum of bool_t bits to be equal to the original exponent value.
488 exponent.assert_equal(exponent_accumulator, "field_t::pow exponent accumulator incorrect");
489
490 // Compute the result of exponentiation
491 field_t accumulator(ctx, bb::fr::one());
492 const field_t one(bb::fr::one());
493 for (size_t i = 0; i < 32; ++i) {
494 accumulator *= accumulator;
495 // If current bit == 1, multiply by the base, else propagate the accumulator
496 const field_t multiplier = conditional_assign(exponent_bits[i], *this, one);
497 accumulator *= multiplier;
498 }
499 accumulator = accumulator.normalize();
500 accumulator.tag = OriginTag(tag, exponent.tag);
501 return accumulator;
502}
503
507template <typename Builder> field_t<Builder> field_t<Builder>::madd(const field_t& to_mul, const field_t& to_add) const
508{
509 Builder* ctx = validate_context<Builder>(context, to_mul.context, to_add.context);
510
511 const bool mul_by_const = is_constant() || to_mul.is_constant();
512
513 if (mul_by_const) {
514 // If at least one of the multiplicands is constant, `madd` is efficiently handled by `*` and `+`
515 // operators.
516 return ((*this) * to_mul + to_add);
517 }
518
519 // Let:
520 // a = this;
521 // b = to_mul;
522 // c = to_add;
523 // a.v = ctx->variables[this.witness_index];
524 // b.v = ctx->variables[to_mul.witness_index];
525 // c.v = ctx->variables[to_add.witness_index];
526 // .mul = .multiplicative_constant;
527 // .add = .additive_constant.
528 //
529 // result = a * b + c
530 // = (a.v * a.mul + a.add) * (b.v * b.mul + b.add) + (c.v * c.mul + c.add)
531 // = a.v * b.v * [a.mul * b.mul] + a.v * [a.mul * b.add] + b.v * [b.mul + a.add] + c.v * [c.mul]
532 // + [a.add * b.add + c.add]
533 // = a.v * b.v * [ mul_scaling ] + a.v * [ a_scaling ] + b.v * [ b_scaling ] + c.v * [ c_scaling ]
534 // + [ const_scaling ]
535
536 bb::fr mul_scaling = multiplicative_constant * to_mul.multiplicative_constant;
537 bb::fr a_scaling = multiplicative_constant * to_mul.additive_constant;
538 bb::fr b_scaling = to_mul.multiplicative_constant * additive_constant;
539 bb::fr c_scaling = to_add.multiplicative_constant;
540 bb::fr const_scaling = additive_constant * to_mul.additive_constant + to_add.additive_constant;
541
542 // Note: the value of a constant field_t is wholly tracked by the field_t's `additive_constant` member, which is
543 // accounted for in the above-calculated selectors (`q_`'s). Therefore no witness (`variables[witness_index]`)
544 // exists for constants, and so the field_t's corresponding wire value is set to `0` in the gate equation.
545 bb::fr a = is_constant() ? bb::fr::zero() : ctx->get_variable(witness_index);
546 bb::fr b = to_mul.is_constant() ? bb::fr::zero() : ctx->get_variable(to_mul.witness_index);
547 bb::fr c = to_add.is_constant() ? bb::fr::zero() : ctx->get_variable(to_add.witness_index);
548
549 bb::fr out = a * b * mul_scaling + a * a_scaling + b * b_scaling + c * c_scaling + const_scaling;
550
551 field_t<Builder> result(ctx);
552 result.witness_index = ctx->add_variable(out);
553 ctx->create_big_mul_gate({
554 .a = is_constant() ? ctx->zero_idx : witness_index,
555 .b = to_mul.is_constant() ? ctx->zero_idx : to_mul.witness_index,
556 .c = to_add.is_constant() ? ctx->zero_idx : to_add.witness_index,
557 .d = result.witness_index,
558 .mul_scaling = mul_scaling,
559 .a_scaling = a_scaling,
560 .b_scaling = b_scaling,
561 .c_scaling = c_scaling,
562 .d_scaling = bb::fr::neg_one(),
563 .const_scaling = const_scaling,
564 });
565 result.tag = OriginTag(tag, to_mul.tag, to_add.tag);
566 return result;
567}
568
572template <typename Builder> field_t<Builder> field_t<Builder>::add_two(const field_t& add_b, const field_t& add_c) const
573{
574 const bool has_const_summand = is_constant() || add_b.is_constant() || add_c.is_constant();
575
576 if (has_const_summand) {
577 // If at least one of the summands is constant, the summation is efficiently handled by `+` operator
578 return (*this) + add_b + add_c;
579 }
580 Builder* ctx = validate_context<Builder>(context, add_b.context, add_c.context);
581
582 // Let d := a + (b+c), where
583 // a := *this;
584 // b := add_b;
585 // c := add_c;
586 // define selector values by
587 // mul_scaling := 0
588 // a_scaling := a_mul;
589 // b_scaling := b_mul;
590 // c_scaling := c_mul;
591 // d_scaling := -1;
592 // const_scaling := a_add + b_add + c_add;
593 // Create a `big_mul_gate` to constrain
594 // a * b * mul_scaling + a * a_scaling + b * b_scaling + c * c_scaling + d * d_scaling + const_scaling = 0
595
596 bb::fr a_scaling = multiplicative_constant;
597 bb::fr b_scaling = add_b.multiplicative_constant;
598 bb::fr c_scaling = add_c.multiplicative_constant;
599 bb::fr const_scaling = additive_constant + add_b.additive_constant + add_c.additive_constant;
600
601 // Compute the sum of values of all summands
602 bb::fr a = is_constant() ? bb::fr::zero() : ctx->get_variable(witness_index);
603 bb::fr b = add_b.is_constant() ? bb::fr::zero() : ctx->get_variable(add_b.witness_index);
604 bb::fr c = add_c.is_constant() ? bb::fr::zero() : ctx->get_variable(add_c.witness_index);
605
606 bb::fr out = a * a_scaling + b * b_scaling + c * c_scaling + const_scaling;
607
608 field_t<Builder> result(ctx);
609 result.witness_index = ctx->add_variable(out);
610
611 // Constrain the result
612 ctx->create_big_mul_gate({
613 .a = is_constant() ? ctx->zero_idx : witness_index,
614 .b = add_b.is_constant() ? ctx->zero_idx : add_b.witness_index,
615 .c = add_c.is_constant() ? ctx->zero_idx : add_c.witness_index,
616 .d = result.witness_index,
617 .mul_scaling = bb::fr::zero(),
618 .a_scaling = a_scaling,
619 .b_scaling = b_scaling,
620 .c_scaling = c_scaling,
621 .d_scaling = bb::fr::neg_one(),
622 .const_scaling = const_scaling,
623 });
624 result.tag = OriginTag(tag, add_b.tag, add_c.tag);
625 return result;
626}
627
635template <typename Builder> field_t<Builder> field_t<Builder>::normalize() const
636{
637 if (is_normalized()) {
638 return *this;
639 }
641
642 // Value of this = this.v * this.mul + this.add; // where this.v = context->variables[this.witness_index]
643 // Normalised result = result.v * 1 + 0; // where result.v = this.v * this.mul + this.add
644 // We need a new gate to enforce that the `result` was correctly calculated from `this`.
646 bb::fr value = context->get_variable(witness_index);
647
648 result.witness_index = context->add_variable(value * multiplicative_constant + additive_constant);
651
652 // The aim of a new `add` gate is to constrain
653 // this.v * this.mul + this.add == result.v
654 // Let
655 // a_scaling := this.mul;
656 // b_scaling := 0;
657 // c_scaling := -1;
658 // const_scaling := this.add;
659 // The `add` gate enforces the relation
660 // this.v * a_scaling + result.v * c_scaling + const_scaling = 0
661
662 context->create_add_gate({ .a = witness_index,
663 .b = context->zero_idx,
664 .c = result.witness_index,
665 .a_scaling = multiplicative_constant,
666 .b_scaling = bb::fr::zero(),
667 .c_scaling = bb::fr::neg_one(),
668 .const_scaling = additive_constant });
669 result.tag = tag;
670 return result;
671}
672
676template <typename Builder> void field_t<Builder>::assert_is_zero(std::string const& msg) const
677{
678
679 if (is_constant()) {
680 BB_ASSERT_EQ(additive_constant == bb::fr::zero(), true, msg);
681 return;
682 }
683
684 if (get_value() != bb::fr::zero()) {
685 context->failure(msg);
686 }
687 // Aim of a new `poly` gate: constrain this.v * this.mul + this.add == 0
688 // I.e.:
689 // this.v * 0 * [ 0 ] + this.v * [this.mul] + 0 * [ 0 ] + 0 * [ 0 ] + [this.add] == 0
690 // this.v * 0 * [q_m] + this.v * [ q_l ] + 0 * [q_r] + 0 * [q_o] + [ q_c ] == 0
691
692 context->create_poly_gate({
693 .a = witness_index,
694 .b = context->zero_idx,
695 .c = context->zero_idx,
696 .q_m = bb::fr::zero(),
697 .q_l = multiplicative_constant,
698 .q_r = bb::fr::zero(),
699 .q_o = bb::fr::zero(),
700 .q_c = additive_constant,
701 });
702}
703
707template <typename Builder> void field_t<Builder>::assert_is_not_zero(std::string const& msg) const
708{
709
710 if (is_constant()) {
711 BB_ASSERT_EQ(additive_constant != bb::fr::zero(), true, msg);
712 return;
713 }
714
715 if (get_value() == bb::fr::zero()) {
716 context->failure(msg);
717 }
718
719 bb::fr inverse_value = (get_value() == bb::fr::zero()) ? bb::fr::zero() : get_value().invert();
720
721 field_t<Builder> inverse(witness_t<Builder>(context, inverse_value));
722
723 // inverse is added in the circuit for checking that field element is not zero
724 // and it won't be used anymore, so it's needed to add this element in used witnesses
725 if constexpr (IsUltraBuilder<Builder>) {
726 context->update_used_witnesses(inverse.witness_index);
727 }
728
729 // Aim of a new `poly` gate: `this` has an inverse (hence is not zero).
730 // I.e.:
731 // (this.v * this.mul + this.add) * inverse.v == 1;
732 // <=> this.v * inverse.v * [this.mul] + this.v * [ 0 ] + inverse.v * [this.add] + 0 * [ 0 ] + [ -1] == 0
733 // <=> this.v * inverse.v * [ q_m ] + this.v * [q_l] + inverse.v * [ q_r ] + 0 * [q_o] + [q_c] == 0
734
735 // (a * mul_const + add_const) * b - 1 = 0
736 context->create_poly_gate({
737 .a = witness_index, // input value
738 .b = inverse.witness_index, // inverse
739 .c = context->zero_idx, // no output
740 .q_m = multiplicative_constant, // a * b * mul_const
741 .q_l = bb::fr::zero(), // a * 0
742 .q_r = additive_constant, // b * mul_const
743 .q_o = bb::fr::zero(), // c * 0
744 .q_c = bb::fr::neg_one(), // -1
745 });
746}
747
774template <typename Builder> bool_t<Builder> field_t<Builder>::is_zero() const
775{
776 bb::fr native_value = get_value();
777 const bool is_zero_raw = native_value.is_zero();
778
779 if (is_constant()) {
780 // Create a constant bool_t
781 bool_t is_zero(context, is_zero_raw);
782 is_zero.set_origin_tag(get_origin_tag());
783 return is_zero;
784 }
785
786 bool_t is_zero = witness_t(context, is_zero_raw);
787
788 // This can be done out of circuit, as `is_zero = true` implies `I = 1`.
789 bb::fr inverse_native = (is_zero_raw) ? bb::fr::one() : native_value.invert();
790
791 field_t inverse = witness_t(context, inverse_native);
792
793 // Note that `evaluate_polynomial_identity(a, b, c, d)` checks that `a * b + c + d = 0`, so we are using it for the
794 // constraints 1) and 2) above.
795 // More precisely, to check that `a * I - 1 + is_zero = 0`, it creates a `big_mul_gate` given by the equation:
796 // a.v * I.v * mul_scaling + a.v * a_scaling + I.v * b_scaling + is_zero.v * c_scaling + (-1) * d_scaling +
797 // const_scaling = 0
798 // where
799 // muk_scaling := a.mul * I.mul;
800 // a_scaling := a.mul * I.add;
801 // b_scaling := I.mul * a.add;
802 // c_scaling := 1;
803 // d_scaling := 0;
804 // const_scaling := a.add * I.add + is_zero.add - 1;
805 field_t::evaluate_polynomial_identity(*this, inverse, is_zero, bb::fr::neg_one());
806
807 // To check that `-is_zero * I + is_zero = 0`, create a `big_mul_gate` given by the equation:
808 // is_zero.v * (-I).v * mul_scaling + is_zero.v * a_scaling + (-I).v * b_scaling + is_zero.v * c_scaling + 0 *
809 // d_scaling + const_scaling = 0
810 // where
811 // mul_scaling := is_zero.mul * (-I).mul;
812 // a_scaling := is_zero.mul * (-I).add;
813 // b_scaling := (-I).mul * is_zero.add;
814 // c_scaling := is_zero.mul;
815 // d_scaling := 0;
816 // const_scaling := is_zero.add * (-I).add + is_zero.add;
817 field_t::evaluate_polynomial_identity(is_zero, -inverse, is_zero, bb::fr::zero());
818 is_zero.set_origin_tag(tag);
819 return is_zero;
820}
827template <typename Builder> bb::fr field_t<Builder>::get_value() const
828{
829 if (!is_constant()) {
831 return (multiplicative_constant * context->get_variable(witness_index)) + additive_constant;
832 }
833 BB_ASSERT_EQ(multiplicative_constant, bb::fr::one());
834 // A constant field_t's value is tracked wholly by its additive_constant member.
835 return additive_constant;
836}
837
841template <typename Builder> bool_t<Builder> field_t<Builder>::operator==(const field_t& other) const
842{
843 return ((*this) - other).is_zero();
844}
845
849template <typename Builder> bool_t<Builder> field_t<Builder>::operator!=(const field_t& other) const
850{
851 return !operator==(other);
852}
853
857template <typename Builder>
859{
860 if (predicate.is_constant()) {
861 field_t result = predicate.get_value() ? -(*this) : *this;
862 result.set_origin_tag(OriginTag(get_origin_tag(), predicate.get_origin_tag()));
863 return result;
864 }
865 // Compute
866 // `predicate` * ( -2 * a ) + a.
867 // If predicate's value == true, then the output is `-a`, else it's `a`
868 static constexpr bb::fr minus_two(-2);
869 return field_t(predicate).madd(*this * minus_two, *this);
870}
871
883template <typename Builder>
885 const field_t& lhs,
886 const field_t& rhs)
887{
888 // If the predicate is constant, the conditional assignment can be done out of circuit
889 if (predicate.is_constant()) {
890 auto result = field_t(predicate.get_value() ? lhs : rhs);
891 result.set_origin_tag(OriginTag(predicate.get_origin_tag(), lhs.get_origin_tag(), rhs.get_origin_tag()));
892 return result;
893 }
894 // If lhs and rhs are the same witness or constant, just return it
895 if (lhs.get_witness_index() == rhs.get_witness_index() && (lhs.additive_constant == rhs.additive_constant) &&
897 return lhs;
898 }
899
900 return (lhs - rhs).madd(predicate, rhs);
901}
902
907template <typename Builder>
908void field_t<Builder>::create_range_constraint(const size_t num_bits, std::string const& msg) const
909{
910 if (num_bits == 0) {
911 assert_is_zero("0-bit range_constraint on non-zero field_t.");
912 } else {
913 if (is_constant()) {
914 BB_ASSERT_LT(uint256_t(get_value()).get_msb(), num_bits, msg);
915 } else {
916 context->decompose_into_default_range(
917 get_normalized_witness_index(), num_bits, bb::UltraCircuitBuilder::DEFAULT_PLOOKUP_RANGE_BITNUM, msg);
918 }
919 }
920}
921
929template <typename Builder> void field_t<Builder>::assert_equal(const field_t& rhs, std::string const& msg) const
930{
931 const field_t lhs = *this;
932 Builder* ctx = validate_context(lhs.get_context(), rhs.get_context());
933 (void)OriginTag(get_origin_tag(), rhs.get_origin_tag());
934 if (lhs.is_constant() && rhs.is_constant()) {
935 BB_ASSERT_EQ(lhs.get_value(), rhs.get_value(), "field_t::assert_equal: constants are not equal");
936 return;
937 }
938 if (lhs.is_constant()) {
939 ctx->assert_equal_constant(rhs.get_normalized_witness_index(), lhs.get_value(), msg);
940 } else if (rhs.is_constant()) {
941 ctx->assert_equal_constant(lhs.get_normalized_witness_index(), rhs.get_value(), msg);
942 } else {
943 if (lhs.is_normalized() || rhs.is_normalized()) {
944 ctx->assert_equal(lhs.get_normalized_witness_index(), rhs.get_normalized_witness_index(), msg);
945 } else {
946 // Instead of creating 2 gates for normalizing both witnesses and applying a copy constraint, we use a
947 // single `add` gate constraining a - b = 0
948 ctx->create_add_gate({ .a = lhs.witness_index,
949 .b = rhs.witness_index,
950 .c = ctx->zero_idx,
951 .a_scaling = lhs.multiplicative_constant,
952 .b_scaling = -rhs.multiplicative_constant,
953 .c_scaling = 0,
954 .const_scaling = lhs.additive_constant - rhs.additive_constant });
955 if ((lhs.get_value() != rhs.get_value()) && !ctx->failed()) {
956 ctx->failure(msg);
957 }
958 }
959 }
960}
964template <typename Builder> void field_t<Builder>::assert_not_equal(const field_t& rhs, std::string const& msg) const
965{
966 const field_t lhs = *this;
967 const field_t diff = lhs - rhs;
968 diff.assert_is_not_zero(msg);
969}
973template <typename Builder>
974void field_t<Builder>::assert_is_in_set(const std::vector<field_t>& set, std::string const& msg) const
975{
976 const field_t input = *this;
977 field_t product = (input - set[0]);
978 for (size_t i = 1; i < set.size(); i++) {
979 product *= (input - set[i]);
980 }
981 product.assert_is_zero(msg);
982}
983
991template <typename Builder>
993 const field_t& T1,
994 const field_t& T2,
995 const field_t& T3)
996{
997
999 table[0] = T0; // const coeff
1000 table[1] = T1 - T0; // t0 coeff
1001 table[2] = T2 - T0; // t1 coeff
1002 table[3] = T3.add_two(-table[2], -T1); // t0t1 coeff
1003 return table;
1004}
1005
1009template <typename Builder>
1011 const field_t& T1,
1012 const field_t& T2,
1013 const field_t& T3,
1014 const field_t& T4,
1015 const field_t& T5,
1016 const field_t& T6,
1017 const field_t& T7)
1018{
1020 table[0] = T0; // const coeff
1021 table[1] = T1 - T0; // t0 coeff
1022 table[2] = T2 - T0; // t1 coeff
1023 table[3] = T4 - T0; // t2 coeff
1024 table[4] = T3.add_two(-table[2], -T1); // t0t1 coeff
1025 table[5] = T5.add_two(-table[3], -T1); // t0t2 coeff
1026 table[6] = T6.add_two(-table[3], -T2); // t1t2 coeff
1027 table[7] = T7.add_two(-T6 - T5, T4 - table[4]); // t0t1t2 coeff
1028 return table;
1029}
1030
1035template <typename Builder>
1037 const bool_t<Builder>& t1,
1038 const bool_t<Builder>& t0)
1039{
1040 field_t R0 = field_t(t1).madd(table[3], table[1]);
1041 field_t R1 = R0.madd(field_t(t0), table[0]);
1042 field_t R2 = field_t(t1).madd(table[2], R1);
1043 return R2;
1044}
1045
1057template <typename Builder>
1059 const bool_t<Builder>& t2,
1060 const bool_t<Builder>& t1,
1061 const bool_t<Builder>& t0)
1062{
1063 field_t R0 = field_t(t0).madd(table[7], table[6]);
1064 field_t R1 = field_t(t1).madd(R0, table[3]);
1065 field_t R2 = field_t(t2).madd(R1, table[0]);
1066 field_t R3 = field_t(t0).madd(table[4], table[2]);
1067 field_t R4 = field_t(t1).madd(R3, R2);
1068 field_t R5 = field_t(t2).madd(table[5], table[1]);
1069 field_t R6 = field_t(t0).madd(R5, R4);
1070 return R6;
1071}
1072
1076template <typename Builder>
1078{
1079 Builder* ctx = validate_context(a.context, b.context, c.context, d.context);
1080
1081 if (a.is_constant() && b.is_constant() && c.is_constant() && d.is_constant()) {
1082 BB_ASSERT_EQ(a.get_value() + b.get_value() + c.get_value() + d.get_value(), 0);
1083 return;
1084 }
1085
1086 // validate that a + b + c + d = 0
1087 bb::fr const_scaling = a.additive_constant + b.additive_constant + c.additive_constant + d.additive_constant;
1088
1089 ctx->create_big_add_gate({
1090 .a = a.is_constant() ? ctx->zero_idx : a.witness_index,
1091 .b = b.is_constant() ? ctx->zero_idx : b.witness_index,
1092 .c = c.is_constant() ? ctx->zero_idx : c.witness_index,
1093 .d = d.is_constant() ? ctx->zero_idx : d.witness_index,
1094 .a_scaling = a.multiplicative_constant,
1095 .b_scaling = b.multiplicative_constant,
1096 .c_scaling = c.multiplicative_constant,
1097 .d_scaling = d.multiplicative_constant,
1098 .const_scaling = const_scaling,
1099 });
1100}
1106template <typename Builder>
1108 const field_t& b,
1109 const field_t& c,
1110 const field_t& d)
1111{
1112 if (a.is_constant() && b.is_constant() && c.is_constant() && d.is_constant()) {
1113 ASSERT((a.get_value() * b.get_value() + c.get_value() + d.get_value()).is_zero());
1114 return;
1115 }
1116
1117 Builder* ctx = validate_context(a.context, b.context, c.context, d.context);
1118
1119 // validate that a * b + c + d = 0
1120 bb::fr mul_scaling = a.multiplicative_constant * b.multiplicative_constant;
1121 bb::fr a_scaling = a.multiplicative_constant * b.additive_constant;
1122 bb::fr b_scaling = b.multiplicative_constant * a.additive_constant;
1123 bb::fr c_scaling = c.multiplicative_constant;
1124 bb::fr d_scaling = d.multiplicative_constant;
1125 bb::fr const_scaling = a.additive_constant * b.additive_constant + c.additive_constant + d.additive_constant;
1126
1127 ctx->create_big_mul_gate({
1128 .a = a.is_constant() ? ctx->zero_idx : a.witness_index,
1129 .b = b.is_constant() ? ctx->zero_idx : b.witness_index,
1130 .c = c.is_constant() ? ctx->zero_idx : c.witness_index,
1131 .d = d.is_constant() ? ctx->zero_idx : d.witness_index,
1132 .mul_scaling = mul_scaling,
1133 .a_scaling = a_scaling,
1134 .b_scaling = b_scaling,
1135 .c_scaling = c_scaling,
1136 .d_scaling = d_scaling,
1137 .const_scaling = const_scaling,
1138 });
1139}
1140
1148{
1149 if (input.empty()) {
1150 return field_t(bb::fr::zero());
1151 }
1152
1153 if (input.size() == 1) {
1154 return input[0].normalize();
1155 }
1156
1157 std::vector<field_t> accumulator;
1158 field_t constant_term = bb::fr::zero();
1159
1160 // Remove constant terms from input field elements
1161 for (const auto& element : input) {
1162 if (element.is_constant()) {
1163 constant_term += element;
1164 } else {
1165 accumulator.emplace_back(element);
1166 }
1167 }
1168 if (accumulator.empty()) {
1169 return constant_term;
1170 }
1171 // Add the accumulated constant term to the first witness. It does not create any gates - only the additive
1172 // constant of `accumulator[0]` is updated.
1173 accumulator[0] += constant_term;
1174
1175 // At this point, the `accumulator` vector consisting of witnesses is not empty, so we can extract the context.
1176 Builder* ctx = validate_context<Builder>(accumulator);
1177
1178 // Step 2: compute output value
1179 size_t num_elements = accumulator.size();
1180 bb::fr output = bb::fr::zero();
1181 for (const auto& acc : accumulator) {
1182 output += acc.get_value();
1183 }
1184
1185 // Pad the accumulator with zeroes so that its size is a multiple of 3.
1186 const size_t num_padding_wires = (num_elements % 3) == 0 ? 0 : 3 - (num_elements % 3);
1187 for (size_t i = 0; i < num_padding_wires; ++i) {
1188 accumulator.emplace_back(field_t<Builder>::from_witness_index(ctx, ctx->zero_idx));
1189 }
1190 num_elements = accumulator.size();
1191 const size_t num_gates = (num_elements / 3);
1192 // Last gate is handled separetely
1193 const size_t last_gate_idx = num_gates - 1;
1194
1195 field_t total = witness_t(ctx, output);
1196 field_t accumulating_total = total;
1197
1198 // Let
1199 // a_i := accumulator[3*i];
1200 // b_i := accumulator[3*i+1];
1201 // c_i := accumulator[3*i+2];
1202 // d_0 := total;
1203 // d_i := total - \sum_(j < 3*i) accumulator[j];
1204 // which leads us to equations
1205 // d_{i+1} = d_{i} - a_i - b_i - c_i for i = 0, ..., last_idx - 1;
1206 // 0 = d_{i} - a_i - b_i - c_i for i = last_gate_idx,
1207 // that are turned into constraints below.
1208
1209 for (size_t i = 0; i < last_gate_idx; ++i) {
1210 // For i < last_gate_idx, we create a `big_add_gate` constraint
1211 // a_i.v * a_scaling + b_i.v * b_scaling + c_i.v * c_scaling + d_i.v * d_scaling + const_scaling +
1212 // w_4_omega = 0
1213 // where
1214 // a_scaling := a_i.mul
1215 // b_scaling := b_i.mul
1216 // c_scaling := c_i.mul
1217 // d_scaling := -1
1218 // const_scaling := a_i.add + b_i.add + c_i.add
1219 // w_4_omega := d_{i+1}
1220 ctx->create_big_add_gate(
1221 {
1222 .a = accumulator[3 * i].witness_index,
1223 .b = accumulator[3 * i + 1].witness_index,
1224 .c = accumulator[3 * i + 2].witness_index,
1225 .d = accumulating_total.witness_index,
1226 .a_scaling = accumulator[3 * i].multiplicative_constant,
1227 .b_scaling = accumulator[3 * i + 1].multiplicative_constant,
1228 .c_scaling = accumulator[3 * i + 2].multiplicative_constant,
1229 .d_scaling = -1,
1230 .const_scaling = accumulator[3 * i].additive_constant + accumulator[3 * i + 1].additive_constant +
1231 accumulator[3 * i + 2].additive_constant,
1232 },
1233 /*use_next_gate_w_4 = */ true);
1234 bb::fr new_total = accumulating_total.get_value() - accumulator[3 * i].get_value() -
1235 accumulator[3 * i + 1].get_value() - accumulator[3 * i + 2].get_value();
1236 accumulating_total = witness_t<Builder>(ctx, new_total);
1237 }
1238
1239 // For i = last_gate_idx, we create a `big_add_gate` constraining
1240 // a_i.v * a_scaling + b_i.v * b_scaling + c_i.v * c_scaling + d_i.v * d_scaling + const_scaling = 0
1241 ctx->create_big_add_gate({
1242 .a = accumulator[3 * last_gate_idx].witness_index,
1243 .b = accumulator[3 * last_gate_idx + 1].witness_index,
1244 .c = accumulator[3 * last_gate_idx + 2].witness_index,
1245 .d = accumulating_total.witness_index,
1246 .a_scaling = accumulator[3 * last_gate_idx].multiplicative_constant,
1247 .b_scaling = accumulator[3 * last_gate_idx + 1].multiplicative_constant,
1248 .c_scaling = accumulator[3 * last_gate_idx + 2].multiplicative_constant,
1249 .d_scaling = -1,
1250 .const_scaling = accumulator[3 * last_gate_idx].additive_constant +
1251 accumulator[3 * last_gate_idx + 1].additive_constant +
1252 accumulator[3 * last_gate_idx + 2].additive_constant,
1253 });
1254 OriginTag new_tag{};
1255 for (const auto& single_input : input) {
1256 new_tag = OriginTag(new_tag, single_input.tag);
1257 }
1258 total.tag = new_tag;
1259 return total.normalize();
1260}
1261
1267template <typename Builder>
1269 const size_t num_bits) const
1270{
1271 ASSERT(lsb_index < num_bits);
1273
1274 const uint256_t value = get_value();
1275 const uint256_t hi = value >> lsb_index;
1276 const uint256_t lo = value % (uint256_t(1) << lsb_index);
1277
1278 if (is_constant()) {
1279 // If `*this` is constant, we can return the split values directly
1280 ASSERT(lo + (hi << lsb_index) == value);
1282 }
1283
1284 // Handle edge case when lsb_index == 0
1285 if (lsb_index == 0) {
1286 ASSERT(hi == value);
1287 ASSERT(lo == 0);
1288 create_range_constraint(num_bits, "split_at: hi value too large.");
1289 return std::make_pair(field_t<Builder>(0), *this);
1290 }
1291
1292 Builder* ctx = get_context();
1293 ASSERT(ctx != nullptr);
1294
1295 field_t<Builder> lo_wit(witness_t(ctx, lo));
1296 field_t<Builder> hi_wit(witness_t(ctx, hi));
1297
1298 // Ensure that `lo_wit` is in the range [0, 2^lsb_index - 1]
1299 lo_wit.create_range_constraint(lsb_index, "split_at: lo value too large.");
1300
1301 // Ensure that `hi_wit` is in the range [0, 2^(num_bits - lsb_index) - 1]
1302 hi_wit.create_range_constraint(num_bits - lsb_index, "split_at: hi value too large.");
1303
1304 // Check that *this = lo_wit + hi_wit * 2^{lsb_index}
1305 const field_t<Builder> reconstructed = lo_wit + (hi_wit * field_t<Builder>(uint256_t(1) << lsb_index));
1306 assert_equal(reconstructed, "split_at: decomposition failed");
1307
1308 // Set the origin tag for both witnesses
1309 lo_wit.set_origin_tag(tag);
1310 hi_wit.set_origin_tag(tag);
1311
1312 return std::make_pair(lo_wit, hi_wit);
1313}
1314
1316template class field_t<bb::MegaCircuitBuilder>;
1317
1318} // namespace bb::stdlib
#define BB_ASSERT_EQ(actual, expected,...)
Definition assert.hpp:59
#define BB_ASSERT_LT(left, right,...)
Definition assert.hpp:115
#define ASSERT(expression,...)
Definition assert.hpp:49
static constexpr size_t DEFAULT_PLOOKUP_RANGE_BITNUM
constexpr uint64_t get_msb() const
Implements boolean logic in-circuit.
Definition bool.hpp:59
bool get_value() const
Definition bool.hpp:109
bool is_constant() const
Definition bool.hpp:111
void set_origin_tag(const OriginTag &new_tag) const
Definition bool.hpp:119
uint32_t witness_index
Definition bool.hpp:133
bool witness_inverted
Definition bool.hpp:132
OriginTag tag
Definition bool.hpp:134
OriginTag get_origin_tag() const
Definition bool.hpp:120
void assert_is_zero(std::string const &msg="field_t::assert_is_zero") const
Enforce a copy constraint between *this and 0 stored at zero_idx of the Builder.
Definition field.cpp:676
field_t conditional_negate(const bool_t< Builder > &predicate) const
If predicate's value == true, negate the value, else keep it unchanged.
Definition field.cpp:858
Builder_ Builder
Definition field.hpp:47
void assert_is_in_set(const std::vector< field_t > &set, std::string const &msg="field_t::assert_not_in_set") const
Constrain *this \in set by enforcing that P(X) = \prod_{s \in set} (X - s) is 0 at X = *this.
Definition field.cpp:974
void assert_equal(const field_t &rhs, std::string const &msg="field_t::assert_equal") const
Copy constraint: constrain that *this field is equal to rhs element.
Definition field.cpp:929
void assert_not_equal(const field_t &rhs, std::string const &msg="field_t::assert_not_equal") const
Constrain *this to be not equal to rhs.
Definition field.cpp:964
bool is_normalized() const
Definition field.hpp:400
field_t madd(const field_t &to_mul, const field_t &to_add) const
Definition field.cpp:507
static field_t from_witness_index(Builder *ctx, uint32_t witness_index)
Definition field.cpp:59
field_t operator+(const field_t &other) const
Field addition operator.
Definition field.cpp:121
bool_t< Builder > operator!=(const field_t &other) const
Compute a bool_t equal to (a != b)
Definition field.cpp:849
bb::fr additive_constant
Definition field.hpp:88
static field_t select_from_three_bit_table(const std::array< field_t, 8 > &table, const bool_t< Builder > &t2, const bool_t< Builder > &t1, const bool_t< Builder > &t0)
Given a multilinear polynomial in 3 variables, which is represented by a table of monomial coefficien...
Definition field.cpp:1058
static field_t accumulate(const std::vector< field_t > &input)
Efficiently compute the sum of vector entries. Using big_add_gate we reduce the number of gates neede...
Definition field.cpp:1147
static void evaluate_polynomial_identity(const field_t &a, const field_t &b, const field_t &c, const field_t &d)
Given a, b, c, d, constrain a * b + c + d = 0 by creating a big_mul_gate.
Definition field.cpp:1107
field_t operator-() const
Definition field.hpp:322
void create_range_constraint(size_t num_bits, std::string const &msg="field_t::range_constraint") const
Let x = *this.normalize(), constrain x.v < 2^{num_bits}.
Definition field.cpp:908
static field_t conditional_assign(const bool_t< Builder > &predicate, const field_t &lhs, const field_t &rhs)
If predicate == true then return lhs, else return rhs.
Definition field.cpp:884
field_t divide_no_zero_check(const field_t &other) const
Given field elements a = *this and b = other, output a / b without checking whether b = 0.
Definition field.cpp:309
Builder * context
Definition field.hpp:51
static std::array< field_t, 8 > preprocess_three_bit_table(const field_t &T0, const field_t &T1, const field_t &T2, const field_t &T3, const field_t &T4, const field_t &T5, const field_t &T6, const field_t &T7)
Given a table T of size 8, outputs the monomial coefficients of the multilinear polynomial in t0,...
Definition field.cpp:1010
bb::fr multiplicative_constant
Definition field.hpp:89
Builder * get_context() const
Definition field.hpp:389
field_t sqr() const
Definition field.hpp:258
std::pair< field_t< Builder >, field_t< Builder > > split_at(const size_t lsb_index, const size_t num_bits=grumpkin::MAX_NO_WRAP_INTEGER_BIT_LENGTH) const
Splits the field element into (lo, hi), where:
Definition field.cpp:1268
OriginTag get_origin_tag() const
Definition field.hpp:333
bb::fr get_value() const
Given a := *this, compute its value given by a.v * a.mul + a.add.
Definition field.cpp:827
field_t operator*(const field_t &other) const
Field multiplication operator.
Definition field.cpp:189
field_t(Builder *parent_context=nullptr)
Definition field.cpp:19
field_t normalize() const
Return a new element, where the in-circuit witness contains the actual represented value (multiplicat...
Definition field.cpp:635
static field_t select_from_two_bit_table(const std::array< field_t, 4 > &table, const bool_t< Builder > &t1, const bool_t< Builder > &t0)
Given a multilinear polynomial in 2 variables, which is represented by a table of monomial coefficien...
Definition field.cpp:1036
static void evaluate_linear_identity(const field_t &a, const field_t &b, const field_t &c, const field_t &d)
Constrain a + b + c + d to be equal to 0.
Definition field.cpp:1077
bool_t< Builder > is_zero() const
Validate whether a field_t element is zero.
Definition field.cpp:774
field_t pow(const uint32_t &exponent) const
Raise this field element to the power of the provided uint32_t exponent.
Definition field.cpp:419
bool is_constant() const
Definition field.hpp:399
static std::array< field_t, 4 > preprocess_two_bit_table(const field_t &T0, const field_t &T1, const field_t &T2, const field_t &T3)
Given a table T of size 4, outputs the monomial coefficients of the multilinear polynomial in t0,...
Definition field.cpp:992
uint32_t get_normalized_witness_index() const
Get the index of a normalized version of this element.
Definition field.hpp:471
void set_origin_tag(const OriginTag &new_tag) const
Definition field.hpp:332
uint32_t witness_index
Definition field.hpp:132
field_t add_two(const field_t &add_b, const field_t &add_c) const
Efficiently compute (this + a + b) using big_mul gate.
Definition field.cpp:572
void assert_is_not_zero(std::string const &msg="field_t::assert_is_not_zero") const
Constrain *this to be non-zero by establishing that it has an inverse.
Definition field.cpp:707
field_t operator/(const field_t &other) const
Since in divide_no_zero_check, we check by the constraint , if , we can set to any value and it wil...
Definition field.cpp:299
bool_t< Builder > operator==(const field_t &other) const
Compute a bool_t equal to (a == b)
Definition field.cpp:841
uint32_t get_witness_index() const
Get the witness index of the current field element.
Definition field.hpp:461
StrictMock< MockContext > context
FF a
FF b
constexpr size_t MAX_NO_WRAP_INTEGER_BIT_LENGTH
Definition grumpkin.hpp:15
constexpr T get_msb(const T in)
Definition get_msb.hpp:47
T * validate_context(T *ptr)
Definition field.hpp:16
std::conditional_t< IsGoblinBigGroup< C, Fq, Fr, G >, element_goblin::goblin_element< C, goblin_field< C >, Fr, G >, element_default::element< C, Fq, Fr, G > > element
element wraps either element_default::element or element_goblin::goblin_element depending on parametr...
Entry point for Barretenberg command-line interface.
Univariate< Fr, domain_end, domain_start, skip_count > operator+(const Fr &ff, const Univariate< Fr, domain_end, domain_start, skip_count > &uv)
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
static constexpr field neg_one()
static constexpr field one()
constexpr field invert() const noexcept
BB_INLINE constexpr void self_neg() &noexcept
BB_INLINE constexpr bool is_zero() const noexcept
static constexpr field zero()