barretenberg
Loading...
Searching...
No Matches
keccak_chi.hpp
1#pragma once
2
3#include "../types.hpp"
4#include "barretenberg/common/constexpr_utils.hpp"
5#include "barretenberg/numeric/bitop/pow.hpp"
6
7namespace plookup {
8namespace keccak_tables {
9
59class Chi {
60 public:
61 // 1 + 2a - b + c => a xor (~b & c)
62 static constexpr uint64_t CHI_NORMALIZATION_TABLE[5]{
63 0, 0, 1, 1, 0,
64 };
65
66 static constexpr uint64_t BASE = 11;
67
68 // effective base = maximum value each input 'quasi-bit' can reach at this stage of the Keccak algo
69 // (we use base11 as it's a bit more efficient to use a consistent base across the entire Keccak hash algorithm.
70 // The THETA round requires base-11 in order to most efficiently convert XOR operations into algebraic operations)
71 static constexpr uint64_t EFFECTIVE_BASE = 5;
72
73 // TABLE_BITS defines table size. More bits = fewer lookups but larger tables!
74 static constexpr uint64_t TABLE_BITS = 6;
75
84 static std::array<barretenberg::fr, 2> get_chi_renormalization_values(const std::array<uint64_t, 2> key)
85 {
86 uint64_t accumulator = 0;
87 uint64_t input = key[0];
88 uint64_t base_shift = 1;
89 constexpr uint64_t divisor_exponent = (64 % TABLE_BITS == 0) ? (TABLE_BITS - 1) : (64 % TABLE_BITS) - 1;
90 constexpr uint64_t divisor = numeric::pow64(BASE, divisor_exponent);
91 while (input > 0) {
92 uint64_t slice = input % BASE;
93 uint64_t bit = CHI_NORMALIZATION_TABLE[static_cast<size_t>(slice)];
94 accumulator += (bit * base_shift);
95 input /= BASE;
96 base_shift *= BASE;
97 }
98
99 return { barretenberg::fr(accumulator), barretenberg::fr(accumulator / divisor) };
100 }
101
108 static constexpr std::array<uint64_t, TABLE_BITS> get_scaled_bases()
109 {
110 std::array<uint64_t, TABLE_BITS> result;
111 uint64_t acc = 1;
112 for (size_t i = 0; i < TABLE_BITS; ++i) {
113 result[i] = acc;
114 acc *= BASE;
115 }
116 return result;
117 }
118
132 static std::array<uint64_t, 3> get_column_values_for_next_row(std::array<size_t, TABLE_BITS>& counts)
133 {
134 static constexpr auto scaled_bases = get_scaled_bases();
135
136 // want the most significant bit of the 64-bit integer, when this table is used on the most significant slice
137 constexpr uint64_t divisor_exponent = (64 % TABLE_BITS == 0) ? (TABLE_BITS - 1) : (64 % TABLE_BITS) - 1;
138 constexpr uint64_t divisor = numeric::pow64(static_cast<uint64_t>(BASE), divisor_exponent);
139
140 for (size_t i = 0; i < TABLE_BITS; ++i) {
141 if (counts[i] == EFFECTIVE_BASE - 1) {
142 counts[i] = 0;
143 } else {
144 counts[i] += 1;
145 break;
146 }
147 }
148
149 uint64_t value = 0;
150 uint64_t normalized_value = 0;
151 for (size_t i = 0; i < TABLE_BITS; ++i) {
152 value += counts[i] * scaled_bases[i];
153 normalized_value += (CHI_NORMALIZATION_TABLE[counts[i]]) * scaled_bases[i];
154 }
155 return { value, normalized_value, normalized_value / divisor };
156 }
157
167 static BasicTable generate_chi_renormalization_table(BasicTableId id, const size_t table_index)
168 {
169 BasicTable table;
170 table.id = id;
171 table.table_index = table_index;
172 table.use_twin_keys = false;
173 table.size = numeric::pow64(static_cast<uint64_t>(EFFECTIVE_BASE), TABLE_BITS);
174
175 std::array<size_t, TABLE_BITS> counts{};
176 std::array<uint64_t, 3> column_values{ 0, 0, 0 };
177 for (size_t i = 0; i < table.size; ++i) {
178 table.column_1.emplace_back(column_values[0]);
179 table.column_2.emplace_back(column_values[1]);
180 table.column_3.emplace_back(column_values[2]);
181 column_values = get_column_values_for_next_row(counts);
182 }
183
184 table.get_values_from_key = &get_chi_renormalization_values;
185
186 constexpr uint64_t step_size = numeric::pow64(static_cast<uint64_t>(BASE), TABLE_BITS);
187 table.column_1_step_size = barretenberg::fr(step_size);
188 table.column_2_step_size = barretenberg::fr(step_size);
189 table.column_3_step_size = barretenberg::fr(0);
190 return table;
191 }
192
234 static MultiTable get_chi_output_table(const MultiTableId id = KECCAK_CHI_OUTPUT)
235 {
236 constexpr size_t num_tables_per_multitable =
237 (64 / TABLE_BITS) + (64 % TABLE_BITS == 0 ? 0 : 1); // 64 bits, 8 bits per entry
238
239 // column_multiplier is used to define the gap between rows when deriving colunn values via relative differences
240 uint64_t column_multiplier = numeric::pow64(BASE, TABLE_BITS);
241 MultiTable table(column_multiplier, column_multiplier, 0, num_tables_per_multitable);
242
243 table.id = id;
244 for (size_t i = 0; i < num_tables_per_multitable; ++i) {
245 table.slice_sizes.emplace_back(numeric::pow64(BASE, TABLE_BITS));
246 table.lookup_ids.emplace_back(KECCAK_CHI);
247 table.get_table_values.emplace_back(&get_chi_renormalization_values);
248 }
249 return table;
250 }
251};
252} // namespace keccak_tables
253} // namespace plookup
Generates plookup tables required for CHI round of Keccak hash function.
Definition: keccak_chi.hpp:59
static MultiTable get_chi_output_table(const MultiTableId id=KECCAK_CHI_OUTPUT)
Create the CHI MultiTable used by plookup to generate a sequence of lookups.
Definition: keccak_chi.hpp:234
static std::array< barretenberg::fr, 2 > get_chi_renormalization_values(const std::array< uint64_t, 2 > key)
Given a table input value, return the table output value.
Definition: keccak_chi.hpp:84
static std::array< uint64_t, 3 > get_column_values_for_next_row(std::array< size_t, TABLE_BITS > &counts)
Get column values for next row of plookup table. Used to generate plookup table row values.
Definition: keccak_chi.hpp:132
static constexpr std::array< uint64_t, TABLE_BITS > get_scaled_bases()
Precompute an array of base multipliers (11^i for i = [0, ..., TABLE_BITS - 1]) Code is slightly fast...
Definition: keccak_chi.hpp:108
static BasicTable generate_chi_renormalization_table(BasicTableId id, const size_t table_index)
Generate the CHI plookup table.
Definition: keccak_chi.hpp:167
The structure contains the most basic table serving one function (for, example an xor table)
Definition: types.hpp:263
Definition: types.hpp:124