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

fix: Release the size of goblin translator #4259

Merged
merged 5 commits into from
Jan 30, 2024
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 @@ -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
Loading