Skip to content

Commit

Permalink
feat(ultrahonk): Added a simple filler table to minimize the amount o…
Browse files Browse the repository at this point in the history
…f entries used to make UltraHonk polynomials non-zero (AztecProtocol/barretenberg#531)

feat(ultrahonk): Added a simple filler table to minimize the amount of entries used to make UltraHonk polynomials non-zero
  • Loading branch information
Rumata888 authored Jun 15, 2023
1 parent d22e0a9 commit 656a23c
Show file tree
Hide file tree
Showing 8 changed files with 126 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,11 @@ void UltraHonkComposerHelper_<Flavor>::compute_witness(CircuitConstructor& circu
// TODO(luke): The +1 size for z_lookup is not necessary and can lead to confusion. Resolve.
polynomial z_lookup(subgroup_size + 1); // Only instantiated in this function; nothing assigned.

// Save space for adding random scalars in the s polynomial later. The subtracted 1 allows us to insert a `1` at the
// end, to ensure the evaluations (and hence coefficients) aren't all 0. See ComposerBase::compute_proving_key_base
// for further explanation, as a similar trick is done there.
size_t count = subgroup_size - tables_size - lookups_size - s_randomness - 1;
// TODO(kesha): Look at this once we figure out how we do ZK (previously we had roots cut out, so just added
// randomness)
// The size of empty space in sorted polynomials
size_t count = subgroup_size - tables_size - lookups_size;
ASSERT(count > 0); // We need at least 1 row of zeroes for the permutation argument
for (size_t i = 0; i < count; ++i) {
s_1[i] = 0;
s_2[i] = 0;
Expand Down Expand Up @@ -115,18 +116,7 @@ void UltraHonkComposerHelper_<Flavor>::compute_witness(CircuitConstructor& circu
}
}

// Initialise the `s_randomness` positions in the s polynomials with 0.
// These will be the positions where we will be adding random scalars to add zero knowledge
// to plookup (search for `Blinding` in plonk/proof_system/widgets/random_widgets/plookup_widget_impl.hpp
// ProverPlookupWidget::compute_sorted_list_polynomial())
for (size_t i = 0; i < s_randomness; ++i) {
s_1[count] = 0;
s_2[count] = 0;
s_3[count] = 0;
s_4[count] = 0;
++count;
}

// Polynomial memory is zeroed out when constructed with size hint, so we don't have to initialize trailing space
proving_key->sorted_1 = s_1;
proving_key->sorted_2 = s_2;
proving_key->sorted_3 = s_3;
Expand Down Expand Up @@ -230,7 +220,7 @@ std::shared_ptr<typename Flavor::ProvingKey> UltraHonkComposerHelper_<Flavor>::c
polynomial poly_q_table_column_3(subgroup_size);
polynomial poly_q_table_column_4(subgroup_size);

size_t offset = subgroup_size - tables_size - s_randomness - 1;
size_t offset = subgroup_size - tables_size;

// Create lookup selector polynomials which interpolate each table column.
// Our selector polys always need to interpolate the full subgroup size, so here we offset so as to
Expand Down Expand Up @@ -259,15 +249,7 @@ std::shared_ptr<typename Flavor::ProvingKey> UltraHonkComposerHelper_<Flavor>::c
}
}

// Initialise the last `s_randomness` positions in table polynomials with 0. We don't need to actually randomise
// the table polynomials.
for (size_t i = 0; i < s_randomness; ++i) {
poly_q_table_column_1[offset] = 0;
poly_q_table_column_2[offset] = 0;
poly_q_table_column_3[offset] = 0;
poly_q_table_column_4[offset] = 0;
++offset;
}
// Polynomial memory is zeroed out when constructed with size hint, so we don't have to initialize trailing space

