40
40
#include < nil/blueprint/transpiler/templates/commitment_scheme.hpp>
41
41
#include < nil/blueprint/transpiler/templates/external_gate.hpp>
42
42
#include < nil/blueprint/transpiler/templates/external_lookup.hpp>
43
+ #include < nil/blueprint/transpiler/templates/utils_template.hpp>
43
44
#include < nil/blueprint/transpiler/lpc_scheme_gen.hpp>
44
45
#include < nil/blueprint/transpiler/util.hpp>
45
46
@@ -134,6 +135,7 @@ namespace nil {
134
135
return result.str ();
135
136
}
136
137
138
+ /* Detect whether combination is a polynomial over one variable */
137
139
bool detect_polynomial (crypto3::math::non_linear_combination<variable_type> const & comb) {
138
140
std::unordered_set<variable_type> comb_vars;
139
141
@@ -147,7 +149,32 @@ namespace nil {
147
149
return comb_vars.size () == 1 ;
148
150
}
149
151
150
- std::string constraint_computation_code_optimize_polynomial (
152
+ /* Detect whether term is a power of one variable. If such, return this power */
153
+ std::size_t term_is_power (crypto3::math::term<variable_type> const & term) {
154
+ const auto &vars = term.get_vars ();
155
+ auto var = std::cbegin (vars);
156
+
157
+ if (var == std::cend (vars))
158
+ return 0 ;
159
+
160
+ variable_type prev_var = *var;
161
+ ++var;
162
+
163
+ std::size_t power = 1 ;
164
+
165
+ while (var != std::cend (vars)) {
166
+ if (*var != prev_var) {
167
+ return 0 ;
168
+ }
169
+ ++power;
170
+ prev_var = *var;
171
+ ++var;
172
+ }
173
+
174
+ return power;
175
+ }
176
+
177
+ std::string constraint_computation_code_optimized (
151
178
variable_indices_type &_var_indices,
152
179
const constraint_type &constraint
153
180
){
@@ -189,20 +216,31 @@ namespace nil {
189
216
result << " \t\t /* End using Horner's formula */" << std::endl;
190
217
} else {
191
218
result << " \t\t sum = 0;" << std::endl;
192
- for ( auto it = std::cbegin (comb); it != std::cend (comb); ++it ){
193
- bool coeff_one = (it->get_coeff () == PlaceholderParams::field_type::value_type::one ());
194
- if (!coeff_one) result << " \t\t prod = " << it->get_coeff () << " ;" << std::endl;
195
- const auto &vars = it->get_vars ();
196
- for ( auto it2 = std::cbegin (vars); it2 != std::cend (vars); it2++ ){
197
- const variable_type &v = *it2;
198
- if (coeff_one){
199
- coeff_one = false ;
200
- result << " \t\t prod = basic_marshalling.get_uint256_be(blob, " << _var_indices.at (v) * 0x20 << " );" << std::endl;
201
- } else {
202
- result << " \t\t prod = mulmod(prod, basic_marshalling.get_uint256_be(blob, " << _var_indices.at (v) * 0x20 << " ), modulus);" << std::endl;
219
+ for (auto term = std::cbegin (comb); term != std::cend (comb); ++term) {
220
+ const auto &vars = term->get_vars ();
221
+ std::size_t power;
222
+
223
+ /* Using special powX function is only feasible for powers >= 4 */
224
+ if ( _optimize_powers && ((power = term_is_power (*term)) >= 4 ) ) {
225
+ _term_powers.insert (power);
226
+ result << " \t\t prod = utils.pow" << power << " (basic_marshalling.get_uint256_be(blob, " << _var_indices.at (vars[0 ]) * 0x20 << " ));" << std::endl;
227
+ } else {
228
+ for (auto var = std::cbegin (vars); var != std::cend (vars); ++var) {
229
+ if (var == std::cbegin (vars)) {
230
+ result << " \t\t prod = basic_marshalling.get_uint256_be(blob, " << _var_indices.at (*var) * 0x20 << " );" << std::endl;
231
+ } else {
232
+ result << " \t\t prod = mulmod(prod, basic_marshalling.get_uint256_be(blob, " << _var_indices.at (*var) * 0x20 << " ), modulus);" << std::endl;
233
+ }
203
234
}
204
235
}
205
- result << " \t\t sum = addmod(sum, prod, modulus);" << std::endl;
236
+ if (vars.size () == 0 ) {
237
+ result << " \t\t sum = addmod(sum, " << term->get_coeff () << " , modulus);" << std::endl;
238
+ } else {
239
+ if (term->get_coeff () != PlaceholderParams::field_type::value_type::one ()) {
240
+ result << " \t\t prod = mulmod(prod, " << term->get_coeff () << " , modulus);" << std::endl;
241
+ }
242
+ result << " \t\t sum = addmod(sum, prod, modulus);" << std::endl;
243
+ }
206
244
}
207
245
}
208
246
return result.str ();
@@ -242,11 +280,12 @@ namespace nil {
242
280
const typename PlaceholderParams::commitment_scheme_type &lpc_scheme,
243
281
std::size_t permutation_size,
244
282
std::string folder_name,
245
- std::size_t gates_library_size_threshold = 1600 ,
246
- std::size_t lookups_library_size_threshold = 1600 ,
283
+ std::size_t gates_library_size_threshold = 1400 ,
284
+ std::size_t lookups_library_size_threshold = 1400 ,
247
285
std::size_t gates_contract_size_threshold = 1400 ,
248
286
std::size_t lookups_contract_size_threshold = 1400 ,
249
- bool deduce_horner = true
287
+ bool deduce_horner = true ,
288
+ bool optimize_powers = true
250
289
) :
251
290
_constraint_system (constraint_system),
252
291
_common_data (common_data),
@@ -257,7 +296,8 @@ namespace nil {
257
296
_lookups_library_size_threshold (lookups_library_size_threshold),
258
297
_gates_contract_size_threshold (gates_contract_size_threshold),
259
298
_lookups_contract_size_threshold (lookups_contract_size_threshold),
260
- _deduce_horner (deduce_horner)
299
+ _deduce_horner (deduce_horner),
300
+ _optimize_powers (optimize_powers)
261
301
{
262
302
std::size_t found = folder_name.rfind (" /" );
263
303
if ( found == std::string::npos ){
@@ -346,9 +386,10 @@ namespace nil {
346
386
out << " \t\t gate = 0;" << std::endl;
347
387
int c = 0 ;
348
388
for (const auto &constraint: gate.constraints ){
349
- out << constraint_computation_code_optimize_polynomial (_var_indices, constraint);
389
+ out << constraint_computation_code_optimized (_var_indices, constraint);
350
390
out << " \t\t gate = addmod(gate, mulmod(theta_acc, sum, modulus), modulus);" << std::endl;
351
391
out << " \t\t theta_acc = mulmod(theta_acc, theta, modulus);" << std::endl;
392
+ c++;
352
393
}
353
394
variable_type sel_var (gate.selector_index , 0 , true , variable_type::column_type::selector);
354
395
out << " \t\t gate = mulmod(gate, basic_marshalling.get_uint256_be(blob, " << _var_indices.at (sel_var) * 0x20 << " ), modulus);" << std::endl;
@@ -427,6 +468,29 @@ namespace nil {
427
468
return buckets;
428
469
}
429
470
471
+ std::string generate_power_function (std::size_t power) {
472
+ std::stringstream result;
473
+ std::vector<std::string> ops;
474
+
475
+ result << " \t function pow" << power << " (uint256 base) internal pure returns (uint256 result) {" << std::endl;
476
+ result << " \t\t result = base;" << std::endl;
477
+
478
+ while (power > 1 ) {
479
+ if (power & 1 ) {
480
+ ops.push_back (" \t\t result = mulmod(result, base, modulus);" );
481
+ }
482
+ ops.push_back (" \t\t result = mulmod(result, result, modulus);" );
483
+ power >>= 1 ;
484
+ }
485
+
486
+ for (auto op = ops.rbegin (); op != ops.rend (); ++op) {
487
+ result << *op << std::endl;
488
+ }
489
+
490
+ result << " \t }" << std::endl;
491
+ return result.str ();
492
+ }
493
+
430
494
std::string print_gate_argument (){
431
495
std::size_t gates_count = _constraint_system.gates ().size ();
432
496
if (gates_count == 0 )
@@ -479,6 +543,19 @@ namespace nil {
479
543
print_gates_library_file (lib.first , lib.second , gate_codes);
480
544
}
481
545
546
+ std::stringstream power_functions;
547
+ for (std::size_t power: _term_powers) {
548
+ power_functions << generate_power_function (power);
549
+ }
550
+
551
+ std::string utils_library (utils_library_template);
552
+ boost::replace_all (utils_library, " $MODULUS$" , to_string (PlaceholderParams::field_type::modulus));
553
+ boost::replace_all (utils_library, " $POWER_FUNCTIONS$" , power_functions.str ());
554
+ std::ofstream utils;
555
+ utils.open (_folder_name + " /utils.sol" );
556
+ utils << utils_library;
557
+ utils.close ();
558
+
482
559
if (inlined_gate_codes.size () > 0 ) {
483
560
gate_argument_str << " \t\t uint256 sum;" << std::endl;
484
561
gate_argument_str << " \t\t uint256 prod;" << std::endl;
@@ -708,6 +785,10 @@ namespace nil {
708
785
variable_indices_type _var_indices;
709
786
710
787
bool _deduce_horner;
788
+
789
+ bool _optimize_powers;
790
+ std::unordered_set<std::size_t > _term_powers;
791
+
711
792
std::string _gate_includes;
712
793
std::string _lookup_includes;
713
794
std::size_t _gates_contract_size_threshold;
0 commit comments