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

Commit 325bdde

Browse files
committed
Inline cheap gate evaluation in contract code #24
1 parent 64bf1e2 commit 325bdde

File tree

1 file changed

+64
-27
lines changed

1 file changed

+64
-27
lines changed

include/nil/blueprint/transpiler/evm_verifier_gen.hpp

+64-27
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <fstream>
3131
#include <sstream>
3232
#include <filesystem>
33+
#include <unordered_set>
3334

3435
#include <boost/algorithm/string.hpp>
3536
#include <nil/blueprint/transpiler/templates/modular_verifier.hpp>
@@ -167,15 +168,19 @@ namespace nil {
167168
std::size_t permutation_size,
168169
std::string folder_name,
169170
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
171174
) :
172175
_constraint_system(constraint_system),
173176
_common_data(common_data),
174177
_lpc_scheme(lpc_scheme),
175178
_permutation_size(permutation_size),
176179
_folder_name(folder_name),
177180
_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)
179184
{
180185
std::size_t found = folder_name.rfind("/");
181186
if( found == std::string::npos ){
@@ -209,14 +214,14 @@ namespace nil {
209214

210215
void print_gates_library_file(std::size_t library_id,
211216
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) {
213218

214219
std::string library_gates;
215220

216221
for (auto i: gates_list) {
217222
std::string gate_evaluation = gate_evaluation_template;
218223
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));
220225
library_gates += gate_evaluation;
221226
}
222227

@@ -312,7 +317,8 @@ namespace nil {
312317
}
313318

314319
/** @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
316322
* @param[in] items (item_id, item_size)
317323
* @param[in] max_bucket_size
318324
* @returns buckets (bucket_id -> [item_id])
@@ -321,12 +327,6 @@ namespace nil {
321327
std::vector<std::pair<std::size_t, std::size_t>> &items,
322328
std::size_t max_bucket_size) {
323329

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-
330330
std::unordered_map<std::size_t, std::vector<std::size_t>> buckets;
331331
std::vector<std::size_t> bucket_sizes;
332332

@@ -356,7 +356,7 @@ namespace nil {
356356

357357
std::stringstream gate_argument_str;
358358
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;
360360
std::vector<std::pair<std::size_t, std::size_t>> gate_costs(gates_count);
361361
std::vector<std::size_t> gate_ids(gates_count);
362362

@@ -368,6 +368,28 @@ namespace nil {
368368
++i;
369369
}
370370

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+
371393
auto library_gates_buckets = split_items_into_buckets(gate_costs, _gates_library_size_threshold);
372394
std::vector<std::size_t> gate_lib(gates_count);
373395

@@ -379,27 +401,40 @@ namespace nil {
379401
print_gates_library_file(lib.first, lib.second, gate_codes);
380402
}
381403

404+
405+
if (inlined_gate_codes.size() > 0) {
406+
gate_argument_str << "\t\tuint256 sum;" << std::endl;
407+
gate_argument_str << "\t\tuint256 prod;" << std::endl;
408+
gate_argument_str << "\t\tuint256 gate;" << std::endl;
409+
}
410+
382411
i = 0;
383412
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+
}
391424
++i;
392425
}
393426

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

404439
return gate_argument_str.str();
405440
}
@@ -563,6 +598,8 @@ namespace nil {
563598

564599
std::string _gate_includes;
565600
std::string _lookup_includes;
601+
std::size_t _gates_contract_size_threshold;
602+
std::size_t _lookups_contract_size_threshold;
566603
std::size_t _gates_library_size_threshold;
567604
std::size_t _lookups_library_size_threshold;
568605
};

0 commit comments

Comments
 (0)