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 "../memory/rom_table.hpp"
15#include "../memory/twin_rom_table.hpp"
24template <
class Builder_,
class Fq,
class Fr,
class NativeGroup>
class element {
46 element(
const typename NativeGroup::affine_element& input);
54 const typename NativeGroup::affine_element& native_val = NativeGroup::affine_element::one();
58 for (
auto& limb : val.
x.binary_basis_limbs) {
59 limb_vals[idx++] = limb.element.get_value();
61 for (
auto& limb : val.
y.binary_basis_limbs) {
62 limb_vals[idx++] = limb.element.get_value();
74 const uint32_t start_idx =
x.set_public();
98 if (input.is_point_at_infinity()) {
99 Fq x = Fq::from_witness(ctx, NativeGroup::affine_one.
x);
100 Fq y = Fq::from_witness(ctx, NativeGroup::affine_one.
y);
104 Fq x = Fq::from_witness(ctx, input.x);
105 Fq y = Fq::from_witness(ctx, input.y);
123 if constexpr (!NativeGroup::has_a) {
125 Fq::mult_madd({ _x.
sqr(), _y }, { _x, -_y }, { _b },
true);
130 Fq::mult_madd({ _x.
sqr(), _x, _y }, { _x, _a, -_y }, { _b },
true);
139 this->
x.convert_constant_to_fixed_witness(builder);
140 this->
y.convert_constant_to_fixed_witness(builder);
151 this->
x.fix_witness();
152 this->
y.fix_witness();
169 Fr zero = Fr::from_witness_index(ctx, ctx->zero_idx);
170 zero.unset_free_witness_tag();
184 result.
write(
y.to_byte_array());
185 result.
write(
x.to_byte_array());
197 result.
y = -result.
y;
202 *
this = *
this + other;
207 *
this = *
this - other;
217 result.
y = result.
y.conditional_negate(predicate);
224 result.
x.assert_is_in_field();
225 result.
y.assert_is_in_field();
233 result.
x.self_reduce();
234 result.
y.self_reduce();
278 uint512_t x_val =
x.get_value() % Fq::modulus_u512;
279 uint512_t y_val =
y.get_value() % Fq::modulus_u512;
280 auto result =
typename NativeGroup::affine_element(x_val.
lo, y_val.
lo);
282 result.self_set_infinity();
288 const std::vector<Fr>& _scalars);
297 template <
size_t max_num_bits = 0>
300 const std::vector<Fr>& scalars,
301 const size_t max_num_bits = 0,
302 const bool with_edgecases =
false);
316 template <typename X = NativeGroup, typename = typename std::enable_if_t<std::is_same<X, bb::g1>::value>>
319 const std::vector<Fr>& big_scalars,
321 const std::vector<Fr>& small_scalars,
322 const size_t max_num_small_bits);
324 template <typename X = NativeGroup, typename = typename std::enable_if_t<std::is_same<X, bb::g1>::value>>
327 const std::vector<Fr>& big_scalars,
329 const std::vector<Fr>& small_scalars,
330 const Fr& generator_scalar,
331 const size_t max_num_small_bits);
333 template <typename X = NativeGroup, typename = typename std::enable_if_t<std::is_same<X, secp256k1::g1>::value>>
338 template <
size_t max_num_bits = 0,
size_t WNAF_SIZE = 4>
341 template <
size_t wnaf_size,
size_t staggered_lo_offset = 0,
size_t staggered_hi_offset = 0>
346 if (
x.context !=
nullptr) {
349 if (
y.context !=
nullptr) {
357 if (
x.context !=
nullptr) {
360 if (
y.context !=
nullptr) {
363 if (other.
x.context !=
nullptr) {
364 return other.
x.context;
366 if (other.
y.context !=
nullptr) {
367 return other.
y.context;
378 x.set_origin_tag(tag);
379 y.set_origin_tag(tag);
393 x.unset_free_witness_tag();
394 y.unset_free_witness_tag();
403 x.set_free_witness_tag();
404 y.set_free_witness_tag();
414 template <
size_t num_elements>
418 template <
size_t num_elements>
465 for (
size_t i = 9; i < 16; ++i) {
468 for (
size_t i = 0; i < 8; ++i) {
471 for (
size_t i = 0; i < 16; ++i) {
476 for (
size_t i = 0; i < 8; ++i) {
567 for (
size_t i = 0; i < 8; ++i) {
568 endo_table.
element_table[i + 8].x = base_table[7 - i].x * beta;
590 for (
size_t i = 0; i < 16; ++i) {
591 endo_table.
element_table[i + 16].x = base_table[15 - i].x * beta;
644 points[
offset + 6 * i + 1],
645 points[
offset + 6 * i + 2],
646 points[
offset + 6 * i + 3],
647 points[
offset + 6 * i + 4],
648 points[
offset + 6 * i + 5],
655 points[
offset + 5 * i + 1],
656 points[
offset + 5 * i + 2],
657 points[
offset + 5 * i + 3],
658 points[
offset + 5 * i + 4],
677 singletons.push_back(points[points.size() - 1]);
703 element accumulator = add_accumulator[0];
704 for (
size_t i = 1; i < add_accumulator.size(); ++i) {
705 accumulator = accumulator + add_accumulator[i];
731 if (add_accumulator.size() >= 2) {
733 for (
size_t i = 2; i < add_accumulator.size(); ++i) {
734 output = element::chain_add(add_accumulator[i], output);
745 round_accumulator.push_back(
six_tables[j].
get({ naf_entries[6 * j],
746 naf_entries[6 * j + 1],
747 naf_entries[6 * j + 2],
748 naf_entries[6 * j + 3],
749 naf_entries[6 * j + 4],
750 naf_entries[6 * j + 5] }));
752 size_t offset = num_sixes * 6;
755 naf_entries[
offset + j * 5 + 1],
756 naf_entries[
offset + j * 5 + 2],
757 naf_entries[
offset + j * 5 + 3],
758 naf_entries[
offset + j * 5 + 4] }));
765 naf_entries[
offset + 3] }));
769 round_accumulator.push_back(
779 element::chain_add_accumulator accumulator;
780 if (round_accumulator.size() == 1) {
781 return element::chain_add_accumulator(round_accumulator[0]);
782 }
else if (round_accumulator.size() == 2) {
783 return element::chain_add_start(round_accumulator[0], round_accumulator[1]);
785 accumulator = element::chain_add_start(round_accumulator[0], round_accumulator[1]);
786 for (
size_t j = 2; j < round_accumulator.size(); ++j) {
787 accumulator = element::chain_add(round_accumulator[j], accumulator);
790 return (accumulator);
797 round_accumulator.push_back(
six_tables[j].
get({ naf_entries[6 * j],
798 naf_entries[6 * j + 1],
799 naf_entries[6 * j + 2],
800 naf_entries[6 * j + 3],
801 naf_entries[6 * j + 4],
802 naf_entries[6 * j + 5] }));
804 size_t offset = num_sixes * 6;
808 naf_entries[
offset + 5 * j + 1],
809 naf_entries[
offset + 5 * j + 2],
810 naf_entries[
offset + 5 * j + 3],
811 naf_entries[
offset + 5 * j + 4] }));
822 round_accumulator.push_back(
832 element result = round_accumulator[0];
833 element::chain_add_accumulator accumulator;
834 if (round_accumulator.size() == 1) {
836 }
else if (round_accumulator.size() == 2) {
837 return result + round_accumulator[1];
839 accumulator = element::chain_add_start(round_accumulator[0], round_accumulator[1]);
840 for (
size_t j = 2; j < round_accumulator.size(); ++j) {
841 accumulator = element::chain_add(round_accumulator[j], accumulator);
844 return element::chain_add_end(accumulator);
881 quad_lookup_table({ points[4 * i], points[4 * i + 1], points[4 * i + 2], points[4 * i + 3] }));
886 { points[4 * num_quads], points[4 * num_quads + 1], points[4 * num_quads + 2] }));
893 singletons.push_back(points[points.size() - 1]);
913 element accumulator = add_accumulator[0];
914 for (
size_t i = 1; i < add_accumulator.size(); ++i) {
915 accumulator = accumulator + add_accumulator[i];
935 if (add_accumulator.size() >= 2) {
937 for (
size_t i = 2; i < add_accumulator.size(); ++i) {
938 output = element::chain_add(add_accumulator[i], output);
950 naf_entries[4 * j], naf_entries[4 * j + 1], naf_entries[4 * j + 2], naf_entries[4 * j + 3] }));
955 naf_entries[num_quads * 4], naf_entries[num_quads * 4 + 1], naf_entries[num_quads * 4 + 2] }));
965 element::chain_add_accumulator accumulator;
966 if (round_accumulator.size() == 1) {
967 accumulator.x3_prev = round_accumulator[0].x;
968 accumulator.y3_prev = round_accumulator[0].y;
969 accumulator.is_element =
true;
971 }
else if (round_accumulator.size() == 2) {
972 return element::chain_add_start(round_accumulator[0], round_accumulator[1]);
974 accumulator = element::chain_add_start(round_accumulator[0], round_accumulator[1]);
975 for (
size_t j = 2; j < round_accumulator.size(); ++j) {
976 accumulator = element::chain_add(round_accumulator[j], accumulator);
979 return (accumulator);
987 { naf_entries[4 * j], naf_entries[4 * j + 1], naf_entries[4 * j + 2], naf_entries[4 * j + 3] }));
992 naf_entries[num_quads * 4], naf_entries[num_quads * 4 + 1], naf_entries[num_quads * 4 + 2] }));
995 round_accumulator.push_back(
996 twin_tables[0].
get({ naf_entries[num_quads * 4], naf_entries[num_quads * 4 + 1] }));
1002 element result = round_accumulator[0];
1003 element::chain_add_accumulator accumulator;
1004 if (round_accumulator.size() == 1) {
1006 }
else if (round_accumulator.size() == 2) {
1007 return result + round_accumulator[1];
1009 accumulator = element::chain_add_start(round_accumulator[0], round_accumulator[1]);
1010 for (
size_t j = 2; j < round_accumulator.size(); ++j) {
1011 accumulator = element::chain_add(round_accumulator[j], accumulator);
1014 return element::chain_add_end(accumulator);
1032template <
typename C,
typename Fq,
typename Fr,
typename G>
1035 return os <<
"{ " << v.
x <<
" , " << v.
y <<
" }";
1040template <
typename T>
1043template <
typename Builder,
class Fq,
class Fr,
class NativeGroup>
1052template <
typename C,
typename Fq,
typename Fr,
typename G>
#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()
void unset_free_witness_tag()
OriginTag get_origin_tag() const
Represents a dynamic array of bytes in-circuit.
byte_array & write(byte_array const &other)
Appends the contents of another byte_array (other) to the end of this one.
element checked_unconditional_subtract(const element &other) const
element & operator=(const element &other)
byte_array< Builder > to_byte_array() const
std::array< element, 2 > checked_unconditional_add_sub(const element &) const
Compute (*this) + other AND (*this) - other as a size-2 array.
element operator*(const Fr &other) const
element operator-=(const element &other)
NativeGroup::affine_element get_value() const
void validate_on_curve() const
static secp256k1_wnaf_pair compute_secp256k1_endo_wnaf(const Fr &scalar)
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)
static chain_add_accumulator chain_add_start(const element &p1, const element &p2)
static element from_witness(Builder *ctx, const typename NativeGroup::affine_element &input)
element montgomery_ladder(const element &other) const
static element chain_add_end(const chain_add_accumulator &accumulator)
element operator-() const
void unset_free_witness_tag()
Unset the free witness flag for the element's tags.
static element point_at_infinity(Builder *ctx)
static std::pair< four_bit_table_plookup, four_bit_table_plookup > create_endo_pair_four_bit_table_plookup(const element &input)
static std::vector< field_t< Builder > > compute_wnaf(const Fr &scalar)
static NativeGroup::affine_element compute_table_offset_generator()
Compute an offset generator for use in biggroup tables.
void set_origin_tag(OriginTag tag) const
void set_point_at_infinity(const bool_ct &is_infinity)
static element bn254_endo_batch_mul_with_generator(const std::vector< element > &big_points, const std::vector< Fr > &big_scalars, const std::vector< element > &small_points, const std::vector< Fr > &small_scalars, const Fr &generator_scalar, const size_t max_num_small_bits)
static std::pair< quad_lookup_table, quad_lookup_table > create_endo_pair_quad_lookup_table(const std::array< element, 4 > &inputs)
element normalize() const
element(const typename NativeGroup::affine_element &input)
element quadruple_and_add(const std::vector< element > &to_add) const
Compute 4.P + to_add[0] + ... + to_add[to_add.size() - 1].
OriginTag get_origin_tag() const
static element bn254_endo_batch_mul(const std::vector< element > &big_points, const std::vector< Fr > &big_scalars, const std::vector< element > &small_points, const std::vector< Fr > &small_scalars, const size_t max_num_small_bits)
void convert_constant_to_fixed_witness(Builder *builder)
Creates fixed witnesses from a constant element.
static std::array< fr, PUBLIC_INPUTS_SIZE > construct_dummy()
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 wnaf_batch_mul(const std::vector< element > &points, const std::vector< Fr > &scalars)
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)
uint32_t set_public() const
Set the witness indices for the x and y coordinates to public.
static element read_group_element_rom_tables(const std::array< twin_rom_table< Builder >, 5 > &tables, const field_t< Builder > &index, const std::array< uint256_t, 8 > &limb_max)
static std::pair< lookup_table_plookup< 5 >, lookup_table_plookup< 5 > > create_endo_pair_five_lookup_table(const std::array< element, 5 > &inputs)
Builder * get_context() 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)
Replace all pairs (∞, scalar) by the pair (one, 0) where one is a fixed generator of the curve.
void set_free_witness_tag()
Set the free witness flag for the element's tags.
element get_standard_form() const
Enforce x and y coordinates of a point to be (0,0) in the case of point at infinity.
static element reconstruct_from_public(const std::span< const Fr, PUBLIC_INPUTS_SIZE > &limbs)
Reconstruct a biggroup element from limbs of its coordinates (generally stored in the public inputs)
static constexpr size_t PUBLIC_INPUTS_SIZE
element operator+(const element &other) const
static chain_add_accumulator chain_add(const element &p1, const chain_add_accumulator &accumulator)
static std::array< twin_rom_table< Builder >, 5 > create_group_element_rom_tables(const std::array< element, num_elements > &elements, std::array< uint256_t, 8 > &limb_max)
static std::pair< std::vector< element >, std::vector< Fr > > mask_points(const std::vector< element > &_points, const std::vector< Fr > &_scalars)
Given two lists of points that need to be multiplied by scalars, create a new list of length +1 with ...
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 secp256k1_ecdsa_mul(const element &pubkey, const Fr &u1, const Fr &u2)
Custom element class for when using goblin.
#define G(r, i, a, b, c, d)
uint8_t const size_t length
FF const & operator[](size_t idx) const
Retruns the element in beta_products at place #idx.
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()
static constexpr size_t PUBLIC_INPUTS_SIZE
BB_INLINE constexpr field sqr() const noexcept
static field reconstruct_from_public(const std::span< const field< V >, PUBLIC_INPUTS_SIZE > &limbs)
static constexpr field zero()
batch_lookup_table_base(const std::vector< element > &points)
element get(std::vector< bool_ct > &naf_entries) const
std::vector< triple_lookup_table > triple_tables
std::vector< twin_lookup_table > twin_tables
std::vector< element > singletons
element get_initial_entry() const
chain_add_accumulator get_chain_initial_entry() const
std::vector< quad_lookup_table > quad_tables
element::chain_add_accumulator get_chain_add_accumulator(std::vector< bool_ct > &naf_entries) const
element get(std::vector< bool_ct > &naf_entries) const
chain_add_accumulator get_chain_initial_entry() const
element get_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(chain_add_accumulator &&other)=default
chain_add_accumulator(const chain_add_accumulator &other)=default
chain_add_accumulator(const element &input)
chain_add_accumulator & operator=(chain_add_accumulator &&other)=default
chain_add_accumulator & operator=(const chain_add_accumulator &other)=default
eight_bit_fixed_base_table & operator=(const eight_bit_fixed_base_table &other)=default
element operator[](const field_t< Builder > &index) const
eight_bit_fixed_base_table(const CurveType input_curve_type, bool use_endo)
eight_bit_fixed_base_table(const eight_bit_fixed_base_table &other)=default
std::array< uint256_t, 8 > limb_max
std::array< twin_rom_table< Builder >, 5 > coordinates
element operator[](const field_t< Builder > &index) const
four_bit_table_plookup(const four_bit_table_plookup &other)=default
std::array< element, 16 > element_table
element operator[](const size_t idx) const
four_bit_table_plookup & operator=(const four_bit_table_plookup &other)=default
std::array< field_t< Builder >, table_size > x_b0_table
std::array< field_t< Builder >, table_size > y_b0_table
std::array< field_t< Builder >, table_size > y_b2_table
std::array< field_t< Builder >, table_size > y_b3_table
lookup_table_base & operator=(const lookup_table_base &other)=default
std::array< field_t< Builder >, table_size > x_b1_table
std::array< field_t< Builder >, table_size > x_b3_table
std::array< field_t< Builder >, table_size > y_b1_table
lookup_table_base(const lookup_table_base &other)=default
element get(const std::array< bool_ct, length > &bits) const
std::array< element, table_size > element_table
std::array< field_t< Builder >, table_size > x_b2_table
static constexpr size_t table_size
element operator[](const size_t idx) const
std::array< uint256_t, 8 > limb_max
lookup_table_plookup(const lookup_table_plookup &other)=default
std::array< element, table_size > element_table
lookup_table_plookup & operator=(const lookup_table_plookup &other)=default
element operator[](const size_t idx) const
std::array< twin_rom_table< Builder >, 5 > coordinates
static constexpr size_t table_size
element get(const std::array< bool_ct, length > &bits) const
std::vector< field_t< Builder > > wnaf
field_t< Builder > positive_skew
field_t< Builder > least_significant_wnaf_fragment
field_t< Builder > negative_skew