// // In the case of using UltraPlonkComposer for a circuit which does _not_ make use of any lookup tables, all
// four
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,6 @@ template <UltraFlavor Flavor> class UltraHonkComposerHelper_ {
bool contains_recursive_proof = false;
bool computed_witness = false;

// This variable controls the amount with which the lookup table and witness values need to be shifted
// above to make room for adding randomness into the permutation and witness polynomials in the plookup widget.
// This must be (num_roots_cut_out_of_the_vanishing_polynomial - 1), since the variable num_roots_cut_out_of_
// vanishing_polynomial cannot be trivially fetched here, I am directly setting this to 4 - 1 = 3.
static constexpr size_t s_randomness = 3;

explicit UltraHonkComposerHelper_(std::shared_ptr<srs::factories::CrsFactory> crs_factory)
: crs_factory_(std::move(crs_factory))
{}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,7 @@ class UltraHonkComposerTests : public ::testing::Test {
TEST_F(UltraHonkComposerTests, ANonZeroPolynomialIsAGoodPolynomial)
{
auto composer = UltraHonkComposer();

composer.add_gates_to_ensure_all_polys_are_non_zero();
// The composer should call add_gates_to_ensure_all_polys_are_non_zero by default

auto prover = composer.create_prover();
auto proof = prover.construct_proof();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,30 +93,24 @@ void UltraCircuitConstructor::add_gates_to_ensure_all_polys_are_non_zero()
create_big_add_gate({ zero_idx, zero_idx, zero_idx, one_idx, 0, 0, 0, 1, -1 });

// Take care of all polys related to lookups (q_lookup, tables, sorted, etc)
// by doing an arbitrary xor and an "and" lookup.
// by doing a dummy lookup with a special table.
// Note: the 4th table poly is the table index: this is not the value of the table
// type enum but rather the index of the table in the list of all tables utilized
// in the circuit. Therefore we naively need two different tables (indices 0, 1)
// to get a non-zero value in table_4. I assume this index is arbitrary and could
// start from 1 instead of 0?
// in the circuit. Therefore we naively need two different basic tables (indices 0, 1)
// to get a non-zero value in table_4.
// The multitable operates on 2-bit values, so the maximum is 3
uint32_t left_value = 3;
uint32_t right_value = 5;
uint32_t right_value = 3;

fr left_witness_value = fr{ left_value, 0, 0, 0 }.to_montgomery_form();
fr right_witness_value = fr{ right_value, 0, 0, 0 }.to_montgomery_form();

uint32_t left_witness_index = add_variable(left_witness_value);
uint32_t right_witness_index = add_variable(right_witness_value);

const auto and_accumulators = plookup::get_lookup_accumulators(
plookup::MultiTableId::UINT32_AND, left_witness_value, right_witness_value, true);
const auto xor_accumulators = plookup::get_lookup_accumulators(
plookup::MultiTableId::UINT32_XOR, left_witness_value, right_witness_value, true);

create_gates_from_plookup_accumulators(
plookup::MultiTableId::UINT32_AND, and_accumulators, left_witness_index, right_witness_index);
const auto dummy_accumulators = plookup::get_lookup_accumulators(
plookup::MultiTableId::HONK_DUMMY_MULTI, left_witness_value, right_witness_value, true);
create_gates_from_plookup_accumulators(
plookup::MultiTableId::UINT32_XOR, xor_accumulators, left_witness_index, right_witness_index);
plookup::MultiTableId::HONK_DUMMY_MULTI, dummy_accumulators, left_witness_index, right_witness_index);
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
#pragma once
/**
* @file dummy.hpp
* @author Rumata888
* @brief This file contains functions for the dummy tables that we use in UltraHonk to make table, sorted and lookup
* selector polynomials non-zero.
*
*/

#include "types.hpp"

namespace plookup {
namespace dummy_tables {

/**
* @brief Lookup the value corresponding to a specific key
*
* @details We need this function for when we are constructing the circuit and want to query the table. Since we need
* two basic tables to make the table polynomial have non-zero values, we instantiate two tables with the same function,
* but change it slightly through templating
*
* @tparam id The id of the basic table used to parametrize the values for 2 fake tables
* @param key The key that we are looking up
* @return std::array<barretenberg::fr, 2>
*/
template <uint64_t id> inline std::array<barretenberg::fr, 2> get_value_from_key(const std::array<uint64_t, 2> key)
{
return { key[0] * 3 + key[1] * 4 + id * 0x1337ULL, 0ULL };
}

/**
* @brief Generate the whole table
*
* @details This function is used to generate the whole table for the table polynomial. It's templated with id, since we
* generate 2 slightly different fake tables.
*
* @tparam table_id The id of the table this function is instantiated for
* @param id Table id that is the same for all circuits
* @param table_index The index for this table that is used in this circuit. 0, 1, ...
* @return A table of values
*/
template <uint64_t table_id>
inline BasicTable generate_honk_dummy_table(const BasicTableId id, const size_t table_index)
{

// We do the assertion, since this function is templated, but the general API for these functions contains the id,
// too. This helps us ensure that the correct instantion is used for a particular BasicTableId
ASSERT(table_id == static_cast<uint64_t>(id));
const size_t base = 1 << 1; // Probably has to be a power of 2
BasicTable table;
table.id = id;
table.table_index = table_index;
table.size = base * base;
table.use_twin_keys = true;
for (uint64_t i = 0; i < base; ++i) {
for (uint64_t j = 0; j < base; ++j) {
table.column_1.emplace_back(i);
table.column_2.emplace_back(j);
table.column_3.emplace_back(i * 3 + j * 4 + static_cast<uint64_t>(id) * 0x1337ULL);
}
}

table.get_values_from_key = &get_value_from_key<table_id>;

table.column_1_step_size = base;
table.column_2_step_size = base;
table.column_3_step_size = base;

return table;
}
/**
* @brief Create a multitable for filling UltraHonk polynomials with non-zero values
*
* @details Consists of 2 Basic tables that are almost identical. Each of those basic tables should only have 4 entries,
* so the overall overhead is just 8
*
*/
inline MultiTable get_honk_dummy_multitable()
{
const MultiTableId id = HONK_DUMMY_MULTI;
const size_t number_of_elements_in_argument = 1 << 1; // Probably has to be a power of 2
const size_t number_of_lookups = 2;
MultiTable table(number_of_elements_in_argument,
number_of_elements_in_argument,
number_of_elements_in_argument,
number_of_lookups);
table.id = id;
table.slice_sizes.emplace_back(number_of_elements_in_argument);
table.lookup_ids.emplace_back(HONK_DUMMY_BASIC1);
table.get_table_values.emplace_back(&get_value_from_key<HONK_DUMMY_BASIC1>);
table.slice_sizes.emplace_back(number_of_elements_in_argument);
table.lookup_ids.emplace_back(HONK_DUMMY_BASIC2);
table.get_table_values.emplace_back(&get_value_from_key<HONK_DUMMY_BASIC2>);
return table;
}
} // namespace dummy_tables
} // namespace plookup
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ void init_multi_tables()
MULTI_TABLES[(size_t)MultiTableId::KECCAK_NORMALIZE_AND_ROTATE + i] =
keccak_tables::Rho<8, i>::get_rho_output_table(MultiTableId::KECCAK_NORMALIZE_AND_ROTATE);
});
MULTI_TABLES[MultiTableId::HONK_DUMMY_MULTI] = dummy_tables::get_honk_dummy_multitable();
}
} // namespace

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "keccak/keccak_output.hpp"
#include "keccak/keccak_rho.hpp"
#include "keccak/keccak_theta.hpp"
#include "dummy.hpp"

