Skip to content

Commit

Permalink
compiler fixes, namespace changes
Browse files Browse the repository at this point in the history
  • Loading branch information
zac-williamson committed Sep 5, 2024
1 parent 70d28aa commit 418e1fe
Show file tree
Hide file tree
Showing 11 changed files with 130 additions and 114 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ concept IsGoblinBigGroup =
std::same_as<Fr, bb::stdlib::field_t<Builder>> && std::same_as<NativeGroup, bb::g1>;

} // namespace bb::stdlib
namespace bb::stdlib::element_inner {
namespace bb::stdlib::element_default {

// ( ͡° ͜ʖ ͡°)
template <class Builder, class Fq, class Fr, class NativeGroup> class element {
Expand Down Expand Up @@ -233,8 +233,8 @@ template <class Builder, class Fq, class Fr, class NativeGroup> class element {
const bool with_edgecases = false);

// we want to conditionally compile this method iff our curve params are the BN254 curve.
// This is a bit tricky to do with `std::enable_if`, because `bn254_endo_batch_mul` is a member function of a class
// template
// This is a bit tricky to do with `std::enable_if`, because `bn254_endo_batch_mul` is a member function of a
// class template
// && the compiler can't perform partial template specialization on member functions of class templates
// => our template parameter cannot be a value but must instead by a type
// Our input to `std::enable_if` is a comparison between two types (NativeGroup and bb::g1), which
Expand Down Expand Up @@ -947,16 +947,16 @@ inline std::ostream& operator<<(std::ostream& os, element<C, Fq, Fr, G> const& v
{
return os << "{ " << v.x << " , " << v.y << " }";
}
} // namespace bb::stdlib::element_inner
} // namespace bb::stdlib::element_default

namespace bb::stdlib {
template <typename T>
concept IsBigGroup = std::is_same_v<typename T::biggroup_tag, T>;

template <typename C, typename Fq, typename Fr, typename G>
using element = std::conditional_t<IsGoblinBigGroup<C, Fq, Fr, G>,
goblin_element<C, goblin_field<C>, Fr, G>,
element_inner::element<C, Fq, Fr, G>>;
element_goblin::goblin_element<C, goblin_field<C>, Fr, G>,
element_default::element<C, Fq, Fr, G>>;
} // namespace bb::stdlib
#include "biggroup_batch_mul.hpp"
#include "biggroup_bn254.hpp"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

#include "barretenberg/stdlib/primitives/biggroup/biggroup_edgecase_handling.hpp"
#include <cstddef>
namespace bb::stdlib::element_inner {
namespace bb::stdlib::element_default {

/**
* @brief Multiscalar multiplication that utilizes 4-bit wNAF lookup tables.
Expand Down Expand Up @@ -62,4 +62,4 @@ element<C, Fq, Fr, G> element<C, Fq, Fr, G>::wnaf_batch_mul(const std::vector<el
accumulator -= offset_generators.second;
return accumulator;
}
} // namespace bb::stdlib::element_inner
} // namespace bb::stdlib::element_default
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
**/
#include "barretenberg/stdlib/primitives/biggroup/biggroup.hpp"
#include "barretenberg/stdlib/primitives/circuit_builders/circuit_builders.hpp"
namespace bb::stdlib::element_inner {
namespace bb::stdlib::element_default {

/**
* Perform a multi-scalar multiplication over the BN254 curve
Expand Down Expand Up @@ -120,7 +120,8 @@ element<C, Fq, Fr, G> element<C, Fq, Fr, G>::bn254_endo_batch_mul_with_generator
};

// Perform multiple rounds of the montgomery ladder algoritm per "iteration" of our main loop.
// This is in order to reduce the number of field reductions required when calling `multiple_montgomery_ladder`
// This is in order to reduce the number of field reductions required when calling
// `multiple_montgomery_ladder`
constexpr size_t num_rounds_per_iteration = 4;

// we require that we perform max of one generator per iteration
Expand Down Expand Up @@ -213,8 +214,8 @@ element<C, Fq, Fr, G> element<C, Fq, Fr, G>::bn254_endo_batch_mul_with_generator
* small_points : group elements we will multiply by short scalar mutipliers whose max value will be (1 <<
*max_num_small_bits) small_scalars : short scalar mutipliers whose max value will be (1 << max_num_small_bits)
* max_num_small_bits : MINIMUM value must be 128 bits
* (we will be splitting `big_scalars` into two 128-bit scalars, we assume all scalars after this transformation are 128
*bits)
* (we will be splitting `big_scalars` into two 128-bit scalars, we assume all scalars after this transformation are
*128 bits)
**/
template <typename C, class Fq, class Fr, class G>
template <typename, typename>
Expand Down Expand Up @@ -311,10 +312,10 @@ element<C, Fq, Fr, G> element<C, Fq, Fr, G>::bn254_endo_batch_mul(const std::vec
/**
* Compute scalar multiplier NAFs
*
* A Non Adjacent Form is a representation of an integer where each 'bit' is either +1 OR -1, i.e. each bit entry is
*non-zero. This is VERY useful for biggroup operations, as this removes the need to conditionally add points
*depending on whether the scalar mul bit is +1 or 0 (instead we multiply the y-coordinate by the NAF value, which
*is cheaper)
* A Non Adjacent Form is a representation of an integer where each 'bit' is either +1 OR -1, i.e. each bit
*entry is non-zero. This is VERY useful for biggroup operations, as this removes the need to conditionally add
*points depending on whether the scalar mul bit is +1 or 0 (instead we multiply the y-coordinate by the NAF
*value, which is cheaper)
*
* The vector `naf_entries` tracks the `naf` set for each point, where each `naf` set is a vector of bools
* if `naf[i][j] = 0` this represents a NAF value of -1
Expand All @@ -328,14 +329,15 @@ element<C, Fq, Fr, G> element<C, Fq, Fr, G>::bn254_endo_batch_mul(const std::vec
}

/**
* Initialize accumulator point with an offset generator. See `compute_offset_generators` for detailed explanation
* Initialize accumulator point with an offset generator. See `compute_offset_generators` for detailed
*explanation
**/
const auto offset_generators = compute_offset_generators(num_rounds);

/**
* Get the initial entry of our point table. This is the same as point_table.get_accumulator for the most
*significant NAF entry. HOWEVER, we know the most significant NAF value is +1 because our scalar muls are positive.
* `get_initial_entry` handles this special case as it's cheaper than `point_table.get_accumulator`
*significant NAF entry. HOWEVER, we know the most significant NAF value is +1 because our scalar muls are
*positive. `get_initial_entry` handles this special case as it's cheaper than `point_table.get_accumulator`
**/
element accumulator = offset_generators.first + point_table.get_initial_entry();

Expand All @@ -349,10 +351,11 @@ element<C, Fq, Fr, G> element<C, Fq, Fr, G>::bn254_endo_batch_mul(const std::vec
* 3. Repeat the above 2 steps but for bit `2 * i` (`add_2`)
* 4. Compute `accumulator = 4 * accumulator + 2 * add_1 + add_2` using `multiple_montgomery_ladder` method
*
* The purpose of the above is to minimize the number of required range checks (vs a simple double and add algo).
* The purpose of the above is to minimize the number of required range checks (vs a simple double and add
*algo).
*
* When computing repeated iterations of the montgomery ladder algorithm, we can neglect computing the y-coordinate
*of each ladder output. See `multiple_montgomery_ladder` for more details.
* When computing repeated iterations of the montgomery ladder algorithm, we can neglect computing the
*y-coordinate of each ladder output. See `multiple_montgomery_ladder` for more details.
**/
for (size_t i = 1; i < num_rounds / 2; ++i) {
// `nafs` tracks the naf value for each point for the current round
Expand All @@ -370,8 +373,8 @@ element<C, Fq, Fr, G> element<C, Fq, Fr, G>::bn254_endo_batch_mul(const std::vec
*
* This is represented using the `chain_add_accumulator` type. See the type declaration for more details
*
* (this is cheaper than regular additions iff point_table.get_accumulator require 2 or more point additions.
* Cost is the same as `point_table.get_accumulator` if 1 or 0 point additions are required)
* (this is cheaper than regular additions iff point_table.get_accumulator require 2 or more point
*additions. Cost is the same as `point_table.get_accumulator` if 1 or 0 point additions are required)
**/
element::chain_add_accumulator add_1 = point_table.get_chain_add_accumulator(nafs);
for (size_t j = 0; j < points.size(); ++j) {
Expand Down Expand Up @@ -424,4 +427,4 @@ element<C, Fq, Fr, G> element<C, Fq, Fr, G>::bn254_endo_batch_mul(const std::vec
// Return our scalar mul output
return accumulator;
}
} // namespace bb::stdlib::element_inner
} // namespace bb::stdlib::element_default
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
#pragma once
#include "barretenberg/stdlib/primitives/biggroup/biggroup.hpp"

namespace bb::stdlib::element_inner {
namespace bb::stdlib::element_default {

/**
* @brief Compute an offset generator for use in biggroup tables
*
*@details Sometimes the points from which we construct the tables are going to be dependent in such a way that
*combining them for constructing the table is not possible without handling the edgecases such as the point at infinity
*and doubling. To avoid handling those we add multiples of this offset generator to the points.
*combining them for constructing the table is not possible without handling the edgecases such as the point at
*infinity and doubling. To avoid handling those we add multiples of this offset generator to the points.
*
* @param num_rounds
*/
Expand All @@ -22,11 +22,11 @@ typename G::affine_element element<C, Fq, Fr, G>::compute_table_offset_generator
}

/**
* @brief Given two lists of points that need to be multiplied by scalars, create a new list of length +1 with original
* points masked, but the same scalar product sum
* @brief Given two lists of points that need to be multiplied by scalars, create a new list of length +1 with
* original points masked, but the same scalar product sum
* @details Add +1G, +2G, +4G etc to the original points and adds a new point 2ⁿ⋅G and scalar x to the lists. By
* doubling the point every time, we ensure that no +-1 combination of 6 sequential elements run into edgecases, unless
* the points are deliberately constructed to trigger it.
* doubling the point every time, we ensure that no +-1 combination of 6 sequential elements run into edgecases,
* unless the points are deliberately constructed to trigger it.
*/
template <typename C, class Fq, class Fr, class G>
std::pair<std::vector<element<C, Fq, Fr, G>>, std::vector<Fr>> element<C, Fq, Fr, G>::mask_points(
Expand Down Expand Up @@ -100,4 +100,4 @@ std::pair<std::vector<element<C, Fq, Fr, G>>, std::vector<Fr>> element<C, Fq, Fr

return { points, scalars };
}
} // namespace bb::stdlib::element_inner
} // namespace bb::stdlib::element_default
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,11 @@
// functions. template <typename Builder, typename NativeGroup> concept IsNotGoblinInefficiencyTrap =
// !(IsMegaBuilder<Builder> && std::same_as<NativeGroup, bb::g1>);

namespace bb::stdlib {
namespace bb::stdlib::element_goblin {

// ( ͡° ͜ʖ ͡°)
template <class Builder, class Fq, class Fr, class NativeGroup> class goblin_element {
public:
using element = goblin_element;
using BaseField = Fq;
using bool_ct = stdlib::bool_t<Builder>;
using biggroup_tag = goblin_element; // Facilitates a constexpr check IsBigGroup
Expand All @@ -38,20 +37,20 @@ template <class Builder, class Fq, class Fr, class NativeGroup> class goblin_ele
, _is_infinity(false)
{}

goblin_element(const element& other) = default;
goblin_element(element&& other) noexcept = default;
goblin_element& operator=(const element& other) = default;
goblin_element& operator=(element&& other) = default;
// static element from_witness_unsafe(Builder* ctx, const typename NativeGroup::affine_element& input)
goblin_element(const goblin_element& other) = default;
goblin_element(goblin_element&& other) noexcept = default;
goblin_element& operator=(const goblin_element& other) = default;
goblin_element& operator=(goblin_element&& other) = default;
// static goblin_element from_witness_unsafe(Builder* ctx, const typename NativeGroup::affine_element& input)
// {
// // only valid usecase of this method is with a goblin builder
// ASSERT(IsMegaBuilder<Builder>);
// element out;
// goblin_element out;
// if (in)
// }
static element from_witness(Builder* ctx, const typename NativeGroup::affine_element& input)
static goblin_element from_witness(Builder* ctx, const typename NativeGroup::affine_element& input)
{
element out;
goblin_element out;
if (input.is_point_at_infinity()) {
Fq x = Fq::from_witness(ctx, NativeGroup::affine_one.x);
Fq y = Fq::from_witness(ctx, NativeGroup::affine_one.y);
Expand All @@ -72,13 +71,13 @@ template <class Builder, class Fq, class Fr, class NativeGroup> class goblin_ele
// happens in goblin eccvm
}

static element one(Builder* ctx)
static goblin_element one(Builder* ctx)
{
uint256_t x = uint256_t(NativeGroup::one.x);
uint256_t y = uint256_t(NativeGroup::one.y);
Fq x_fq(ctx, x);
Fq y_fq(ctx, y);
return element(x_fq, y_fq);
return goblin_element(x_fq, y_fq);
}

// byte_array<Builder> to_byte_array() const
Expand All @@ -89,72 +88,78 @@ template <class Builder, class Fq, class Fr, class NativeGroup> class goblin_ele
// return result;
// }

element checked_unconditional_add(const element& other) const { return element::operator+(*this, other); }
element checked_unconditional_subtract(const element& other) const { return element::operator-(*this, other); }
goblin_element checked_unconditional_add(const goblin_element& other) const
{
return goblin_element::operator+(*this, other);
}
goblin_element checked_unconditional_subtract(const goblin_element& other) const
{
return goblin_element::operator-(*this, other);
}

element operator+(const element& other) const
goblin_element operator+(const goblin_element& other) const
{
// TODO(https://github.com/AztecProtocol/barretenberg/issues/707) Optimize
// Current gate count: 6398
return batch_mul({ *this, other }, { Fr(1), Fr(1) });
}
element operator-(const element& other) const
goblin_element operator-(const goblin_element& other) const
{
// TODO(https://github.com/AztecProtocol/barretenberg/issues/707) Optimize
std::vector<element> points{ *this, other };
std::vector<goblin_element> points{ *this, other };
return batch_mul({ *this, other }, { Fr(1), -Fr(1) });
}
element operator-() const
goblin_element operator-() const
{
// TODO(https://github.com/AztecProtocol/barretenberg/issues/707) Optimize
return batch_mul({ *this }, { -Fr(1) });
}
element operator+=(const element& other)
goblin_element operator+=(const goblin_element& other)
{
*this = *this + other;
return *this;
}
element operator-=(const element& other)
goblin_element operator-=(const goblin_element& other)
{
*this = *this - other;
return *this;
}
std::array<element, 2> checked_unconditional_add_sub(const element& other) const
std::array<goblin_element, 2> checked_unconditional_add_sub(const goblin_element& other) const
{
return std::array<element, 2>{ *this + other, *this - other };
return std::array<goblin_element, 2>{ *this + other, *this - other };
}

element operator*(const Fr& scalar) const { return batch_mul({ *this }, { scalar }); }
goblin_element operator*(const Fr& scalar) const { return batch_mul({ *this }, { scalar }); }

element conditional_negate(const bool_ct& predicate) const
goblin_element conditional_negate(const bool_ct& predicate) const
{
element negated = -(*this);
element result(*this);
goblin_element negated = -(*this);
goblin_element result(*this);
result.y = Fq::conditional_assign(predicate, negated.y, result.y);
return result;
}

element normalize() const
goblin_element normalize() const
{
// no need to normalize, all goblin eccvm operations are returned normalized
return *this;
}

element reduce() const
goblin_element reduce() const
{
// no need to reduce, all goblin eccvm operations are returned normalized
return *this;
}

element dbl() const { return batch_mul({ *this }, { 2 }); }
goblin_element dbl() const { return batch_mul({ *this }, { 2 }); }

// TODO(https://github.com/AztecProtocol/barretenberg/issues/707) max_num_bits is unused; could implement and
// use this to optimize other operations. interface compatible with biggroup.hpp, the final parameter
// handle_edge_cases is not needed as this is always done in the eccvm
static element batch_mul(const std::vector<element>& points,
const std::vector<Fr>& scalars,
const size_t max_num_bits = 0,
const bool handle_edge_cases = false);
static goblin_element batch_mul(const std::vector<goblin_element>& points,
const std::vector<Fr>& scalars,
const size_t max_num_bits = 0,
const bool handle_edge_cases = false);

// we use this data structure to add together a sequence of points.
// By tracking the previous values of x_1, y_1, \lambda, we can avoid
Expand All @@ -181,7 +186,7 @@ template <class Builder, class Fq, class Fr, class NativeGroup> class goblin_ele
return nullptr;
}

Builder* get_context(const element& other) const
Builder* get_context(const goblin_element& other) const
{
if (x.get_context() != nullptr) {
return x.get_context();
Expand All @@ -207,10 +212,10 @@ template <class Builder, class Fq, class Fr, class NativeGroup> class goblin_ele
* coefficients when we get it as output from our optimised algorithms. This function returns a (0,0) point, if
* it is a point at infinity
*/
element get_standard_form() const
goblin_element get_standard_form() const
{
const bool_ct is_infinity = is_point_at_infinity();
element result(*this);
goblin_element result(*this);
const Fq zero = Fq::zero();
result.x = Fq::conditional_assign(is_infinity, zero, result.x);
result.y = Fq::conditional_assign(is_infinity, zero, result.y);
Expand All @@ -229,6 +234,6 @@ inline std::ostream& operator<<(std::ostream& os, goblin_element<C, Fq, Fr, G> c
{
return os << "{ " << v.x << " , " << v.y << " }";
}
} // namespace bb::stdlib
} // namespace bb::stdlib::element_goblin

#include "biggroup_goblin_impl.hpp"
Loading

0 comments on commit 418e1fe

Please sign in to comment.