Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
24 changes: 0 additions & 24 deletions barretenberg/cpp/src/barretenberg/flavor/flavor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,30 +106,6 @@ enum class VKSerializationMode : std::uint8_t {
NO_METADATA // Serialize only commitments, no metadata
};

// Specifies the regions of the execution trace containing non-trivial wire values
struct ActiveRegionData {
void add_range(const size_t start, const size_t end)
{
BB_ASSERT_GTE(start, current_end, "Ranges should be non-overlapping and increasing.");
ranges.emplace_back(start, end);
for (size_t i = start; i < end; ++i) {
idxs.push_back(i);
}
current_end = end;
}

std::vector<std::pair<size_t, size_t>> get_ranges() const { return ranges; }
size_t get_idx(const size_t idx) const { return idxs[idx]; }
std::pair<size_t, size_t> get_range(const size_t idx) const { return ranges.at(idx); }
size_t size() const { return idxs.size(); }
size_t num_ranges() const { return ranges.size(); }

private:
std::vector<std::pair<size_t, size_t>> ranges; // active ranges [start_i, end_i) of the execution trace
std::vector<size_t> idxs; // full set of poly indices corresposponding to active ranges
size_t current_end{ 0 }; // end of last range; for ensuring monotonicity of ranges
};

/**
* @brief Dyadic trace size and public inputs metadata; Common between prover and verifier keys
*/
Expand Down
118 changes: 46 additions & 72 deletions barretenberg/cpp/src/barretenberg/honk/composer/permutation_lib.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,7 @@ namespace bb {

/**
* @brief cycle_node represents the idx of a value of the circuit.
* It will belong to a CyclicPermutation, such that all nodes in a CyclicPermutation
* must have the value.
* It will belong to a CyclicPermutation, which constrains all nodes in a CyclicPermutation to have the same value.
* The total number of constraints is always <2^32 since that is the type used to represent variables, so we can save
* space by using a type smaller than size_t.
*/
Expand All @@ -44,27 +43,15 @@ struct cycle_node {
};

/**
* @brief Permutations subgroup element structure is used to hold data necessary to construct permutation polynomials.
*
* @details All parameters define the evaluation of an id or sigma polynomial.
*
*/
struct permutation_subgroup_element {
uint32_t row_idx = 0;
uint8_t column_idx = 0;
bool is_public_input = false;
bool is_tag = false;
};

/**
* @brief Stores permutation mapping data for a single wire column
* @brief Stores permutation mapping data for a single wire column.
*
*/
struct Mapping {
std::shared_ptr<uint32_t[]> row_idx; // row idx of next entry in copy cycle
std::shared_ptr<uint8_t[]> col_idx; // column idx of next entry in copy cycle
std::shared_ptr<bool[]> is_public_input;
std::shared_ptr<bool[]> is_tag;
std::shared_ptr<bool[]> is_tag; // is this element a tag, (N.B. For each permutation polynomial (i.e., id_i or
// sigma_j), only one element per cycle is a tag.)
size_t _size = 0;

Mapping() = default;
Expand All @@ -80,7 +67,7 @@ struct Mapping {
{}
};

template <size_t NUM_WIRES, bool generalized> struct PermutationMapping {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

generalized toggled whether we compute the id polynomials or not. This was controlled by an IsUltraOrMega<Flavor>, which is all we'll use this for, so I think the logic is simpler when we remove this template parameter.

template <size_t NUM_WIRES> struct PermutationMapping {
std::array<Mapping, NUM_WIRES> sigmas;
std::array<Mapping, NUM_WIRES> ids;

Expand Down Expand Up @@ -108,16 +95,16 @@ template <size_t NUM_WIRES, bool generalized> struct PermutationMapping {
for (uint8_t col_idx = 0; col_idx < NUM_WIRES; ++col_idx) {
for (uint32_t row_idx = start; row_idx < end; ++row_idx) {
auto idx = static_cast<ptrdiff_t>(row_idx);
// sigma polynomials
sigmas[col_idx].row_idx[idx] = row_idx;
sigmas[col_idx].col_idx[idx] = col_idx;
sigmas[col_idx].is_public_input[idx] = false;
sigmas[col_idx].is_tag[idx] = false;
if constexpr (generalized) {
ids[col_idx].row_idx[idx] = row_idx;
ids[col_idx].col_idx[idx] = col_idx;
ids[col_idx].is_public_input[idx] = false;
ids[col_idx].is_tag[idx] = false;
}
// id polynomials
ids[col_idx].row_idx[idx] = row_idx;
ids[col_idx].col_idx[idx] = col_idx;
ids[col_idx].is_public_input[idx] = false;
ids[col_idx].is_tag[idx] = false;
}
}
});
Expand All @@ -129,27 +116,27 @@ using CyclicPermutation = std::vector<cycle_node>;
namespace {

Copy link
Contributor Author

Choose a reason for hiding this comment

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

for easier reasoning-about-indices

/**
* @brief Compute the traditional or generalized permutation mapping
* @brief Compute the permutation mapping
*
* @details Computes the mappings from which the sigma polynomials (and conditionally, the id polynomials)
* can be computed. The output is proving system agnostic.
* @details Computes the mappings from which the sigma and ID polynomials can be computed. The output is proving-system
* agnostic.
*
* @param circuit_constructor
* @param dyadic_size
* @param wire_copy_cycles
* @return PermutationMapping<Flavor::NUM_WIRES, generalized>
* @return PermutationMapping<Flavor::NUM_WIRES>
*/
template <typename Flavor, bool generalized>
PermutationMapping<Flavor::NUM_WIRES, generalized> compute_permutation_mapping(
template <typename Flavor>
PermutationMapping<Flavor::NUM_WIRES> compute_permutation_mapping(
const typename Flavor::CircuitBuilder& circuit_constructor,
const size_t dyadic_size,
const std::vector<CyclicPermutation>& wire_copy_cycles)
{

// Initialize the table of permutations so that every element points to itself
PermutationMapping<Flavor::NUM_WIRES, generalized> mapping(dyadic_size);
PermutationMapping<Flavor::NUM_WIRES> mapping(dyadic_size);

// Represents the idx of a variable in circuit_constructor.variables (needed only for generalized)
// Represents the idx of a variable in circuit_constructor.variables
std::span<const uint32_t> real_variable_tags = circuit_constructor.real_variable_tags;

// Go through each cycle
Expand All @@ -171,21 +158,19 @@ PermutationMapping<Flavor::NUM_WIRES, generalized> compute_permutation_mapping(
mapping.sigmas[current_column].row_idx[current_row] = next_row;
mapping.sigmas[current_column].col_idx[current_row] = next_column;

if constexpr (generalized) {
const bool first_node = (node_idx == 0);
const bool last_node = (next_node_idx == 0);

if (first_node) {
mapping.ids[current_column].is_tag[current_row] = true;
mapping.ids[current_column].row_idx[current_row] = real_variable_tags[cycle_idx];
}
if (last_node) {
mapping.sigmas[current_column].is_tag[current_row] = true;
// modify ID and sigma if we are either at the first or last node of a cycle. this involves both modifying
// `is_tag` and the `row_idx`.
const bool first_node = (node_idx == 0);
const bool last_node = (next_node_idx == 0);

// TODO(Zac): yikes, std::maps (tau) are expensive. Can we find a way to get rid of this?
mapping.sigmas[current_column].row_idx[current_row] =
circuit_constructor.tau().at(real_variable_tags[cycle_idx]);
}
if (first_node) {
mapping.ids[current_column].is_tag[current_row] = true;
mapping.ids[current_column].row_idx[current_row] = real_variable_tags[cycle_idx];
}
if (last_node) {
mapping.sigmas[current_column].is_tag[current_row] = true;
mapping.sigmas[current_column].row_idx[current_row] =
circuit_constructor.tau().at(real_variable_tags[cycle_idx]);
}
}
}
Expand All @@ -194,17 +179,14 @@ PermutationMapping<Flavor::NUM_WIRES, generalized> compute_permutation_mapping(
// permutation polynomials for details.
const auto num_public_inputs = static_cast<uint32_t>(circuit_constructor.num_public_inputs());

size_t pub_inputs_offset = 0;
if constexpr (IsUltraOrMegaHonk<Flavor>) {
pub_inputs_offset = circuit_constructor.blocks.pub_inputs.trace_offset();
}
auto pub_inputs_offset = circuit_constructor.blocks.pub_inputs.trace_offset();
for (size_t i = 0; i < num_public_inputs; ++i) {
uint32_t idx = static_cast<uint32_t>(i + pub_inputs_offset);
mapping.sigmas[0].row_idx[static_cast<ptrdiff_t>(idx)] = idx;
mapping.sigmas[0].col_idx[static_cast<ptrdiff_t>(idx)] = 0;
mapping.sigmas[0].is_public_input[static_cast<ptrdiff_t>(idx)] = true;
if (mapping.sigmas[0].is_tag[static_cast<ptrdiff_t>(idx)]) {
std::cerr << "MAPPING IS BOTH A TAG AND A PUBLIC INPUT" << std::endl;
std::cerr << "MAPPING IS BOTH A TAG AND A PUBLIC INPUT\n";
}
}
return mapping;
Expand All @@ -214,21 +196,19 @@ PermutationMapping<Flavor::NUM_WIRES, generalized> compute_permutation_mapping(
* @brief Compute Sigma/ID polynomials for Honk from a mapping and put into polynomial cache
*
* @details Given a mapping (effectively at table pointing witnesses to other witnesses) compute Sigma/ID polynomials in
* lagrange form and put them into the cache. This version is suitable for traditional and generalized permutations.
* lagrange form and put them into the cache.
*
* @param permutation_polynomials sigma or ID poly
* @param permutation_mappings
* @param active_region_data specifies regions of execution trace with non-trivial values
*/
template <typename Flavor>
void compute_honk_style_permutation_lagrange_polynomials_from_mapping(
const RefSpan<typename Flavor::Polynomial>& permutation_polynomials,
const std::array<Mapping, Flavor::NUM_WIRES>& permutation_mappings,
ActiveRegionData& active_region_data)
const std::array<Mapping, Flavor::NUM_WIRES>& permutation_mappings)
{
using FF = typename Flavor::FF;

size_t domain_size = active_region_data.size();
size_t domain_size = permutation_polynomials[0].size();

// SEPARATOR ensures that the evaluations of `id_i` (`sigma_i`) and `id_j`(`sigma_j`) polynomials on the boolean
// hypercube do not intersect for i != j.
Expand All @@ -243,7 +223,8 @@ void compute_honk_style_permutation_lagrange_polynomials_from_mapping(
const size_t start = thread_data.start[j];
const size_t end = thread_data.end[j];
for (size_t i = start; i < end; ++i) {
const size_t poly_idx = active_region_data.get_idx(i);
const size_t poly_idx =
i + 1; // Sigma/ID polynomials are allocated starting at index 1 (shiftable), so offset by 1
const auto idx = static_cast<ptrdiff_t>(poly_idx);
const auto& current_row_idx = permutation_mappings[wire_idx].row_idx[idx];
const auto& current_col_idx = permutation_mappings[wire_idx].col_idx[idx];
Expand All @@ -253,7 +234,7 @@ void compute_honk_style_permutation_lagrange_polynomials_from_mapping(
// We intentionally want to break the cycles of the public input variables.
// During the witness generation, the left and right wire polynomials at idx i contain the i-th
// public input. Let n = SEPARATOR. The CyclicPermutation created for these variables
// always start with (i) -> (n+i), followed by the indices of the variables in the "real" gates. We
// always starts with (i) -> (n+i), followed by the indices of the variables in the "real" gates. We
// make i point to -(i+1), so that the only way of repairing the cycle is add the mapping
// -(i+1) -> (n+i)
// These indices are chosen so they can easily be computed by the verifier. They can expect
Expand All @@ -276,33 +257,26 @@ void compute_honk_style_permutation_lagrange_polynomials_from_mapping(
} // namespace

/**
* @brief Compute Honk style generalized permutation sigmas and ids and add to prover_instance, where the
* copy_cycles are pre-computed sets of wire addresses whose values should be copy constrained.
* @brief Compute Honk-style permutation sigma/id polynomials and add to prover_instance, where the
* copy_cycles are pre-computed sets of wire addresses whose values should be copy-constrained.
*/
template <typename Flavor>
void compute_permutation_argument_polynomials(const typename Flavor::CircuitBuilder& circuit,
typename Flavor::ProverPolynomials& polynomials,
const std::vector<CyclicPermutation>& copy_cycles,
ActiveRegionData& active_region_data)
const std::vector<CyclicPermutation>& copy_cycles)
{
constexpr bool generalized = IsUltraOrMegaHonk<Flavor>;
const size_t polynomial_size = polynomials.get_polynomial_size();
auto mapping = compute_permutation_mapping<Flavor, generalized>(circuit, polynomial_size, copy_cycles);
auto mapping = compute_permutation_mapping<Flavor>(circuit, polynomial_size, copy_cycles);

// Compute Honk-style sigma and ID polynomials from the corresponding mappings
{

BB_BENCH_NAME("compute_honk_style_permutation_lagrange_polynomials_from_mapping");

compute_honk_style_permutation_lagrange_polynomials_from_mapping<Flavor>(
polynomials.get_sigmas(), mapping.sigmas, active_region_data);
compute_honk_style_permutation_lagrange_polynomials_from_mapping<Flavor>(polynomials.get_sigmas(),
mapping.sigmas);
}
{

BB_BENCH_NAME("compute_honk_style_permutation_lagrange_polynomials_from_mapping");

compute_honk_style_permutation_lagrange_polynomials_from_mapping<Flavor>(
polynomials.get_ids(), mapping.ids, active_region_data);
compute_honk_style_permutation_lagrange_polynomials_from_mapping<Flavor>(polynomials.get_ids(), mapping.ids);
}
}

Expand Down
Loading
Loading