Skip to content

Commit

Permalink
Added polynomial detection and Horner's formula #32
Browse files Browse the repository at this point in the history
  • Loading branch information
vo-nil committed Oct 17, 2023
1 parent 24b45f0 commit 739dcc4
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 5 deletions.
94 changes: 89 additions & 5 deletions include/nil/blueprint/transpiler/evm_verifier_gen.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,84 @@ namespace nil {
return result.str();
}

bool detect_polynomial(crypto3::math::non_linear_combination<variable_type> const& comb) {
std::unordered_set<variable_type> comb_vars;

for (auto it = std::begin(comb); it != std::cend(comb); ++it ) {
const auto &vars = it->get_vars();
for (auto v = std::cbegin(vars); v != std::cend(vars); ++v) {
comb_vars.insert(*v);
}
}

return comb_vars.size() == 1;
}

std::string constraint_computation_code_optimize_polynomial(
variable_indices_type &_var_indices,
const constraint_type &constraint
){
std::stringstream result;

crypto3::math::expression_to_non_linear_combination_visitor<variable_type> visitor;
auto comb = visitor.convert(constraint);
std::cout << "generating for constraint:" << constraint << std::endl;

if (_deduce_horner && detect_polynomial(comb)) {
comb.sort_terms_by_degree();
/* First term always exists, as polynomial contains at least one term */
std::size_t degree = comb.terms[0].get_vars().size();
std::cout << "Poly degree: " << degree << std::endl;
result << "\t\t/* Constraint is a polynomial over one variable. Using Horner's formula */" << std::endl;
auto it = std::cbegin(comb);
/* Load temporary variable */
result << "\t\tx = basic_marshalling.get_uint256_be(blob, " << _var_indices.at(comb.terms[0].get_vars()[0]) * 0x20 << ");" << std::endl;
if (it->get_coeff() == PlaceholderParams::field_type::value_type::one()) {
result << "\t\tsum = x;" << std::endl;
} else {
result << "\t\tsum = " << it->get_coeff() <<";" << std::endl;
result << "\t\tsum = mulmod(sum, x, modulus);" << std::endl;
}
++it;
--degree;
while (degree != 0) {
if (degree == it->get_vars().size()) {
result << "\t\tsum = addmod(sum, " << it->get_coeff() << ", modulus);" << std::endl;
++it;
} else {
result << "/* term with zero coeficient is skipped */" << std::endl;
std::cout << "zero!" << std::endl;
}
result << "\t\tsum = mulmod(sum, x, modulus);" << std::endl;
--degree;
}
if (it != std::cend(comb)) {
result << "/* last term */" << std::endl;
result << "\t\tsum = addmod(sum, " << it->get_coeff() << ", modulus);" << std::endl;
}
result << "\t\t/* End using Horner's formula */" << std::endl;
} else {
result << "\t\tsum = 0;" << std::endl;
for( auto it = std::cbegin(comb); it != std::cend(comb); ++it ){
std::cout << "it: " << *it << std::endl;
bool coeff_one = (it->get_coeff() == PlaceholderParams::field_type::value_type::one());
if(!coeff_one) result << "\t\tprod = " << it->get_coeff() << ";" << std::endl;
const auto &vars = it->get_vars();
for( auto it2 = std::cbegin(vars); it2 != std::cend(vars); it2++ ){
const variable_type &v = *it2;
if(coeff_one){
coeff_one = false;
result << "\t\tprod = basic_marshalling.get_uint256_be(blob, " << _var_indices.at(v) * 0x20 << ");" << std::endl;
} else{
result << "\t\tprod = mulmod(prod, basic_marshalling.get_uint256_be(blob, " << _var_indices.at(v) * 0x20 << "), modulus);" << std::endl;
}
}
result << "\t\tsum = addmod(sum, prod, modulus);" << std::endl;
}
}
return result.str();
}

std::string constraint_computation_code(
variable_indices_type &_var_indices,
const constraint_type &constraint
Expand All @@ -144,7 +222,7 @@ namespace nil {
crypto3::math::expression_to_non_linear_combination_visitor<variable_type> visitor;
auto comb = visitor.convert(constraint);
result << "\t\tsum = 0;" << std::endl;
for( auto it = std::cbegin(comb); it != std::cend(comb); it++ ){
for( auto it = std::cbegin(comb); it != std::cend(comb); ++it ){
bool coeff_one = (it->get_coeff() == PlaceholderParams::field_type::value_type::one());
if(!coeff_one) result << "\t\tprod = " << it->get_coeff() << ";" << std::endl;
const auto &vars = it->get_vars();
Expand All @@ -171,7 +249,8 @@ namespace nil {
std::size_t gates_library_size_threshold = 1600,
std::size_t lookups_library_size_threshold = 1600,
std::size_t gates_contract_size_threshold = 1400,
std::size_t lookups_contract_size_threshold = 1400
std::size_t lookups_contract_size_threshold = 1400,
bool deduce_horner = true
) :
_constraint_system(constraint_system),
_common_data(common_data),
Expand All @@ -181,7 +260,8 @@ namespace nil {
_gates_library_size_threshold(gates_library_size_threshold),
_lookups_library_size_threshold(lookups_library_size_threshold),
_gates_contract_size_threshold(gates_contract_size_threshold),
_lookups_contract_size_threshold(lookups_contract_size_threshold)
_lookups_contract_size_threshold(lookups_contract_size_threshold),
_deduce_horner(deduce_horner)
{
std::size_t found = folder_name.rfind("/");
if( found == std::string::npos ){
Expand Down Expand Up @@ -264,12 +344,14 @@ namespace nil {
out.close();
}

std::string gate_computation_code(const gate_type& gate){
std::string gate_computation_code(const gate_type& gate) {
std::stringstream out;

out << "\t\tgate = 0;" << std::endl;
int c = 0;
for(const auto &constraint: gate.constraints){
out << constraint_computation_code(_var_indices, constraint);
std::cout << "constraint: " << c++ << std::endl;
out << constraint_computation_code_optimize_polynomial(_var_indices, constraint);
out << "\t\tgate = addmod(gate, mulmod(theta_acc, sum, modulus), modulus);" << std::endl;
out << "\t\ttheta_acc = mulmod(theta_acc, theta, modulus);" << std::endl;
}
Expand Down Expand Up @@ -363,6 +445,7 @@ namespace nil {

i = 0;
for(const auto &gate: _constraint_system.gates()) {
std::cout << "gate: " << i << std::endl;
std::string code = gate_computation_code(gate);
gate_costs[i] = std::make_pair(i, estimate_gate_cost(code));
gate_codes[i] = code;
Expand Down Expand Up @@ -630,6 +713,7 @@ namespace nil {
std::size_t _public_input_offset;
variable_indices_type _var_indices;

bool _deduce_horner;
std::string _gate_includes;
std::string _lookup_includes;
std::size_t _gates_contract_size_threshold;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ namespace nil {
uint256 sum;
uint256 gate;
uint256 prod;
uint256 x;
$GATE_ASSEMBLY_CODE$
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ contract modular_gate_argument_$TEST_NAME$ is IGateArgument{
) external view returns (uint256 F){
uint256 theta_acc = 1;
uint256 eval;
uint256 x;
$GATE_ARGUMENT_COMPUTATION$
}
Expand Down

0 comments on commit 739dcc4

Please sign in to comment.