namespace plookup {

Expand Down Expand Up @@ -242,6 +243,12 @@ inline BasicTable create_basic_table(const BasicTableId id, const size_t index)
case PEDERSEN_IV_BASE: {
return pedersen_tables::basic::generate_pedersen_iv_table(PEDERSEN_IV_BASE);
}
case HONK_DUMMY_BASIC1: {
return dummy_tables::generate_honk_dummy_table<HONK_DUMMY_BASIC1>(HONK_DUMMY_BASIC1, index);
}
case HONK_DUMMY_BASIC2: {
return dummy_tables::generate_honk_dummy_table<HONK_DUMMY_BASIC2>(HONK_DUMMY_BASIC2, index);
}
case KECCAK_INPUT: {
return keccak_tables::KeccakInput::generate_keccak_input_table(KECCAK_INPUT, index);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ enum BasicTableId {
PEDERSEN_1,
PEDERSEN_0,
PEDERSEN_IV_BASE,
HONK_DUMMY_BASIC1,
HONK_DUMMY_BASIC2,
KECCAK_INPUT,
KECCAK_THETA,
KECCAK_RHO,
Expand Down Expand Up @@ -136,6 +138,7 @@ enum MultiTableId {
BLAKE_XOR_ROTATE_8,
BLAKE_XOR_ROTATE_7,
PEDERSEN_IV,
HONK_DUMMY_MULTI,
KECCAK_THETA_OUTPUT,
KECCAK_CHI_OUTPUT,
KECCAK_FORMAT_INPUT,
Expand All @@ -145,6 +148,7 @@ enum MultiTableId {
};

struct MultiTable {
// Coefficients are accumulated products of corresponding step sizes until that point
std::vector<barretenberg::fr> column_1_coefficients;
std::vector<barretenberg::fr> column_2_coefficients;
std::vector<barretenberg::fr> column_3_coefficients;
Expand Down

0 comments on commit 656a23c

Please sign in to comment.