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"
26template <
class Builder_,
class Fq,
class Fr,
class NativeGroup>
class element {
43 element(
const Fq&
x,
const Fq&
y,
const bool assert_on_curve =
true);
60 const uint32_t start_idx = standard._x.set_public();
61 standard._y.set_public();
79 if (input.is_point_at_infinity()) {
80 x = Fq::from_witness(ctx,
typename NativeGroup::Fq(0));
81 y = Fq::from_witness(ctx,
typename NativeGroup::Fq(0));
83 x = Fq::from_witness(ctx, input.x);
84 y = Fq::from_witness(ctx, input.y);
102 Fq validate_on_curve(std::string
const& msg =
"biggroup::validate_on_curve",
bool assert_is_on_curve =
true)
const
106 BB_ASSERT(this->
get_value().on_curve(),
"biggroup::validate_on_curve: constant point not on curve");
107 return typename Fq::native(this->
get_value().on_curve() ? 0 : 1);
121 if constexpr (!NativeGroup::has_a) {
122 result = Fq::mult_madd({
_x.
sqr(),
_y }, {
_x, -
_y }, { adjusted_b }, assert_is_on_curve);
127 result = Fq::mult_madd({
_x.
sqr(),
_x,
_y }, {
_x, adjusted_a, -
_y }, { adjusted_b }, assert_is_on_curve);
130 if ((!has_circuit_failed) && (
get_context()->failed())) {
131 vinfo(
"Original bigfield error generated by biggroup::validate_on_curve: ",
get_context()->err());
140 const bool x_is_const =
_x.is_constant();
141 const bool y_is_const =
_y.is_constant();
142 BB_ASSERT_EQ(x_is_const, y_is_const,
"biggroup: x and y coordinate constant status mismatch");
151 this->
_x.convert_constant_to_fixed_witness(builder);
152 this->
_y.convert_constant_to_fixed_witness(builder);
163 this->
_x.fix_witness();
164 this->
_y.fix_witness();
207 result.
_y = -result.
_y;
212 *
this = *
this + other;
217 *
this = *
this - other;
226 result.
_y = result.
_y.conditional_negate(predicate);
241 auto result = predicate.
get_value() ? other : *
this;
249 BB_ASSERT_NEQ(ctx,
nullptr,
"biggroup::conditional_select must have a context");
252 result.
_x = result.
_x.conditional_select(other.
_x, predicate);
253 result.
_y = result.
_y.conditional_select(other.
_y, predicate);
261 return rhs.conditional_select(lhs, predicate);
275 const std::string msg =
"biggroup::incomplete_assert_equal")
const
278 _x.assert_equal(other.
_x, msg +
" (x coordinate)");
279 _y.assert_equal(other.
_y, msg +
" (y coordinate)");
285 result.
_x.reduce_mod_target_modulus();
286 result.
_y.reduce_mod_target_modulus();
294 result.
_x.self_reduce();
295 result.
_y.self_reduce();
301 _x.assert_is_in_field(msg +
" (x coordinate)");
302 _y.assert_is_in_field(msg +
" (y coordinate)");
322 , is_full_element(true)
349 uint512_t x_val =
_x.get_value() % Fq::modulus_u512;
350 uint512_t y_val =
_y.get_value() % Fq::modulus_u512;
351 auto result =
typename NativeGroup::affine_element(x_val.
lo, y_val.
lo);
353 result.self_set_infinity();
359 const std::vector<Fr>& scalars,
360 const size_t max_num_bits = 0,
361 const bool with_edgecases =
false);
363 template <typename X = NativeGroup, typename = typename std::enable_if_t<std::is_same<X, secp256k1::g1>::value>>
391 template <
size_t wnaf_size,
size_t staggered_lo_offset = 0,
size_t staggered_hi_offset = 0>
410 _x.set_origin_tag(
tag);
411 _y.set_origin_tag(
tag);
417 _x.clear_round_provenance();
418 _y.clear_round_provenance();
432 _x.unset_free_witness_tag();
433 _y.unset_free_witness_tag();
442 _x.set_free_witness_tag();
443 _y.set_free_witness_tag();
464 const std::vector<Fr>& scalars,
465 const size_t max_num_bits = 0,
466 const bool with_edgecases =
false);
483 const std::vector<Fr>& _scalars);
510 template <
size_t num_bits,
size_t wnaf_size,
size_t lo_stagger,
size_t hi_stagger>
515 const bool range_constrain_wnaf =
true,
527 template <
size_t wnaf_size>
529 const uint64_t stagger,
546 template <
size_t wnaf_size>
548 const uint64_t* wnaf_values,
551 const bool range_constrain_wnaf =
true);
564 template <
size_t wnaf_size>
570 const size_t stagger,
571 const size_t rounds);
573 template <
size_t num_elements>
577 template <
size_t num_elements>
682 for (
size_t i = 0; i < 8; ++i) {
683 endo_table.
element_table[i + 8].x = base_table[7 - i].x * beta;
726 remaining_points -= 4;
732 remaining_points -= 3;
738 remaining_points -= 2;
749 "point allocation mismatch");
755 points[
offset + (6 * i) + 1],
756 points[
offset + (6 * i) + 2],
757 points[
offset + (6 * i) + 3],
758 points[
offset + (6 * i) + 4],
759 points[
offset + (6 * i) + 5],
766 points[
offset + (5 * i) + 1],
767 points[
offset + (5 * i) + 2],
768 points[
offset + (5 * i) + 3],
769 points[
offset + (5 * i) + 4],
786 singletons.push_back(points[points.size() - 1]);
811 if (add_accumulator.size() >= 2) {
813 for (
size_t i = 2; i < add_accumulator.size(); ++i) {
814 output = element::chain_add(add_accumulator[i], output);
825 round_accumulator.push_back(
six_tables[j].
get({ naf_entries[6 * j],
826 naf_entries[(6 * j) + 1],
827 naf_entries[(6 * j) + 2],
828 naf_entries[(6 * j) + 3],
829 naf_entries[(6 * j) + 4],
830 naf_entries[(6 * j) + 5] }));
832 size_t offset = num_sixes * 6;
835 naf_entries[
offset + (j * 5) + 1],
836 naf_entries[
offset + (j * 5) + 2],
837 naf_entries[
offset + (j * 5) + 3],
838 naf_entries[
offset + (j * 5) + 4] }));
845 naf_entries[
offset + 3] }));
849 round_accumulator.push_back(
859 if (round_accumulator.size() == 1) {
860 return element::chain_add_accumulator(round_accumulator[0]);
863 if (round_accumulator.size() == 2) {
864 return element::chain_add_start(round_accumulator[0], round_accumulator[1]);
868 element::chain_add_accumulator accumulator =
869 element::chain_add_start(round_accumulator[0], round_accumulator[1]);
870 for (
size_t j = 2; j < round_accumulator.size(); ++j) {
871 accumulator = element::chain_add(round_accumulator[j], accumulator);
874 return (accumulator);
881 round_accumulator.push_back(
six_tables[j].
get({ naf_entries[(6 * j)],
882 naf_entries[(6 * j) + 1],
883 naf_entries[(6 * j) + 2],
884 naf_entries[(6 * j) + 3],
885 naf_entries[(6 * j) + 4],
886 naf_entries[(6 * j) + 5] }));
888 size_t offset = num_sixes * 6;
892 naf_entries[
offset + (5 * j) + 1],
893 naf_entries[
offset + (5 * j) + 2],
894 naf_entries[
offset + (5 * j) + 3],
895 naf_entries[
offset + (5 * j) + 4] }));
905 round_accumulator.push_back(
915 element result = round_accumulator[0];
916 element::chain_add_accumulator accumulator;
917 if (round_accumulator.size() == 1) {
921 if (round_accumulator.size() == 2) {
922 return result + round_accumulator[1];
926 accumulator = element::chain_add_start(round_accumulator[0], round_accumulator[1]);
927 for (
size_t j = 2; j < round_accumulator.size(); ++j) {
928 accumulator = element::chain_add(round_accumulator[j], accumulator);
931 return element::chain_add_end(accumulator);
953 const std::vector<Fr>& scalars,
954 const size_t max_num_bits);
960 template <
typename C,
typename Fq,
typename Fr,
typename G,
size_t wnaf_size>
967 fragment_u64, stagger, is_negative, wnaf_skew);
970 template <
typename C,
typename Fq,
typename Fr,
typename G>
977 template <
typename C,
typename Fq,
typename Fr,
typename G>
989 template <
typename C,
typename Fq,
typename Fr,
typename G>
993 bool assert_on_curve =
false)
999template <
typename C,
typename Fq,
typename Fr,
typename G>
1002 return os <<
"{ " << v.
x() <<
" , " << v.
y() <<
" }";
1007template <
typename T>
1010template <
typename Builder,
class Fq,
class Fr,
class NativeGroup>
1020template <
typename C,
typename Fq,
typename Fr,
typename G>
#define BB_ASSERT(expression,...)
#define BB_ASSERT_NEQ(actual, expected,...)
#define BB_ASSERT_EQ(actual, expected,...)
constexpr uint256_t slice(uint64_t start, uint64_t end) const
Implements boolean logic in-circuit.
void set_origin_tag(const OriginTag &new_tag) const
void set_free_witness_tag()
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.
void unset_free_witness_tag()
Builder * get_context() const
void clear_round_provenance() const
void assert_equal(const bool_t &rhs, std::string const &msg="bool_t::assert_equal") const
Implements copy constraint for bool_t elements.
OriginTag get_origin_tag() const
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)
static auto get_staggered_wnaf_fragment_value(uint64_t fragment_u64, uint64_t stagger, bool is_negative, bool wnaf_skew)
static element< C, Fq, Fr, G > create_element_with_explicit_infinity(const Fq &x, const Fq &y, const stdlib::bool_t< C > &is_infinity, bool assert_on_curve=false)
Create an element with explicit infinity flag (for testing only).
static auto checked_unconditional_add_sub(const element< C, Fq, Fr, G > &elem1, const element< C, Fq, Fr, G > &elem2)
element checked_unconditional_subtract(const element &other) const
element & operator=(const element &other)
element add_internal(const element &other) const
Internal implementation of ECC point addition.
void assert_coordinates_in_field(const std::string &msg="biggroup::assert_coordinates_in_field") const
element operator-=(const element &other)
stdlib::bool_t< Builder > bool_ct
NativeGroup::affine_element get_value() const
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.
element(const Fq &x, const Fq &y, const bool_ct &is_infinity, bool assert_on_curve)
Builder * get_context(const element &other) const
element multiple_montgomery_ladder(const std::vector< chain_add_accumulator > &to_add) const
Perform repeated iterations of the montgomery ladder algorithm.
static element one(Builder *ctx)
Creates a constant group generator.
static chain_add_accumulator chain_add_start(const element &p1, const element &p2)
Optimized chained addition for non-infinity points.
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.
void fix_witness()
Fix a witness. The value of the witness is constrained with a selector.
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.
void clear_round_provenance() const
static element chain_add_end(const chain_add_accumulator &accumulator)
End an addition chain and compute the final y-coordinate.
element operator-() const
Fq validate_on_curve(std::string const &msg="biggroup::validate_on_curve", bool assert_is_on_curve=true) const
Check that the point is on the curve.
void unset_free_witness_tag()
Unset the free witness flag for the element's tags.
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
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).
stdlib::witness_t< Builder > witness_ct
static std::pair< quad_lookup_table, quad_lookup_table > create_endo_pair_quad_lookup_table(const std::array< element, 4 > &inputs)
element normalize() const
static element process_strauss_msm_rounds(const std::vector< element > &points, const std::vector< Fr > &scalars, const size_t max_num_bits)
OriginTag get_origin_tag() const
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.
element dbl_internal() const
Internal implementation of point doubling.
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)
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.
static element conditional_assign(const bool_t< Builder > &predicate, const element &lhs, const element &rhs)
Builder * get_context() const
element operator*(const Fr &scalar) const
element conditional_negate(const bool_ct &predicate) const
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)
static element constant_infinity(Builder *ctx)
Creates a constant point at infinity with canonical (0, 0) coordinates.
void set_free_witness_tag()
Set the free witness flag for the element's tags.
element conditional_select(const element &other, const bool_ct &predicate) const
Selects this if predicate is false, other if predicate is true.
element subtract_internal(const element &other) const
Internal implementation of ECC point subtraction.
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
element operator+(const element &other) const
Evaluate ECC point addition over *this and other.
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< std::vector< element >, std::vector< Fr > > mask_points(const std::vector< element > &_points, const std::vector< Fr > &_scalars)
Mask points for batch multiplication to handle edge cases.
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)
Generic batch multiplication that works for all elliptic curve types.
static std::pair< element, element > compute_offset_generators(const size_t num_rounds)
bool_ct is_point_at_infinity() const
static element batch_mul_internal(const std::vector< element > &points, const std::vector< Fr > &scalars, const size_t max_num_bits=0, const bool with_edgecases=false)
Internal implementation of generic batch multiplication that works for all elliptic curve types.
static element secp256k1_ecdsa_mul(const element &pubkey, const Fr &u1, const Fr &u2)
element dbl() const
Evaluates a point doubling.
Custom element class for when using goblin.
std::array< goblin_element, 2 > checked_unconditional_add_sub(const goblin_element &other) const
#define G(r, i, a, b, c, d)
uint8_t const size_t length
std::ostream & operator<<(std::ostream &os, element< C, Fq, Fr, G > const &v)
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...
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
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
chain_add_accumulator get_chain_initial_entry() const
std::vector< quad_lookup_table > quad_tables
std::vector< lookup_table_plookup< 6 > > six_tables
std::vector< lookup_table_plookup< 5 > > five_tables
std::vector< element > singletons
std::vector< triple_lookup_table > triple_tables
element::chain_add_accumulator get_chain_add_accumulator(std::vector< bool_ct > &naf_entries) const
batch_lookup_table_plookup(const std::vector< element > &points)
std::vector< twin_lookup_table > twin_tables
chain_add_accumulator()=default
chain_add_accumulator(chain_add_accumulator &&other) noexcept=default
chain_add_accumulator(const chain_add_accumulator &other)=default
chain_add_accumulator(const element &input)
~chain_add_accumulator()=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.
element operator[](const field_ct &index) const
eight_bit_fixed_base_table & operator=(eight_bit_fixed_base_table &&other) noexcept=default
~eight_bit_fixed_base_table()=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)
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.
std::array< uint256_t, Fq::NUM_LIMBS *2 > limb_max
four_bit_table_plookup & operator=(four_bit_table_plookup &&other) noexcept=default
four_bit_table_plookup(const four_bit_table_plookup &other)=default
std::array< element, 16 > element_table
four_bit_table_plookup()=default
~four_bit_table_plookup()=default
four_bit_table_plookup(four_bit_table_plookup &&other) noexcept=default
std::array< twin_rom_table< Builder >, Fq::NUM_LIMBS+1 > coordinates
element operator[](const size_t idx) const
four_bit_table_plookup & operator=(const four_bit_table_plookup &other)=default
element operator[](const field_ct &index) const
Generic lookup table that uses ROM tables internally to access group elements.
std::array< twin_rom_table< Builder >, Fq::NUM_LIMBS+1 > coordinates
lookup_table_plookup(const lookup_table_plookup &other)=default
std::array< element, table_size > element_table
lookup_table_plookup(lookup_table_plookup &&other) noexcept=default
~lookup_table_plookup()=default
lookup_table_plookup & operator=(lookup_table_plookup &&other) noexcept=default
lookup_table_plookup & operator=(const lookup_table_plookup &other)=default
element operator[](const size_t idx) const
lookup_table_plookup()=default
static constexpr size_t table_size
element get(const std::array< bool_ct, length > &bits) const
std::array< uint256_t, Fq::NUM_LIMBS *2 > limb_max
std::vector< field_t< Builder > > wnaf
field_t< Builder > least_significant_wnaf_fragment
curve::BN254::BaseField Fq