Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Clean up and refactor arithmetization #3164

Merged
merged 9 commits into from
Nov 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ void enforce_nonzero_selector_polynomials(const auto& circuit_constructor, auto*
{
for (size_t idx = 0; idx < circuit_constructor.num_selectors; ++idx) {
auto current_selector =
proving_key->polynomial_store.get(circuit_constructor.selector_names_[idx] + "_lagrange");
proving_key->polynomial_store.get(circuit_constructor.selector_names[idx] + "_lagrange");
current_selector[current_selector.size() - 1] = idx + 1;
proving_key->polynomial_store.put(circuit_constructor.selector_names_[idx] + "_lagrange",
proving_key->polynomial_store.put(circuit_constructor.selector_names[idx] + "_lagrange",
std::move(current_selector));
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,167 +17,96 @@ namespace arithmetization {
* @remark It may make sense to say this is only partial arithmetization data, with the full data being
* contained in the circuit constructor. We could change the name of this class if it conflicts with common usage.
*
* @tparam _NUM_WIRES
* @tparam _num_selectors
* @note For even greater modularity, in each instantiation we could specify a list of components here, where a
* component is a meaningful collection of functions for creating gates, as in:
*
* struct Component {
* using Arithmetic = component::Arithmetic3Wires;
* using RangeConstraints = component::Base4Accumulators or component::GenPerm or...
* using LookupTables = component::Plookup4Wire or component::CQ8Wire or...
* ...
* };
*
* We should only do this if it becomes necessary or convenient.
*/
template <size_t _NUM_WIRES, size_t _num_selectors> struct Arithmetization {
static constexpr size_t NUM_WIRES = _NUM_WIRES;
static constexpr size_t num_selectors = _num_selectors;

// Note: For even greater modularity, in each instantiation we could specify a list of components here, where a
// component is a meaningful collection of functions for creating gates, as in:
//
// struct Component {
// using Arithmetic = component::Arithmetic3Wires;
// using RangeConstraints = component::Base4Accumulators or component::GenPerm or...
// using LookupTables = component::Plookup4Wire or component::CQ8Wire or...
// ...
// };
//
// We should only do this if it becomes necessary or convenient.
};

template <typename FF, size_t num_selectors> struct SelectorsBase {
using DataType = std::array<std::vector<FF, barretenberg::ContainerSlabAllocator<FF>>, num_selectors>;
DataType _data;
size_t size() { return _data.size(); };
typename DataType::const_iterator begin() const { return _data.begin(); };
typename DataType::iterator begin() { return _data.begin(); };
typename DataType::const_iterator end() const { return _data.end(); };
typename DataType::iterator end() { return _data.end(); };
};

// These are not magic numbers and they should not be written with global constants. These parameters are not accessible
// through clearly named static class members.
template <typename _FF> class Standard : public Arithmetization</*NUM_WIRES =*/3, /*num_selectors =*/5> {
template <typename FF_> class Standard {
public:
using FF = _FF;
struct Selectors : SelectorsBase<FF, num_selectors> {
std::vector<FF, barretenberg::ContainerSlabAllocator<FF>>& q_m = std::get<0>(this->_data);
std::vector<FF, barretenberg::ContainerSlabAllocator<FF>>& q_1 = std::get<1>(this->_data);
std::vector<FF, barretenberg::ContainerSlabAllocator<FF>>& q_2 = std::get<2>(this->_data);
std::vector<FF, barretenberg::ContainerSlabAllocator<FF>>& q_3 = std::get<3>(this->_data);
std::vector<FF, barretenberg::ContainerSlabAllocator<FF>>& q_c = std::get<4>(this->_data);
Selectors()
: SelectorsBase<FF, num_selectors>(){};
Selectors(const Selectors& other)
: SelectorsBase<FF, num_selectors>(other)
{}
Selectors(Selectors&& other)
{
this->_data = std::move(other._data);
this->q_m = std::get<0>(this->_data);
this->q_1 = std::get<1>(this->_data);
this->q_2 = std::get<2>(this->_data);
this->q_3 = std::get<3>(this->_data);
this->q_c = std::get<4>(this->_data);
};
Selectors& operator=(Selectors&& other)
{
SelectorsBase<FF, num_selectors>::operator=(other);
return *this;
}
~Selectors() = default;
};
};
static constexpr size_t NUM_WIRES = 3;
static constexpr size_t num_selectors = 5;
using FF = FF_;
using SelectorType = std::vector<FF, barretenberg::ContainerSlabAllocator<FF>>;

template <typename _FF> class Turbo : public Arithmetization</*NUM_WIRES =*/4, /*num_selectors =*/11> {
public:
using FF = _FF;
struct Selectors : SelectorsBase<FF, num_selectors> {
std::vector<FF, barretenberg::ContainerSlabAllocator<FF>>& q_m = std::get<0>(this->_data);
std::vector<FF, barretenberg::ContainerSlabAllocator<FF>>& q_c = std::get<1>(this->_data);
std::vector<FF, barretenberg::ContainerSlabAllocator<FF>>& q_1 = std::get<2>(this->_data);
std::vector<FF, barretenberg::ContainerSlabAllocator<FF>>& q_2 = std::get<3>(this->_data);
std::vector<FF, barretenberg::ContainerSlabAllocator<FF>>& q_3 = std::get<4>(this->_data);
std::vector<FF, barretenberg::ContainerSlabAllocator<FF>>& q_4 = std::get<5>(this->_data);
std::vector<FF, barretenberg::ContainerSlabAllocator<FF>>& q_5 = std::get<6>(this->_data);
std::vector<FF, barretenberg::ContainerSlabAllocator<FF>>& q_arith = std::get<7>(this->_data);
std::vector<FF, barretenberg::ContainerSlabAllocator<FF>>& q_fixed_base = std::get<8>(this->_data);
std::vector<FF, barretenberg::ContainerSlabAllocator<FF>>& q_range = std::get<9>(this->_data);
std::vector<FF, barretenberg::ContainerSlabAllocator<FF>>& q_logic = std::get<10>(this->_data);
Selectors()
: SelectorsBase<FF, num_selectors>(){};
Selectors(const Selectors& other)
: SelectorsBase<FF, num_selectors>(other)
{}
Selectors(Selectors&& other)
{
this->_data = std::move(other._data);
this->q_m = std::get<0>(this->_data);
this->q_c = std::get<1>(this->_data);
this->q_1 = std::get<2>(this->_data);
this->q_2 = std::get<3>(this->_data);
this->q_3 = std::get<4>(this->_data);
this->q_4 = std::get<5>(this->_data);
this->q_5 = std::get<6>(this->_data);
this->q_arith = std::get<7>(this->_data);
this->q_fixed_base = std::get<8>(this->_data);
this->q_range = std::get<9>(this->_data);
this->q_logic = std::get<10>(this->_data);
};
Selectors& operator=(Selectors&& other)
{
SelectorsBase<FF, num_selectors>::operator=(other);
return *this;
std::vector<SelectorType> selectors;

SelectorType& q_m() { return selectors[0]; };
SelectorType& q_1() { return selectors[1]; };
SelectorType& q_2() { return selectors[2]; };
SelectorType& q_3() { return selectors[3]; };
SelectorType& q_c() { return selectors[4]; };

Standard()
: selectors(num_selectors)
{}

const auto& get() const { return selectors; };

void reserve(size_t size_hint)
{
for (auto& p : selectors) {
p.reserve(size_hint);
}
~Selectors() = default;
};
}

// Note: These are needed for Plonk only (for poly storage in a std::map). Must be in same order as above struct.
inline static const std::vector<std::string> selector_names = { "q_m", "q_1", "q_2", "q_3", "q_c" };
};

template <typename _FF> class Ultra : public Arithmetization</*NUM_WIRES =*/4, /*num_selectors =*/11> {
template <typename FF_> class Ultra {
public:
using FF = _FF;
struct Selectors : SelectorsBase<FF, num_selectors> {
std::vector<FF, barretenberg::ContainerSlabAllocator<FF>>& q_m = std::get<0>(this->_data);
std::vector<FF, barretenberg::ContainerSlabAllocator<FF>>& q_c = std::get<1>(this->_data);
std::vector<FF, barretenberg::ContainerSlabAllocator<FF>>& q_1 = std::get<2>(this->_data);
std::vector<FF, barretenberg::ContainerSlabAllocator<FF>>& q_2 = std::get<3>(this->_data);
std::vector<FF, barretenberg::ContainerSlabAllocator<FF>>& q_3 = std::get<4>(this->_data);
std::vector<FF, barretenberg::ContainerSlabAllocator<FF>>& q_4 = std::get<5>(this->_data);
std::vector<FF, barretenberg::ContainerSlabAllocator<FF>>& q_arith = std::get<6>(this->_data);
std::vector<FF, barretenberg::ContainerSlabAllocator<FF>>& q_sort = std::get<7>(this->_data);
std::vector<FF, barretenberg::ContainerSlabAllocator<FF>>& q_elliptic = std::get<8>(this->_data);
std::vector<FF, barretenberg::ContainerSlabAllocator<FF>>& q_aux = std::get<9>(this->_data);
std::vector<FF, barretenberg::ContainerSlabAllocator<FF>>& q_lookup_type = std::get<10>(this->_data);
Selectors()
: SelectorsBase<FF, num_selectors>(){};
Selectors(const Selectors& other)
: SelectorsBase<FF, num_selectors>(other)
{}
Selectors(Selectors&& other)
{
this->_data = std::move(other._data);
this->q_m = std::get<0>(this->_data);
this->q_c = std::get<1>(this->_data);
this->q_1 = std::get<2>(this->_data);
this->q_2 = std::get<3>(this->_data);
this->q_3 = std::get<4>(this->_data);
this->q_4 = std::get<5>(this->_data);
this->q_arith = std::get<6>(this->_data);
this->q_sort = std::get<7>(this->_data);
this->q_elliptic = std::get<8>(this->_data);
this->q_aux = std::get<9>(this->_data);
this->q_lookup_type = std::get<10>(this->_data);
};
Selectors& operator=(Selectors&& other)
{
SelectorsBase<FF, num_selectors>::operator=(other);
return *this;
static constexpr size_t NUM_WIRES = 4;
static constexpr size_t num_selectors = 11;
using FF = FF_;
using SelectorType = std::vector<FF, barretenberg::ContainerSlabAllocator<FF>>;

std::vector<SelectorType> selectors;

SelectorType& q_m() { return selectors[0]; };
SelectorType& q_c() { return selectors[1]; };
SelectorType& q_1() { return selectors[2]; };
SelectorType& q_2() { return selectors[3]; };
SelectorType& q_3() { return selectors[4]; };
SelectorType& q_4() { return selectors[5]; };
SelectorType& q_arith() { return selectors[6]; };
SelectorType& q_sort() { return selectors[7]; };
SelectorType& q_elliptic() { return selectors[8]; };
SelectorType& q_aux() { return selectors[9]; };
SelectorType& q_lookup_type() { return selectors[10]; };

Ultra()
: selectors(num_selectors)
{}

const auto& get() const { return selectors; };

void reserve(size_t size_hint)
{
for (auto& p : selectors) {
p.reserve(size_hint);
}
~Selectors() = default;
// Selectors() = default;
// Selectors(const Selectors& other) = default;
// Selectors(Selectors&& other) = default;
// Selectors& operator=(Selectors const& other) = default;
// Selectors& operator=(Selectors&& other) = default;
// ~Selectors() = default;
};
}

// Note: These are needed for Plonk only (for poly storage in a std::map). Must be in same order as above struct.
inline static const std::vector<std::string> selector_names = { "q_m", "q_c", "q_1", "q_2",
"q_3", "q_4", "q_arith", "q_sort",
"q_elliptic", "q_aux", "table_type" };
};
class GoblinTranslator : public Arithmetization</*NUM_WIRES =*/81, /*num_selectors =*/0> {

class GoblinTranslator {
public:
// Dirty hack
using Selectors = bool;
using FF = curve::BN254::ScalarField;
static constexpr size_t NUM_WIRES = 81;
static constexpr size_t num_selectors = 0;
};
} // namespace arithmetization
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ namespace proof_system {
* @param b_variable_idx Index of a variable in class b.
* @param msg Class tag.
* */
template <typename Arithmetization>
void CircuitBuilderBase<Arithmetization>::assert_equal(const uint32_t a_variable_idx,
const uint32_t b_variable_idx,
std::string const& msg)
template <typename FF>
void CircuitBuilderBase<FF>::assert_equal(const uint32_t a_variable_idx,
const uint32_t b_variable_idx,
std::string const& msg)
{
assert_valid_variables({ a_variable_idx, b_variable_idx });
bool values_equal = (get_variable(a_variable_idx) == get_variable(b_variable_idx));
Expand Down Expand Up @@ -43,8 +43,6 @@ void CircuitBuilderBase<Arithmetization>::assert_equal(const uint32_t a_variable
real_variable_tags[a_real_idx] = real_variable_tags[b_real_idx];
}
// Standard honk/ plonk instantiation
template class CircuitBuilderBase<arithmetization::Standard<barretenberg::fr>>;
template class CircuitBuilderBase<arithmetization::Standard<grumpkin::fr>>;
template class CircuitBuilderBase<arithmetization::Ultra<barretenberg::fr>>;
template class CircuitBuilderBase<arithmetization::GoblinTranslator>;
template class CircuitBuilderBase<barretenberg::fr>;
template class CircuitBuilderBase<grumpkin::fr>;
} // namespace proof_system
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#pragma once
#include "barretenberg/common/slab_allocator.hpp"
#include "barretenberg/ecc/curves/bn254/fr.hpp"
#include "barretenberg/ecc/curves/grumpkin/grumpkin.hpp"
#include "barretenberg/proof_system/arithmetization/arithmetization.hpp"
Expand All @@ -12,25 +11,14 @@
namespace proof_system {
static constexpr uint32_t DUMMY_TAG = 0;

template <typename Arithmetization> class CircuitBuilderBase {
template <typename FF_> class CircuitBuilderBase {
public:
using FF = typename Arithmetization::FF;
using FF = FF_;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason to not just call it FF instead of doing this using?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is to allow access to FF via e.g. Standard::FF from outside of this class. This has always felt a bit hacky but I'm not aware of another way to access the template param.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gotcha, might not be anything better then, thanks.

using EmbeddedCurve =
std::conditional_t<std::same_as<FF, barretenberg::g1::coordinate_field>, curve::BN254, curve::Grumpkin>;

static constexpr size_t NUM_WIRES = Arithmetization::NUM_WIRES;
// Keeping NUM_WIRES, at least temporarily, for backward compatibility
static constexpr size_t program_width = Arithmetization::NUM_WIRES;
static constexpr size_t num_selectors = Arithmetization::num_selectors;

// TODO(Cody): These are plonk-specific and could be specified in the plonk flavors.
// Also, there is loose coupling with the vectors of SelectorProperties
std::vector<std::string> selector_names_;
size_t num_gates = 0;

std::array<std::vector<uint32_t, barretenberg::ContainerSlabAllocator<uint32_t>>, NUM_WIRES> wires;
typename Arithmetization::Selectors selectors;

std::vector<uint32_t> public_inputs;
std::vector<FF> variables;
std::unordered_map<uint32_t, std::string> variable_names;
Expand All @@ -57,26 +45,14 @@ template <typename Arithmetization> class CircuitBuilderBase {
static constexpr uint32_t REAL_VARIABLE = UINT32_MAX - 1;
static constexpr uint32_t FIRST_VARIABLE_IN_CLASS = UINT32_MAX - 2;

// Enum values spaced in increments of 30-bits (multiples of 2 ** 30).
// TODO(#216)(Adrian): This is unused, and this type of hard coded data should be avoided
// Cody: This is used by compute_wire_copy_cycles in Plonk.
// enum WireType { LEFT = 0U, RIGHT = (1U << 30U), OUTPUT = (1U << 31U), FOURTH = 0xc0000000 };

CircuitBuilderBase(std::vector<std::string> selector_names, size_t size_hint = 0)
: selector_names_(std::move(selector_names))
CircuitBuilderBase(size_t size_hint = 0)
{
variables.reserve(size_hint * 3);
variable_names.reserve(size_hint * 3);
next_var_index.reserve(size_hint * 3);
prev_var_index.reserve(size_hint * 3);
real_variable_index.reserve(size_hint * 3);
real_variable_tags.reserve(size_hint * 3);
// We set selectors type to bool, when we don't actually use them
if constexpr (!std::is_same<typename Arithmetization::Selectors, bool>::value) {
for (auto& p : selectors) {
p.reserve(size_hint);
}
}
}

CircuitBuilderBase(const CircuitBuilderBase& other) = default;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,15 @@ namespace proof_system {
* microlimb.
*
*/
class GoblinTranslatorCircuitBuilder : public CircuitBuilderBase<arithmetization::GoblinTranslator> {
class GoblinTranslatorCircuitBuilder : public CircuitBuilderBase<barretenberg::fr> {
// We don't need templating for Goblin
using Fr = barretenberg::fr;
using Fq = barretenberg::fq;
using Arithmetization = arithmetization::GoblinTranslator;

public:
static constexpr size_t NUM_WIRES = Arithmetization::NUM_WIRES;

/**
* We won't need these standard gates that are defined as virtual in circuit builder base
*
Expand Down Expand Up @@ -324,6 +327,8 @@ class GoblinTranslatorCircuitBuilder : public CircuitBuilderBase<arithmetization
// The input we evaluate polynomials on
Fq evaluation_input_x;

std::array<std::vector<uint32_t, barretenberg::ContainerSlabAllocator<uint32_t>>, NUM_WIRES> wires;

/**
* @brief Construct a new Goblin Translator Circuit Builder object
*
Expand All @@ -334,11 +339,11 @@ class GoblinTranslatorCircuitBuilder : public CircuitBuilderBase<arithmetization
* @param evaluation_input_x_
*/
GoblinTranslatorCircuitBuilder(Fq batching_challenge_v_, Fq evaluation_input_x_)
: CircuitBuilderBase({}, DEFAULT_TRANSLATOR_VM_LENGTH)
: CircuitBuilderBase(DEFAULT_TRANSLATOR_VM_LENGTH)
, batching_challenge_v(batching_challenge_v_)
, evaluation_input_x(evaluation_input_x_)
{
add_variable(FF::zero());
add_variable(Fr::zero());
for (auto& wire : wires) {
wire.emplace_back(0);
}
Expand Down
Loading