30
30
#include < fstream>
31
31
#include < sstream>
32
32
#include < filesystem>
33
+ #include < unordered_set>
33
34
34
35
#include < boost/algorithm/string.hpp>
35
36
#include < nil/blueprint/transpiler/templates/modular_verifier.hpp>
@@ -167,15 +168,19 @@ namespace nil {
167
168
std::size_t permutation_size,
168
169
std::string folder_name,
169
170
std::size_t gates_library_size_threshold = 1600 ,
170
- std::size_t lookups_library_size_threshold = 1600
171
+ std::size_t lookups_library_size_threshold = 1600 ,
172
+ std::size_t gates_contract_size_threshold = 1400 ,
173
+ std::size_t lookups_contract_size_threshold = 1400
171
174
) :
172
175
_constraint_system (constraint_system),
173
176
_common_data (common_data),
174
177
_lpc_scheme (lpc_scheme),
175
178
_permutation_size (permutation_size),
176
179
_folder_name (folder_name),
177
180
_gates_library_size_threshold (gates_library_size_threshold),
178
- _lookups_library_size_threshold (lookups_library_size_threshold)
181
+ _lookups_library_size_threshold (lookups_library_size_threshold),
182
+ _gates_contract_size_threshold (gates_contract_size_threshold),
183
+ _lookups_contract_size_threshold (lookups_contract_size_threshold)
179
184
{
180
185
std::size_t found = folder_name.rfind (" /" );
181
186
if ( found == std::string::npos ){
@@ -209,14 +214,14 @@ namespace nil {
209
214
210
215
void print_gates_library_file (std::size_t library_id,
211
216
std::vector<std::size_t > const & gates_list,
212
- std::vector< std::string> const & gate_codes) {
217
+ std::unordered_map<std:: size_t , std::string> const & gate_codes) {
213
218
214
219
std::string library_gates;
215
220
216
221
for (auto i: gates_list) {
217
222
std::string gate_evaluation = gate_evaluation_template;
218
223
boost::replace_all (gate_evaluation, " $GATE_ID$" , to_string (i) );
219
- boost::replace_all (gate_evaluation, " $GATE_ASSEMBLY_CODE$" , gate_codes[i] );
224
+ boost::replace_all (gate_evaluation, " $GATE_ASSEMBLY_CODE$" , gate_codes. at (i) );
220
225
library_gates += gate_evaluation;
221
226
}
222
227
@@ -312,7 +317,8 @@ namespace nil {
312
317
}
313
318
314
319
/* * @brief Split items into buckets, each bucket is limited
315
- * to max_bucket_size, minimizes number of buckets
320
+ * to max_bucket_size, minimizes number of buckets.
321
+ * items must be sorted
316
322
* @param[in] items (item_id, item_size)
317
323
* @param[in] max_bucket_size
318
324
* @returns buckets (bucket_id -> [item_id])
@@ -321,12 +327,6 @@ namespace nil {
321
327
std::vector<std::pair<std::size_t , std::size_t >> &items,
322
328
std::size_t max_bucket_size) {
323
329
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
330
std::unordered_map<std::size_t , std::vector<std::size_t >> buckets;
331
331
std::vector<std::size_t > bucket_sizes;
332
332
@@ -356,7 +356,7 @@ namespace nil {
356
356
357
357
std::stringstream gate_argument_str;
358
358
std::size_t i = 0 ;
359
- std::vector <std::string> gate_codes (gates_count) ;
359
+ std::unordered_map <std::size_t , std:: string> gate_codes;
360
360
std::vector<std::pair<std::size_t , std::size_t >> gate_costs (gates_count);
361
361
std::vector<std::size_t > gate_ids (gates_count);
362
362
@@ -368,6 +368,28 @@ namespace nil {
368
368
++i;
369
369
}
370
370
371
+ std::sort (gate_costs.begin (), gate_costs.end (),
372
+ [](const std::pair<std::size_t , std::size_t > &a,
373
+ const std::pair<std::size_t , std::size_t > &b) {
374
+ return a.second > b.second ;
375
+ });
376
+
377
+ /* Fill contract inline gate computation, inline small gates first */
378
+ std::unordered_set<std::size_t > inlined_gate_codes;
379
+ std::size_t inlined_gate_codes_size = 0 ;
380
+ for (auto gate=gate_costs.rbegin (); gate != gate_costs.rend (); ++gate) {
381
+ if (gate->second + inlined_gate_codes_size < _gates_contract_size_threshold) {
382
+ inlined_gate_codes.insert (gate->first );
383
+ inlined_gate_codes_size += gate->second ;
384
+ }
385
+ }
386
+
387
+ auto inlined_gates_end = std::remove_if (gate_costs.begin (), gate_costs.end (),
388
+ [&inlined_gate_codes](const std::pair<std::size_t , std::size_t >& cost) {
389
+ return inlined_gate_codes.count (cost.first ) == 1 ;
390
+ });
391
+ gate_costs.erase (inlined_gates_end, gate_costs.end ());
392
+
371
393
auto library_gates_buckets = split_items_into_buckets (gate_costs, _gates_library_size_threshold);
372
394
std::vector<std::size_t > gate_lib (gates_count);
373
395
@@ -379,27 +401,40 @@ namespace nil {
379
401
print_gates_library_file (lib.first , lib.second , gate_codes);
380
402
}
381
403
404
+
405
+ if (inlined_gate_codes.size () > 0 ) {
406
+ gate_argument_str << " \t\t uint256 sum;" << std::endl;
407
+ gate_argument_str << " \t\t uint256 prod;" << std::endl;
408
+ gate_argument_str << " \t\t uint256 gate;" << std::endl;
409
+ }
410
+
382
411
i = 0 ;
383
412
for (const auto &gate: _constraint_system.gates ()){
384
- std::string gate_eval_string = gate_call_template;
385
- boost::replace_all (gate_eval_string, " $TEST_NAME$" , _test_name);
386
- boost::replace_all (gate_eval_string, " $GATE_LIB_ID$" , to_string (gate_lib[i]));
387
- boost::replace_all (gate_eval_string, " $GATE_ID$" , to_string (i));
388
- boost::replace_all (gate_eval_string, " $MODULUS$" , to_string (PlaceholderParams::field_type::modulus));
389
- gate_argument_str << gate_eval_string << std::endl;
390
- gate_ids.push_back (i);
413
+ if (inlined_gate_codes.count (i) == 1 ) {
414
+ gate_argument_str << " /* -- gate " << i << " is inlined -- */" << std::endl;
415
+ gate_argument_str << gate_codes[i] << std::endl;
416
+ } else {
417
+ std::string gate_eval_string = gate_call_template;
418
+ boost::replace_all (gate_eval_string, " $TEST_NAME$" , _test_name);
419
+ boost::replace_all (gate_eval_string, " $GATE_LIB_ID$" , to_string (gate_lib[i]));
420
+ boost::replace_all (gate_eval_string, " $GATE_ID$" , to_string (i));
421
+ boost::replace_all (gate_eval_string, " $MODULUS$" , to_string (PlaceholderParams::field_type::modulus));
422
+ gate_argument_str << gate_eval_string << std::endl;
423
+ }
391
424
++i;
392
425
}
393
426
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;
427
+ if (library_gates_buckets.size () > 0 ) {
428
+ std::ofstream out;
429
+ out.open (_folder_name + " /gate_libs_list.json" );
430
+ out << " [" << std::endl;
431
+ for (i = 0 ; i < library_gates_buckets.size ()-1 ; ++i ) {
432
+ out << " \" " << " gate_" << _test_name << " _" << i << " \" ," << std::endl;
433
+ }
434
+ out << " \" " << " gate_" << _test_name << " _" << library_gates_buckets.size ()-1 << " \" " << std::endl;
435
+ out << " ]" << std::endl;
436
+ out.close ();
399
437
}
400
- out << " \" " << " gate_" << _test_name << " _" << library_gates_buckets.size ()-1 << " \" " << std::endl;
401
- out << " ]" << std::endl;
402
- out.close ();
403
438
404
439
return gate_argument_str.str ();
405
440
}
@@ -563,6 +598,8 @@ namespace nil {
563
598
564
599
std::string _gate_includes;
565
600
std::string _lookup_includes;
601
+ std::size_t _gates_contract_size_threshold;
602
+ std::size_t _lookups_contract_size_threshold;
566
603
std::size_t _gates_library_size_threshold;
567
604
std::size_t _lookups_library_size_threshold;
568
605
};
0 commit comments