barretenberg
Loading...
Searching...
No Matches
keccak_rho.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
55template <size_t TABLE_BITS = 0, size_t LANE_INDEX = 0> class Rho {
56
57 public:
58 static constexpr uint64_t BASE = 11;
59
60 // EFFECTIVE_BASE = maximum value each input 'quasi-bit' can reach at this stage in the Keccak algo
61 // (we use base11 as it's a bit more efficient to use a consistent base across the entire Keccak hash algorithm.
62 // The THETA round requires base-11 in order to most efficiently convert XOR operations into algebraic operations)
63 static constexpr uint64_t EFFECTIVE_BASE = 3;
64
65 // The maximum number of bits of a Rho lookup table (TABLE_BITS <= MAXIMUM_MULTITABLE_BITS).
66 // Used in get_rho_output_table
67 static constexpr size_t MAXIMUM_MULTITABLE_BITS = 8;
68
69 // Rotation offsets, y vertically, x horizontally: r[y * 5 + x]
70 static constexpr std::array<size_t, 25> ROTATIONS = {
71 0, 1, 62, 28, 27, 36, 44, 6, 55, 20, 3, 10, 43, 25, 39, 41, 45, 15, 21, 8, 18, 2, 61, 56, 14,
72 };
73
74 static constexpr uint64_t RHO_NORMALIZATION_TABLE[3]{
75 0,
76 1,
77 0,
78 };
79
88 static std::array<barretenberg::fr, 2> get_rho_renormalization_values(const std::array<uint64_t, 2> key)
89 {
90 uint64_t accumulator = 0;
91 uint64_t input = key[0];
92 uint64_t base_shift = 1;
93 constexpr uint64_t divisor_exponent = TABLE_BITS - 1;
94 constexpr uint64_t divisor = numeric::pow64(BASE, divisor_exponent);
95 while (input > 0) {
96 uint64_t slice = input % BASE;
97 uint64_t bit = RHO_NORMALIZATION_TABLE[static_cast<size_t>(slice)];
98 accumulator += (bit * base_shift);
99 input /= BASE;
100 base_shift *= BASE;
101 }
102
103 return { barretenberg::fr(accumulator), barretenberg::fr(accumulator / divisor) };
104 }
105
112 static constexpr std::array<uint64_t, TABLE_BITS> get_scaled_bases()
113 {
114 std::array<uint64_t, TABLE_BITS> result;
115 uint64_t acc = 1;
116 for (size_t i = 0; i < TABLE_BITS; ++i) {
117 result[i] = acc;
118 acc *= BASE;
119 }
120 return result;
121 }
122
136 static std::array<uint64_t, 3> get_column_values_for_next_row(std::array<size_t, TABLE_BITS>& counts)
137 {
138 static constexpr auto scaled_bases = get_scaled_bases();
139
140 // want the most significant bit of the 64-bit integer, when this table is used on the most significant slice
141 constexpr uint64_t divisor = numeric::pow64(static_cast<uint64_t>(BASE), TABLE_BITS - 1);
142
143 for (size_t i = 0; i < TABLE_BITS; ++i) {
144 if (counts[i] == EFFECTIVE_BASE - 1) {
145 counts[i] = 0;
146 } else {
147 counts[i] += 1;
148 break;
149 }
150 }
151
152 uint64_t value = 0;
153 uint64_t normalized_value = 0;
154 for (size_t i = 0; i < TABLE_BITS; ++i) {
155 value += counts[i] * scaled_bases[i];
156 normalized_value += (RHO_NORMALIZATION_TABLE[counts[i]]) * scaled_bases[i];
157 }
158 return { value, normalized_value, normalized_value / divisor };
159 }
160
168 static BasicTable generate_rho_renormalization_table(BasicTableId id, const size_t table_index)
169 {
170 BasicTable table;
171 table.id = id;
172 table.table_index = table_index;
173 table.use_twin_keys = false;
174 table.size = numeric::pow64(static_cast<uint64_t>(EFFECTIVE_BASE), TABLE_BITS);
175
176 std::array<size_t, TABLE_BITS> counts{};
177 std::array<uint64_t, 3> column_values{ 0, 0, 0 };
178
179 for (size_t i = 0; i < table.size; ++i) {
180 table.column_1.emplace_back(column_values[0]);
181 table.column_2.emplace_back(column_values[1]);
182 table.column_3.emplace_back(column_values[2]);
183 column_values = get_column_values_for_next_row(counts);
184 }
185
186 table.get_values_from_key = &get_rho_renormalization_values;
187
188 uint64_t step_size = numeric::pow64(static_cast<uint64_t>(BASE), TABLE_BITS);
189 table.column_1_step_size = barretenberg::fr(step_size);
190 table.column_2_step_size = barretenberg::fr(step_size);
191 table.column_3_step_size = barretenberg::fr(0);
192 return table;
193 }
194
232 static MultiTable get_rho_output_table(const MultiTableId id = KECCAK_NORMALIZE_AND_ROTATE)
233 {
234 constexpr size_t left_bits = ROTATIONS[LANE_INDEX];
235 constexpr size_t right_bits = 64 - ROTATIONS[LANE_INDEX];
236 constexpr size_t num_left_tables =
237 left_bits / MAXIMUM_MULTITABLE_BITS + (left_bits % MAXIMUM_MULTITABLE_BITS > 0 ? 1 : 0);
238 constexpr size_t num_right_tables =
239 right_bits / MAXIMUM_MULTITABLE_BITS + (right_bits % MAXIMUM_MULTITABLE_BITS > 0 ? 1 : 0);
240
241 MultiTable table;
242 table.id = id;
243
244 table.column_1_step_sizes.push_back(1);
245 table.column_2_step_sizes.push_back(1);
246 table.column_3_step_sizes.push_back(1);
247
248 // generate table selector values for the 'right' slice
249 barretenberg::constexpr_for<0, num_right_tables, 1>([&]<size_t i> {
250 constexpr size_t num_bits_processed = (i * MAXIMUM_MULTITABLE_BITS);
251 constexpr size_t bit_slice = (num_bits_processed + MAXIMUM_MULTITABLE_BITS > right_bits)
252 ? right_bits % MAXIMUM_MULTITABLE_BITS
253 : MAXIMUM_MULTITABLE_BITS;
254
255 constexpr uint64_t scaled_base = numeric::pow64(BASE, bit_slice);
256 if (i == num_right_tables - 1) {
257 table.column_1_step_sizes.push_back(scaled_base);
258 table.column_2_step_sizes.push_back(0);
259 table.column_3_step_sizes.push_back(0);
260 } else {
261 table.column_1_step_sizes.push_back(scaled_base);
262 table.column_2_step_sizes.push_back(scaled_base);
263 table.column_3_step_sizes.push_back(0);
264 }
265
266 table.slice_sizes.push_back(scaled_base);
267 table.get_table_values.emplace_back(&get_rho_renormalization_values);
268 table.lookup_ids.push_back((BasicTableId)((size_t)KECCAK_RHO_1 + (bit_slice - 1)));
269 });
270
271 // generate table selector values for the 'left' slice
272 barretenberg::constexpr_for<0, num_left_tables, 1>([&]<size_t i> {
273 constexpr size_t num_bits_processed = (i * MAXIMUM_MULTITABLE_BITS);
274
275 constexpr size_t bit_slice = (num_bits_processed + MAXIMUM_MULTITABLE_BITS > left_bits)
276 ? left_bits % MAXIMUM_MULTITABLE_BITS
277 : MAXIMUM_MULTITABLE_BITS;
278 constexpr uint64_t scaled_base = numeric::pow64(BASE, bit_slice);
279
280 if (i != num_left_tables - 1) {
281 table.column_1_step_sizes.push_back(scaled_base);
282 table.column_2_step_sizes.push_back(scaled_base);
283 table.column_3_step_sizes.push_back(0);
284 }
285
286 table.slice_sizes.push_back(scaled_base);
287 table.get_table_values.emplace_back(&get_rho_renormalization_values);
288 table.lookup_ids.push_back((BasicTableId)((size_t)KECCAK_RHO_1 + (bit_slice - 1)));
289 });
290
291 return table;
292 }
293};
294
295} // namespace keccak_tables
296} // namespace plookup
Generate the plookup tables used for the RHO round of the Keccak hash algorithm.
Definition: keccak_rho.hpp:55
static BasicTable generate_rho_renormalization_table(BasicTableId id, const size_t table_index)
Generate plookup table that normalizes a TABLE_BITS-slice of a base-11 integer and extracts the msb.
Definition: keccak_rho.hpp:168
static std::array< barretenberg::fr, 2 > get_rho_renormalization_values(const std::array< uint64_t, 2 > key)
Given a table input value, return the table output value.
Definition: keccak_rho.hpp:88
static MultiTable get_rho_output_table(const MultiTableId id=KECCAK_NORMALIZE_AND_ROTATE)
Create the Rho MultiTable used by plookup to generate a sequence of lookups.
Definition: keccak_rho.hpp:232
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_rho.hpp:112
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_rho.hpp:136
The structure contains the most basic table serving one function (for, example an xor table)
Definition: types.hpp:263
Definition: types.hpp:124