Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
biggroup.hpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: Complete, auditors: [Suyash], commit: 553c5eb82901955c638b943065acd3e47fc918c0}
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
7#pragma once
8
9#include "../bigfield/bigfield.hpp"
10#include "../bigfield/goblin_field.hpp"
11#include "../byte_array/byte_array.hpp"
12#include "../circuit_builders/circuit_builders_fwd.hpp"
13#include "../field/field.hpp"
14#include "../field/field_utils.hpp"
15#include "../memory/rom_table.hpp"
16#include "../memory/twin_rom_table.hpp"
21#include <cstddef>
22
24
25// ( ͡° ͜ʖ ͡°)
26template <class Builder_, class Fq, class Fr, class NativeGroup> class element {
27 public:
28 using Builder = Builder_;
32 using biggroup_tag = element; // Facilitates a constexpr check IsBigGroup
33 using BaseField = Fq;
34
35 // Number of bb::fr field elements used to represent a goblin element in the public inputs
36 static constexpr size_t PUBLIC_INPUTS_SIZE = BIGGROUP_PUBLIC_INPUTS_SIZE;
37
38 element();
39 element(const typename NativeGroup::affine_element& input);
40
41 // Construct a biggroup element from its coordinates
42 // By default, we validate that the point is on the curve
43 element(const Fq& x, const Fq& y, const bool assert_on_curve = true);
44 element(const Fq& x, const Fq& y, const bool_ct& is_infinity, bool assert_on_curve = true);
45
46 element(const element& other);
47 element(element&& other) noexcept;
48
49 ~element() = default;
50
56 uint32_t set_public() const
57 {
58 const uint32_t start_idx = _x.set_public();
59 _y.set_public();
60
61 return start_idx;
62 }
63
72 static element from_witness(Builder* ctx, const typename NativeGroup::affine_element& input)
73 {
74 element out;
75 if (input.is_point_at_infinity()) {
76 Fq x = Fq::from_witness(ctx, NativeGroup::affine_one.x);
77 Fq y = Fq::from_witness(ctx, NativeGroup::affine_one.y);
78 out._x = x;
79 out._y = y;
80 } else {
81 Fq x = Fq::from_witness(ctx, input.x);
82 Fq y = Fq::from_witness(ctx, input.y);
83 out._x = x;
84 out._y = y;
85 }
86 out.set_point_at_infinity(witness_ct(ctx, input.is_point_at_infinity()));
87
88 // Mark the element as coming out of nowhere
91 return out;
92 }
93
97 void validate_on_curve(std::string const& msg = "biggroup::validate_on_curve") const
98 {
99 bool has_circuit_failed = get_context()->failed();
100
101 Fq b(get_context(), uint256_t(NativeGroup::curve_b));
102 Fq adjusted_b = Fq::conditional_assign(is_point_at_infinity(), Fq::zero(), b);
103 Fq adjusted_x = Fq::conditional_assign(is_point_at_infinity(), Fq::zero(), _x);
104 Fq adjusted_y = Fq::conditional_assign(is_point_at_infinity(), Fq::zero(), _y);
105 if constexpr (!NativeGroup::has_a) {
106 // we validate y^2 = x^3 + b by setting "fix_remainder_zero = true" when calling mult_madd
107 Fq::mult_madd({ adjusted_x.sqr(), adjusted_y }, { adjusted_x, -adjusted_y }, { adjusted_b }, true);
108 } else {
109 Fq a(get_context(), uint256_t(NativeGroup::curve_a));
110 Fq adjusted_a = Fq::conditional_assign(is_point_at_infinity(), Fq::zero(), a);
111 // we validate y^2 = x^3 + ax + b by setting "fix_remainder_zero = true" when calling mult_madd
112 Fq::mult_madd({ adjusted_x.sqr(), adjusted_x, adjusted_y },
113 { adjusted_x, adjusted_a, -adjusted_y },
114 { adjusted_b },
115 true);
116 }
117
118 if ((!has_circuit_failed) && (get_context()->failed())) {
119 vinfo("Original bigfield error generated by biggroup::validate_on_curve: ", get_context()->err());
120 get_context()->failure(msg);
121 }
122 }
123
124 [[nodiscard]] bool is_constant() const
125 {
126 const bool x_is_const = _x.is_constant();
127 const bool y_is_const = _y.is_constant();
128 BB_ASSERT_EQ(x_is_const, y_is_const, "biggroup: x and y coordinate constant status mismatch");
129 return x_is_const;
130 }
131
136 {
137 this->_x.convert_constant_to_fixed_witness(builder);
138 this->_y.convert_constant_to_fixed_witness(builder);
139 // Origin tags should be unset after fixing the witness
141 }
142
147 {
148 // Origin tags should be updated within
149 this->_x.fix_witness();
150 this->_y.fix_witness();
151
152 // This is now effectively a constant
154 }
155
159 static element one(Builder* ctx)
160 {
161 uint256_t x = uint256_t(NativeGroup::one.x);
162 uint256_t y = uint256_t(NativeGroup::one.y);
163 Fq x_fq(ctx, x);
164 Fq y_fq(ctx, y);
165 return element(x_fq, y_fq, /*assert_on_curve=*/false);
166 }
167
169 {
170 Fr zero = Fr::from_witness_index(ctx, ctx->zero_idx());
171 zero.unset_free_witness_tag();
172 Fq x_fq(zero, zero);
173 Fq y_fq(zero, zero);
174 element result(x_fq, y_fq, /*assert_on_curve=*/false);
175 result.set_point_at_infinity(true);
176 return result;
177 }
178
179 element& operator=(const element& other);
180 element& operator=(element&& other) noexcept;
181
182 element checked_unconditional_add(const element& other) const;
184
185 element operator+(const element& other) const;
186 element operator-(const element& other) const;
188 {
189 element result(*this);
190 result._y = -result._y;
191 return result;
192 }
194 {
195 *this = *this + other;
196 return *this;
197 }
199 {
200 *this = *this - other;
201 return *this;
202 }
203
204 element operator*(const Fr& scalar) const;
205
206 element conditional_negate(const bool_ct& predicate) const
207 {
208 element result(*this);
209 result._y = result._y.conditional_negate(predicate);
210 return result;
211 }
212
220 element conditional_select(const element& other, const bool_ct& predicate) const
221 {
222 // If predicate is constant, we can select out of circuit
223 if (predicate.is_constant()) {
224 auto result = predicate.get_value() ? other : *this;
225 result.set_origin_tag(
226 OriginTag(predicate.get_origin_tag(), other.get_origin_tag(), this->get_origin_tag()));
227 return result;
228 }
229
230 // Get the builder context
231 Builder* ctx = validate_context<Builder>(get_context(), other.get_context(), predicate.get_context());
232 BB_ASSERT_NEQ(ctx, nullptr, "biggroup::conditional_select must have a context");
233
234 element result(*this);
235 result._x = result._x.conditional_select(other._x, predicate);
236 result._y = result._y.conditional_select(other._y, predicate);
237 result._is_infinity =
239 return result;
240 }
241
253 const std::string msg = "biggroup::incomplete_assert_equal") const
254 {
255 is_point_at_infinity().assert_equal(other.is_point_at_infinity(), msg + " (infinity flag)");
256 _x.assert_equal(other._x, msg + " (x coordinate)");
257 _y.assert_equal(other._y, msg + " (y coordinate)");
258 }
259
261 {
262 element result(*this);
263 result._x.reduce_mod_target_modulus();
264 result._y.reduce_mod_target_modulus();
265 return result;
266 }
267 element scalar_mul(const Fr& scalar, const size_t max_num_bits = 0) const;
268
270 {
271 element result(*this);
272 result._x.self_reduce();
273 result._y.self_reduce();
274 return result;
275 }
276
277 void assert_coordinates_in_field(const std::string& msg = "biggroup::assert_coordinates_in_field") const
278 {
279 _x.assert_is_in_field(msg + " (x coordinate)");
280 _y.assert_is_in_field(msg + " (y coordinate)");
281 }
282
283 element dbl() const;
284
285 // we use this data structure to add together a sequence of points.
286 // By tracking the previous values of x_1, y_1, \lambda, we can avoid
287 // computing the output y-coordinate of intermediate additions
294 bool is_full_element = false;
295
297 explicit chain_add_accumulator(const element& input)
298 : x3_prev(input._x)
299 , y3_prev(input._y)
300 , is_full_element(true)
301 {}
303 chain_add_accumulator(chain_add_accumulator&& other) noexcept = default;
307 };
308
314 static chain_add_accumulator chain_add_start(const element& p1, const element& p2);
315 static chain_add_accumulator chain_add(const element& p1, const chain_add_accumulator& accumulator);
316 static element chain_add_end(const chain_add_accumulator& accumulator);
318
319 typename NativeGroup::affine_element get_value() const
320 {
321 uint512_t x_val = _x.get_value() % Fq::modulus_u512;
322 uint512_t y_val = _y.get_value() % Fq::modulus_u512;
323 auto result = typename NativeGroup::affine_element(x_val.lo, y_val.lo);
325 result.self_set_infinity();
326 }
327 return result;
328 }
329
330 static element batch_mul(const std::vector<element>& points,
331 const std::vector<Fr>& scalars,
332 const size_t max_num_bits = 0,
333 const bool with_edgecases = false,
334 const Fr& masking_scalar = Fr(1));
335
336 template <typename X = NativeGroup, typename = typename std::enable_if_t<std::is_same<X, secp256k1::g1>::value>>
337 static element secp256k1_ecdsa_mul(const element& pubkey, const Fr& u1, const Fr& u2);
338
343 static std::vector<bool_ct> compute_naf(const Fr& scalar, const size_t max_num_bits = 0);
344
345 // Internal struct to represent wNAF for a secp256k1 scalar
353
354 // Internal struct to represent a pair of secp256k1 wNAFs
359
364 template <size_t wnaf_size, size_t staggered_lo_offset = 0, size_t staggered_hi_offset = 0>
365 static secp256k1_wnaf_pair compute_secp256k1_endo_wnaf(const Fr& scalar, const bool range_constrain_wnaf = true);
366
367 Builder* get_context() const { return validate_context<Builder>(_x.get_context(), _y.get_context()); }
368
369 Builder* get_context(const element& other) const
370 {
371 return validate_context<Builder>(get_context(), other.get_context());
372 }
373
374 // Coordinate accessors (non-owning, const reference)
375 const Fq& x() const { return _x; }
376 const Fq& y() const { return _y; }
377
379 void set_point_at_infinity(const bool_ct& is_infinity, const bool& add_to_used_witnesses = false)
380 {
381 _is_infinity = is_infinity.normalize();
382 if (add_to_used_witnesses) {
384 };
385 }
387
389 {
390 _x.set_origin_tag(tag);
391 _y.set_origin_tag(tag);
393 }
394
396 {
397 _x.clear_round_provenance();
398 _y.clear_round_provenance();
400 }
401
403 {
404 return OriginTag(_x.get_origin_tag(), _y.get_origin_tag(), _is_infinity.get_origin_tag());
405 }
406
411 {
412 _x.unset_free_witness_tag();
413 _y.unset_free_witness_tag();
415 }
416
421 {
422 _x.set_free_witness_tag();
423 _y.set_free_witness_tag();
425 }
426
427 // For testing purposes only
429
430 private:
434
440
450 static std::pair<std::vector<element>, std::vector<Fr>> mask_points(const std::vector<element>& _points,
451 const std::vector<Fr>& _scalars,
452 const Fr& masking_scalar);
453
463 const std::vector<element>& _points, const std::vector<Fr>& _scalars);
464
479 template <size_t num_bits, size_t wnaf_size, size_t lo_stagger, size_t hi_stagger>
481 const secp256k1::fr& scalar,
482 size_t stagger,
483 bool is_negative,
484 const bool range_constrain_wnaf = true,
485 bool is_lo = false);
486
496 template <size_t wnaf_size>
497 static std::pair<uint64_t, bool> get_staggered_wnaf_fragment_value(const uint64_t fragment_u64,
498 const uint64_t stagger,
499 bool is_negative,
500 bool wnaf_skew);
501
515 template <size_t wnaf_size>
517 const uint64_t* wnaf_values,
518 bool is_negative,
519 size_t rounds,
520 const bool range_constrain_wnaf = true);
521
533 template <size_t wnaf_size>
535 const std::vector<field_ct>& wnaf,
536 const bool_ct& positive_skew,
537 const bool_ct& negative_skew,
538 const field_ct& stagger_fragment,
539 const size_t stagger,
540 const size_t rounds);
541
542 template <size_t num_elements>
545
546 template <size_t num_elements>
547 static element read_group_element_rom_tables(const std::array<twin_rom_table<Builder>, Fq::NUM_LIMBS + 1>& tables,
548 const field_ct& index,
550
551 static std::pair<element, element> compute_offset_generators(const size_t num_rounds);
552 static typename NativeGroup::affine_element compute_table_offset_generator();
553
561 four_bit_table_plookup(const element& input);
562
568
569 element operator[](const field_ct& index) const;
570 element operator[](const size_t idx) const { return element_table[idx]; }
572
573 // Each coordinate is an Fq element, which has 4 binary basis limbs and 1 prime basis limb
575 std::array<uint256_t, Fq::NUM_LIMBS * 2> limb_max; // tracks the maximum size of each binary basis limb
576 };
577
586 eight_bit_fixed_base_table(const CurveType input_curve_type, bool use_endo)
587 : curve_type(input_curve_type)
588 , use_endomorphism(use_endo)
589 {}
590
596
597 element operator[](const field_ct& index) const;
598
599 element operator[](const size_t index) const;
600
603 };
604
606 const element& input);
607
612 template <size_t length> struct lookup_table_plookup {
613 static constexpr size_t table_size = (1ULL << (length));
618 lookup_table_plookup(lookup_table_plookup&& other) noexcept = default;
621
622 element get(const std::array<bool_ct, length>& bits) const;
623
624 element operator[](const size_t idx) const { return element_table[idx]; }
625
627
628 // Each coordinate is an Fq element, which has 4 binary basis limbs and 1 prime basis limb
629 // ROM tables: (idx, x0, x1), (idx, x2, x3), (idx, y0, y1), (idx, y2, y3), (idx, xp, yp)
632 };
633
635
637
639
646 {
647 quad_lookup_table base_table(inputs);
648 quad_lookup_table endo_table;
650 Fq beta(bb::fr(beta_val.slice(0, 136)), bb::fr(beta_val.slice(136, 256)), false);
651 for (size_t i = 0; i < 8; ++i) {
652 endo_table.element_table[i + 8].x = base_table[7 - i].x * beta;
653 endo_table.element_table[i + 8].y = base_table[7 - i].y;
654
655 endo_table.element_table[7 - i] = (-endo_table.element_table[i + 8]);
656 }
657
658 endo_table.coordinates = create_group_element_rom_tables<16>(endo_table.element_table, endo_table.limb_max);
659 return std::make_pair<quad_lookup_table, quad_lookup_table>(base_table, endo_table);
660 }
661
668 : num_points(points.size())
669 , num_fives(num_points / 5)
670 {
671 // size-6 table is expensive and only benefits us if creating them reduces the number of total tables
672 if (num_points == 1) {
673 num_fives = 0;
674 num_sixes = 0;
675 } else if (num_fives * 5 == (num_points - 1)) {
676 // last 6 points to be added as one 6-table
677 num_fives -= 1;
678 num_sixes = 1;
679 } else if (num_fives * 5 == (num_points - 2) && num_fives >= 2) {
680 // last 12 points to be added as two 6-tables
681 num_fives -= 2;
682 num_sixes = 2;
683 } else if (num_fives * 5 == (num_points - 3) && num_fives >= 3) {
684 // last 18 points to be added as three 6-tables
685 num_fives -= 3;
686 num_sixes = 3;
687 }
688
689 // Calculate remaining points after allocating fives and sixes tables
690 size_t remaining_points = num_points - (num_fives * 5 + num_sixes * 6);
691
692 // Allocate one quad table if required (and update remaining points)
693 has_quad = (remaining_points >= 4) && (num_points >= 4);
694 if (has_quad) {
695 remaining_points -= 4;
696 }
697
698 // Allocate one triple table if required (and update remaining points)
699 has_triple = (remaining_points >= 3) && (num_points >= 3);
700 if (has_triple) {
701 remaining_points -= 3;
702 }
703
704 // Allocate one twin table if required (and update remaining points)
705 has_twin = (remaining_points >= 2) && (num_points >= 2);
706 if (has_twin) {
707 remaining_points -= 2;
708 }
709
710 // If there is anything remaining, allocate a singleton
711 has_singleton = (remaining_points != 0) && (num_points >= 1);
712
713 // Sanity check
715 num_sixes * 6 + num_fives * 5 + static_cast<size_t>(has_quad) * 4 +
716 static_cast<size_t>(has_triple) * 3 + static_cast<size_t>(has_twin) * 2 +
717 static_cast<size_t>(has_singleton) * 1,
718 "point allocation mismatch");
719
720 size_t offset = 0;
721 for (size_t i = 0; i < num_sixes; ++i) {
723 points[offset + (6 * i)],
724 points[offset + (6 * i) + 1],
725 points[offset + (6 * i) + 2],
726 points[offset + (6 * i) + 3],
727 points[offset + (6 * i) + 4],
728 points[offset + (6 * i) + 5],
729 }));
730 }
731 offset += 6 * num_sixes;
732 for (size_t i = 0; i < num_fives; ++i) {
734 points[offset + (5 * i)],
735 points[offset + (5 * i) + 1],
736 points[offset + (5 * i) + 2],
737 points[offset + (5 * i) + 3],
738 points[offset + (5 * i) + 4],
739 }));
740 }
741 offset += 5 * num_fives;
742
743 if (has_quad) {
744 quad_tables.push_back(
745 quad_lookup_table({ points[offset], points[offset + 1], points[offset + 2], points[offset + 3] }));
746 }
747 if (has_triple) {
748 triple_tables.push_back(
749 triple_lookup_table({ points[offset], points[offset + 1], points[offset + 2] }));
750 }
751 if (has_twin) {
752 twin_tables.push_back(twin_lookup_table({ points[offset], points[offset + 1] }));
753 }
754 if (has_singleton) {
755 singletons.push_back(points[points.size() - 1]);
756 }
757 }
758
760 {
761 std::vector<element> add_accumulator;
762 for (size_t i = 0; i < num_sixes; ++i) {
763 add_accumulator.push_back(six_tables[i][0]);
764 }
765 for (size_t i = 0; i < num_fives; ++i) {
766 add_accumulator.push_back(five_tables[i][0]);
767 }
768 if (has_quad) {
769 add_accumulator.push_back(quad_tables[0][0]);
770 }
771 if (has_twin) {
772 add_accumulator.push_back(twin_tables[0][0]);
773 }
774 if (has_triple) {
775 add_accumulator.push_back(triple_tables[0][0]);
776 }
777 if (has_singleton) {
778 add_accumulator.push_back(singletons[0]);
779 }
780 if (add_accumulator.size() >= 2) {
781 chain_add_accumulator output = element::chain_add_start(add_accumulator[0], add_accumulator[1]);
782 for (size_t i = 2; i < add_accumulator.size(); ++i) {
783 output = element::chain_add(add_accumulator[i], output);
784 }
785 return output;
786 }
787 return chain_add_accumulator(add_accumulator[0]);
788 }
789
790 element::chain_add_accumulator get_chain_add_accumulator(std::vector<bool_ct>& naf_entries) const
791 {
792 std::vector<element> round_accumulator;
793 for (size_t j = 0; j < num_sixes; ++j) {
794 round_accumulator.push_back(six_tables[j].get({ naf_entries[6 * j],
795 naf_entries[(6 * j) + 1],
796 naf_entries[(6 * j) + 2],
797 naf_entries[(6 * j) + 3],
798 naf_entries[(6 * j) + 4],
799 naf_entries[(6 * j) + 5] }));
800 }
801 size_t offset = num_sixes * 6;
802 for (size_t j = 0; j < num_fives; ++j) {
803 round_accumulator.push_back(five_tables[j].get({ naf_entries[offset + (j * 5)],
804 naf_entries[offset + (j * 5) + 1],
805 naf_entries[offset + (j * 5) + 2],
806 naf_entries[offset + (j * 5) + 3],
807 naf_entries[offset + (j * 5) + 4] }));
808 }
809 offset += num_fives * 5;
810 if (has_quad) {
811 round_accumulator.push_back(quad_tables[0].get({ naf_entries[offset],
812 naf_entries[offset + 1],
813 naf_entries[offset + 2],
814 naf_entries[offset + 3] }));
815 }
816
817 if (has_triple) {
818 round_accumulator.push_back(
819 triple_tables[0].get({ naf_entries[offset], naf_entries[offset + 1], naf_entries[offset + 2] }));
820 }
821 if (has_twin) {
822 round_accumulator.push_back(twin_tables[0].get({ naf_entries[offset], naf_entries[offset + 1] }));
823 }
824 if (has_singleton) {
825 round_accumulator.push_back(singletons[0].conditional_negate(naf_entries[num_points - 1]));
826 }
827
828 if (round_accumulator.size() == 1) {
829 return element::chain_add_accumulator(round_accumulator[0]);
830 }
831
832 if (round_accumulator.size() == 2) {
833 return element::chain_add_start(round_accumulator[0], round_accumulator[1]);
834 }
835
836 // Use chain add for at least 3 elements
837 element::chain_add_accumulator accumulator =
838 element::chain_add_start(round_accumulator[0], round_accumulator[1]);
839 for (size_t j = 2; j < round_accumulator.size(); ++j) {
840 accumulator = element::chain_add(round_accumulator[j], accumulator);
841 }
842
843 return (accumulator);
844 }
845
846 element get(std::vector<bool_ct>& naf_entries) const
847 {
848 std::vector<element> round_accumulator;
849 for (size_t j = 0; j < num_sixes; ++j) {
850 round_accumulator.push_back(six_tables[j].get({ naf_entries[(6 * j)],
851 naf_entries[(6 * j) + 1],
852 naf_entries[(6 * j) + 2],
853 naf_entries[(6 * j) + 3],
854 naf_entries[(6 * j) + 4],
855 naf_entries[(6 * j) + 5] }));
856 }
857 size_t offset = num_sixes * 6;
858
859 for (size_t j = 0; j < num_fives; ++j) {
860 round_accumulator.push_back(five_tables[j].get({ naf_entries[offset + (5 * j)],
861 naf_entries[offset + (5 * j) + 1],
862 naf_entries[offset + (5 * j) + 2],
863 naf_entries[offset + (5 * j) + 3],
864 naf_entries[offset + (5 * j) + 4] }));
865 }
866
867 offset += num_fives * 5;
868
869 if (has_quad) {
870 round_accumulator.push_back(quad_tables[0].get(
871 naf_entries[offset], naf_entries[offset + 1], naf_entries[offset + 2], naf_entries[offset + 3]));
872 }
873 if (has_triple) {
874 round_accumulator.push_back(
875 triple_tables[0].get(naf_entries[offset], naf_entries[offset + 1], naf_entries[offset + 2]));
876 }
877 if (has_twin) {
878 round_accumulator.push_back(twin_tables[0].get(naf_entries[offset], naf_entries[offset + 1]));
879 }
880 if (has_singleton) {
881 round_accumulator.push_back(singletons[0].conditional_negate(naf_entries[num_points - 1]));
882 }
883
884 element result = round_accumulator[0];
885 element::chain_add_accumulator accumulator;
886 if (round_accumulator.size() == 1) {
887 return result;
888 }
889
890 if (round_accumulator.size() == 2) {
891 return result + round_accumulator[1];
892 }
893
894 // For 3 or more elements, use chain addition
895 accumulator = element::chain_add_start(round_accumulator[0], round_accumulator[1]);
896 for (size_t j = 2; j < round_accumulator.size(); ++j) {
897 accumulator = element::chain_add(round_accumulator[j], accumulator);
898 }
899
900 return element::chain_add_end(accumulator);
901 }
902
910
911 size_t num_sixes = 0;
912 size_t num_fives;
917 };
918
920
922 const std::vector<Fr>& scalars,
923 const size_t max_num_bits);
924};
925
926// For testing purposes only
928 public:
929 template <typename C, typename Fq, typename Fr, typename G, size_t wnaf_size>
930 static auto get_staggered_wnaf_fragment_value(uint64_t fragment_u64,
931 uint64_t stagger,
932 bool is_negative,
933 bool wnaf_skew)
934 {
935 return element<C, Fq, Fr, G>::template get_staggered_wnaf_fragment_value<wnaf_size>(
936 fragment_u64, stagger, is_negative, wnaf_skew);
937 }
938
939 template <typename C, typename Fq, typename Fr, typename G>
941 {
942 return elem1.checked_unconditional_add_sub(elem2);
943 }
944
945 // Overload for goblin_element
946 template <typename C, typename Fq, typename Fr, typename G>
952};
953
954template <typename C, typename Fq, typename Fr, typename G>
955inline std::ostream& operator<<(std::ostream& os, element<C, Fq, Fr, G> const& v)
956{
957 return os << "{ " << v.x() << " , " << v.y() << " }";
958}
959} // namespace bb::stdlib::element_default
960
961namespace bb::stdlib {
962template <typename T>
964
965template <typename Builder, class Fq, class Fr, class NativeGroup>
969
975template <typename C, typename Fq, typename Fr, typename G>
979} // namespace bb::stdlib
981#include "biggroup_goblin.hpp"
982#include "biggroup_impl.hpp"
983#include "biggroup_nafs.hpp"
984#include "biggroup_secp256k1.hpp"
985#include "biggroup_tables.hpp"
#define BB_ASSERT_NEQ(actual, expected,...)
Definition assert.hpp:98
#define BB_ASSERT_EQ(actual, expected,...)
Definition assert.hpp:83
constexpr uint256_t slice(uint64_t start, uint64_t end) 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
bool_t normalize() const
A bool_t element is normalized if witness_inverted == false. For a given *this, output its normalized...
Definition bool.cpp:529
void set_free_witness_tag()
Definition bool.hpp:156
static bool_t conditional_assign(const bool_t< Builder > &predicate, const bool_t &lhs, const bool_t &rhs)
Conditionally assign lhs or rhs based on predicate, always returns normalized result.
Definition bool.cpp:478
void unset_free_witness_tag()
Definition bool.hpp:157
Builder * get_context() const
Definition bool.hpp:152
void clear_round_provenance() const
Definition bool.hpp:158
void assert_equal(const bool_t &rhs, std::string const &msg="bool_t::assert_equal") const
Implements copy constraint for bool_t elements.
Definition bool.cpp:433
OriginTag get_origin_tag() const
Definition bool.hpp:155
static auto checked_unconditional_add_sub(const element_goblin::goblin_element< C, Fq, Fr, G > &elem1, const element_goblin::goblin_element< C, Fq, Fr, G > &elem2)
Definition biggroup.hpp:947
static auto get_staggered_wnaf_fragment_value(uint64_t fragment_u64, uint64_t stagger, bool is_negative, bool wnaf_skew)
Definition biggroup.hpp:930
static auto checked_unconditional_add_sub(const element< C, Fq, Fr, G > &elem1, const element< C, Fq, Fr, G > &elem2)
Definition biggroup.hpp:940
element checked_unconditional_subtract(const element &other) const
element & operator=(const element &other)
void assert_coordinates_in_field(const std::string &msg="biggroup::assert_coordinates_in_field") const
Definition biggroup.hpp:277
element operator-=(const element &other)
Definition biggroup.hpp:198
NativeGroup::affine_element get_value() const
Definition biggroup.hpp:319
static std::pair< Fr, secp256k1_wnaf > compute_secp256k1_single_wnaf(Builder *builder, const secp256k1::fr &scalar, size_t stagger, bool is_negative, const bool range_constrain_wnaf=true, bool is_lo=false)
Compute the wNAF representation (in circuit) of a scalar for secp256k1.
Builder * get_context(const element &other) const
Definition biggroup.hpp:369
element multiple_montgomery_ladder(const std::vector< chain_add_accumulator > &to_add) const
Perform repeated iterations of the montgomery ladder algorithm.
void validate_on_curve(std::string const &msg="biggroup::validate_on_curve") const
Check that the point is on the curve.
Definition biggroup.hpp:97
static element one(Builder *ctx)
Creates a constant group generator.
Definition biggroup.hpp:159
static chain_add_accumulator chain_add_start(const element &p1, const element &p2)
Begin a chain of additions.
static element from_witness(Builder *ctx, const typename NativeGroup::affine_element &input)
Create a biggroup witness from a native group element, allocating new witnesses as necessary.
Definition biggroup.hpp:72
void fix_witness()
Fix a witness. The value of the witness is constrained with a selector.
Definition biggroup.hpp:146
static std::pair< four_bit_table_plookup, four_bit_table_plookup > create_endo_pair_four_bit_table_plookup(const element &input)
Create a endo pair four bit table for the given group element.
static element chain_add_end(const chain_add_accumulator &accumulator)
End an addition chain and compute the final y-coordinate.
static element batch_mul(const std::vector< element > &points, const std::vector< Fr > &scalars, const size_t max_num_bits=0, const bool with_edgecases=false, const Fr &masking_scalar=Fr(1))
Generic batch multiplication that works for all elliptic curve types.
void unset_free_witness_tag()
Unset the free witness flag for the element's tags.
Definition biggroup.hpp:410
static element point_at_infinity(Builder *ctx)
Definition biggroup.hpp:168
static NativeGroup::affine_element compute_table_offset_generator()
Compute an offset generator for use in biggroup tables.
static std::vector< field_ct > convert_wnaf_values_to_witnesses(Builder *builder, const uint64_t *wnaf_values, bool is_negative, size_t rounds, const bool range_constrain_wnaf=true)
Convert wNAF values to witness values.
void set_origin_tag(OriginTag tag) const
Definition biggroup.hpp:388
void incomplete_assert_equal(const element &other, const std::string msg="biggroup::incomplete_assert_equal") const
Asserts that two group elements are equal (i.e., x, y coordinates and infinity flag are all equal).
Definition biggroup.hpp:252
void set_point_at_infinity(const bool_ct &is_infinity, const bool &add_to_used_witnesses=false)
Definition biggroup.hpp:379
stdlib::witness_t< Builder > witness_ct
Definition biggroup.hpp:31
static std::pair< quad_lookup_table, quad_lookup_table > create_endo_pair_quad_lookup_table(const std::array< element, 4 > &inputs)
Definition biggroup.hpp:644
element(const typename NativeGroup::affine_element &input)
static element process_strauss_msm_rounds(const std::vector< element > &points, const std::vector< Fr > &scalars, const size_t max_num_bits)
static Fr reconstruct_bigfield_from_wnaf(Builder *builder, const std::vector< field_ct > &wnaf, const bool_ct &positive_skew, const bool_ct &negative_skew, const field_ct &stagger_fragment, const size_t stagger, const size_t rounds)
Reconstruct a scalar from its wNAF representation in circuit.
static std::array< twin_rom_table< Builder >, Fq::NUM_LIMBS+1 > create_group_element_rom_tables(const std::array< element, num_elements > &rom_data, std::array< uint256_t, Fq::NUM_LIMBS *2 > &limb_max)
void convert_constant_to_fixed_witness(Builder *builder)
Creates fixed witnesses from a constant element.
Definition biggroup.hpp:135
element scalar_mul(const Fr &scalar, const size_t max_num_bits=0) const
Implements scalar multiplication that supports short scalars. For multiple scalar multiplication use ...
element operator+=(const element &other)
Definition biggroup.hpp:193
static element read_group_element_rom_tables(const std::array< twin_rom_table< Builder >, Fq::NUM_LIMBS+1 > &tables, const field_ct &index, const std::array< uint256_t, Fq::NUM_LIMBS *2 > &limb_max)
static secp256k1_wnaf_pair compute_secp256k1_endo_wnaf(const Fr &scalar, const bool range_constrain_wnaf=true)
Compute endomorphism for a secp256k1 scalar, and then compute the wNAF representation of both halves.
element checked_unconditional_add(const element &other) const
static std::vector< bool_ct > compute_naf(const Fr &scalar, const size_t max_num_bits=0)
Compute Non-Adjacent Form (NAF) representation of a scalar.
static std::pair< uint64_t, bool > get_staggered_wnaf_fragment_value(const uint64_t fragment_u64, const uint64_t stagger, bool is_negative, bool wnaf_skew)
Compute the stagger-related part of wNAF and the final skew.
uint32_t set_public() const
Set the witness indices for the x and y coordinates to public.
Definition biggroup.hpp:56
static std::pair< std::vector< element >, std::vector< Fr > > mask_points(const std::vector< element > &_points, const std::vector< Fr > &_scalars, const Fr &masking_scalar)
Mask points for batch multiplication to handle edge cases.
element operator*(const Fr &scalar) const
element conditional_negate(const bool_ct &predicate) const
Definition biggroup.hpp:206
static std::pair< std::vector< element >, std::vector< Fr > > handle_points_at_infinity(const std::vector< element > &_points, const std::vector< Fr > &_scalars)
Handle points at infinity in batch operations, replaces (∞, scalar) pairs by (G, 0)
void set_free_witness_tag()
Set the free witness flag for the element's tags.
Definition biggroup.hpp:420
element conditional_select(const element &other, const bool_ct &predicate) const
Selects this if predicate is false, other if predicate is true.
Definition biggroup.hpp:220
element get_standard_form() const
Enforce x and y coordinates of a point to be (0, 0) in the case of point at infinity.
std::array< element, 2 > checked_unconditional_add_sub(const element &other) const
Compute both add and subtract (a + b, a - b) results simultaneously.
static constexpr size_t PUBLIC_INPUTS_SIZE
Definition biggroup.hpp:36
element operator+(const element &other) const
static chain_add_accumulator chain_add(const element &p1, const chain_add_accumulator &accumulator)
Evaluate a chain addition using incomplete addition formulae.
static std::pair< element, element > compute_offset_generators(const size_t num_rounds)
static element secp256k1_ecdsa_mul(const element &pubkey, const Fr &u1, const Fr &u2)
Custom element class for when using goblin.
std::array< goblin_element, 2 > checked_unconditional_add_sub(const goblin_element &other) const
#define vinfo(...)
Definition log.hpp:94
AluTraceBuilder builder
Definition alu.test.cpp:124
FF a
FF b
#define G(r, i, a, b, c, d)
Definition blake2s.cpp:116
uint8_t const size_t length
Definition data_store.hpp:9
ssize_t offset
Definition engine.cpp:46
AvmProvingInputs inputs
std::ostream & operator<<(std::ostream &os, element< C, Fq, Fr, G > const &v)
Definition biggroup.hpp:955
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...
Definition biggroup.hpp:978
void mark_witness_as_used(const field_t< Builder > &field)
Mark a field_t witness as used (for UltraBuilder only).
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
Curve::ScalarField Fr
static constexpr field cube_root_of_unity()
BB_INLINE constexpr field sqr() const noexcept
static constexpr field zero()
element get(std::vector< bool_ct > &naf_entries) const
Definition biggroup.hpp:846
std::vector< lookup_table_plookup< 6 > > six_tables
Definition biggroup.hpp:903
std::vector< lookup_table_plookup< 5 > > five_tables
Definition biggroup.hpp:904
element::chain_add_accumulator get_chain_add_accumulator(std::vector< bool_ct > &naf_entries) const
Definition biggroup.hpp:790
batch_lookup_table_plookup(const std::vector< element > &points)
Definition biggroup.hpp:667
chain_add_accumulator(chain_add_accumulator &&other) noexcept=default
chain_add_accumulator(const chain_add_accumulator &other)=default
chain_add_accumulator & operator=(const chain_add_accumulator &other)=default
chain_add_accumulator & operator=(chain_add_accumulator &&other) noexcept=default
Eight-bit fixed base table for scalar multiplication.
Definition biggroup.hpp:584
eight_bit_fixed_base_table & operator=(eight_bit_fixed_base_table &&other) noexcept=default
eight_bit_fixed_base_table & operator=(const eight_bit_fixed_base_table &other)=default
eight_bit_fixed_base_table(const CurveType input_curve_type, bool use_endo)
Definition biggroup.hpp:586
eight_bit_fixed_base_table(eight_bit_fixed_base_table &&other) noexcept=default
eight_bit_fixed_base_table(const eight_bit_fixed_base_table &other)=default
Four-bit variable-base table for scalar multiplication.
Definition biggroup.hpp:559
std::array< uint256_t, Fq::NUM_LIMBS *2 > limb_max
Definition biggroup.hpp:575
four_bit_table_plookup & operator=(four_bit_table_plookup &&other) noexcept=default
four_bit_table_plookup(const four_bit_table_plookup &other)=default
four_bit_table_plookup(four_bit_table_plookup &&other) noexcept=default
std::array< twin_rom_table< Builder >, Fq::NUM_LIMBS+1 > coordinates
Definition biggroup.hpp:574
four_bit_table_plookup & operator=(const four_bit_table_plookup &other)=default
Generic lookup table that uses ROM tables internally to access group elements.
Definition biggroup.hpp:612
std::array< twin_rom_table< Builder >, Fq::NUM_LIMBS+1 > coordinates
Definition biggroup.hpp:630
lookup_table_plookup(const lookup_table_plookup &other)=default
lookup_table_plookup(lookup_table_plookup &&other) noexcept=default
lookup_table_plookup & operator=(lookup_table_plookup &&other) noexcept=default
lookup_table_plookup & operator=(const lookup_table_plookup &other)=default
element get(const std::array< bool_ct, length > &bits) const
std::array< uint256_t, Fq::NUM_LIMBS *2 > limb_max
Definition biggroup.hpp:631
curve::BN254::BaseField Fq