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 (
0 commit comments