Skip to content
This repository was archived by the owner on Feb 17, 2025. It is now read-only.

Commit 3141ef4

Browse files
committed
Fixed hash decomposition component.
1 parent 85edb97 commit 3141ef4

File tree

6 files changed

+176
-188
lines changed

6 files changed

+176
-188
lines changed

include/nil/blueprint/components/hashes/sha2/plonk/decomposition.hpp

Lines changed: 130 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// Copyright (c) 2021 Nikita Kaskov <[email protected]>
44
// Copyright (c) 2022 Alisa Cherniaeva <[email protected]>
55
// Copyright (c) 2022 Ekaterina Chukavina <[email protected]>
6+
// Copyright (c) 2023 Dmitrii Tabalin <[email protected]>
67
//
78
// MIT License
89
//
@@ -80,11 +81,11 @@ namespace nil {
8081

8182
constexpr static std::size_t get_rows_amount(std::size_t witness_amount,
8283
std::size_t lookup_column_amount) {
83-
return 3;
84+
return 4;
8485
}
8586

8687
const std::size_t rows_amount = get_rows_amount(this->witness_amount(), 0);
87-
constexpr static const std::size_t gates_amount = 1;
88+
constexpr static const std::size_t gates_amount = 2;
8889

8990
struct input_type {
9091
std::array<var, 2> data;
@@ -98,14 +99,14 @@ namespace nil {
9899
std::array<var, 8> output;
99100

100101
result_type(const decomposition &component, std::uint32_t start_row_index) {
101-
output = {var(component.W(0), start_row_index + 1, false),
102-
var(component.W(1), start_row_index + 1, false),
103-
var(component.W(2), start_row_index + 1, false),
104-
var(component.W(3), start_row_index + 1, false),
105-
var(component.W(4), start_row_index + 1, false),
102+
output = {var(component.W(6), start_row_index + 1, false),
106103
var(component.W(5), start_row_index + 1, false),
107-
var(component.W(6), start_row_index + 1, false),
108-
var(component.W(7), start_row_index + 1, false)};
104+
var(component.W(4), start_row_index + 1, false),
105+
var(component.W(3), start_row_index + 1, false),
106+
var(component.W(6), start_row_index + 3, false),
107+
var(component.W(5), start_row_index + 3, false),
108+
var(component.W(4), start_row_index + 3, false),
109+
var(component.W(3), start_row_index + 3, false)};
109110
}
110111

111112
std::vector<var> all_vars() const {
@@ -130,6 +131,13 @@ namespace nil {
130131
std::initializer_list<typename component_type::public_input_container_type::value_type>
131132
public_inputs) :
132133
component_type(witnesses, constants, public_inputs, get_manifest()) {};
134+
135+
std::map<std::string, std::size_t> component_lookup_tables(){
136+
std::map<std::string, std::size_t> lookup_tables;
137+
lookup_tables["sha256_sparse_base4/first_column"] = 0; // REQUIRED_TABLE
138+
139+
return lookup_tables;
140+
}
133141
};
134142

135143
template<typename BlueprintFieldType, typename ArithmetizationParams>
@@ -146,77 +154,126 @@ namespace nil {
146154
const typename plonk_native_decomposition<BlueprintFieldType, ArithmetizationParams>::input_type
147155
instance_input,
148156
const std::uint32_t start_row_index) {
157+
using integral_type = typename BlueprintFieldType::integral_type;
149158

150-
std::size_t row = start_row_index;
151-
std::array<typename BlueprintFieldType::integral_type, 2> data = {
152-
typename BlueprintFieldType::integral_type(var_value(assignment, instance_input.data[0]).data),
153-
typename BlueprintFieldType::integral_type(var_value(assignment, instance_input.data[1]).data)};
154-
std::array<typename BlueprintFieldType::integral_type, 16> range_chunks;
159+
std::array<integral_type, 2> data = {
160+
integral_type(var_value(assignment, instance_input.data[0]).data),
161+
integral_type(var_value(assignment, instance_input.data[1]).data)};
162+
std::array<std::array<std::array<integral_type, 3>, 4>, 2> range_chunks;
163+
std::array<std::array<integral_type, 4>, 2> output_chunks;
155164
std::size_t shift = 0;
156165

157-
for (std::size_t i = 0; i < 8; i++) {
158-
range_chunks[i] = (data[0] >> shift) & ((65536) - 1);
159-
assignment.witness(component.W(i), row) = range_chunks[i];
160-
range_chunks[i + 8] = (data[1] >> shift) & ((65536) - 1);
161-
assignment.witness(component.W(i), row + 2) = range_chunks[i + 8];
162-
shift += 16;
166+
for (std::size_t data_idx = 0; data_idx < 2; data_idx++) {
167+
for (std::size_t chunk_idx = 0; chunk_idx < 4; chunk_idx++) {
168+
output_chunks[data_idx][chunk_idx] = (data[data_idx] >> (chunk_idx * 32)) & 0xFFFFFFFF;
169+
// subchunks are 14, 14, and 4 bits long respectively
170+
range_chunks[data_idx][chunk_idx][0] =
171+
(output_chunks[data_idx][chunk_idx] & 0b11111111111111000000000000000000) >> 18;
172+
range_chunks[data_idx][chunk_idx][1] =
173+
(output_chunks[data_idx][chunk_idx] & 0b00000000000000111111111111110000) >> 4;
174+
range_chunks[data_idx][chunk_idx][2] =
175+
(output_chunks[data_idx][chunk_idx] & 0b00000000000000000000000000001111);
176+
BOOST_ASSERT(
177+
output_chunks[data_idx][chunk_idx] ==
178+
range_chunks[data_idx][chunk_idx][0] * (1 << 18) +
179+
range_chunks[data_idx][chunk_idx][1] * (1 << 4) +
180+
range_chunks[data_idx][chunk_idx][2]);
181+
}
182+
}
183+
for (std::size_t data_idx = 0; data_idx < 2; data_idx++) {
184+
const std::size_t first_row = start_row_index + 2 * data_idx,
185+
second_row = start_row_index + 2 * data_idx + 1;
186+
// placing subchunks for first three chunks
187+
for (std::size_t chunk_idx = 0; chunk_idx < 3; chunk_idx++) {
188+
for (std::size_t subchunk_idx = 0; subchunk_idx < 3; subchunk_idx++) {
189+
assignment.witness(component.W(3 * chunk_idx + subchunk_idx), first_row) =
190+
range_chunks[data_idx][chunk_idx][subchunk_idx];
191+
}
192+
}
193+
// placing subchunk for the last chunk
194+
for (std::size_t subchunk_idx = 0; subchunk_idx < 3; subchunk_idx++) {
195+
assignment.witness(component.W(subchunk_idx), second_row) =
196+
range_chunks[data_idx][3][subchunk_idx];
197+
}
198+
// placing chunks
199+
for (std::size_t chunk_idx = 0; chunk_idx < 4; chunk_idx++) {
200+
assignment.witness(component.W(3 + chunk_idx), second_row) =
201+
output_chunks[data_idx][chunk_idx];
202+
}
203+
// placing the original data
204+
assignment.witness(component.W(7), second_row) = data[data_idx];
163205
}
164-
165-
assignment.witness(component.W(8), row) = data[0];
166-
assignment.witness(component.W(8), row + 2) = data[1];
167-
168-
assignment.witness(component.W(3), row + 1) = range_chunks[1] * (65536) + range_chunks[0];
169-
assignment.witness(component.W(2), row + 1) = range_chunks[3] * (65536) + range_chunks[2];
170-
assignment.witness(component.W(1), row + 1) = range_chunks[5] * (65536) + range_chunks[4];
171-
assignment.witness(component.W(0), row + 1) = range_chunks[7] * (65536) + range_chunks[6];
172-
173-
assignment.witness(component.W(7), row + 1) = range_chunks[9] * (65536) + range_chunks[8];
174-
assignment.witness(component.W(6), row + 1) = range_chunks[11] * (65536) + range_chunks[10];
175-
assignment.witness(component.W(5), row + 1) = range_chunks[13] * (65536) + range_chunks[12];
176-
assignment.witness(component.W(4), row + 1) = range_chunks[15] * (65536) + range_chunks[14];
177206

178207
return typename plonk_native_decomposition<BlueprintFieldType, ArithmetizationParams>::result_type(
179208
component, start_row_index);
180209
}
181210

182211
template<typename BlueprintFieldType, typename ArithmetizationParams>
183-
std::size_t generate_gates(
212+
std::array<std::size_t, 2> generate_gates(
184213
const plonk_native_decomposition<BlueprintFieldType, ArithmetizationParams> &component,
185214
circuit<crypto3::zk::snark::plonk_constraint_system<BlueprintFieldType, ArithmetizationParams>> &bp,
186215
assignment<crypto3::zk::snark::plonk_constraint_system<BlueprintFieldType, ArithmetizationParams>>
187216
&assignment,
188217
const typename plonk_native_decomposition<BlueprintFieldType, ArithmetizationParams>::input_type
189-
&instance_input) {
218+
&instance_input,
219+
const typename lookup_library<BlueprintFieldType>::left_reserved_type &lookup_tables_indices) {
190220

191221
using var = typename plonk_native_decomposition<BlueprintFieldType, ArithmetizationParams>::var;
192-
193-
auto constraint_1 =
194-
var(component.W(8), -1) - (var(component.W(3), 0) + var(component.W(2), 0) * 0x100000000_cppui255 +
195-
var(component.W(1), 0) * 0x10000000000000000_cppui255 +
196-
var(component.W(0), 0) * 0x1000000000000000000000000_cppui255);
197-
auto constraint_2 =
198-
var(component.W(8), 1) - (var(component.W(7), 0) + var(component.W(6), 0) * 0x100000000_cppui255 +
199-
var(component.W(5), 0) * 0x10000000000000000_cppui255 +
200-
var(component.W(4), 0) * 0x1000000000000000000000000_cppui255);
201-
auto constraint_3 = var(component.W(3), 0) -
202-
(var(component.W(0), -1) + var(component.W(1), -1) * (65536));
203-
auto constraint_4 = var(component.W(2), 0) -
204-
(var(component.W(2), -1) + var(component.W(3), -1) * (65536));
205-
auto constraint_5 = var(component.W(1), 0) -
206-
(var(component.W(4), -1) + var(component.W(5), -1) * (65536));
207-
auto constraint_6 = var(component.W(0), 0) -
208-
(var(component.W(6), -1) + var(component.W(7), -1) * (65536));
209-
auto constraint_7 = var(component.W(7), 0) -
210-
(var(component.W(0), +1) + var(component.W(1), +1) * (65536));
211-
auto constraint_8 = var(component.W(6), 0) -
212-
(var(component.W(2), +1) + var(component.W(3), +1) * (65536));
213-
auto constraint_9 = var(component.W(5), 0) -
214-
(var(component.W(4), +1) + var(component.W(5), +1) * (65536));
215-
auto constraint_10 = var(component.W(4), 0) -
216-
(var(component.W(6), +1) + var(component.W(7), +1) * (65536));
217-
return bp.add_gate(
218-
{constraint_1, constraint_2, constraint_3, constraint_4, constraint_5, constraint_6,
219-
constraint_7, constraint_8, constraint_9, constraint_10});
222+
using lookup_constraint = crypto3::zk::snark::plonk_lookup_constraint<BlueprintFieldType>;
223+
using constraint = crypto3::zk::snark::plonk_constraint<BlueprintFieldType>;
224+
225+
const typename BlueprintFieldType::integral_type one = 1;
226+
std::array<std::size_t, 2> selectors;
227+
228+
std::vector<lookup_constraint> subchunk_lookup_constraints(12);
229+
// lookup constraints for the first three chunks
230+
for (std::size_t chunk_idx = 0; chunk_idx < 3; chunk_idx++) {
231+
subchunk_lookup_constraints[3 * chunk_idx] =
232+
{lookup_tables_indices.at("sha256_sparse_base4/first_column"),
233+
{var(component.W(3 * chunk_idx), -1)}};
234+
subchunk_lookup_constraints[3 * chunk_idx + 1] =
235+
{lookup_tables_indices.at("sha256_sparse_base4/first_column"),
236+
{var(component.W(3 * chunk_idx + 1), -1)}};
237+
subchunk_lookup_constraints[3 * chunk_idx + 2] =
238+
{lookup_tables_indices.at("sha256_sparse_base4/first_column"),
239+
{1024 * var(component.W(3 * chunk_idx + 2), -1)}};
240+
}
241+
// lookup constraints for the last chunk
242+
subchunk_lookup_constraints[9] =
243+
{lookup_tables_indices.at("sha256_sparse_base4/first_column"),
244+
{var(component.W(0), 0)}};
245+
subchunk_lookup_constraints[10] =
246+
{lookup_tables_indices.at("sha256_sparse_base4/first_column"),
247+
{var(component.W(1), 0)}};
248+
subchunk_lookup_constraints[11] =
249+
{lookup_tables_indices.at("sha256_sparse_base4/first_column"),
250+
{1024 * var(component.W(2), 0)}};
251+
252+
selectors[0] = bp.add_lookup_gate(subchunk_lookup_constraints);
253+
254+
std::vector<constraint> chunk_constraints(5);
255+
// chunk sum constraints for the first three chunks
256+
for (std::size_t chunk_idx = 0; chunk_idx < 3; chunk_idx++) {
257+
chunk_constraints[chunk_idx] =
258+
var(component.W(3 * chunk_idx), -1) * (1 << 18) +
259+
var(component.W(3 * chunk_idx + 1), -1) * (1 << 4) +
260+
var(component.W(3 * chunk_idx + 2), -1) -
261+
var(component.W(3 + chunk_idx), 0);
262+
}
263+
// chunk sum constraints for the last chunk
264+
chunk_constraints[3] =
265+
var(component.W(0), 0) * (1 << 18) +
266+
var(component.W(1), 0) * (1 << 4) +
267+
var(component.W(2), 0) -
268+
var(component.W(6), 0);
269+
// chunk sum constraint for input
270+
chunk_constraints[4] =
271+
var(component.W(3), 0) + var(component.W(4), 0) * (one << 32) +
272+
var(component.W(5), 0) * (one << 64) + var(component.W(6), 0) * (one << 96) -
273+
var(component.W(7), 0);
274+
selectors[1] = bp.add_gate(chunk_constraints);
275+
276+
return selectors;
220277
}
221278

222279
template<typename BlueprintFieldType, typename ArithmetizationParams>
@@ -230,11 +287,9 @@ namespace nil {
230287
const std::size_t start_row_index) {
231288

232289
using var = typename plonk_native_decomposition<BlueprintFieldType, ArithmetizationParams>::var;
233-
// CRITICAL: these copy constraints might not be sufficient, but are definitely required.
234-
// I've added copy constraints for the inputs, but internal ones might be missing
235-
// Proceed with care
236-
bp.add_copy_constraint({instance_input.data[0], var(component.W(8), start_row_index, false)});
237-
bp.add_copy_constraint({instance_input.data[1], var(component.W(8), start_row_index + 2, false)});
290+
291+
bp.add_copy_constraint({instance_input.data[0], var(component.W(7), start_row_index + 1, false)});
292+
bp.add_copy_constraint({instance_input.data[1], var(component.W(7), start_row_index + 3, false)});
238293
}
239294

240295
template<typename BlueprintFieldType, typename ArithmetizationParams>
@@ -248,10 +303,14 @@ namespace nil {
248303
&instance_input,
249304
const std::size_t start_row_index) {
250305

251-
std::size_t j = start_row_index + 1;
252-
std::size_t selector_index = generate_gates(component, bp, assignment, instance_input);
306+
std::array<std::size_t, 2> selector_indices =
307+
generate_gates(component, bp, assignment, instance_input, bp.get_reserved_indices());
308+
309+
assignment.enable_selector(selector_indices[0], start_row_index + 1);
310+
assignment.enable_selector(selector_indices[0], start_row_index + 3);
311+
assignment.enable_selector(selector_indices[1], start_row_index + 1);
312+
assignment.enable_selector(selector_indices[1], start_row_index + 3);
253313

254-
assignment.enable_selector(selector_index, j);
255314
generate_copy_constraints(component, bp, assignment, instance_input, start_row_index);
256315

257316
return typename plonk_native_decomposition<BlueprintFieldType, ArithmetizationParams>::result_type(

include/nil/blueprint/components/hashes/sha2/plonk/sha256.hpp

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -139,30 +139,6 @@ namespace nil {
139139
using lookup_table_definition = typename
140140
nil::crypto3::zk::snark::lookup_table_definition<BlueprintFieldType>;
141141

142-
std::vector<std::shared_ptr<lookup_table_definition>> component_custom_lookup_tables(){
143-
std::vector<std::shared_ptr<lookup_table_definition>> result = {};
144-
145-
auto sparse_values_base4 = std::shared_ptr<lookup_table_definition>(new typename sha256_process_type::sparse_values_base4_table());
146-
result.push_back(sparse_values_base4);
147-
148-
auto sparse_values_base7 = std::shared_ptr<lookup_table_definition>(new typename sha256_process_type::sparse_values_base7_table());
149-
result.push_back(sparse_values_base7);
150-
151-
auto maj = std::shared_ptr<lookup_table_definition>(new typename sha256_process_type::maj_function_table());
152-
result.push_back(maj);
153-
154-
auto reverse_sparse_sigmas_base4 = std::shared_ptr<lookup_table_definition>(new typename sha256_process_type::reverse_sparse_sigmas_base4_table());
155-
result.push_back(reverse_sparse_sigmas_base4);
156-
157-
auto reverse_sparse_sigmas_base7 = std::shared_ptr<lookup_table_definition>(new typename sha256_process_type::reverse_sparse_sigmas_base7_table());
158-
result.push_back(reverse_sparse_sigmas_base7);
159-
160-
auto ch = std::shared_ptr<lookup_table_definition>(new typename sha256_process_type::ch_function_table());
161-
result.push_back(ch);
162-
163-
return result;
164-
}
165-
166142
std::map<std::string, std::size_t> component_lookup_tables(){
167143
std::map<std::string, std::size_t> lookup_tables;
168144
lookup_tables["sha256_sparse_base4/full"] = 0; // REQUIRED_TABLE

0 commit comments

Comments
 (0)