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: Complete, auditors: [Sergei], commit: 458fb330efa8c470567ab4b84a8a92a58b00586a}
3// external_1: { status: Complete, auditors: [@ed25519, @JakubHeba (Spearbit)], commit:
4// 4433c06ae693451c6f69a2f63b7da6628078d872}
5// external_2: { status: not started, auditors: [], commit: }
6// =====================
7
8#include "field.hpp"
9#include "../bool/bool.hpp"
10#include "../circuit_builders/circuit_builders.hpp"
13#include "field_utils.hpp"
14#include <functional>
15
16using namespace bb;
17
18namespace bb::stdlib {
19
20template <typename Builder>
22 : context(parent_context)
23 , additive_constant(bb::fr::zero())
24 , multiplicative_constant(bb::fr::one())
25 , witness_index(IS_CONSTANT)
26{
28}
29
30template <typename Builder>
33 , additive_constant(bb::fr::zero())
34 , multiplicative_constant(bb::fr::one())
35 , witness_index(value.witness_index)
36{
38}
39
40template <typename Builder>
42 : context(parent_context)
43 , additive_constant(value)
44 , multiplicative_constant(bb::fr::one())
45 , witness_index(IS_CONSTANT)
46{
48}
49
50template <typename Builder>
65
66template <typename Builder>
68{
69 field_t<Builder> result(ctx);
70 result.witness_index = witness_index;
71 // Since this is now a witness (not a constant), set the free witness tag
72 // The caller should set the appropriate tag if this element has a known provenance
73 result.set_free_witness_tag();
74 return result;
75}
76
83template <typename Builder> field_t<Builder>::operator bool_t<Builder>() const
84{
85 // If `this` is a constant field_t element, the resulting bool is also constant.
86 // In this case, `additive_constant` uniquely determines the value of `this`.
87 // After ensuring that `additive_constant` \in {0, 1}, we set the `.witness_bool` field of `result` to match the
88 // value of `additive_constant`.
89 if (is_constant()) {
90 BB_ASSERT(additive_constant == bb::fr::one() || additive_constant == bb::fr::zero(),
91 "Attempting to create a bool_t from a witness_t not satisfying x^2 - x = 0");
93 result.witness_bool = (additive_constant == bb::fr::one());
94 result.set_origin_tag(tag);
95 return result;
96 }
97
98 const bool add_constant_check = (additive_constant == bb::fr::zero());
99 const bool mul_constant_check = (multiplicative_constant == bb::fr::one());
100 const bool inverted_check = (additive_constant == bb::fr::one()) && (multiplicative_constant == bb::fr::neg_one());
101 bool result_inverted = false;
102 // Process the elements of the form
103 // a = a.v * 1 + 0 and a = a.v * (-1) + 1
104 // They do not need to be normalized if `a.v` is constrained to be boolean. In the first case, we have
105 // a == a.v,
106 // and in the second case
107 // a == ¬(a.v).
108 // The distinction between the cases is tracked by the .witness_inverted field of bool_t.
109 uint32_t witness_idx = witness_index;
110 if ((add_constant_check && mul_constant_check) || inverted_check) {
111 result_inverted = inverted_check;
112 } else {
113 // In general, the witness has to be normalized.
114 witness_idx = normalize().witness_index;
115 }
116 // Get the normalized value of the witness
117 bb::fr witness = context->get_variable(witness_idx);
118 BB_ASSERT(witness == bb::fr::zero() || witness == bb::fr::one(),
119 "Attempting to create a bool_t from a witness_t not satisfying x^2 - x = 0");
120 bool_t result(context, witness == bb::fr::one());
121 result.witness_inverted = result_inverted;
122 result.witness_index = witness_idx;
123 context->create_bool_gate(witness_idx);
124 result.set_origin_tag(tag);
125 return result;
126}
127
132template <typename Builder> field_t<Builder> field_t<Builder>::operator+(const field_t& other) const
133{
135 field_t<Builder> result(ctx);
136 // Ensure that non-constant circuit elements can not be added without context
137 BB_ASSERT(ctx || (is_constant() && other.is_constant()));
138
139 if (witness_indices_match(*this, other) && !is_constant()) {
140 // If summands represent the same circuit variable, i.e. their witness indices coincide, we just need to update
141 // the scaling factors of this variable.
142 result.additive_constant = additive_constant + other.additive_constant;
143 result.multiplicative_constant = multiplicative_constant + other.multiplicative_constant;
144 result.witness_index = witness_index;
145 } else if (is_constant() && other.is_constant()) {
146 // both inputs are constant - don't add a gate
147 result.additive_constant = additive_constant + other.additive_constant;
148 } else if (!is_constant() && other.is_constant()) {
149 // one input is constant - don't add a gate, but update scaling factors
150 result.additive_constant = additive_constant + other.additive_constant;
151 result.multiplicative_constant = multiplicative_constant;
152 result.witness_index = witness_index;
153 } else if (is_constant() && !other.is_constant()) {
154 result.additive_constant = additive_constant + other.additive_constant;
156 result.witness_index = other.witness_index;
157 } else {
158 // The summands are distinct circuit variables, the result needs to be constrained.
159 // a + b = a.v * a.mul + b.v * b.mul + (a.add + b.add)
160 // which leads to the constraint
161 // a.v * q_l + b.v * q_r + result.v * q_o + q_c = 0,
162 // where q_l, q_r, q_0, and q_c are the selectors storing corresponding scaling factors.
163 bb::fr left = ctx->get_variable(witness_index); // =: a.v
164 bb::fr right = ctx->get_variable(other.witness_index); // =: b.v
165 bb::fr result_value = left * multiplicative_constant;
166 result_value += right * other.multiplicative_constant;
167 result_value += additive_constant;
168 result_value += other.additive_constant;
169 result.witness_index = ctx->add_variable(result_value);
170
171 ctx->create_add_gate({ .a = witness_index,
172 .b = other.witness_index,
173 .c = result.witness_index,
174 .a_scaling = multiplicative_constant,
175 .b_scaling = other.multiplicative_constant,
176 .c_scaling = bb::fr::neg_one(),
177 .const_scaling = (additive_constant + other.additive_constant) });
178 }
179 result.tag = OriginTag(tag, other.tag);
180 return result;
181}
185template <typename Builder> field_t<Builder> field_t<Builder>::operator-(const field_t& other) const
186{
187 field_t<Builder> rhs(other);
188 rhs.additive_constant.self_neg();
189 if (!rhs.is_constant()) {
190 // Negate the multiplicative constant of the rhs then feed to `+` operator
191 rhs.multiplicative_constant.self_neg();
192 }
193 return operator+(rhs);
194}
195
200template <typename Builder> field_t<Builder> field_t<Builder>::operator*(const field_t& other) const
201{
203 field_t<Builder> result(ctx);
204 // Ensure that non-constant circuit elements can not be multiplied without context
205 BB_ASSERT(ctx || (is_constant() && other.is_constant()));
206
207 if (is_constant() && other.is_constant()) {
208 // Both inputs are constant - don't add a gate.
209 // The value of a constant is tracked in `.additive_constant`.
210 result.additive_constant = additive_constant * other.additive_constant;
211 } else if (!is_constant() && other.is_constant()) {
212
213 // Here and in the next case, only one input is not constant: don't add a gate, but update scaling factors.
214 // More concretely, let:
215 // a := this;
216 // b := other;
217 // a.v := ctx->variables[a.witness_index], the value of a;
218 // b.v := ctx->variables[b.witness_index], the value of b;
219 // .mul = .multiplicative_constant
220 // .add = .additive_constant
221 // Value of this = a.v * a.mul + a.add;
222 // Value of other = b.add
223 // Value of result = a * b = a.v * [a.mul * b.add] + [a.add * b.add]
224 // ^ ^result.mul ^result.add
225 // ^result.v
226
227 result.additive_constant = additive_constant * other.additive_constant;
228 result.multiplicative_constant = multiplicative_constant * other.additive_constant;
229 // We simply updated the scaling factors of `*this`, so `witness_index` of `result` must be equal to
230 // `this->witness_index`.
231 result.witness_index = witness_index;
232 } else if (is_constant() && !other.is_constant()) {
233 // Only one input is not constant: don't add a gate, but update scaling factors
234 result.additive_constant = additive_constant * other.additive_constant;
235 result.multiplicative_constant = other.multiplicative_constant * additive_constant;
236 // We simply updated the scaling factors of `other`, so `witness_index` of `result` must be equal to
237 // `other->witness_index`.
238 result.witness_index = other.witness_index;
239 } else {
258 bb::fr T0;
259 bb::fr q_m;
260 bb::fr q_l;
261 bb::fr q_r;
262 bb::fr q_c;
263
264 // Compute selector values
265 q_c = additive_constant * other.additive_constant;
266 q_r = additive_constant * other.multiplicative_constant;
267 q_l = multiplicative_constant * other.additive_constant;
268 q_m = multiplicative_constant * other.multiplicative_constant;
269
270 bb::fr left = context->get_variable(witness_index); // =: a.v
271 bb::fr right = context->get_variable(other.witness_index); // =: b.v
272 bb::fr result_value;
273
274 result_value = left * right;
275 result_value *= q_m;
276 // Scale `b.v` by the constant `a_mul * b_add`
277 T0 = left * q_l;
278 result_value += T0;
279 // Scale `a.v` by the constant `a_add * b_mul`
280 T0 = right * q_r;
281 result_value += T0;
282 result_value += q_c;
283 result.witness_index = ctx->add_variable(result_value);
284 // Constrain
285 // a.v * b.v * q_m + a.v * q_l + b_v * q_r + q_c + result.v * q_o = 0
286 ctx->create_arithmetic_gate({ .a = witness_index,
287 .b = other.witness_index,
288 .c = result.witness_index,
289 .q_m = q_m,
290 .q_l = q_l,
291 .q_r = q_r,
292 .q_o = bb::fr::neg_one(),
293 .q_c = q_c });
294 }
295 result.tag = OriginTag(tag, other.tag);
296 return result;
297}
298
310template <typename Builder> field_t<Builder> field_t<Builder>::operator/(const field_t& other) const
311{
312 // If the denominator is a constant 0, the division is aborted. Otherwise, it is constrained to be non-zero.
313 other.assert_is_not_zero("field_t::operator/ divisor is 0");
314 return divide_no_zero_check(other);
315}
316
320template <typename Builder> field_t<Builder> field_t<Builder>::divide_no_zero_check(const field_t& other) const
321{
322
323 // Let
324 // a := this;
325 // b := other;
326 // q := a / b;
328 field_t<Builder> result(ctx);
329 // Ensure that non-constant circuit elements can not be divided without context
330 BB_ASSERT(ctx || (is_constant() && other.is_constant()));
331
332 bb::fr additive_multiplier = bb::fr::one();
333
334 if (is_constant() && other.is_constant()) {
335 // Both inputs are constant, the result is given by
336 // q = a.add / b.add, if b != 0.
337 // q = a.add , if b == 0
338 if (!(other.additive_constant == bb::fr::zero())) {
339 additive_multiplier = other.additive_constant.invert();
340 }
341 result.additive_constant = additive_constant * additive_multiplier;
342 } else if (!is_constant() && other.is_constant()) {
343 // The numerator is a circuit variable, the denominator is a constant.
344 // The result is obtained by updating the circuit variable `a`
345 // q = a.v * [a.mul / b.add] + a.add / b.add, if b != 0.
346 // q = a , if b == 0
347 // with q.witness_index = a.witness_index.
348 if (!(other.additive_constant == bb::fr::zero())) {
349 additive_multiplier = other.additive_constant.invert();
350 }
351 result.additive_constant = additive_constant * additive_multiplier;
352 result.multiplicative_constant = multiplicative_constant * additive_multiplier;
353 result.witness_index = witness_index;
354 } else if (is_constant() && !other.is_constant()) {
355 // The numerator is a constant, the denominator is a circuit variable.
356 // If a == 0, the result is a constant 0, otherwise the result is a new variable that has to be constrained.
357 if (get_value() == 0) {
358 result.additive_constant = 0;
359 result.multiplicative_constant = 1;
360 result.witness_index = IS_CONSTANT;
361 } else {
362 bb::fr numerator = get_value();
363 bb::fr denominator_inv = other.get_value();
364 denominator_inv = denominator_inv.is_zero() ? 0 : denominator_inv.invert();
365
366 bb::fr out(numerator * denominator_inv);
367 result.witness_index = ctx->add_variable(out);
368 // Define non-zero selector values for an arithmetic gate
369 // q_m := b.mul
370 // q_l := b.add
371 // q_c := a (= a.add, since a is constant)
374 bb::fr q_c = -get_value();
375 // The value of the quotient q = a / b has to satisfy
376 // q * (b.v * b.mul + b.add) = a
377 // Create an arithmetic gate to constrain the quotient.
378 // q * b.v * q_m + q * q_l + 0 * b + 0 * c + q_c = 0
379 ctx->create_arithmetic_gate({ .a = result.witness_index,
380 .b = other.witness_index,
381 .c = result.witness_index,
382 .q_m = q_m,
383 .q_l = q_l,
384 .q_r = 0,
385 .q_o = 0,
386 .q_c = q_c });
387 }
388 } else {
389 // Both numerator and denominator are circuit variables. Create a new circuit variable with the value a / b.
390 bb::fr numerator = get_value();
391 bb::fr denominator_inv = other.get_value();
392 denominator_inv = denominator_inv.is_zero() ? 0 : denominator_inv.invert();
393
394 bb::fr out(numerator * denominator_inv);
395 result.witness_index = ctx->add_variable(out);
396
397 // The value of the quotient q = a / b has to satisfy
398 // q * (b.v * b.mul + b.add) = a.v * a.mul + a.add
399 // Create an arithmetic gate to constrain the quotient
400 // q * b.v * q_m + q * q_l + 0 * c + a.v * q_o + q_c = 0,
401 // where the selector values are defined as follows:
402 // q_m = b.mul;
403 // q_l = b.add;
404 // q_r = 0;
405 // q_o = - a.mul;
406 // q_c = - a.add.
408 bb::fr q_l = other.additive_constant;
409 bb::fr q_r = bb::fr::zero();
410 bb::fr q_o = -multiplicative_constant;
411 bb::fr q_c = -additive_constant;
412
413 ctx->create_arithmetic_gate({ .a = result.witness_index,
414 .b = other.witness_index,
415 .c = witness_index,
416 .q_m = q_m,
417 .q_l = q_l,
418 .q_r = q_r,
419 .q_o = q_o,
420 .q_c = q_c });
421 }
422 result.tag = OriginTag(tag, other.tag);
423 return result;
425
430template <typename Builder> field_t<Builder> field_t<Builder>::pow(const uint32_t& exponent) const
431{
432 if (is_constant()) {
433 return field_t(get_value().pow(exponent));
435 if (exponent == 0) {
436 return field_t(bb::fr::one());
438
439 bool accumulator_initialized = false;
440 field_t<Builder> accumulator;
441 field_t<Builder> running_power = *this;
442 auto shifted_exponent = exponent;
443
444 // Square and multiply, there's no need to constrain the exponent bit decomposition, as it is an integer constant.
445 while (shifted_exponent != 0) {
446 if (shifted_exponent & 1) {
447 if (!accumulator_initialized) {
448 accumulator = running_power;
449 accumulator_initialized = true;
450 } else {
451 accumulator *= running_power;
452 }
453 }
454 if (shifted_exponent >= 2) {
455 // Don't update `running_power` if `shifted_exponent` = 1, as it won't be used anywhere.
456 running_power = running_power.sqr();
457 }
458 shifted_exponent >>= 1;
459 }
460 return accumulator;
461}
462
467template <typename Builder>
468template <size_t num_bits>
470{
471 uint256_t exponent_value = exponent.get_value();
472 BB_ASSERT_LT(exponent_value.get_msb(), num_bits, "Exponent too large in field_t::pow");
473
474 if (is_constant() && exponent.is_constant()) {
475 return field_t(get_value().pow(exponent_value));
476 }
477 // Use the constant version that perfoms only the necessary multiplications if the exponent is constant
478 if (exponent.is_constant()) {
479 return pow(static_cast<uint32_t>(exponent_value));
480 }
481
482 auto* ctx = validate_context(context, exponent.context);
483
484 std::array<bool_t<Builder>, num_bits> exponent_bits;
485 // Collect individual bits as bool_t's
486 for (size_t i = 0; i < exponent_bits.size(); ++i) {
487 uint256_t value_bit = exponent_value & 1;
488 bool_t<Builder> bit;
489 bit = bool_t<Builder>(witness_t<Builder>(ctx, value_bit.data[0]));
490 bit.set_origin_tag(exponent.tag);
491 exponent_bits[num_bits - 1 - i] = bit;
492 exponent_value >>= 1;
493 }
494
495 field_t<Builder> exponent_accumulator(bb::fr::zero());
496 for (const auto& bit : exponent_bits) {
497 exponent_accumulator += exponent_accumulator;
498 exponent_accumulator += bit;
499 }
500 // Constrain the sum of bool_t bits to be equal to the original exponent value.
501 exponent.assert_equal(exponent_accumulator, "field_t::pow exponent accumulator incorrect");
502
503 // Compute the result of exponentiation
504 field_t accumulator(ctx, bb::fr::one());
505 const field_t one(bb::fr::one());
506 for (size_t i = 0; i < num_bits; ++i) {
507 accumulator *= accumulator;
508 // If current bit == 1, multiply by the base, else propagate the accumulator
509 const field_t multiplier = conditional_assign_internal(exponent_bits[i], *this, one);
510 accumulator *= multiplier;
511 }
512 accumulator = accumulator.normalize();
513 accumulator.tag = OriginTag(tag, exponent.tag);
514 return accumulator;
515}
516
520template <typename Builder> field_t<Builder> field_t<Builder>::madd(const field_t& to_mul, const field_t& to_add) const
521{
522 Builder* ctx = validate_context<Builder>(context, to_mul.context, to_add.context);
523
524 const bool mul_by_const = is_constant() || to_mul.is_constant();
525
526 if (mul_by_const) {
527 // If at least one of the multiplicands is constant, `madd` is efficiently handled by `*` and `+`
528 // operators.
529 return ((*this) * to_mul + to_add);
530 }
531
532 // Let:
533 // a = this;
534 // b = to_mul;
535 // c = to_add;
536 // a.v = ctx->variables[this.witness_index];
537 // b.v = ctx->variables[to_mul.witness_index];
538 // c.v = ctx->variables[to_add.witness_index];
539 // .mul = .multiplicative_constant;
540 // .add = .additive_constant.
541 //
542 // result = a * b + c
543 // = (a.v * a.mul + a.add) * (b.v * b.mul + b.add) + (c.v * c.mul + c.add)
544 // = a.v * b.v * [a.mul * b.mul] + a.v * [a.mul * b.add] + b.v * [b.mul + a.add] + c.v * [c.mul]
545 // + [a.add * b.add + c.add]
546 // = a.v * b.v * [ mul_scaling ] + a.v * [ a_scaling ] + b.v * [ b_scaling ] + c.v * [ c_scaling ]
547 // + [ const_scaling ]
548
549 bb::fr mul_scaling = multiplicative_constant * to_mul.multiplicative_constant;
550 bb::fr a_scaling = multiplicative_constant * to_mul.additive_constant;
551 bb::fr b_scaling = to_mul.multiplicative_constant * additive_constant;
552 bb::fr c_scaling = to_add.multiplicative_constant;
553 bb::fr const_scaling = additive_constant * to_mul.additive_constant + to_add.additive_constant;
554
555 // Note: the value of a constant field_t is wholly tracked by the field_t's `additive_constant` member, which is
556 // accounted for in the above-calculated selectors (`q_`'s). Therefore no witness (`variables[witness_index]`)
557 // exists for constants, and so the field_t's corresponding wire value is set to `0` in the gate equation.
558 bb::fr a = is_constant() ? bb::fr::zero() : ctx->get_variable(witness_index);
559 bb::fr b = to_mul.is_constant() ? bb::fr::zero() : ctx->get_variable(to_mul.witness_index);
560 bb::fr c = to_add.is_constant() ? bb::fr::zero() : ctx->get_variable(to_add.witness_index);
561
562 bb::fr out = a * b * mul_scaling + a * a_scaling + b * b_scaling + c * c_scaling + const_scaling;
563
564 field_t<Builder> result(ctx);
565 result.witness_index = ctx->add_variable(out);
566 ctx->create_big_mul_add_gate({
567 .a = is_constant() ? ctx->zero_idx() : witness_index,
568 .b = to_mul.is_constant() ? ctx->zero_idx() : to_mul.witness_index,
569 .c = to_add.is_constant() ? ctx->zero_idx() : to_add.witness_index,
570 .d = result.witness_index,
571 .mul_scaling = mul_scaling,
572 .a_scaling = a_scaling,
573 .b_scaling = b_scaling,
574 .c_scaling = c_scaling,
575 .d_scaling = bb::fr::neg_one(),
576 .const_scaling = const_scaling,
577 });
578 result.tag = OriginTag(tag, to_mul.tag, to_add.tag);
579 return result;
580}
581
585template <typename Builder> field_t<Builder> field_t<Builder>::add_two(const field_t& add_b, const field_t& add_c) const
586{
587 const bool has_const_summand = is_constant() || add_b.is_constant() || add_c.is_constant();
588
589 if (has_const_summand) {
590 // If at least one of the summands is constant, the summation is efficiently handled by `+` operator
591 return (*this) + add_b + add_c;
592 }
593 Builder* ctx = validate_context<Builder>(context, add_b.context, add_c.context);
594
595 // Let d := a + (b+c), where
596 // a := *this;
597 // b := add_b;
598 // c := add_c;
599 // define selector values by
600 // mul_scaling := 0
601 // a_scaling := a_mul;
602 // b_scaling := b_mul;
603 // c_scaling := c_mul;
604 // d_scaling := -1;
605 // const_scaling := a_add + b_add + c_add;
606 // Create a `big_mul_gate` to constrain
607 // a * b * mul_scaling + a * a_scaling + b * b_scaling + c * c_scaling + d * d_scaling + const_scaling = 0
608
609 bb::fr a_scaling = multiplicative_constant;
610 bb::fr b_scaling = add_b.multiplicative_constant;
611 bb::fr c_scaling = add_c.multiplicative_constant;
612 bb::fr const_scaling = additive_constant + add_b.additive_constant + add_c.additive_constant;
613
614 // Compute the sum of values of all summands
615 bb::fr a = is_constant() ? bb::fr::zero() : ctx->get_variable(witness_index);
616 bb::fr b = add_b.is_constant() ? bb::fr::zero() : ctx->get_variable(add_b.witness_index);
617 bb::fr c = add_c.is_constant() ? bb::fr::zero() : ctx->get_variable(add_c.witness_index);
618
619 bb::fr out = a * a_scaling + b * b_scaling + c * c_scaling + const_scaling;
620
621 field_t<Builder> result(ctx);
622 result.witness_index = ctx->add_variable(out);
623
624 // Constrain the result
625 ctx->create_big_mul_add_gate({
626 .a = is_constant() ? ctx->zero_idx() : witness_index,
627 .b = add_b.is_constant() ? ctx->zero_idx() : add_b.witness_index,
628 .c = add_c.is_constant() ? ctx->zero_idx() : add_c.witness_index,
629 .d = result.witness_index,
630 .mul_scaling = bb::fr::zero(),
631 .a_scaling = a_scaling,
632 .b_scaling = b_scaling,
633 .c_scaling = c_scaling,
634 .d_scaling = bb::fr::neg_one(),
635 .const_scaling = const_scaling,
636 });
637 result.tag = OriginTag(tag, add_b.tag, add_c.tag);
638 return result;
639}
640
648template <typename Builder> field_t<Builder> field_t<Builder>::normalize() const
649{
650 if (is_normalized()) {
651 return *this;
652 }
654
655 // Value of this = this.v * this.mul + this.add; // where this.v = context->variables[this.witness_index]
656 // Normalised result = result.v * 1 + 0; // where result.v = this.v * this.mul + this.add
657 // We need a new gate to enforce that the `result` was correctly calculated from `this`.
659 bb::fr value = context->get_variable(witness_index);
660
661 result.witness_index = context->add_variable(value * multiplicative_constant + additive_constant);
664
665 // The aim of a new `add` gate is to constrain
666 // this.v * this.mul + this.add == result.v
667 // Let
668 // a_scaling := this.mul;
669 // b_scaling := 0;
670 // c_scaling := -1;
671 // const_scaling := this.add;
672 // The `add` gate enforces the relation
673 // this.v * a_scaling + result.v * c_scaling + const_scaling = 0
674
675 context->create_add_gate({ .a = witness_index,
676 .b = context->zero_idx(),
677 .c = result.witness_index,
678 .a_scaling = multiplicative_constant,
679 .b_scaling = bb::fr::zero(),
680 .c_scaling = bb::fr::neg_one(),
681 .const_scaling = additive_constant });
682 result.tag = tag;
683 return result;
684}
685
689template <typename Builder> void field_t<Builder>::assert_is_zero(std::string const& msg) const
690{
691
692 if (is_constant()) {
693 BB_ASSERT_EQ(additive_constant == bb::fr::zero(), true, msg);
694 return;
695 }
696
697 if ((get_value() != bb::fr::zero()) && !context->failed()) {
698 context->failure(msg);
699 }
700 // Aim of a new arithmetic gate: constrain this.v * this.mul + this.add == 0
701 // I.e.:
702 // this.v * 0 * [ 0 ] + this.v * [this.mul] + 0 * [ 0 ] + 0 * [ 0 ] + [this.add] == 0
703 // this.v * 0 * [q_m] + this.v * [ q_l ] + 0 * [q_r] + 0 * [q_o] + [ q_c ] == 0
704
705 context->create_arithmetic_gate({
706 .a = witness_index,
707 .b = context->zero_idx(),
708 .c = context->zero_idx(),
709 .q_m = bb::fr::zero(),
710 .q_l = multiplicative_constant,
711 .q_r = bb::fr::zero(),
712 .q_o = bb::fr::zero(),
713 .q_c = additive_constant,
714 });
715}
716
720template <typename Builder> void field_t<Builder>::assert_is_not_zero(std::string const& msg) const
721{
722
723 if (is_constant()) {
724 BB_ASSERT_EQ(additive_constant != bb::fr::zero(), true, msg);
725 return;
726 }
727
728 if ((get_value() == bb::fr::zero()) && !context->failed()) {
729 context->failure(msg);
730 }
731
732 bb::fr inverse_value = (get_value() == bb::fr::zero()) ? bb::fr::zero() : get_value().invert();
733
734 field_t<Builder> inverse(witness_t<Builder>(context, inverse_value));
735
736 // inverse is added in the circuit for checking that field element is not zero
737 // and it won't be used anymore, so it's needed to add this element in used witnesses
738 mark_witness_as_used(inverse);
739
740 // Aim of a new arithmetic gate: `this` has an inverse (hence is not zero).
741 // I.e.:
742 // (this.v * this.mul + this.add) * inverse.v == 1;
743 // <=> this.v * inverse.v * [this.mul] + this.v * [ 0 ] + inverse.v * [this.add] + 0 * [ 0 ] + [ -1] == 0
744 // <=> this.v * inverse.v * [ q_m ] + this.v * [q_l] + inverse.v * [ q_r ] + 0 * [q_o] + [q_c] == 0
745
746 // (a * mul_const + add_const) * b - 1 = 0
747 context->create_arithmetic_gate({
748 .a = witness_index, // input value
749 .b = inverse.witness_index, // inverse
750 .c = context->zero_idx(), // no output
751 .q_m = multiplicative_constant, // a * b * mul_const
752 .q_l = bb::fr::zero(), // a * 0
753 .q_r = additive_constant, // b * mul_const
754 .q_o = bb::fr::zero(), // c * 0
755 .q_c = bb::fr::neg_one(), // -1
756 });
757}
758
785template <typename Builder> bool_t<Builder> field_t<Builder>::is_zero() const
786{
787 bb::fr native_value = get_value();
788 const bool is_zero_raw = native_value.is_zero();
789
790 if (is_constant()) {
791 // Create a constant bool_t
792 bool_t is_zero(context, is_zero_raw);
793 is_zero.set_origin_tag(get_origin_tag());
794 return is_zero;
795 }
796
797 bool_t is_zero = witness_t(context, is_zero_raw);
798
799 // This can be done out of circuit, as `is_zero = true` implies `I = 1`.
800 bb::fr inverse_native = (is_zero_raw) ? bb::fr::one() : native_value.invert();
801
802 field_t inverse = witness_t(context, inverse_native);
803
804 // Note that `evaluate_polynomial_identity(a, b, c, d)` checks that `a * b + c + d = 0`, so we are using it for the
805 // constraints 1) and 2) above.
806 // More precisely, to check that `a * I - 1 + is_zero = 0`, it creates a `big_mul_gate` given by the equation:
807 // a.v * I.v * mul_scaling + a.v * a_scaling + I.v * b_scaling + is_zero.v * c_scaling + (-1) * d_scaling +
808 // const_scaling = 0
809 // where
810 // muk_scaling := a.mul * I.mul;
811 // a_scaling := a.mul * I.add;
812 // b_scaling := I.mul * a.add;
813 // c_scaling := 1;
814 // d_scaling := 0;
815 // const_scaling := a.add * I.add + is_zero.add - 1;
816 field_t::evaluate_polynomial_identity(*this, inverse, is_zero, bb::fr::neg_one());
817
818 // To check that `-is_zero * I + is_zero = 0`, create a `big_mul_gate` given by the equation:
819 // is_zero.v * (-I).v * mul_scaling + is_zero.v * a_scaling + (-I).v * b_scaling + is_zero.v * c_scaling + 0 *
820 // d_scaling + const_scaling = 0
821 // where
822 // mul_scaling := is_zero.mul * (-I).mul;
823 // a_scaling := is_zero.mul * (-I).add;
824 // b_scaling := (-I).mul * is_zero.add;
825 // c_scaling := is_zero.mul;
826 // d_scaling := 0;
827 // const_scaling := is_zero.add * (-I).add + is_zero.add;
828 field_t::evaluate_polynomial_identity(is_zero, -inverse, is_zero, bb::fr::zero());
829 is_zero.set_origin_tag(tag);
830 return is_zero;
831}
838template <typename Builder> bb::fr field_t<Builder>::get_value() const
839{
840 if (!is_constant()) {
842 return (multiplicative_constant * context->get_variable(witness_index)) + additive_constant;
843 }
844 BB_ASSERT_DEBUG(multiplicative_constant == bb::fr::one());
845 // A constant field_t's value is tracked wholly by its additive_constant member.
846 return additive_constant;
847}
848
852template <typename Builder> bool_t<Builder> field_t<Builder>::operator==(const field_t& other) const
853{
854 return ((*this) - other).is_zero();
855}
856
860template <typename Builder> bool_t<Builder> field_t<Builder>::operator!=(const field_t& other) const
861{
862 return !operator==(other);
863}
864
868template <typename Builder>
870{
871 if (predicate.is_constant()) {
872 field_t result = predicate.get_value() ? -(*this) : *this;
873 result.set_origin_tag(OriginTag(get_origin_tag(), predicate.get_origin_tag()));
874 return result;
875 }
876 // Compute
877 // `predicate` * ( -2 * a ) + a.
878 // If predicate's value == true, then the output is `-a`, else it's `a`
879 static constexpr bb::fr minus_two(-2);
880 return field_t(predicate).madd(*this * minus_two, *this);
881}
882
894template <typename Builder>
896 const field_t& lhs,
897 const field_t& rhs)
898{
899 // If the predicate is constant, the conditional assignment can be done out of circuit
900 if (predicate.is_constant()) {
901 auto result = field_t(predicate.get_value() ? lhs : rhs);
902 result.set_origin_tag(OriginTag(predicate.get_origin_tag(), lhs.get_origin_tag(), rhs.get_origin_tag()));
903 return result;
904 }
905 // If lhs and rhs are the same witness or constant, just return it (but still merge tags)
906 if (witness_indices_match(lhs, rhs) && (lhs.additive_constant == rhs.additive_constant) &&
907 (lhs.multiplicative_constant == rhs.multiplicative_constant)) {
908 auto result = lhs;
909 result.set_origin_tag(OriginTag(predicate.get_origin_tag(), lhs.get_origin_tag(), rhs.get_origin_tag()));
910 return result;
911 }
912
913 return (lhs - rhs).madd(predicate, rhs);
914}
915
920template <typename Builder>
921void field_t<Builder>::create_range_constraint(const size_t num_bits, std::string const& msg) const
922{
923 if (num_bits == 0) {
924 assert_is_zero("0-bit range_constraint on non-zero field_t.");
925 } else {
926 if (is_constant()) {
927 BB_ASSERT_LT(uint256_t(get_value()).get_msb(), num_bits, msg);
928 } else {
929 context->create_limbed_range_constraint(
930 normalize().witness_index, num_bits, bb::UltraCircuitBuilder::DEFAULT_PLOOKUP_RANGE_BITNUM, msg);
931 }
932 }
933}
934
942template <typename Builder> void field_t<Builder>::assert_equal(const field_t& rhs, std::string const& msg) const
943{
944 const field_t lhs = *this;
945 Builder* ctx = validate_context(lhs.get_context(), rhs.get_context());
946 if (lhs.is_constant() && rhs.is_constant()) {
947 BB_ASSERT_EQ(lhs.get_value(), rhs.get_value(), "field_t::assert_equal: constants are not equal");
948 return;
949 }
950 if (lhs.is_constant()) {
951 ctx->assert_equal_constant(rhs.get_witness_index(), lhs.get_value(), msg);
952 } else if (rhs.is_constant()) {
953 ctx->assert_equal_constant(lhs.get_witness_index(), rhs.get_value(), msg);
954 } else {
955 // Both are witnesses - save original tags and clear them to allow different transcript/free witness sources
956 // (e.g., proving 2 separate properties about same object through 2 different transcripts)
957 const auto lhs_original_tag = lhs.get_origin_tag();
958 const auto rhs_original_tag = rhs.get_origin_tag();
959 auto empty_tag = OriginTag::constant(); // Disable origin checking during intermediate operations
960 lhs.set_origin_tag(empty_tag);
961 rhs.set_origin_tag(empty_tag);
962
963 if (lhs.is_normalized() || rhs.is_normalized()) {
964 ctx->assert_equal(lhs.get_witness_index(), rhs.get_witness_index(), msg);
965 } else {
966 // Instead of creating 2 gates for normalizing both witnesses and applying a copy constraint, we use a
967 // single `add` gate constraining a - b = 0
968 ctx->create_add_gate({ .a = lhs.witness_index,
969 .b = rhs.witness_index,
970 .c = ctx->zero_idx(),
971 .a_scaling = lhs.multiplicative_constant,
972 .b_scaling = -rhs.multiplicative_constant,
973 .c_scaling = 0,
974 .const_scaling = lhs.additive_constant - rhs.additive_constant });
975 if ((lhs.get_value() != rhs.get_value()) && !ctx->failed()) {
976 ctx->failure(msg);
977 }
978 }
979
980 // Restore tags
981 lhs.set_origin_tag(lhs_original_tag);
982 rhs.set_origin_tag(rhs_original_tag);
983 }
984}
988template <typename Builder> void field_t<Builder>::assert_not_equal(const field_t& rhs, std::string const& msg) const
989{
990 const field_t lhs = *this;
991 const field_t diff = lhs - rhs;
992 diff.assert_is_not_zero(msg);
993}
997template <typename Builder>
998void field_t<Builder>::assert_is_in_set(const std::vector<field_t>& set, std::string const& msg) const
999{
1000 const field_t input = *this;
1001 field_t product = (input - set[0]);
1002 for (size_t i = 1; i < set.size(); i++) {
1003 product *= (input - set[i]);
1004 }
1005 product.assert_is_zero(msg);
1006}
1007
1015template <typename Builder>
1017 const field_t& T1,
1018 const field_t& T2,
1019 const field_t& T3)
1020{
1021
1023 table[0] = T0; // const coeff
1024 table[1] = T1 - T0; // t0 coeff
1025 table[2] = T2 - T0; // t1 coeff
1026 table[3] = T3.add_two(-table[2], -T1); // t0t1 coeff
1027 return table;
1028}
1029
1033template <typename Builder>
1035 const field_t& T1,
1036 const field_t& T2,
1037 const field_t& T3,
1038 const field_t& T4,
1039 const field_t& T5,
1040 const field_t& T6,
1041 const field_t& T7)
1042{
1044 table[0] = T0; // const coeff
1045 table[1] = T1 - T0; // t0 coeff
1046 table[2] = T2 - T0; // t1 coeff
1047 table[3] = T4 - T0; // t2 coeff
1048 table[4] = T3.add_two(-table[2], -T1); // t0t1 coeff
1049 table[5] = T5.add_two(-table[3], -T1); // t0t2 coeff
1050 table[6] = T6.add_two(-table[3], -T2); // t1t2 coeff
1051 table[7] = T7.add_two(-T6 - T5, T4 - table[4]); // t0t1t2 coeff
1052 return table;
1053}
1054
1059template <typename Builder>
1061 const bool_t<Builder>& t1,
1062 const bool_t<Builder>& t0)
1063{
1064 field_t R0 = field_t(t1).madd(table[3], table[1]);
1065 field_t R1 = R0.madd(field_t(t0), table[0]);
1066 field_t R2 = field_t(t1).madd(table[2], R1);
1067 return R2;
1068}
1069
1081template <typename Builder>
1083 const bool_t<Builder>& t2,
1084 const bool_t<Builder>& t1,
1085 const bool_t<Builder>& t0)
1086{
1087 field_t R0 = field_t(t0).madd(table[7], table[6]);
1088 field_t R1 = field_t(t1).madd(R0, table[3]);
1089 field_t R2 = field_t(t2).madd(R1, table[0]);
1090 field_t R3 = field_t(t0).madd(table[4], table[2]);
1091 field_t R4 = field_t(t1).madd(R3, R2);
1092 field_t R5 = field_t(t2).madd(table[5], table[1]);
1093 field_t R6 = field_t(t0).madd(R5, R4);
1094 return R6;
1095}
1096
1100template <typename Builder>
1102 const field_t& a, const field_t& b, const field_t& c, const field_t& d, const std::string& msg)
1103{
1104 Builder* ctx = validate_context(a.context, b.context, c.context, d.context);
1105
1106 if (a.is_constant() && b.is_constant() && c.is_constant() && d.is_constant()) {
1107 BB_ASSERT_EQ(a.get_value() + b.get_value() + c.get_value() + d.get_value(), 0, msg);
1108 return;
1109 }
1110
1111 const bool identity_holds = (a.get_value() + b.get_value() + c.get_value() + d.get_value()).is_zero();
1112 if (!identity_holds && !ctx->failed()) {
1113 ctx->failure(msg);
1114 }
1115
1116 // validate that a + b + c + d = 0
1117 bb::fr const_scaling = a.additive_constant + b.additive_constant + c.additive_constant + d.additive_constant;
1118
1119 ctx->create_big_add_gate({
1120 .a = a.is_constant() ? ctx->zero_idx() : a.witness_index,
1121 .b = b.is_constant() ? ctx->zero_idx() : b.witness_index,
1122 .c = c.is_constant() ? ctx->zero_idx() : c.witness_index,
1123 .d = d.is_constant() ? ctx->zero_idx() : d.witness_index,
1124 .a_scaling = a.multiplicative_constant,
1125 .b_scaling = b.multiplicative_constant,
1126 .c_scaling = c.multiplicative_constant,
1127 .d_scaling = d.multiplicative_constant,
1128 .const_scaling = const_scaling,
1129 });
1130}
1136template <typename Builder>
1138 const field_t& a, const field_t& b, const field_t& c, const field_t& d, const std::string& msg)
1139{
1140 if (a.is_constant() && b.is_constant() && c.is_constant() && d.is_constant()) {
1141 BB_ASSERT((a.get_value() * b.get_value() + c.get_value() + d.get_value()).is_zero(), msg);
1142 return;
1143 }
1144
1145 Builder* ctx = validate_context(a.context, b.context, c.context, d.context);
1146
1147 const bool identity_holds = ((a.get_value() * b.get_value()) + c.get_value() + d.get_value()).is_zero();
1148 if (!identity_holds && !ctx->failed()) {
1149 ctx->failure(msg);
1150 }
1151
1152 // validate that a * b + c + d = 0
1153 bb::fr mul_scaling = a.multiplicative_constant * b.multiplicative_constant;
1154 bb::fr a_scaling = a.multiplicative_constant * b.additive_constant;
1155 bb::fr b_scaling = b.multiplicative_constant * a.additive_constant;
1156 bb::fr c_scaling = c.multiplicative_constant;
1157 bb::fr d_scaling = d.multiplicative_constant;
1158 bb::fr const_scaling = a.additive_constant * b.additive_constant + c.additive_constant + d.additive_constant;
1159
1160 ctx->create_big_mul_add_gate({
1161 .a = a.is_constant() ? ctx->zero_idx() : a.witness_index,
1162 .b = b.is_constant() ? ctx->zero_idx() : b.witness_index,
1163 .c = c.is_constant() ? ctx->zero_idx() : c.witness_index,
1164 .d = d.is_constant() ? ctx->zero_idx() : d.witness_index,
1165 .mul_scaling = mul_scaling,
1166 .a_scaling = a_scaling,
1167 .b_scaling = b_scaling,
1168 .c_scaling = c_scaling,
1169 .d_scaling = d_scaling,
1170 .const_scaling = const_scaling,
1171 });
1172}
1173
1181{
1182 if (input.empty()) {
1183 return field_t(bb::fr::zero());
1184 }
1185
1186 if (input.size() == 1) {
1187 return input[0].normalize();
1188 }
1189
1190 std::vector<field_t> accumulator;
1191 field_t constant_term = bb::fr::zero();
1192
1193 // Remove constant terms from input field elements
1194 for (const auto& element : input) {
1195 if (element.is_constant()) {
1196 constant_term += element;
1197 } else {
1198 accumulator.emplace_back(element);
1199 }
1200 }
1201 if (accumulator.empty()) {
1202 return constant_term;
1203 }
1204 // Add the accumulated constant term to the first witness. It does not create any gates - only the additive
1205 // constant of `accumulator[0]` is updated.
1206 accumulator[0] += constant_term;
1207
1208 // At this point, the `accumulator` vector consisting of witnesses is not empty, so we can extract the context.
1209 Builder* ctx = validate_context<Builder>(accumulator);
1210
1211 // Step 2: compute output value
1212 size_t num_elements = accumulator.size();
1213 bb::fr output = bb::fr::zero();
1214 for (const auto& acc : accumulator) {
1215 output += acc.get_value();
1216 }
1217
1218 // Pad the accumulator with zeroes so that its size is a multiple of 3.
1219 const size_t num_padding_wires = (num_elements % 3) == 0 ? 0 : 3 - (num_elements % 3);
1220 for (size_t i = 0; i < num_padding_wires; ++i) {
1221 accumulator.emplace_back(field_t<Builder>::from_witness_index(ctx, ctx->zero_idx()));
1222 }
1223 num_elements = accumulator.size();
1224 const size_t num_gates = (num_elements / 3);
1225 // Last gate is handled separetely
1226 const size_t last_gate_idx = num_gates - 1;
1227
1228 field_t total = witness_t(ctx, output);
1229 field_t accumulating_total = total;
1230
1231 // Let
1232 // a_i := accumulator[3*i];
1233 // b_i := accumulator[3*i+1];
1234 // c_i := accumulator[3*i+2];
1235 // d_0 := total;
1236 // d_i := total - \sum_(j < 3*i) accumulator[j];
1237 // which leads us to equations
1238 // d_{i+1} = d_{i} - a_i - b_i - c_i for i = 0, ..., last_idx - 1;
1239 // 0 = d_{i} - a_i - b_i - c_i for i = last_gate_idx,
1240 // that are turned into constraints below.
1241
1242 for (size_t i = 0; i < last_gate_idx; ++i) {
1243 // For i < last_gate_idx, we create a `big_add_gate` constraint
1244 // a_i.v * a_scaling + b_i.v * b_scaling + c_i.v * c_scaling + d_i.v * d_scaling + const_scaling +
1245 // w_4_omega = 0
1246 // where
1247 // a_scaling := a_i.mul
1248 // b_scaling := b_i.mul
1249 // c_scaling := c_i.mul
1250 // d_scaling := -1
1251 // const_scaling := a_i.add + b_i.add + c_i.add
1252 // w_4_omega := d_{i+1}
1253 ctx->create_big_add_gate(
1254 {
1255 .a = accumulator[3 * i].witness_index,
1256 .b = accumulator[3 * i + 1].witness_index,
1257 .c = accumulator[3 * i + 2].witness_index,
1258 .d = accumulating_total.witness_index,
1259 .a_scaling = accumulator[3 * i].multiplicative_constant,
1260 .b_scaling = accumulator[3 * i + 1].multiplicative_constant,
1261 .c_scaling = accumulator[3 * i + 2].multiplicative_constant,
1262 .d_scaling = -1,
1263 .const_scaling = accumulator[3 * i].additive_constant + accumulator[3 * i + 1].additive_constant +
1264 accumulator[3 * i + 2].additive_constant,
1265 },
1266 /*use_next_gate_w_4 = */ true);
1267 bb::fr new_total = accumulating_total.get_value() - accumulator[3 * i].get_value() -
1268 accumulator[3 * i + 1].get_value() - accumulator[3 * i + 2].get_value();
1269 accumulating_total = witness_t<Builder>(ctx, new_total);
1270 }
1271
1272 // For i = last_gate_idx, we create a `big_add_gate` constraining
1273 // a_i.v * a_scaling + b_i.v * b_scaling + c_i.v * c_scaling + d_i.v * d_scaling + const_scaling = 0
1274 ctx->create_big_add_gate({
1275 .a = accumulator[3 * last_gate_idx].witness_index,
1276 .b = accumulator[3 * last_gate_idx + 1].witness_index,
1277 .c = accumulator[3 * last_gate_idx + 2].witness_index,
1278 .d = accumulating_total.witness_index,
1279 .a_scaling = accumulator[3 * last_gate_idx].multiplicative_constant,
1280 .b_scaling = accumulator[3 * last_gate_idx + 1].multiplicative_constant,
1281 .c_scaling = accumulator[3 * last_gate_idx + 2].multiplicative_constant,
1282 .d_scaling = -1,
1283 .const_scaling = accumulator[3 * last_gate_idx].additive_constant +
1284 accumulator[3 * last_gate_idx + 1].additive_constant +
1285 accumulator[3 * last_gate_idx + 2].additive_constant,
1286 });
1287 OriginTag new_tag = OriginTag::constant(); // Initialize as CONSTANT so merging with input tags works correctly
1288 for (const auto& single_input : input) {
1289 new_tag = OriginTag(new_tag, single_input.tag);
1290 }
1291 total.tag = new_tag;
1292 return total.normalize();
1293}
1294
1303template <typename Builder>
1305 const size_t num_bits) const
1306{
1307 BB_ASSERT(lsb_index < num_bits);
1309
1310 const uint256_t value = get_value();
1311 const uint256_t hi = value >> lsb_index;
1312 const uint256_t lo = value % (uint256_t(1) << lsb_index);
1313
1314 if (is_constant()) {
1315 // If `*this` is constant, we can return the split values directly
1316 BB_ASSERT(lo + (hi << lsb_index) == value);
1318 }
1319
1320 // Handle edge case when lsb_index == 0
1321 if (lsb_index == 0) {
1322 BB_ASSERT(hi == value);
1323 BB_ASSERT(lo == 0);
1324 create_range_constraint(num_bits, "split_at: hi value too large.");
1325 return std::make_pair(field_t<Builder>(0), *this);
1326 }
1327
1328 Builder* ctx = get_context();
1329 BB_ASSERT(ctx != nullptr);
1330
1331 field_t<Builder> lo_wit(witness_t(ctx, lo));
1332 field_t<Builder> hi_wit(witness_t(ctx, hi));
1333
1334 // Ensure that `lo_wit` is in the range [0, 2^lsb_index - 1]
1335 lo_wit.create_range_constraint(lsb_index, "split_at: lo value too large.");
1336
1337 // Ensure that `hi_wit` is in the range [0, 2^(num_bits - lsb_index) - 1]
1338 hi_wit.create_range_constraint(num_bits - lsb_index, "split_at: hi value too large.");
1339
1340 // Check that *this = lo_wit + hi_wit * 2^{lsb_index}
1341 const field_t<Builder> reconstructed = lo_wit + (hi_wit * field_t<Builder>(uint256_t(1) << lsb_index));
1342 assert_equal(reconstructed, "split_at: decomposition failed");
1343
1344 // Set the origin tag for both witnesses
1345 lo_wit.set_origin_tag(tag);
1346 hi_wit.set_origin_tag(tag);
1347
1348 return std::make_pair(lo_wit, hi_wit);
1349}
1350
1351// Explicit instantations of pow
1354
1356 const field_t<bb::MegaCircuitBuilder>&) const;
1357
1360
1362 const field_t<bb::MegaCircuitBuilder>&) const;
1363
1365template class field_t<bb::MegaCircuitBuilder>;
1366
1367} // namespace bb::stdlib
#define BB_ASSERT(expression,...)
Definition assert.hpp:70
#define BB_ASSERT_DEBUG(expression,...)
Definition assert.hpp:55
#define BB_ASSERT_EQ(actual, expected,...)
Definition assert.hpp:83
#define BB_ASSERT_LT(left, right,...)
Definition assert.hpp:143
static constexpr size_t DEFAULT_PLOOKUP_RANGE_BITNUM
constexpr uint64_t get_msb() const
Implements boolean logic in-circuit.
Definition bool.hpp:60
bool get_value() const
Definition bool.hpp:125
bool is_constant() const
Definition bool.hpp:127
void set_origin_tag(const OriginTag &new_tag) const
Definition bool.hpp:154
uint32_t witness_index
Index of the witness in the builder's witness vector.
Definition bool.hpp:178
bool witness_inverted
Definition bool.hpp:170
OriginTag tag
Definition bool.hpp:179
OriginTag get_origin_tag() const
Definition bool.hpp:155
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:689
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:869
Builder_ Builder
Definition field.hpp:48
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:998
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:942
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:988
bool is_normalized() const
Definition field.hpp:443
field_t madd(const field_t &to_mul, const field_t &to_add) const
Definition field.cpp:520
static field_t from_witness_index(Builder *ctx, uint32_t witness_index)
Definition field.cpp:67
field_t operator+(const field_t &other) const
Field addition operator.
Definition field.cpp:132
bool_t< Builder > operator!=(const field_t &other) const
Compute a bool_t equal to (a != b)
Definition field.cpp:860
bb::fr additive_constant
Definition field.hpp:94
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:1082
static void evaluate_polynomial_identity(const field_t &a, const field_t &b, const field_t &c, const field_t &d, const std::string &msg="field_t::evaluate_polynomial_identity")
Given a, b, c, d, constrain a * b + c + d = 0 by creating a big_mul_gate.
Definition field.cpp:1137
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:1180
field_t operator-() const
Definition field.hpp:348
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:921
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:320
Builder * context
Definition field.hpp:57
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:1034
bb::fr multiplicative_constant
Definition field.hpp:95
Builder * get_context() const
Definition field.hpp:432
field_t sqr() const
Definition field.hpp:283
static field_t conditional_assign_internal(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:895
OriginTag get_origin_tag() const
Definition field.hpp:359
bb::fr get_value() const
Given a := *this, compute its value given by a.v * a.mul + a.add.
Definition field.cpp:838
field_t operator*(const field_t &other) const
Field multiplication operator.
Definition field.cpp:200
field_t(Builder *parent_context=nullptr)
Definition field.cpp:21
field_t normalize() const
Return a new element, where the in-circuit witness contains the actual represented value (multiplicat...
Definition field.cpp:648
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:1060
bool_t< Builder > is_zero() const
Validate whether a field_t element is zero.
Definition field.cpp:785
field_t pow(const uint32_t &exponent) const
Raise this field element to the power of the provided uint32_t exponent.
Definition field.cpp:430
static void evaluate_linear_identity(const field_t &a, const field_t &b, const field_t &c, const field_t &d, const std::string &msg="field_t::evaluate_linear_identity")
Constrain a + b + c + d to be equal to 0.
Definition field.cpp:1101
bool is_constant() const
Definition field.hpp:442
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:1016
void set_free_witness_tag()
Set the free witness flag for the field element's tag.
Definition field.hpp:364
void set_origin_tag(const OriginTag &new_tag) const
Definition field.hpp:358
uint32_t witness_index
Definition field.hpp:145
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:585
std::pair< field_t< Builder >, field_t< Builder > > no_wrap_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:1304
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:720
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:310
bool_t< Builder > operator==(const field_t &other) const
Compute a bool_t equal to (a == b)
Definition field.cpp:852
uint32_t get_witness_index() const
Get the witness index of the current field element.
Definition field.hpp:519
StrictMock< MockContext > context
FF a
FF b
constexpr size_t MAX_NO_WRAP_INTEGER_BIT_LENGTH
Definition grumpkin.hpp:16
constexpr T get_msb(const T in)
Definition get_msb.hpp:50
T * validate_context(T *ptr)
Definition field.hpp:17
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...
void mark_witness_as_used(const field_t< Builder > &field)
Mark a field_t witness as used (for UltraBuilder only).
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
Univariate< Fr, domain_end > operator+(const Fr &ff, const Univariate< Fr, domain_end > &uv)
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
static OriginTag constant()
static constexpr field neg_one()
static constexpr field one()
constexpr field invert() const noexcept
BB_INLINE constexpr bool is_zero() const noexcept
static constexpr field zero()