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

Commit b8fb56d

Browse files
authored
Added polynomial detection and Horner's formula #32 (#35)
* Added polynomial detection and Horner's formula #32 * Removed debug tracing #32
1 parent 24b45f0 commit b8fb56d

File tree

3 files changed

+85
-5
lines changed

3 files changed

+85
-5
lines changed

include/nil/blueprint/transpiler/evm_verifier_gen.hpp

+83-5
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,80 @@ namespace nil {
134134
return result.str();
135135
}
136136

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\tx = 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\tsum = x;" << std::endl;
169+
} else {
170+
result << "\t\tsum = " << it->get_coeff() <<";" << std::endl;
171+
result << "\t\tsum = 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\tsum = 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\tsum = mulmod(sum, x, modulus);" << std::endl;
183+
--degree;
184+
}
185+
if (it != std::cend(comb)) {
186+
result << "/* last term */" << std::endl;
187+
result << "\t\tsum = 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\tsum = 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\tprod = " << 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\tprod = basic_marshalling.get_uint256_be(blob, " << _var_indices.at(v) * 0x20 << ");" << std::endl;
201+
} else{
202+
result << "\t\tprod = mulmod(prod, basic_marshalling.get_uint256_be(blob, " << _var_indices.at(v) * 0x20 << "), modulus);" << std::endl;
203+
}
204+
}
205+
result << "\t\tsum = addmod(sum, prod, modulus);" << std::endl;
206+
}
207+
}
208+
return result.str();
209+
}
210+
137211
std::string constraint_computation_code(
138212
variable_indices_type &_var_indices,
139213
const constraint_type &constraint
@@ -144,7 +218,7 @@ namespace nil {
144218
crypto3::math::expression_to_non_linear_combination_visitor<variable_type> visitor;
145219
auto comb = visitor.convert(constraint);
146220
result << "\t\tsum = 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 ){
148222
bool coeff_one = (it->get_coeff() == PlaceholderParams::field_type::value_type::one());
149223
if(!coeff_one) result << "\t\tprod = " << it->get_coeff() << ";" << std::endl;
150224
const auto &vars = it->get_vars();
@@ -171,7 +245,8 @@ namespace nil {
171245
std::size_t gates_library_size_threshold = 1600,
172246
std::size_t lookups_library_size_threshold = 1600,
173247
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
175250
) :
176251
_constraint_system(constraint_system),
177252
_common_data(common_data),
@@ -181,7 +256,8 @@ namespace nil {
181256
_gates_library_size_threshold(gates_library_size_threshold),
182257
_lookups_library_size_threshold(lookups_library_size_threshold),
183258
_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)
185261
{
186262
std::size_t found = folder_name.rfind("/");
187263
if( found == std::string::npos ){
@@ -264,12 +340,13 @@ namespace nil {
264340
out.close();
265341
}
266342

267-
std::string gate_computation_code(const gate_type& gate){
343+
std::string gate_computation_code(const gate_type& gate) {
268344
std::stringstream out;
269345

270346
out << "\t\tgate = 0;" << std::endl;
347+
int c = 0;
271348
for(const auto &constraint: gate.constraints){
272-
out << constraint_computation_code(_var_indices, constraint);
349+
out << constraint_computation_code_optimize_polynomial(_var_indices, constraint);
273350
out << "\t\tgate = addmod(gate, mulmod(theta_acc, sum, modulus), modulus);" << std::endl;
274351
out << "\t\ttheta_acc = mulmod(theta_acc, theta, modulus);" << std::endl;
275352
}
@@ -630,6 +707,7 @@ namespace nil {
630707
std::size_t _public_input_offset;
631708
variable_indices_type _var_indices;
632709

710+
bool _deduce_horner;
633711
std::string _gate_includes;
634712
std::string _lookup_includes;
635713
std::size_t _gates_contract_size_threshold;

include/nil/blueprint/transpiler/templates/external_gate.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ namespace nil {
1414
uint256 sum;
1515
uint256 gate;
1616
uint256 prod;
17+
uint256 x;
1718
1819
$GATE_ASSEMBLY_CODE$
1920

include/nil/blueprint/transpiler/templates/gate_argument.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ contract modular_gate_argument_$TEST_NAME$ is IGateArgument{
4343
) external view returns (uint256 F){
4444
uint256 theta_acc = 1;
4545
uint256 eval;
46+
uint256 x;
4647
4748
$GATE_ARGUMENT_COMPUTATION$
4849
}

0 commit comments

Comments
 (0)