@@ -134,6 +134,80 @@ namespace nil {
134
134
return result.str ();
135
135
}
136
136
137
+ bool detect_polynomial (crypto3::math::non_linear_combination<variable_type> const & comb) {
138
+ std::unordered_set<variable_type> comb_vars;
139
+
140
+ for (auto it = std::begin (comb); it != std::cend (comb); ++it ) {
141
+ const auto &vars = it->get_vars ();
142
+ for (auto v = std::cbegin (vars); v != std::cend (vars); ++v) {
143
+ comb_vars.insert (*v);
144
+ }
145
+ }
146
+
147
+ return comb_vars.size () == 1 ;
148
+ }
149
+
150
+ std::string constraint_computation_code_optimize_polynomial (
151
+ variable_indices_type &_var_indices,
152
+ const constraint_type &constraint
153
+ ){
154
+ std::stringstream result;
155
+
156
+ crypto3::math::expression_to_non_linear_combination_visitor<variable_type> visitor;
157
+ auto comb = visitor.convert (constraint);
158
+
159
+ if (_deduce_horner && detect_polynomial (comb)) {
160
+ comb.sort_terms_by_degree ();
161
+ /* First term always exists, as polynomial contains at least one term */
162
+ std::size_t degree = comb.terms [0 ].get_vars ().size ();
163
+ result << " \t\t /* Constraint is a polynomial over one variable. Using Horner's formula */" << std::endl;
164
+ auto it = std::cbegin (comb);
165
+ /* Load temporary variable */
166
+ result << " \t\t x = basic_marshalling.get_uint256_be(blob, " << _var_indices.at (comb.terms [0 ].get_vars ()[0 ]) * 0x20 << " );" << std::endl;
167
+ if (it->get_coeff () == PlaceholderParams::field_type::value_type::one ()) {
168
+ result << " \t\t sum = x;" << std::endl;
169
+ } else {
170
+ result << " \t\t sum = " << it->get_coeff () <<" ;" << std::endl;
171
+ result << " \t\t sum = mulmod(sum, x, modulus);" << std::endl;
172
+ }
173
+ ++it;
174
+ --degree;
175
+ while (degree != 0 ) {
176
+ if (degree == it->get_vars ().size ()) {
177
+ result << " \t\t sum = addmod(sum, " << it->get_coeff () << " , modulus);" << std::endl;
178
+ ++it;
179
+ } else {
180
+ result << " /* term with zero coeficient is skipped */" << std::endl;
181
+ }
182
+ result << " \t\t sum = mulmod(sum, x, modulus);" << std::endl;
183
+ --degree;
184
+ }
185
+ if (it != std::cend (comb)) {
186
+ result << " /* last term */" << std::endl;
187
+ result << " \t\t sum = addmod(sum, " << it->get_coeff () << " , modulus);" << std::endl;
188
+ }
189
+ result << " \t\t /* End using Horner's formula */" << std::endl;
190
+ } else {
191
+ 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;
203
+ }
204
+ }
205
+ result << " \t\t sum = addmod(sum, prod, modulus);" << std::endl;
206
+ }
207
+ }
208
+ return result.str ();
209
+ }
210
+
137
211
std::string constraint_computation_code (
138
212
variable_indices_type &_var_indices,
139
213
const constraint_type &constraint
@@ -144,7 +218,7 @@ namespace nil {
144
218
crypto3::math::expression_to_non_linear_combination_visitor<variable_type> visitor;
145
219
auto comb = visitor.convert (constraint);
146
220
result << " \t\t sum = 0;" << std::endl;
147
- for ( auto it = std::cbegin (comb); it != std::cend (comb); it++ ){
221
+ for ( auto it = std::cbegin (comb); it != std::cend (comb); ++it ){
148
222
bool coeff_one = (it->get_coeff () == PlaceholderParams::field_type::value_type::one ());
149
223
if (!coeff_one) result << " \t\t prod = " << it->get_coeff () << " ;" << std::endl;
150
224
const auto &vars = it->get_vars ();
@@ -171,7 +245,8 @@ namespace nil {
171
245
std::size_t gates_library_size_threshold = 1600 ,
172
246
std::size_t lookups_library_size_threshold = 1600 ,
173
247
std::size_t gates_contract_size_threshold = 1400 ,
174
- std::size_t lookups_contract_size_threshold = 1400
248
+ std::size_t lookups_contract_size_threshold = 1400 ,
249
+ bool deduce_horner = true
175
250
) :
176
251
_constraint_system (constraint_system),
177
252
_common_data (common_data),
@@ -181,7 +256,8 @@ namespace nil {
181
256
_gates_library_size_threshold (gates_library_size_threshold),
182
257
_lookups_library_size_threshold (lookups_library_size_threshold),
183
258
_gates_contract_size_threshold (gates_contract_size_threshold),
184
- _lookups_contract_size_threshold (lookups_contract_size_threshold)
259
+ _lookups_contract_size_threshold (lookups_contract_size_threshold),
260
+ _deduce_horner (deduce_horner)
185
261
{
186
262
std::size_t found = folder_name.rfind (" /" );
187
263
if ( found == std::string::npos ){
@@ -264,12 +340,13 @@ namespace nil {
264
340
out.close ();
265
341
}
266
342
267
- std::string gate_computation_code (const gate_type& gate){
343
+ std::string gate_computation_code (const gate_type& gate) {
268
344
std::stringstream out;
269
345
270
346
out << " \t\t gate = 0;" << std::endl;
347
+ int c = 0 ;
271
348
for (const auto &constraint: gate.constraints ){
272
- out << constraint_computation_code (_var_indices, constraint);
349
+ out << constraint_computation_code_optimize_polynomial (_var_indices, constraint);
273
350
out << " \t\t gate = addmod(gate, mulmod(theta_acc, sum, modulus), modulus);" << std::endl;
274
351
out << " \t\t theta_acc = mulmod(theta_acc, theta, modulus);" << std::endl;
275
352
}
@@ -630,6 +707,7 @@ namespace nil {
630
707
std::size_t _public_input_offset;
631
708
variable_indices_type _var_indices;
632
709
710
+ bool _deduce_horner;
633
711
std::string _gate_includes;
634
712
std::string _lookup_includes;
635
713
std::size_t _gates_contract_size_threshold;
0 commit comments