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,15 +81,15 @@ 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 constexpr static std::size_t get_empty_rows_amount () {
8687 return 1 ;
8788 }
8889
8990 const std::size_t rows_amount = get_rows_amount(this ->witness_amount (), 0);
9091 const std::size_t empty_rows_amount = get_empty_rows_amount();
91- constexpr static const std::size_t gates_amount = 1 ;
92+ constexpr static const std::size_t gates_amount = 2 ;
9293
9394 struct input_type {
9495 std::array<var, 2 > data;
@@ -102,14 +103,14 @@ namespace nil {
102103 std::array<var, 8 > output;
103104
104105 result_type (const decomposition &component, std::uint32_t start_row_index) {
105- output = {var (component.W (0 ), start_row_index + 1 , false ),
106- var (component.W (1 ), start_row_index + 1 , false ),
107- var (component.W (2 ), start_row_index + 1 , false ),
108- var (component.W (3 ), start_row_index + 1 , false ),
109- var (component.W (4 ), start_row_index + 1 , false ),
106+ output = {var (component.W (6 ), start_row_index + 1 , false ),
110107 var (component.W (5 ), start_row_index + 1 , false ),
111- var (component.W (6 ), start_row_index + 1 , false ),
112- var (component.W (7 ), start_row_index + 1 , false )};
108+ var (component.W (4 ), start_row_index + 1 , false ),
109+ var (component.W (3 ), start_row_index + 1 , false ),
110+ var (component.W (6 ), start_row_index + 3 , false ),
111+ var (component.W (5 ), start_row_index + 3 , false ),
112+ var (component.W (4 ), start_row_index + 3 , false ),
113+ var (component.W (3 ), start_row_index + 3 , false )};
113114 }
114115
115116 result_type (const decomposition &component, std::uint32_t start_row_index, bool skip) {
@@ -172,6 +173,13 @@ namespace nil {
172173 }
173174 return output;
174175 }
176+
177+ std::map<std::string, std::size_t > component_lookup_tables () const {
178+ std::map<std::string, std::size_t > lookup_tables;
179+ lookup_tables[" sha256_sparse_base4/first_column" ] = 0 ; // REQUIRED_TABLE
180+
181+ return lookup_tables;
182+ }
175183 };
176184
177185 template <typename BlueprintFieldType>
@@ -188,34 +196,55 @@ namespace nil {
188196 const typename plonk_native_decomposition<BlueprintFieldType>::input_type
189197 instance_input,
190198 const std::uint32_t start_row_index) {
199+ using integral_type = typename BlueprintFieldType::integral_type;
191200
192- std::size_t row = start_row_index;
193- std::array< typename BlueprintFieldType::integral_type, 2 > data = {
194- typename BlueprintFieldType:: integral_type (var_value (assignment, instance_input.data [0 ]).data ),
195- typename BlueprintFieldType:: integral_type( var_value (assignment, instance_input. data [ 1 ]). data )} ;
196- std::array<typename BlueprintFieldType:: integral_type, 16 > range_chunks ;
201+ std::array<integral_type, 2 > data = {
202+ integral_type ( var_value (assignment, instance_input. data [ 0 ]). data ),
203+ integral_type (var_value (assignment, instance_input.data [1 ]).data )};
204+ std::array<std::array<std::array< integral_type, 3 >, 4 >, 2 > range_chunks ;
205+ std::array<std::array< integral_type, 4 >, 2 > output_chunks ;
197206 std::size_t shift = 0 ;
198207
199- for (std::size_t i = 0 ; i < 8 ; i++) {
200- range_chunks[i] = (data[0 ] >> shift) & ((65536 ) - 1 );
201- assignment.witness (component.W (i), row) = range_chunks[i];
202- range_chunks[i + 8 ] = (data[1 ] >> shift) & ((65536 ) - 1 );
203- assignment.witness (component.W (i), row + 2 ) = range_chunks[i + 8 ];
204- shift += 16 ;
208+ for (std::size_t data_idx = 0 ; data_idx < 2 ; data_idx++) {
209+ for (std::size_t chunk_idx = 0 ; chunk_idx < 4 ; chunk_idx++) {
210+ output_chunks[data_idx][chunk_idx] = (data[data_idx] >> (chunk_idx * 32 )) & 0xFFFFFFFF ;
211+ // subchunks are 14, 14, and 4 bits long respectively
212+ range_chunks[data_idx][chunk_idx][0 ] =
213+ (output_chunks[data_idx][chunk_idx] & 0b11111111111111000000000000000000 ) >> 18 ;
214+ range_chunks[data_idx][chunk_idx][1 ] =
215+ (output_chunks[data_idx][chunk_idx] & 0b00000000000000111111111111110000 ) >> 4 ;
216+ range_chunks[data_idx][chunk_idx][2 ] =
217+ (output_chunks[data_idx][chunk_idx] & 0b00000000000000000000000000001111 );
218+ BOOST_ASSERT (
219+ output_chunks[data_idx][chunk_idx] ==
220+ range_chunks[data_idx][chunk_idx][0 ] * (1 << 18 ) +
221+ range_chunks[data_idx][chunk_idx][1 ] * (1 << 4 ) +
222+ range_chunks[data_idx][chunk_idx][2 ]);
223+ }
224+ }
225+ for (std::size_t data_idx = 0 ; data_idx < 2 ; data_idx++) {
226+ const std::size_t first_row = start_row_index + 2 * data_idx,
227+ second_row = start_row_index + 2 * data_idx + 1 ;
228+ // placing subchunks for first three chunks
229+ for (std::size_t chunk_idx = 0 ; chunk_idx < 3 ; chunk_idx++) {
230+ for (std::size_t subchunk_idx = 0 ; subchunk_idx < 3 ; subchunk_idx++) {
231+ assignment.witness (component.W (3 * chunk_idx + subchunk_idx), first_row) =
232+ range_chunks[data_idx][chunk_idx][subchunk_idx];
233+ }
234+ }
235+ // placing subchunk for the last chunk
236+ for (std::size_t subchunk_idx = 0 ; subchunk_idx < 3 ; subchunk_idx++) {
237+ assignment.witness (component.W (subchunk_idx), second_row) =
238+ range_chunks[data_idx][3 ][subchunk_idx];
239+ }
240+ // placing chunks
241+ for (std::size_t chunk_idx = 0 ; chunk_idx < 4 ; chunk_idx++) {
242+ assignment.witness (component.W (3 + chunk_idx), second_row) =
243+ output_chunks[data_idx][chunk_idx];
244+ }
245+ // placing the original data
246+ assignment.witness (component.W (7 ), second_row) = data[data_idx];
205247 }
206-
207- assignment.witness (component.W (8 ), row) = data[0 ];
208- assignment.witness (component.W (8 ), row + 2 ) = data[1 ];
209-
210- assignment.witness (component.W (3 ), row + 1 ) = range_chunks[1 ] * (65536 ) + range_chunks[0 ];
211- assignment.witness (component.W (2 ), row + 1 ) = range_chunks[3 ] * (65536 ) + range_chunks[2 ];
212- assignment.witness (component.W (1 ), row + 1 ) = range_chunks[5 ] * (65536 ) + range_chunks[4 ];
213- assignment.witness (component.W (0 ), row + 1 ) = range_chunks[7 ] * (65536 ) + range_chunks[6 ];
214-
215- assignment.witness (component.W (7 ), row + 1 ) = range_chunks[9 ] * (65536 ) + range_chunks[8 ];
216- assignment.witness (component.W (6 ), row + 1 ) = range_chunks[11 ] * (65536 ) + range_chunks[10 ];
217- assignment.witness (component.W (5 ), row + 1 ) = range_chunks[13 ] * (65536 ) + range_chunks[12 ];
218- assignment.witness (component.W (4 ), row + 1 ) = range_chunks[15 ] * (65536 ) + range_chunks[14 ];
219248
220249 return typename plonk_native_decomposition<BlueprintFieldType>::result_type (
221250 component, start_row_index);
@@ -256,33 +285,58 @@ namespace nil {
256285
257286 using var = typename plonk_native_decomposition<BlueprintFieldType>::var;
258287
259- auto constraint_1 =
260- var (component.W (8 ), -1 ) - (var (component.W (3 ), 0 ) + var (component.W (2 ), 0 ) * 0x100000000_cppui255 +
261- var (component.W (1 ), 0 ) * 0x10000000000000000_cppui255 +
262- var (component.W (0 ), 0 ) * 0x1000000000000000000000000_cppui255);
263- auto constraint_2 =
264- var (component.W (8 ), 1 ) - (var (component.W (7 ), 0 ) + var (component.W (6 ), 0 ) * 0x100000000_cppui255 +
265- var (component.W (5 ), 0 ) * 0x10000000000000000_cppui255 +
266- var (component.W (4 ), 0 ) * 0x1000000000000000000000000_cppui255);
267- auto constraint_3 = var (component.W (3 ), 0 ) -
268- (var (component.W (0 ), -1 ) + var (component.W (1 ), -1 ) * (65536 ));
269- auto constraint_4 = var (component.W (2 ), 0 ) -
270- (var (component.W (2 ), -1 ) + var (component.W (3 ), -1 ) * (65536 ));
271- auto constraint_5 = var (component.W (1 ), 0 ) -
272- (var (component.W (4 ), -1 ) + var (component.W (5 ), -1 ) * (65536 ));
273- auto constraint_6 = var (component.W (0 ), 0 ) -
274- (var (component.W (6 ), -1 ) + var (component.W (7 ), -1 ) * (65536 ));
275- auto constraint_7 = var (component.W (7 ), 0 ) -
276- (var (component.W (0 ), +1 ) + var (component.W (1 ), +1 ) * (65536 ));
277- auto constraint_8 = var (component.W (6 ), 0 ) -
278- (var (component.W (2 ), +1 ) + var (component.W (3 ), +1 ) * (65536 ));
279- auto constraint_9 = var (component.W (5 ), 0 ) -
280- (var (component.W (4 ), +1 ) + var (component.W (5 ), +1 ) * (65536 ));
281- auto constraint_10 = var (component.W (4 ), 0 ) -
282- (var (component.W (6 ), +1 ) + var (component.W (7 ), +1 ) * (65536 ));
283- return bp.add_gate (
284- {constraint_1, constraint_2, constraint_3, constraint_4, constraint_5, constraint_6,
285- constraint_7, constraint_8, constraint_9, constraint_10});
288+ const typename BlueprintFieldType::integral_type one = 1 ;
289+ std::array<std::size_t , 2 > selectors;
290+
291+ std::vector<lookup_constraint> subchunk_lookup_constraints (12 );
292+ // lookup constraints for the first three chunks
293+ for (std::size_t chunk_idx = 0 ; chunk_idx < 3 ; chunk_idx++) {
294+ subchunk_lookup_constraints[3 * chunk_idx] =
295+ {lookup_tables_indices.at (" sha256_sparse_base4/first_column" ),
296+ {var (component.W (3 * chunk_idx), -1 )}};
297+ subchunk_lookup_constraints[3 * chunk_idx + 1 ] =
298+ {lookup_tables_indices.at (" sha256_sparse_base4/first_column" ),
299+ {var (component.W (3 * chunk_idx + 1 ), -1 )}};
300+ subchunk_lookup_constraints[3 * chunk_idx + 2 ] =
301+ {lookup_tables_indices.at (" sha256_sparse_base4/first_column" ),
302+ {1024 * var (component.W (3 * chunk_idx + 2 ), -1 )}};
303+ }
304+ // lookup constraints for the last chunk
305+ subchunk_lookup_constraints[9 ] =
306+ {lookup_tables_indices.at (" sha256_sparse_base4/first_column" ),
307+ {var (component.W (0 ), 0 )}};
308+ subchunk_lookup_constraints[10 ] =
309+ {lookup_tables_indices.at (" sha256_sparse_base4/first_column" ),
310+ {var (component.W (1 ), 0 )}};
311+ subchunk_lookup_constraints[11 ] =
312+ {lookup_tables_indices.at (" sha256_sparse_base4/first_column" ),
313+ {1024 * var (component.W (2 ), 0 )}};
314+
315+ selectors[0 ] = bp.add_lookup_gate (subchunk_lookup_constraints);
316+
317+ std::vector<constraint> chunk_constraints (5 );
318+ // chunk sum constraints for the first three chunks
319+ for (std::size_t chunk_idx = 0 ; chunk_idx < 3 ; chunk_idx++) {
320+ chunk_constraints[chunk_idx] =
321+ var (component.W (3 * chunk_idx), -1 ) * (1 << 18 ) +
322+ var (component.W (3 * chunk_idx + 1 ), -1 ) * (1 << 4 ) +
323+ var (component.W (3 * chunk_idx + 2 ), -1 ) -
324+ var (component.W (3 + chunk_idx), 0 );
325+ }
326+ // chunk sum constraints for the last chunk
327+ chunk_constraints[3 ] =
328+ var (component.W (0 ), 0 ) * (1 << 18 ) +
329+ var (component.W (1 ), 0 ) * (1 << 4 ) +
330+ var (component.W (2 ), 0 ) -
331+ var (component.W (6 ), 0 );
332+ // chunk sum constraint for input
333+ chunk_constraints[4 ] =
334+ var (component.W (3 ), 0 ) + var (component.W (4 ), 0 ) * (one << 32 ) +
335+ var (component.W (5 ), 0 ) * (one << 64 ) + var (component.W (6 ), 0 ) * (one << 96 ) -
336+ var (component.W (7 ), 0 );
337+ selectors[1 ] = bp.add_gate (chunk_constraints);
338+
339+ return selectors;
286340 }
287341
288342 template <typename BlueprintFieldType>
@@ -296,11 +350,9 @@ namespace nil {
296350 const std::size_t start_row_index) {
297351
298352 using var = typename plonk_native_decomposition<BlueprintFieldType>::var;
299- // CRITICAL: these copy constraints might not be sufficient, but are definitely required.
300- // I've added copy constraints for the inputs, but internal ones might be missing
301- // Proceed with care
302- bp.add_copy_constraint ({instance_input.data [0 ], var (component.W (8 ), start_row_index, false )});
303- bp.add_copy_constraint ({instance_input.data [1 ], var (component.W (8 ), start_row_index + 2 , false )});
353+
354+ bp.add_copy_constraint ({instance_input.data [0 ], var (component.W (7 ), start_row_index + 1 , false )});
355+ bp.add_copy_constraint ({instance_input.data [1 ], var (component.W (7 ), start_row_index + 3 , false )});
304356 }
305357
306358 template <typename BlueprintFieldType>
@@ -314,10 +366,14 @@ namespace nil {
314366 &instance_input,
315367 const std::size_t start_row_index) {
316368
317- std::size_t j = start_row_index + 1 ;
318- std::size_t selector_index = generate_gates (component, bp, assignment, instance_input);
369+ std::array<std::size_t , 2 > selector_indices =
370+ generate_gates (component, bp, assignment, instance_input, bp.get_reserved_indices ());
371+
372+ assignment.enable_selector (selector_indices[0 ], start_row_index + 1 );
373+ assignment.enable_selector (selector_indices[0 ], start_row_index + 3 );
374+ assignment.enable_selector (selector_indices[1 ], start_row_index + 1 );
375+ assignment.enable_selector (selector_indices[1 ], start_row_index + 3 );
319376
320- assignment.enable_selector (selector_index, j);
321377 generate_copy_constraints (component, bp, assignment, instance_input, start_row_index);
322378
323379 return typename plonk_native_decomposition<BlueprintFieldType>::result_type (
0 commit comments