Skip to content

Commit b20b401

Browse files
authored
feat(ultrahonk): Added a simple filler table to minimize the amount of entries used to make UltraHonk polynomials non-zero (#531)
feat(ultrahonk): Added a simple filler table to minimize the amount of entries used to make UltraHonk polynomials non-zero
1 parent d7b1499 commit b20b401

File tree

8 files changed

+126
-48
lines changed

8 files changed

+126
-48
lines changed

cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.cpp

Lines changed: 8 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,11 @@ void UltraHonkComposerHelper_<Flavor>::compute_witness(CircuitConstructor& circu
5959
// TODO(luke): The +1 size for z_lookup is not necessary and can lead to confusion. Resolve.
6060
polynomial z_lookup(subgroup_size + 1); // Only instantiated in this function; nothing assigned.
6161

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

118-
// Initialise the `s_randomness` positions in the s polynomials with 0.
119-
// These will be the positions where we will be adding random scalars to add zero knowledge
120-
// to plookup (search for `Blinding` in plonk/proof_system/widgets/random_widgets/plookup_widget_impl.hpp
121-
// ProverPlookupWidget::compute_sorted_list_polynomial())
122-
for (size_t i = 0; i < s_randomness; ++i) {
123-
s_1[count] = 0;
124-
s_2[count] = 0;
125-
s_3[count] = 0;
126-
s_4[count] = 0;
127-
++count;
128-
}
129-
119+
// Polynomial memory is zeroed out when constructed with size hint, so we don't have to initialize trailing space
130120
proving_key->sorted_1 = s_1;
131121
proving_key->sorted_2 = s_2;
132122
proving_key->sorted_3 = s_3;
@@ -230,7 +220,7 @@ std::shared_ptr<typename Flavor::ProvingKey> UltraHonkComposerHelper_<Flavor>::c
230220
polynomial poly_q_table_column_3(subgroup_size);
231221
polynomial poly_q_table_column_4(subgroup_size);
232222

233-
size_t offset = subgroup_size - tables_size - s_randomness - 1;
223+
size_t offset = subgroup_size - tables_size;
234224

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

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

272254
// // In the case of using UltraPlonkComposer for a circuit which does _not_ make use of any lookup tables, all
273255
// four

cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.hpp

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,6 @@ template <UltraFlavor Flavor> class UltraHonkComposerHelper_ {
3838
bool contains_recursive_proof = false;
3939
bool computed_witness = false;
4040

41-
// This variable controls the amount with which the lookup table and witness values need to be shifted
42-
// above to make room for adding randomness into the permutation and witness polynomials in the plookup widget.
43-
// This must be (num_roots_cut_out_of_the_vanishing_polynomial - 1), since the variable num_roots_cut_out_of_
44-
// vanishing_polynomial cannot be trivially fetched here, I am directly setting this to 4 - 1 = 3.
45-
static constexpr size_t s_randomness = 3;
46-
4741
explicit UltraHonkComposerHelper_(std::shared_ptr<srs::factories::CrsFactory> crs_factory)
4842
: crs_factory_(std::move(crs_factory))
4943
{}

cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,7 @@ class UltraHonkComposerTests : public ::testing::Test {
7676
TEST_F(UltraHonkComposerTests, ANonZeroPolynomialIsAGoodPolynomial)
7777
{
7878
auto composer = UltraHonkComposer();
79-
80-
composer.add_gates_to_ensure_all_polys_are_non_zero();
79+
// The composer should call add_gates_to_ensure_all_polys_are_non_zero by default
8180

8281
auto prover = composer.create_prover();
8382
auto proof = prover.construct_proof();

cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.cpp

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -93,30 +93,24 @@ void UltraCircuitConstructor::add_gates_to_ensure_all_polys_are_non_zero()
9393
create_big_add_gate({ zero_idx, zero_idx, zero_idx, one_idx, 0, 0, 0, 1, -1 });
9494

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

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

108108
uint32_t left_witness_index = add_variable(left_witness_value);
109109
uint32_t right_witness_index = add_variable(right_witness_value);
110-
111-
const auto and_accumulators = plookup::get_lookup_accumulators(
112-
plookup::MultiTableId::UINT32_AND, left_witness_value, right_witness_value, true);
113-
const auto xor_accumulators = plookup::get_lookup_accumulators(
114-
plookup::MultiTableId::UINT32_XOR, left_witness_value, right_witness_value, true);
115-
116-
create_gates_from_plookup_accumulators(
117-
plookup::MultiTableId::UINT32_AND, and_accumulators, left_witness_index, right_witness_index);
110+
const auto dummy_accumulators = plookup::get_lookup_accumulators(
111+
plookup::MultiTableId::HONK_DUMMY_MULTI, left_witness_value, right_witness_value, true);
118112
create_gates_from_plookup_accumulators(
119-
plookup::MultiTableId::UINT32_XOR, xor_accumulators, left_witness_index, right_witness_index);
113+
plookup::MultiTableId::HONK_DUMMY_MULTI, dummy_accumulators, left_witness_index, right_witness_index);
120114
}
121115

122116
/**
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
#pragma once
2+
/**
3+
* @file dummy.hpp
4+
* @author Rumata888
5+
* @brief This file contains functions for the dummy tables that we use in UltraHonk to make table, sorted and lookup
6+
* selector polynomials non-zero.
7+
*
8+
*/
9+
10+
#include "types.hpp"
11+
12+
namespace plookup {
13+
namespace dummy_tables {
14+
15+
/**
16+
* @brief Lookup the value corresponding to a specific key
17+
*
18+
* @details We need this function for when we are constructing the circuit and want to query the table. Since we need
19+
* two basic tables to make the table polynomial have non-zero values, we instantiate two tables with the same function,
20+
* but change it slightly through templating
21+
*
22+
* @tparam id The id of the basic table used to parametrize the values for 2 fake tables
23+
* @param key The key that we are looking up
24+
* @return std::array<barretenberg::fr, 2>
25+
*/
26+
template <uint64_t id> inline std::array<barretenberg::fr, 2> get_value_from_key(const std::array<uint64_t, 2> key)
27+
{
28+
return { key[0] * 3 + key[1] * 4 + id * 0x1337ULL, 0ULL };
29+
}
30+
31+
/**
32+
* @brief Generate the whole table
33+
*
34+
* @details This function is used to generate the whole table for the table polynomial. It's templated with id, since we
35+
* generate 2 slightly different fake tables.
36+
*
37+
* @tparam table_id The id of the table this function is instantiated for
38+
* @param id Table id that is the same for all circuits
39+
* @param table_index The index for this table that is used in this circuit. 0, 1, ...
40+
* @return A table of values
41+
*/
42+
template <uint64_t table_id>
43+
inline BasicTable generate_honk_dummy_table(const BasicTableId id, const size_t table_index)
44+
{
45+
46+
// We do the assertion, since this function is templated, but the general API for these functions contains the id,
47+
// too. This helps us ensure that the correct instantion is used for a particular BasicTableId
48+
ASSERT(table_id == static_cast<uint64_t>(id));
49+
const size_t base = 1 << 1; // Probably has to be a power of 2
50+
BasicTable table;
51+
table.id = id;
52+
table.table_index = table_index;
53+
table.size = base * base;
54+
table.use_twin_keys = true;
55+
for (uint64_t i = 0; i < base; ++i) {
56+
for (uint64_t j = 0; j < base; ++j) {
57+
table.column_1.emplace_back(i);
58+
table.column_2.emplace_back(j);
59+
table.column_3.emplace_back(i * 3 + j * 4 + static_cast<uint64_t>(id) * 0x1337ULL);
60+
}
61+
}
62+
63+
table.get_values_from_key = &get_value_from_key<table_id>;
64+
65+
table.column_1_step_size = base;
66+
table.column_2_step_size = base;
67+
table.column_3_step_size = base;
68+
69+
return table;
70+
}
71+
/**
72+
* @brief Create a multitable for filling UltraHonk polynomials with non-zero values
73+
*
74+
* @details Consists of 2 Basic tables that are almost identical. Each of those basic tables should only have 4 entries,
75+
* so the overall overhead is just 8
76+
*
77+
*/
78+
inline MultiTable get_honk_dummy_multitable()
79+
{
80+
const MultiTableId id = HONK_DUMMY_MULTI;
81+
const size_t number_of_elements_in_argument = 1 << 1; // Probably has to be a power of 2
82+
const size_t number_of_lookups = 2;
83+
MultiTable table(number_of_elements_in_argument,
84+
number_of_elements_in_argument,
85+
number_of_elements_in_argument,
86+
number_of_lookups);
87+
table.id = id;
88+
table.slice_sizes.emplace_back(number_of_elements_in_argument);
89+
table.lookup_ids.emplace_back(HONK_DUMMY_BASIC1);
90+
table.get_table_values.emplace_back(&get_value_from_key<HONK_DUMMY_BASIC1>);
91+
table.slice_sizes.emplace_back(number_of_elements_in_argument);
92+
table.lookup_ids.emplace_back(HONK_DUMMY_BASIC2);
93+
table.get_table_values.emplace_back(&get_value_from_key<HONK_DUMMY_BASIC2>);
94+
return table;
95+
}
96+
} // namespace dummy_tables
97+
} // namespace plookup

cpp/src/barretenberg/proof_system/plookup_tables/plookup_tables.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ void init_multi_tables()
9696
MULTI_TABLES[(size_t)MultiTableId::KECCAK_NORMALIZE_AND_ROTATE + i] =
9797
keccak_tables::Rho<8, i>::get_rho_output_table(MultiTableId::KECCAK_NORMALIZE_AND_ROTATE);
9898
});
99+
MULTI_TABLES[MultiTableId::HONK_DUMMY_MULTI] = dummy_tables::get_honk_dummy_multitable();
99100
}
100101
} // namespace
101102

