diff --git a/include/nil/crypto3/zk/snark/arithmetization/plonk/constraint_system.hpp b/include/nil/crypto3/zk/snark/arithmetization/plonk/constraint_system.hpp index 6732765c..08c6bc2b 100644 --- a/include/nil/crypto3/zk/snark/arithmetization/plonk/constraint_system.hpp +++ b/include/nil/crypto3/zk/snark/arithmetization/plonk/constraint_system.hpp @@ -253,6 +253,58 @@ namespace nil { } + std::vector lookup_parts( + std::size_t max_quotient_chunks + ) const { + if( max_quotient_chunks == 0 ){ + return {this->sorted_lookup_columns_number()}; + } + + using VariableType = plonk_variable; + typedef math::expression_max_degree_visitor degree_visitor_type; + std::vector lookup_parts; + degree_visitor_type lookup_visitor; + + std::size_t lookup_chunk = 0; + std::size_t lookup_part = 0; + std::size_t max_constraint_degree; + for (const auto& gate :_lookup_gates) { + for (const auto& constr : gate.constraints) { + max_constraint_degree = 0; + for (const auto& li : constr.lookup_input) { + std::size_t deg = lookup_visitor.compute_max_degree(li); + max_constraint_degree = std::max( + max_constraint_degree, + deg + ); + } + if( lookup_chunk + max_constraint_degree + 1>= max_quotient_chunks ){ + lookup_parts.push_back(lookup_part); + lookup_chunk = 0; + lookup_part = 0; + } + // +1 because lookup input is multiplied by selector + lookup_chunk += max_constraint_degree + 1; + lookup_part++; + } + } + for (const auto& table : _lookup_tables) { + for( const auto &lookup_options: table.lookup_options ){ + // +3 because now any lookup option is lookup_column * lookup_selector * (1-q_last-q_blind) -- three polynomials degree rows_amount-1 + if( lookup_chunk + 3 >= max_quotient_chunks ){ + lookup_parts.push_back(lookup_part); + lookup_chunk = 0; + lookup_part = 0; + } + lookup_chunk += 3; + lookup_part++; + } + } + + lookup_parts.push_back(lookup_part); + return lookup_parts; + } + bool operator==(const plonk_constraint_system &other) const { return (this->_gates == other._gates) && (this->_copy_constraints == other._copy_constraints) && (this->_lookup_gates == other._lookup_gates) && (this->_lookup_tables == other._lookup_tables) && diff --git a/include/nil/crypto3/zk/snark/arithmetization/plonk/copy_constraint.hpp b/include/nil/crypto3/zk/snark/arithmetization/plonk/copy_constraint.hpp index a7b8220a..1dc44538 100644 --- a/include/nil/crypto3/zk/snark/arithmetization/plonk/copy_constraint.hpp +++ b/include/nil/crypto3/zk/snark/arithmetization/plonk/copy_constraint.hpp @@ -50,54 +50,24 @@ namespace nil { } plonk_variable first; plonk_variable second; - bool operator==(const plonk_copy_constraint &other){ - return ((first == other.first ) && (second == other.second)); - } protected: void initialize( const plonk_variable &_first, const plonk_variable &_second ){ - BOOST_ASSERT(_first.relative == false); - BOOST_ASSERT(_second.relative == false); - if(_first.type == _second.type){ - if(_first.index < _second.index){ - first = plonk_variable(_first); - second = plonk_variable(_second); - } else if (_first.index > _second.index){ - first = plonk_variable(_second); - second = plonk_variable(_first); - } else if (_first.rotation < _second.rotation){ - first = plonk_variable(_first); - second = plonk_variable(_second); - } else if (_first.rotation > _second.rotation){ - first = plonk_variable(_second); - second = plonk_variable(_first); - } else { - BOOST_ASSERT_MSG(false, "Copy constraint with equal variables"); - } - return; - } - if( _first.type == plonk_variable::column_type::witness){ - first = plonk_variable(_first); - second = plonk_variable(_second); - } else if ( - _first.type == plonk_variable::column_type::public_input && - _second.type != plonk_variable::column_type::witness - ){ - first = plonk_variable(_first); - second = plonk_variable(_second); - } else if( - _first.type == plonk_variable::column_type::constant && - _second.type == plonk_variable::column_type::selector - ){ - first = plonk_variable(_first); - second = plonk_variable(_second); + if( _first.relative || _second.relative ) std::cout << "Relative variable " << _first << " " << _second << std::endl; + if( _first == _second ) std::cout << "First == second " << _first << " " << _second << std::endl; + BOOST_ASSERT_MSG( _first != _second, "First and second variables are equal" ); + BOOST_ASSERT_MSG( _first.relative == false, "First variable in copy constraint is relative" ); + BOOST_ASSERT_MSG( _second.relative == false, "Second variable in copy constraint is relative" ); + + if(_first < _second ){ + first = _first; + second = _second; } else { - first = plonk_variable(_second); - second = plonk_variable(_first); + first = _second; + second = _first; } - return; } }; @@ -105,6 +75,16 @@ namespace nil { bool operator==(const plonk_copy_constraint &a, const plonk_copy_constraint &b) { return a.first == b.first && a.second == b.second; } + + template + bool operator!=(const plonk_copy_constraint &a, const plonk_copy_constraint &b) { + return !(a == b); + } + + template + bool operator<(const plonk_copy_constraint &a, const plonk_copy_constraint &b) { + return a.first < b.first || (a.first == b.first && a.second < b.second); + } } // namespace snark } // namespace zk } // namespace crypto3 diff --git a/include/nil/crypto3/zk/snark/systems/plonk/placeholder/detail/profiling.hpp b/include/nil/crypto3/zk/snark/systems/plonk/placeholder/detail/profiling.hpp index f96677ff..5e18e4cb 100644 --- a/include/nil/crypto3/zk/snark/systems/plonk/placeholder/detail/profiling.hpp +++ b/include/nil/crypto3/zk/snark/systems/plonk/placeholder/detail/profiling.hpp @@ -33,7 +33,6 @@ #include #include -#include #include namespace nil { @@ -46,52 +45,96 @@ namespace nil { // but it is not convenient to place it inside any of these classes. // // This piece of code is used in different projects with verifiers, and it's not good ot repeat it. + template struct placeholder_info{ + using variable_indices_type = std::map, std::size_t>; + std::size_t batches_num; std::vector batches_sizes; std::size_t poly_num; std::size_t quotient_size; + std::size_t permutation_batch_size; bool use_lookups; + bool use_permutations; + + // Commitments order in placeholder proof + int variable_value_batch_order; + int permutation_batch_order; + int quotient_batch_order; + int lookup_batch_order; + + // Polynomial_amount + std::size_t permutation_poly_amount; + std::size_t lookup_poly_amount; + std::size_t permutation_size; std::size_t round_proof_layers_num; + + variable_indices_type var_indices; + std::vector permuted_zero_indices; }; template - placeholder_info prepare_placeholder_info(); + placeholder_info prepare_placeholder_info(); // TODO remove permutation size template, bool> = true> - placeholder_info prepare_placeholder_info( + placeholder_info prepare_placeholder_info( const typename PlaceholderParams::constraint_system_type &constraint_system, - const typename nil::crypto3::zk::snark::placeholder_public_preprocessor::preprocessed_data_type::common_data_type &common_data, - const typename PlaceholderParams::commitment_scheme_type::params_type &fri_params, - std::size_t perm_size + const typename nil::crypto3::zk::snark::placeholder_public_preprocessor::preprocessed_data_type::common_data_type &common_data ) { + placeholder_info res; auto &desc = common_data.desc; - placeholder_info res; + auto &fri_params = common_data.commitment_params; - res.permutation_size = perm_size; + res.permutation_size = common_data.permuted_columns.size(); res.use_lookups = constraint_system.num_lookup_gates() != 0; - res.batches_num = res.use_lookups ? 5 : 4; + res.use_permutations = common_data.permuted_columns.size() != 0; + + res.variable_value_batch_order = 0; + res.permutation_batch_order = res.use_lookups || res.use_permutations ? 1 : -1; + res.quotient_batch_order = res.use_lookups || res.use_permutations ? 2: 1; + res.lookup_batch_order = res.use_lookups? 3: -1; + std::cout << "Quotient batch order " << res.quotient_batch_order << std::endl; + + res.batches_num = 3; + if( res.use_lookups || res.use_permutations ) res.batches_num++; + if( res.use_lookups ) res.batches_num++; + + std::size_t cur = 0; res.batches_sizes.resize(res.batches_num); - res.batches_sizes[0] = res.permutation_size * 2 + 2 + desc.constant_columns + desc.selector_columns; - res.batches_sizes[1] = desc.witness_columns + desc.public_input_columns; - res.batches_sizes[2] = res.use_lookups ? 2 : 1; - // TODO: place it to one single place to prevent code duplication - std::size_t split_polynomial_size = std::max( - (res.permutation_size + 2) * (desc.rows_amount -1 ), - (constraint_system.lookup_poly_degree_bound() + 1) * (desc.rows_amount -1 )//, - ); - split_polynomial_size = std::max( - split_polynomial_size, - (common_data.max_gates_degree + 1) * (desc.rows_amount -1) - ); - split_polynomial_size = (split_polynomial_size % desc.rows_amount != 0)? - (split_polynomial_size / desc.rows_amount + 1): - (split_polynomial_size / desc.rows_amount); - res.quotient_size = res.batches_sizes[3] = split_polynomial_size; - if(res.use_lookups) res.batches_sizes[4] = constraint_system.sorted_lookup_columns_number(); + res.batches_sizes[cur++] = res.permutation_size * 2 + 2 + desc.constant_columns + desc.selector_columns; + res.batches_sizes[cur++] = desc.witness_columns + desc.public_input_columns; + + std::size_t full_permutation_polynomial_size = res.use_permutations? (res.permutation_size + 2) : 0; + std::size_t full_lookup_polynomial_size = res.use_lookups? (constraint_system.lookup_poly_degree_bound() + 1) : 0; + std::size_t full_gate_polynomial_size = (common_data.max_gates_degree + 1); + std::size_t max_quotient_size = std::max(full_permutation_polynomial_size, full_lookup_polynomial_size); + max_quotient_size = std::max(max_quotient_size, full_gate_polynomial_size); + res.permutation_batch_size = 0; + res.permutation_poly_amount = res.use_permutations? 1: 0; + res.lookup_poly_amount = res.use_lookups? 1: 0; + if( res.use_lookups || res.use_permutations ){ + res.permutation_batch_size = res.use_lookups ? 2 : 1; + if( common_data.max_quotient_chunks > 0 ){ + res.permutation_batch_size += full_permutation_polynomial_size/common_data.max_quotient_chunks; + res.permutation_batch_size += full_lookup_polynomial_size/common_data.max_quotient_chunks; + res.permutation_poly_amount += full_permutation_polynomial_size/common_data.max_quotient_chunks; + res.lookup_poly_amount += full_lookup_polynomial_size/common_data.max_quotient_chunks; + } + res.batches_sizes[cur++] = res.permutation_batch_size; + } + + max_quotient_size *= (desc.rows_amount - 1); + max_quotient_size = max_quotient_size % desc.rows_amount == 0 ? max_quotient_size / desc.rows_amount : max_quotient_size / desc.rows_amount + 1 ; + if( common_data.max_quotient_chunks == 0 ){ + res.quotient_size = res.batches_sizes[cur++] = max_quotient_size; + } else { + res.quotient_size = res.batches_sizes[cur++] = max_quotient_size < common_data.max_quotient_chunks? max_quotient_size: common_data.max_quotient_chunks; + } + + if(res.use_lookups) res.batches_sizes[cur++] = constraint_system.sorted_lookup_columns_number(); res.poly_num = std::accumulate(res.batches_sizes.begin(), res.batches_sizes.end(), 0); res.round_proof_layers_num = 0; @@ -99,6 +142,51 @@ namespace nil { res.round_proof_layers_num += log2(fri_params.D[i]->m) -1; } + // variable indices + using variable_type = nil::crypto3::zk::snark::plonk_variable; + auto &col_rotations = common_data.columns_rotations; + std::size_t j = 0; + + std::map zero_indices; + + for(std::size_t i = 0; i < common_data.desc.constant_columns; i++){ + for(auto& rot: col_rotations[i + common_data.desc.witness_columns + common_data.desc.public_input_columns]){ + variable_type v(i, rot, true, variable_type::column_type::constant); + res.var_indices[v] = j; + if( rot == 0 ) zero_indices[i + common_data.desc.witness_columns + common_data.desc.public_input_columns] = j; + j++; + } + } + for(std::size_t i = 0; i < common_data.desc.selector_columns; i++){ + for(auto& rot: col_rotations[i + common_data.desc.witness_columns + common_data.desc.public_input_columns + common_data.desc.constant_columns]){ + variable_type v(i, rot, true, variable_type::column_type::selector); + res.var_indices[v] = j; + if( rot == 0) zero_indices[i + common_data.desc.witness_columns + common_data.desc.public_input_columns + common_data.desc.constant_columns] = j; + j++; + } + } + for(std::size_t i = 0; i < common_data.desc.witness_columns; i++){ + for(auto& rot: col_rotations[i]){ + variable_type v(i, rot, true, variable_type::column_type::witness); + res.var_indices[v] = j; + if(rot == 0) zero_indices[i] = j; + j++; + } + } + for(std::size_t i = 0; i < common_data.desc.public_input_columns; i++){ + for(auto& rot: col_rotations[i + common_data.desc.witness_columns]){ + variable_type v(i, rot, true, variable_type::column_type::public_input); + res.var_indices[v] = j; + if(rot == 0) zero_indices[i + common_data.desc.witness_columns] = j; + j++; + } + } + + for( std::size_t i = 0; i < common_data.permuted_columns.size(); i++ ){ + std::size_t ind = common_data.permuted_columns[i]; + res.permuted_zero_indices.push_back(zero_indices[ind]); + } + return res; } diff --git a/include/nil/crypto3/zk/snark/systems/plonk/placeholder/lookup_argument.hpp b/include/nil/crypto3/zk/snark/systems/plonk/placeholder/lookup_argument.hpp index dc1acca6..149fc52e 100644 --- a/include/nil/crypto3/zk/snark/systems/plonk/placeholder/lookup_argument.hpp +++ b/include/nil/crypto3/zk/snark/systems/plonk/placeholder/lookup_argument.hpp @@ -199,7 +199,7 @@ namespace nil { typename FieldType::value_type beta = transcript.template challenge(); typename FieldType::value_type gamma = transcript.template challenge(); - auto part_sizes = lookup_parts(constraint_system, preprocessed_data.common_data.max_quotient_chunks); + auto part_sizes = constraint_system.lookup_parts(preprocessed_data.common_data.max_quotient_chunks); std::vector lookup_alphas; for(std::size_t i = 0; i < part_sizes.size() - 1; i++){ lookup_alphas.push_back(transcript.template challenge()); @@ -745,7 +745,7 @@ namespace nil { typename FieldType::value_type gamma = transcript.template challenge(); std::vector lookup_alphas; - auto parts = lookup_parts(constraint_system, common_data.max_quotient_chunks); + auto parts = constraint_system.lookup_parts(common_data.max_quotient_chunks); for(std::size_t i = 0; i < parts.size() - 1; i++){ lookup_alphas.push_back(transcript.template challenge()); } diff --git a/include/nil/crypto3/zk/snark/systems/plonk/placeholder/preprocessor.hpp b/include/nil/crypto3/zk/snark/systems/plonk/placeholder/preprocessor.hpp index d2118043..f2c4e590 100644 --- a/include/nil/crypto3/zk/snark/systems/plonk/placeholder/preprocessor.hpp +++ b/include/nil/crypto3/zk/snark/systems/plonk/placeholder/preprocessor.hpp @@ -558,7 +558,7 @@ namespace nil { BOOST_ASSERT(max_quotient_poly_chunks == 0 || max_quotient_poly_chunks > max_gates_degree ); std::size_t permutation_parts_num = permutation_partitions_num(permuted_columns.size(), max_quotient_poly_chunks); - std::size_t lookup_parts_num = lookup_parts(constraint_system, max_quotient_poly_chunks).size(); + std::size_t lookup_parts_num = constraint_system.lookup_parts(max_quotient_poly_chunks).size(); typename preprocessed_data_type::public_commitments_type public_commitments = commitments( public_polynomial_table, id_perm_polys, diff --git a/include/nil/crypto3/zk/snark/systems/plonk/placeholder/prover.hpp b/include/nil/crypto3/zk/snark/systems/plonk/placeholder/prover.hpp index 4f07262f..79010d74 100644 --- a/include/nil/crypto3/zk/snark/systems/plonk/placeholder/prover.hpp +++ b/include/nil/crypto3/zk/snark/systems/plonk/placeholder/prover.hpp @@ -368,11 +368,12 @@ namespace nil { } } - if(_is_lookup_enabled || constraint_system.copy_constraints().size() > 0){ + if(_is_lookup_enabled||constraint_system.copy_constraints().size() > 0){ _commitment_scheme.append_eval_point(PERMUTATION_BATCH, _proof.eval_proof.challenge); - _commitment_scheme.append_eval_point(PERMUTATION_BATCH, 0, _proof.eval_proof.challenge * _omega); } + if( constraint_system.copy_constraints().size() > 0 ) + _commitment_scheme.append_eval_point(PERMUTATION_BATCH, 0, _proof.eval_proof.challenge * _omega); if(_is_lookup_enabled){ _commitment_scheme.append_eval_point(PERMUTATION_BATCH, preprocessed_public_data.common_data.permutation_parts , _proof.eval_proof.challenge * _omega); diff --git a/include/nil/crypto3/zk/snark/systems/plonk/placeholder/verifier.hpp b/include/nil/crypto3/zk/snark/systems/plonk/placeholder/verifier.hpp index 46297842..175fd8b2 100644 --- a/include/nil/crypto3/zk/snark/systems/plonk/placeholder/verifier.hpp +++ b/include/nil/crypto3/zk/snark/systems/plonk/placeholder/verifier.hpp @@ -95,9 +95,11 @@ namespace nil { if( _is_lookup_enabled || constraint_system.copy_constraints().size() > 0){ _commitment_scheme.append_eval_point(PERMUTATION_BATCH, challenge); - _commitment_scheme.append_eval_point(PERMUTATION_BATCH, 0, challenge * _omega); } + if( constraint_system.copy_constraints().size() > 0 ) + _commitment_scheme.append_eval_point(PERMUTATION_BATCH, 0 , challenge * _omega); + if (_is_lookup_enabled) { _commitment_scheme.append_eval_point(PERMUTATION_BATCH, common_data.permutation_parts , challenge * _omega); _commitment_scheme.append_eval_point(LOOKUP_BATCH, challenge); @@ -267,7 +269,7 @@ namespace nil { } } - for (std::size_t i = 0; i < 0 + public_input_columns; i++) { + for (std::size_t i = 0; i < public_input_columns; i++) { std::size_t i_global_index = witness_columns + i; std::size_t j = 0;