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

Commit f4dbcd2

Browse files
committed
Split gates and lookups into multiple libs #24
1 parent d71a68d commit f4dbcd2

File tree

5 files changed

+237
-182
lines changed

5 files changed

+237
-182
lines changed

include/nil/blueprint/transpiler/evm_verifier_gen.hpp

+145-103
Original file line numberDiff line numberDiff line change
@@ -166,15 +166,16 @@ namespace nil {
166166
const typename PlaceholderParams::commitment_scheme_type &lpc_scheme,
167167
std::size_t permutation_size,
168168
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
170171
) :
171172
_constraint_system(constraint_system),
172173
_common_data(common_data),
173174
_lpc_scheme(lpc_scheme),
174175
_permutation_size(permutation_size),
175176
_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)
178179
{
179180
std::size_t found = folder_name.rfind("/");
180181
if( found == std::string::npos ){
@@ -183,7 +184,7 @@ namespace nil {
183184
_test_name = folder_name.substr(found + 1);
184185
}
185186
_use_lookups = _constraint_system.lookup_gates().size() > 0;
186-
187+
187188
_z_offset = _use_lookups ? 0xc9 : 0xa1;
188189
_special_selectors_offset = _z_offset + _permutation_size * 0x80;
189190
_table_z_offset = _special_selectors_offset + 0xc0;
@@ -206,41 +207,53 @@ namespace nil {
206207
_var_indices = get_plonk_variable_indices(_common_data.columns_rotations);
207208
}
208209

209-
void print_library_file(std::size_t library_id,
210+
void print_gates_library_file(std::size_t library_id,
210211
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) {
212213

213-
std::string all_gates;
214+
std::string library_gates;
214215

215-
for(auto const& i: gates_list) {
216+
for (auto i: gates_list) {
216217
std::string gate_evaluation = gate_evaluation_template;
217218
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;
220221
}
221222

222223
std::string result = modular_external_gate_library_template;
223224
boost::replace_all(result, "$TEST_NAME$", _test_name);
224225
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);
226227
boost::replace_all(result, "$MODULUS$", to_string(PlaceholderParams::field_type::modulus));
227228

228229
std::ofstream out;
229230
out.open(_folder_name + "/gate_" + to_string(library_id) + ".sol");
230-
out <<result;
231+
out << result;
231232
out.close();
232233
}
233234

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+
235248
std::string result = modular_external_lookup_library_template;
236249
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);
239252
boost::replace_all(result, "$MODULUS$", to_string(PlaceholderParams::field_type::modulus));
240253

241254
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;
244257
out.close();
245258
}
246259

@@ -280,93 +293,90 @@ namespace nil {
280293
return out.str();
281294
}
282295

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';
308301
}
309-
out << "]" << std::endl;
310-
out.close();
302+
return lines;
311303
}
312304

313-
std::size_t estimate_cost(std::string const& solana_code) {
305+
std::size_t estimate_lookup_cost(std::string const& code) {
314306
/* proof-of-concept: cost = number of lines */
315307
std::size_t lines = 0;
316-
for(auto &ch: solana_code) {
308+
for(auto &ch: code) {
317309
lines += ch == '\n';
318310
}
319311
return lines;
320312
}
321313

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+
322352
std::string print_gate_argument(){
323-
std::stringstream gate_argument_str;
324353
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;
327358
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);
328361
std::vector<std::size_t> gate_ids(gates_count);
329362

330363
i = 0;
331364
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;
335368
++i;
336369
}
337370

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);
340372
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) {
344373

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;
361378
}
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);
370380
}
371381

372382
i = 0;
@@ -378,45 +388,76 @@ namespace nil {
378388
boost::replace_all(gate_eval_string, "$MODULUS$", to_string(PlaceholderParams::field_type::modulus));
379389
gate_argument_str << gate_eval_string << std::endl;
380390
gate_ids.push_back(i);
381-
i++;
391+
++i;
382392
}
383393

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;
394399
}
400+
out << "\"" << "gate_" << _test_name << "_" << library_gates_buckets.size()-1 << "\"" << std::endl;
401+
out << "]" << std::endl;
402+
out.close();
395403

396404
return gate_argument_str.str();
397405
}
398406

399407
std::string print_lookup_argument(){
408+
std::size_t lookup_count = _constraint_system.lookup_gates().size();
409+
if (lookup_count == 0)
410+
return "";
411+
400412
std::stringstream lookup_str;
401413
std::size_t j = 0;
402414
std::size_t i = 0;
403415
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);
406430

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;
407441
for(const auto &lookup_gate: _constraint_system.lookup_gates()){
408442
std::string lookup_eval_string = lookup_call_template;
409443
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));
411446
boost::replace_all(lookup_eval_string, "$MODULUS$", to_string(PlaceholderParams::field_type::modulus));
412447
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;
418456
}
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+
420461
j = 0;
421462
std::size_t table_index = 1;
422463
for(const auto &table: _constraint_system.lookup_tables()){
@@ -450,10 +491,10 @@ namespace nil {
450491
table_index++;
451492
}
452493
lookup_str << std::endl;
453-
494+
454495
return lookup_str.str();
455496
}
456-
497+
457498
void print(){
458499
std::filesystem::create_directory(_folder_name);
459500
std::cout << "Generating verifier " << _test_name << std::endl;
@@ -523,6 +564,7 @@ namespace nil {
523564
std::string _gate_includes;
524565
std::string _lookup_includes;
525566
std::size_t _gates_library_size_threshold;
567+
std::size_t _lookups_library_size_threshold;
526568
};
527569
}
528570
}

include/nil/blueprint/transpiler/lpc_scheme_gen.hpp

+4-2
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333

3434
#include <boost/algorithm/string.hpp>
3535
#include <nil/blueprint/transpiler/util.hpp>
36+
#include <nil/blueprint/transpiler/templates/commitment_scheme.hpp>
37+
#include <nil/crypto3/zk/snark/systems/plonk/placeholder/preprocessor.hpp>
3638

3739
namespace nil {
3840
namespace blueprint {
@@ -177,7 +179,7 @@ namespace nil {
177179
replacements["$GRINDING_CHECK$"] = modular_commitment_grinding_check_template;
178180
} else {
179181
replacements["$GRINDING_CHECK$"] = "";
180-
}
182+
}
181183
}
182184

183185
template<typename PlaceholderParams>
@@ -197,4 +199,4 @@ namespace nil {
197199
}
198200
}
199201

200-
#endif //__MODULAR_CONTRACTS_TEMPLATES_HPP__
202+
#endif //__MODULAR_CONTRACTS_TEMPLATES_HPP__

0 commit comments

Comments
 (0)