cpp/src/barretenberg/proof_system/plookup_tables/plookup_tables.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "keccak/keccak_output.hpp"
1515
#include "keccak/keccak_rho.hpp"
1616
#include "keccak/keccak_theta.hpp"
17+
#include "dummy.hpp"
1718

1819
namespace plookup {
1920

@@ -242,6 +243,12 @@ inline BasicTable create_basic_table(const BasicTableId id, const size_t index)
242243
case PEDERSEN_IV_BASE: {
243244
return pedersen_tables::basic::generate_pedersen_iv_table(PEDERSEN_IV_BASE);
244245
}
246+
case HONK_DUMMY_BASIC1: {
247+
return dummy_tables::generate_honk_dummy_table<HONK_DUMMY_BASIC1>(HONK_DUMMY_BASIC1, index);
248+
}
249+
case HONK_DUMMY_BASIC2: {
250+
return dummy_tables::generate_honk_dummy_table<HONK_DUMMY_BASIC2>(HONK_DUMMY_BASIC2, index);
251+
}
245252
case KECCAK_INPUT: {
246253
return keccak_tables::KeccakInput::generate_keccak_input_table(KECCAK_INPUT, index);
247254
}

cpp/src/barretenberg/proof_system/plookup_tables/types.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ enum BasicTableId {
8383
PEDERSEN_1,
8484
PEDERSEN_0,
8585
PEDERSEN_IV_BASE,
86+
HONK_DUMMY_BASIC1,
87+
HONK_DUMMY_BASIC2,
8688
KECCAK_INPUT,
8789
KECCAK_THETA,
8890
KECCAK_RHO,
@@ -136,6 +138,7 @@ enum MultiTableId {
136138
BLAKE_XOR_ROTATE_8,
137139
BLAKE_XOR_ROTATE_7,
138140
PEDERSEN_IV,
141+
HONK_DUMMY_MULTI,
139142
KECCAK_THETA_OUTPUT,
140143
KECCAK_CHI_OUTPUT,
141144
KECCAK_FORMAT_INPUT,
@@ -145,6 +148,7 @@ enum MultiTableId {
145148
};
146149

147150
struct MultiTable {
151+
// Coefficients are accumulated products of corresponding step sizes until that point
148152
std::vector<barretenberg::fr> column_1_coefficients;
149153
std::vector<barretenberg::fr> column_2_coefficients;
150154
std::vector<barretenberg::fr> column_3_coefficients;

0 commit comments

Comments
 (0)