@@ -166,15 +166,16 @@ namespace nil {
166
166
const typename PlaceholderParams::commitment_scheme_type &lpc_scheme,
167
167
std::size_t permutation_size,
168
168
std::string folder_name,
169
- std::size_t gates_library_size_threshold = 24000
169
+ std::size_t gates_library_size_threshold = 1600 ,
170
+ std::size_t lookups_library_size_threshold = 1600
170
171
) :
171
172
_constraint_system (constraint_system),
172
173
_common_data (common_data),
173
174
_lpc_scheme (lpc_scheme),
174
175
_permutation_size (permutation_size),
175
176
_folder_name (folder_name),
176
- _gates_library_size_threshold (gates_library_size_threshold)
177
-
177
+ _gates_library_size_threshold (gates_library_size_threshold),
178
+ _lookups_library_size_threshold (lookups_library_size_threshold)
178
179
{
179
180
std::size_t found = folder_name.rfind (" /" );
180
181
if ( found == std::string::npos ){
@@ -183,7 +184,7 @@ namespace nil {
183
184
_test_name = folder_name.substr (found + 1 );
184
185
}
185
186
_use_lookups = _constraint_system.lookup_gates ().size () > 0 ;
186
-
187
+
187
188
_z_offset = _use_lookups ? 0xc9 : 0xa1 ;
188
189
_special_selectors_offset = _z_offset + _permutation_size * 0x80 ;
189
190
_table_z_offset = _special_selectors_offset + 0xc0 ;
@@ -206,41 +207,53 @@ namespace nil {
206
207
_var_indices = get_plonk_variable_indices (_common_data.columns_rotations );
207
208
}
208
209
209
- void print_library_file (std::size_t library_id,
210
+ void print_gates_library_file (std::size_t library_id,
210
211
std::vector<std::size_t > const & gates_list,
211
- std::vector<std::string> const & gate_computation_codes ) {
212
+ std::vector<std::string> const & gate_codes ) {
212
213
213
- std::string all_gates ;
214
+ std::string library_gates ;
214
215
215
- for (auto const & i: gates_list) {
216
+ for (auto i: gates_list) {
216
217
std::string gate_evaluation = gate_evaluation_template;
217
218
boost::replace_all (gate_evaluation, " $GATE_ID$" , to_string (i) );
218
- boost::replace_all (gate_evaluation, " $GATE_ASSEMBLY_CODE$" , gate_computation_codes [i]);
219
- all_gates += gate_evaluation;
219
+ boost::replace_all (gate_evaluation, " $GATE_ASSEMBLY_CODE$" , gate_codes [i]);
220
+ library_gates += gate_evaluation;
220
221
}
221
222
222
223
std::string result = modular_external_gate_library_template;
223
224
boost::replace_all (result, " $TEST_NAME$" , _test_name);
224
225
boost::replace_all (result, " $GATE_LIB_ID$" , to_string (library_id));
225
- boost::replace_all (result, " $GATES_COMPUTATION_CODE$" , all_gates );
226
+ boost::replace_all (result, " $GATES_COMPUTATION_CODE$" , library_gates );
226
227
boost::replace_all (result, " $MODULUS$" , to_string (PlaceholderParams::field_type::modulus));
227
228
228
229
std::ofstream out;
229
230
out.open (_folder_name + " /gate_" + to_string (library_id) + " .sol" );
230
- out <<result;
231
+ out << result;
231
232
out.close ();
232
233
}
233
234
234
- void print_lookup_file (std::string lookup_computation_code, std::size_t lookup_id){
235
+ void print_lookups_library_file (std::size_t library_id,
236
+ std::vector<std::size_t > const & lookups_list,
237
+ std::vector<std::string> const & lookup_codes) {
238
+
239
+ std::string library_lookups;
240
+
241
+ for (auto const & i: lookups_list) {
242
+ std::string lookup_evaluation = lookup_evaluation_template;
243
+ boost::replace_all (lookup_evaluation, " $LOOKUP_ID$" , to_string (i) );
244
+ boost::replace_all (lookup_evaluation, " $LOOKUP_ASSEMBLY_CODE$" , lookup_codes[i]);
245
+ library_lookups += lookup_evaluation;
246
+ }
247
+
235
248
std::string result = modular_external_lookup_library_template;
236
249
boost::replace_all (result, " $TEST_NAME$" , _test_name);
237
- boost::replace_all (result, " $LOOKUP_LIB_ID$" , to_string (lookup_id ));
238
- boost::replace_all (result, " $LOOKUP_ASSEMBLY_CODE $" , lookup_computation_code );
250
+ boost::replace_all (result, " $LOOKUP_LIB_ID$" , to_string (library_id ));
251
+ boost::replace_all (result, " $LOOKUP_COMPUTATION_CODE $" , library_lookups );
239
252
boost::replace_all (result, " $MODULUS$" , to_string (PlaceholderParams::field_type::modulus));
240
253
241
254
std::ofstream out;
242
- out.open (_folder_name + " /lookup_" + to_string (lookup_id ) + " .sol" );
243
- out <<result;
255
+ out.open (_folder_name + " /lookup_" + to_string (library_id ) + " .sol" );
256
+ out << result;
244
257
out.close ();
245
258
}
246
259
@@ -280,93 +293,90 @@ namespace nil {
280
293
return out.str ();
281
294
}
282
295
283
- void print_gate_libs_list (std::vector<std::size_t > library_ids){
284
- std::ofstream out;
285
- out.open (_folder_name + " /gate_libs_list.json" );
286
- out << " [" << std::endl;
287
- for (std::size_t i=0 ; i < library_ids.size (); i++){
288
- out << " \" " << " gate_" << _test_name << " _" << library_ids[i] << " \" " ;
289
- if (i < library_ids.size () - 1 ){
290
- out << " ," ;
291
- }
292
- out << std::endl;
293
- }
294
- out << " ]" << std::endl;
295
- out.close ();
296
- }
297
-
298
- void print_lookup_libs_list (std::vector<std::size_t > gate_ids){
299
- std::ofstream out;
300
- out.open (_folder_name + " /lookup_libs_list.json" );
301
- out << " [" << std::endl;
302
- for (std::size_t i=0 ; i < gate_ids.size (); i++){
303
- out << " \" " << " lookup_" << _test_name << " _" << gate_ids[i] << " \" " ;
304
- if (i < gate_ids.size () - 1 ){
305
- out << " ," ;
306
- }
307
- out << std::endl;
296
+ std::size_t estimate_gate_cost (std::string const & code) {
297
+ /* proof-of-concept: cost = number of lines */
298
+ std::size_t lines = 0 ;
299
+ for (auto &ch: code) {
300
+ lines += ch == ' \n ' ;
308
301
}
309
- out << " ]" << std::endl;
310
- out.close ();
302
+ return lines;
311
303
}
312
304
313
- std::size_t estimate_cost (std::string const & solana_code ) {
305
+ std::size_t estimate_lookup_cost (std::string const & code ) {
314
306
/* proof-of-concept: cost = number of lines */
315
307
std::size_t lines = 0 ;
316
- for (auto &ch: solana_code ) {
308
+ for (auto &ch: code ) {
317
309
lines += ch == ' \n ' ;
318
310
}
319
311
return lines;
320
312
}
321
313
314
+ /* * @brief Split items into buckets, each bucket is limited
315
+ * to max_bucket_size, minimizes number of buckets
316
+ * @param[in] items (item_id, item_size)
317
+ * @param[in] max_bucket_size
318
+ * @returns buckets (bucket_id -> [item_id])
319
+ * */
320
+ std::unordered_map<std::size_t , std::vector<std::size_t >> split_items_into_buckets (
321
+ std::vector<std::pair<std::size_t , std::size_t >> &items,
322
+ std::size_t max_bucket_size) {
323
+
324
+ std::sort (items.begin (), items.end (),
325
+ [](const std::pair<std::size_t , std::size_t > &a,
326
+ const std::pair<std::size_t , std::size_t > &b) {
327
+ return a.second > b.second ;
328
+ });
329
+
330
+ std::unordered_map<std::size_t , std::vector<std::size_t >> buckets;
331
+ std::vector<std::size_t > bucket_sizes;
332
+
333
+ for (auto const & item : items) {
334
+ bool bucket_found = false ;
335
+ for (std::size_t i = 0 ; i < bucket_sizes.size (); ++i) {
336
+ if (bucket_sizes[i]+item.second <= max_bucket_size) {
337
+ buckets[i].push_back (item.first );
338
+ bucket_sizes[i] += item.second ;
339
+ bucket_found = true ;
340
+ break ;
341
+ }
342
+ }
343
+
344
+ if (!bucket_found) {
345
+ bucket_sizes.push_back (item.second );
346
+ buckets[bucket_sizes.size ()-1 ].push_back (item.first );
347
+ }
348
+ }
349
+ return buckets;
350
+ }
351
+
322
352
std::string print_gate_argument (){
323
- std::stringstream gate_argument_str;
324
353
std::size_t gates_count = _constraint_system.gates ().size ();
325
- std::vector<std::string> gates_computation_code (gates_count);
326
- std::vector<std::size_t > gates_cost (gates_count);
354
+ if (gates_count == 0 )
355
+ return " " ;
356
+
357
+ std::stringstream gate_argument_str;
327
358
std::size_t i = 0 ;
359
+ std::vector<std::string> gate_codes (gates_count);
360
+ std::vector<std::pair<std::size_t , std::size_t >> gate_costs (gates_count);
328
361
std::vector<std::size_t > gate_ids (gates_count);
329
362
330
363
i = 0 ;
331
364
for (const auto &gate: _constraint_system.gates ()) {
332
- std::string comp = gate_computation_code (gate);
333
- gates_cost [i] = estimate_cost (comp );
334
- gates_computation_code [i] = comp ;
365
+ std::string code = gate_computation_code (gate);
366
+ gate_costs [i] = std::make_pair (i, estimate_gate_cost (code) );
367
+ gate_codes [i] = code ;
335
368
++i;
336
369
}
337
370
338
- std::size_t library_size = 0 ;
339
- std::size_t libraries_count = 0 ;
371
+ auto library_gates_buckets = split_items_into_buckets (gate_costs, _gates_library_size_threshold);
340
372
std::vector<std::size_t > gate_lib (gates_count);
341
- std::map<std::size_t , std::vector<std::size_t >> library_gates;
342
-
343
- if (gates_count > 0 ) {
344
373
345
- for (i = 0 ; i < gates_count; ++i) {
346
- /* start a new library if current gate won't fit */
347
- if ((library_size + gates_cost[i] > _gates_library_size_threshold) && (library_size > 0 )) {
348
- library_size = 0 ;
349
- ++libraries_count;
350
- std::cout << " library is above threshold, starting new.." << std::endl;
351
- }
352
-
353
- gate_lib[i] = libraries_count;
354
- library_gates[libraries_count].push_back (i);
355
- library_size += gates_cost[i];
356
- std::cout << " library grew by " << gates_cost[i] << " clicks: " << library_size << std::endl;
357
-
358
- if (library_gates[libraries_count].size () == 1 ) {
359
- _gate_includes += " import \" ./gate_" + to_string (libraries_count) + " .sol\" ;\n " ;
360
- }
374
+ for (auto const & lib: library_gates_buckets) {
375
+ _gate_includes += " import \" ./gate_" + to_string (lib.first ) + " .sol\" ;\n " ;
376
+ for (auto g: lib.second ) {
377
+ gate_lib[g] = lib.first ;
361
378
}
362
-
363
- ++libraries_count;
364
- }
365
-
366
- std::cout << " gate inc: [" << _gate_includes << " ]" << std::endl;
367
-
368
- for (auto const & [library_id, gates_list]: library_gates) {
369
- print_library_file (library_id, gates_list, gates_computation_code);
379
+ print_gates_library_file (lib.first , lib.second , gate_codes);
370
380
}
371
381
372
382
i = 0 ;
@@ -378,45 +388,76 @@ namespace nil {
378
388
boost::replace_all (gate_eval_string, " $MODULUS$" , to_string (PlaceholderParams::field_type::modulus));
379
389
gate_argument_str << gate_eval_string << std::endl;
380
390
gate_ids.push_back (i);
381
- i++ ;
391
+ ++i ;
382
392
}
383
393
384
- if (libraries_count > 0 ) {
385
- std::ofstream out;
386
- out.open (_folder_name + " /gate_libs_list.json" );
387
- out << " [" << std::endl;
388
- for (i = 0 ; i < libraries_count-1 ; ++i ) {
389
- out << " \" " << " gate_" << _test_name << " _" << i << " \" ," << std::endl;
390
- }
391
- out << " \" " << " gate_" << _test_name << " _" << libraries_count-1 << " \" " << std::endl;
392
- out << " ]" << std::endl;
393
- out.close ();
394
+ std::ofstream out;
395
+ out.open (_folder_name + " /gate_libs_list.json" );
396
+ out << " [" << std::endl;
397
+ for (i = 0 ; i < library_gates_buckets.size ()-1 ; ++i ) {
398
+ out << " \" " << " gate_" << _test_name << " _" << i << " \" ," << std::endl;
394
399
}
400
+ out << " \" " << " gate_" << _test_name << " _" << library_gates_buckets.size ()-1 << " \" " << std::endl;
401
+ out << " ]" << std::endl;
402
+ out.close ();
395
403
396
404
return gate_argument_str.str ();
397
405
}
398
406
399
407
std::string print_lookup_argument (){
408
+ std::size_t lookup_count = _constraint_system.lookup_gates ().size ();
409
+ if (lookup_count == 0 )
410
+ return " " ;
411
+
400
412
std::stringstream lookup_str;
401
413
std::size_t j = 0 ;
402
414
std::size_t i = 0 ;
403
415
std::size_t cur = 0 ;
404
- std::vector<std::string> lookups_computation_code;
405
- std::vector<std::size_t > lookup_ids;
416
+ std::vector<std::string> lookup_codes (lookup_count);
417
+ std::vector<std::size_t > lookup_ids (lookup_count);
418
+ std::vector<std::pair<std::size_t , std::size_t >> lookup_costs (lookup_count);
419
+ std::vector<std::size_t > lookup_lib (lookup_count);
420
+
421
+ i = 0 ;
422
+ for (const auto &lookup: _constraint_system.lookup_gates ()) {
423
+ std::string code = lookup_computation_code (lookup);
424
+ lookup_costs[i] = std::make_pair (i, estimate_lookup_cost (code));
425
+ lookup_codes[i] = code;
426
+ ++i;
427
+ }
428
+
429
+ auto library_lookup_buckets = split_items_into_buckets (lookup_costs, _lookups_library_size_threshold);
406
430
431
+ _lookup_includes = " " ;
432
+ for (auto const & lib: library_lookup_buckets) {
433
+ _lookup_includes += " import \" ./lookup_" + to_string (lib.first ) + " .sol\" ;\n " ;
434
+ for (auto l: lib.second ) {
435
+ lookup_lib[l] = lib.first ;
436
+ }
437
+ print_lookups_library_file (lib.first , lib.second , lookup_codes);
438
+ }
439
+
440
+ i = 0 ;
407
441
for (const auto &lookup_gate: _constraint_system.lookup_gates ()){
408
442
std::string lookup_eval_string = lookup_call_template;
409
443
boost::replace_all (lookup_eval_string, " $TEST_NAME$" , _test_name);
410
- boost::replace_all (lookup_eval_string, " $LOOKUP_LIB_ID$" , to_string (i));
444
+ boost::replace_all (lookup_eval_string, " $LOOKUP_LIB_ID$" , to_string (lookup_lib[i]));
445
+ boost::replace_all (lookup_eval_string, " $LOOKUP_ID$" , to_string (i));
411
446
boost::replace_all (lookup_eval_string, " $MODULUS$" , to_string (PlaceholderParams::field_type::modulus));
412
447
lookup_str << lookup_eval_string;
413
- lookup_ids.push_back (i);
414
- _lookup_includes += " import \" ./lookup_" + to_string (i) + " .sol\" ; \n " ;
415
- lookups_computation_code.push_back (lookup_computation_code (lookup_gate));
416
- print_lookup_file (lookups_computation_code[i], i);
417
- i++;
448
+ ++i;
449
+ }
450
+
451
+ std::ofstream out;
452
+ out.open (_folder_name + " /lookup_libs_list.json" );
453
+ out << " [" << std::endl;
454
+ for (i = 0 ; i < library_lookup_buckets.size ()-1 ; ++i ) {
455
+ out << " \" " << " lookup_" << _test_name << " _" << i << " \" ," << std::endl;
418
456
}
419
- if (_use_lookups) print_lookup_libs_list (lookup_ids);
457
+ out << " \" " << " lookup_" << _test_name << " _" << library_lookup_buckets.size ()-1 << " \" " << std::endl;
458
+ out << " ]" << std::endl;
459
+ out.close ();
460
+
420
461
j = 0 ;
421
462
std::size_t table_index = 1 ;
422
463
for (const auto &table: _constraint_system.lookup_tables ()){
@@ -450,10 +491,10 @@ namespace nil {
450
491
table_index++;
451
492
}
452
493
lookup_str << std::endl;
453
-
494
+
454
495
return lookup_str.str ();
455
496
}
456
-
497
+
457
498
void print (){
458
499
std::filesystem::create_directory (_folder_name);
459
500
std::cout << " Generating verifier " << _test_name << std::endl;
@@ -523,6 +564,7 @@ namespace nil {
523
564
std::string _gate_includes;
524
565
std::string _lookup_includes;
525
566
std::size_t _gates_library_size_threshold;
567
+ std::size_t _lookups_library_size_threshold;
526
568
};
527
569
}
528
570
}
0 commit comments