Skip to content

Commit

Permalink
fix: Release the size of goblin translator (#4259)
Browse files Browse the repository at this point in the history
Goblin Translator was fixed to have a mini-circuit size of 2048, which
led to errors for larger circuits.
  • Loading branch information
Rumata888 authored Jan 30, 2024
1 parent 728c5ac commit 6e1d958
Show file tree
Hide file tree
Showing 8 changed files with 58 additions and 55 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -563,17 +563,17 @@ template <typename Curve> class ZeroMorphVerifier_ {
// If applicable, add contribution from concatenated polynomial commitments
// Note: this is an implementation detail related to Goblin Translator and is not part of the standard protocol.
if (!concatenation_groups_commitments.empty()) {
size_t CONCATENATION_INDEX = concatenation_groups_commitments[0].size();
size_t MINICIRCUIT_N = N / CONCATENATION_INDEX;
size_t CONCATENATION_GROUP_SIZE = concatenation_groups_commitments[0].size();
size_t MINICIRCUIT_N = N / CONCATENATION_GROUP_SIZE;
std::vector<FF> x_shifts;
auto current_x_shift = x_challenge;
auto x_to_minicircuit_n = x_challenge.pow(MINICIRCUIT_N);
for (size_t i = 0; i < CONCATENATION_INDEX; ++i) {
for (size_t i = 0; i < CONCATENATION_GROUP_SIZE; ++i) {
x_shifts.emplace_back(current_x_shift);
current_x_shift *= x_to_minicircuit_n;
}
for (auto& concatenation_group_commitment : concatenation_groups_commitments) {
for (size_t i = 0; i < CONCATENATION_INDEX; ++i) {
for (size_t i = 0; i < CONCATENATION_GROUP_SIZE; ++i) {
scalars.emplace_back(rho_pow * x_shifts[i]);
commitments.emplace_back(concatenation_group_commitment[i]);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,13 @@ class GoblinTranslator {
// None of this parameters can be changed

// How many mini_circuit_size polynomials are concatenated in one concatenated_*
static constexpr size_t CONCATENATION_INDEX = 16;
static constexpr size_t CONCATENATION_GROUP_SIZE = 16;

// The number of concatenated_* wires
static constexpr size_t NUM_CONCATENATED_WIRES = 4;

// Actual circuit size
static constexpr size_t FULL_CIRCUIT_SIZE = MINI_CIRCUIT_SIZE * CONCATENATION_INDEX;
static constexpr size_t FULL_CIRCUIT_SIZE = MINI_CIRCUIT_SIZE * CONCATENATION_GROUP_SIZE;

// Number of wires
static constexpr size_t NUM_WIRES = CircuitBuilder::NUM_WIRES;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,10 @@ template <typename Flavor, typename StorageHandle> void compute_concatenated_pol
// Resulting concatenated polynomials
auto targets = proving_key->get_concatenated_constraints();

// Targets have to be full-sized polynomials. We can compute the mini circuit size from them by dividing by
// concatenation index
const size_t MINI_CIRCUIT_SIZE = targets[0].size() / Flavor::CONCATENATION_GROUP_SIZE;
ASSERT(MINI_CIRCUIT_SIZE * Flavor::CONCATENATION_GROUP_SIZE == targets[0].size());
// A function that produces 1 concatenated polynomial
// TODO(#756): This can be rewritten to use more cores. Currently uses at maximum the number of concatenated
// polynomials (4 in Goblin Translator)
Expand All @@ -201,8 +205,8 @@ template <typename Flavor, typename StorageHandle> void compute_concatenated_pol
for (size_t j = 0; j < my_group.size(); j++) {
auto starting_write_offset = current_target.begin();
auto finishing_read_offset = my_group[j].begin();
std::advance(starting_write_offset, j * Flavor::MINI_CIRCUIT_SIZE);
std::advance(finishing_read_offset, Flavor::MINI_CIRCUIT_SIZE);
std::advance(starting_write_offset, j * MINI_CIRCUIT_SIZE);
std::advance(finishing_read_offset, MINI_CIRCUIT_SIZE);
// Copy into appropriate position in the concatenated polynomial
std::copy(my_group[j].begin(), finishing_read_offset, starting_write_offset);
}
Expand Down Expand Up @@ -233,16 +237,17 @@ template <typename Flavor, typename StorageHandle> void compute_concatenated_pol
* @param proving_key
*/
template <typename Flavor, typename StorageHandle>
void compute_goblin_translator_range_constraint_ordered_polynomials(StorageHandle* proving_key)
void compute_goblin_translator_range_constraint_ordered_polynomials(StorageHandle* proving_key,
size_t mini_circuit_dyadic_size)
{

using FF = typename Flavor::FF;

// Get constants
constexpr auto sort_step = Flavor::SORT_STEP;
constexpr auto num_concatenated_wires = Flavor::NUM_CONCATENATED_WIRES;
constexpr auto full_circuit_size = Flavor::FULL_CIRCUIT_SIZE;
constexpr auto mini_circuit_size = Flavor::MINI_CIRCUIT_SIZE;
const auto mini_circuit_size = mini_circuit_dyadic_size;
const auto full_circuit_size = mini_circuit_dyadic_size * Flavor::CONCATENATION_GROUP_SIZE;

// The value we have to end polynomials with
constexpr uint32_t max_value = (1 << Flavor::MICRO_LIMB_BITS) - 1;
Expand All @@ -251,7 +256,7 @@ void compute_goblin_translator_range_constraint_ordered_polynomials(StorageHandl
constexpr size_t sorted_elements_count = (max_value / sort_step) + 1 + (max_value % sort_step == 0 ? 0 : 1);

// Check if we can construct these polynomials
static_assert((num_concatenated_wires + 1) * sorted_elements_count < full_circuit_size);
ASSERT((num_concatenated_wires + 1) * sorted_elements_count < full_circuit_size);

// First use integers (easier to sort)
std::vector<size_t> sorted_elements(sorted_elements_count);
Expand All @@ -278,7 +283,7 @@ void compute_goblin_translator_range_constraint_ordered_polynomials(StorageHandl
// Get the group and the main target vector
auto my_group = concatenation_groups[i];
auto& current_vector = ordered_vectors_uint[i];
current_vector.resize(Flavor::FULL_CIRCUIT_SIZE);
current_vector.resize(full_circuit_size);

// Calculate how much space there is for values from the original polynomials
auto free_space_before_runway = full_circuit_size - sorted_elements_count;
Expand All @@ -287,7 +292,7 @@ void compute_goblin_translator_range_constraint_ordered_polynomials(StorageHandl
size_t extra_denominator_offset = i * sorted_elements_count;

// Go through each polynomial in the concatenation group
for (size_t j = 0; j < Flavor::CONCATENATION_INDEX; j++) {
for (size_t j = 0; j < Flavor::CONCATENATION_GROUP_SIZE; j++) {

// Calculate the offset in the target vector
auto current_offset = j * mini_circuit_size;
Expand Down Expand Up @@ -362,12 +367,14 @@ void compute_goblin_translator_range_constraint_ordered_polynomials(StorageHandl
* contains 5 MAX_VALUE, 5 (MAX_VALUE-STEP),... values
*
* @param key Proving key where we will save the polynomials
* @param dyadic_circuit_size The full size of the circuit
*/
template <typename Flavor> inline void compute_extra_range_constraint_numerator(auto proving_key)
template <typename Flavor>
inline void compute_extra_range_constraint_numerator(auto proving_key, size_t dyadic_circuit_size)
{

// Get the full goblin circuits size (this is the length of concatenated range constraint polynomials)
auto full_circuit_size = Flavor::FULL_CIRCUIT_SIZE;
auto full_circuit_size = dyadic_circuit_size;
auto sort_step = Flavor::SORT_STEP;
auto num_concatenated_wires = Flavor::NUM_CONCATENATED_WIRES;

Expand Down Expand Up @@ -403,8 +410,10 @@ template <typename Flavor> inline void compute_extra_range_constraint_numerator(
* @brief Compute odd and even largrange polynomials (up to mini_circuit length) and put them in the polynomial cache
*
* @param key Proving key where we will save the polynomials
* @param mini_circuit_dyadic_size The size of the part of the circuit where the computation of translated value happens
*/
template <typename Flavor> inline void compute_lagrange_polynomials_for_goblin_translator(auto proving_key)
template <typename Flavor>
inline void compute_lagrange_polynomials_for_goblin_translator(auto proving_key, size_t mini_circuit_dyadic_size)

{
const size_t n = proving_key->circuit_size;
Expand All @@ -413,15 +422,15 @@ template <typename Flavor> inline void compute_lagrange_polynomials_for_goblin_t
typename Flavor::Polynomial lagrange_polynomial_second(n);
typename Flavor::Polynomial lagrange_polynomial_second_to_last_in_minicircuit(n);

for (size_t i = 1; i < Flavor::MINI_CIRCUIT_SIZE - 1; i += 2) {
for (size_t i = 1; i < mini_circuit_dyadic_size - 1; i += 2) {
lagrange_polynomial_odd_in_minicircuit[i] = 1;
lagrange_polynomial_even_in_minicircut[i + 1] = 1;
}
proving_key->lagrange_odd_in_minicircuit = lagrange_polynomial_odd_in_minicircuit.share();

proving_key->lagrange_even_in_minicircuit = lagrange_polynomial_even_in_minicircut.share();
lagrange_polynomial_second[1] = 1;
lagrange_polynomial_second_to_last_in_minicircuit[Flavor::MINI_CIRCUIT_SIZE - 2] = 1;
lagrange_polynomial_second_to_last_in_minicircuit[mini_circuit_dyadic_size - 2] = 1;
proving_key->lagrange_second_to_last_in_minicircuit = lagrange_polynomial_second_to_last_in_minicircuit.share();
proving_key->lagrange_second = lagrange_polynomial_second.share();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ class GoblinTranslatorCircuitBuilder : public CircuitBuilderBase<bb::fr> {

};

// Basic goblin translator has the minicircuit size of 2048, so optimize for that case
// Basic goblin translator has the minimum minicircuit size of 2048, so optimize for that case
// For context, minicircuit is the part of the final polynomials fed into the proving system, where we have all the
// arithmetic logic. However, the full circuit is several times larger (we use a trick to bring down the degree of
// the permutation argument)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,22 +33,14 @@ using Transcript = typename Flavor::Transcript;

void GoblinTranslatorComposer::compute_circuit_size_parameters(CircuitBuilder& circuit_builder)
{
const size_t num_gates = circuit_builder.num_gates;

// number of populated rows in the execution trace
size_t num_rows_populated_in_execution_trace = num_gates;

// Goblin translator circuits always have a predefined size and are structured as a VM (no concept of selectors)
ASSERT(MINI_CIRCUIT_SIZE >= num_rows_populated_in_execution_trace);

total_num_gates = std::max(MINI_CIRCUIT_SIZE, num_rows_populated_in_execution_trace);
total_num_gates = std::max(circuit_builder.num_gates, MINIMUM_MINI_CIRCUIT_SIZE);

// Next power of 2
mini_circuit_dyadic_size = circuit_builder.get_circuit_subgroup_size(total_num_gates);

// The actual circuit size is several times bigger than the trace in the builder, because we use concatenation to
// bring the degree of relations down, while extending the length.
dyadic_circuit_size = mini_circuit_dyadic_size * Flavor::CONCATENATION_INDEX;
dyadic_circuit_size = mini_circuit_dyadic_size * Flavor::CONCATENATION_GROUP_SIZE;
}

/**
Expand Down Expand Up @@ -189,7 +181,7 @@ void GoblinTranslatorComposer::compute_witness(CircuitBuilder& circuit_builder)
// We also contruct ordered polynomials, which have the same values as concatenated ones + enough values to bridge
// the range from 0 to maximum range defined by the range constraint.
bb::honk::permutation_library::compute_goblin_translator_range_constraint_ordered_polynomials<Flavor>(
proving_key.get());
proving_key.get(), mini_circuit_dyadic_size);

computed_witness = true;
}
Expand Down Expand Up @@ -273,11 +265,13 @@ std::shared_ptr<typename Flavor::ProvingKey> GoblinTranslatorComposer::compute_p

// Compute polynomials with odd and even indices set to 1 up to the minicircuit margin + lagrange polynomials at
// second and second to last indices in the minicircuit
bb::honk::permutation_library::compute_lagrange_polynomials_for_goblin_translator<Flavor>(proving_key.get());
bb::honk::permutation_library::compute_lagrange_polynomials_for_goblin_translator<Flavor>(proving_key.get(),
mini_circuit_dyadic_size);

// Compute the numerator for the permutation argument with several repetitions of steps bridging 0 and maximum range
// constraint
bb::honk::permutation_library::compute_extra_range_constraint_numerator<Flavor>(proving_key.get());
bb::honk::permutation_library::compute_extra_range_constraint_numerator<Flavor>(proving_key.get(),
dyadic_circuit_size);

return proving_key;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@ class GoblinTranslatorComposer {
using VerifierCommitmentKey = typename Flavor::VerifierCommitmentKey;
using Polynomial = typename Flavor::Polynomial;
using Transcript = BaseTranscript;
static constexpr size_t MINI_CIRCUIT_SIZE = Flavor::MINI_CIRCUIT_SIZE;

static constexpr std::string_view NAME_STRING = "GoblinTranslator";
static constexpr size_t NUM_WIRES = CircuitBuilder::NUM_WIRES;
// The minimum size of the mini-circuit (or sorted constraints won't work)
static constexpr size_t MINIMUM_MINI_CIRCUIT_SIZE = 2048;
std::shared_ptr<ProvingKey> proving_key;
std::shared_ptr<VerificationKey> verification_key;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,6 @@ class GoblinTranslatorProver {
using Curve = typename Flavor::Curve;
using Transcript = typename Flavor::Transcript;

static size_t constexpr MINI_CIRCUIT_SIZE = Flavor::MINI_CIRCUIT_SIZE;
static size_t constexpr FULL_CIRCUIT_SIZE = Flavor::FULL_CIRCUIT_SIZE;

public:
explicit GoblinTranslatorProver(const std::shared_ptr<ProvingKey>& input_key,
const std::shared_ptr<CommitmentKey>& commitment_key,
Expand Down
Loading

0 comments on commit 6e1d958

Please sign in to comment.