diff --git a/include/nil/crypto3/zk/commitments/batched_commitment.hpp b/include/nil/crypto3/zk/commitments/batched_commitment.hpp index 510720ea..d500881c 100644 --- a/include/nil/crypto3/zk/commitments/batched_commitment.hpp +++ b/include/nil/crypto3/zk/commitments/batched_commitment.hpp @@ -35,6 +35,7 @@ #include #include +#include #include #include @@ -223,14 +224,14 @@ namespace nil { void append_eval_points(std::size_t batch_id, std::set points){ BOOST_ASSERT(_locked[batch_id]); // We can add points only after polynomails are commited. for(std::size_t i = 0; i < _points[batch_id].size(); i++){ - _points[batch_id][i].insert(points.first(), points.last()); + _points[batch_id][i].insert(_points[batch_id][i].end(), points.begin(), points.end()); } } // This function don't check evaluation points repeats void append_eval_points(std::size_t batch_id, std::size_t poly_id, std::set points){ BOOST_ASSERT(_locked[batch_id]); // We can add points only after polynomails are commited. - _points[batch_id][poly_id].insert(points.first(), points.last()); + _points[batch_id][poly_id].insert(_points[batch_id][poly_id].end(), points.begin(), points.end()); } void set_batch_size(std::size_t batch_id, std::size_t batch_size){ diff --git a/include/nil/crypto3/zk/commitments/polynomial/kzg.hpp b/include/nil/crypto3/zk/commitments/polynomial/kzg.hpp index 85f6dc22..c2781f96 100644 --- a/include/nil/crypto3/zk/commitments/polynomial/kzg.hpp +++ b/include/nil/crypto3/zk/commitments/polynomial/kzg.hpp @@ -823,6 +823,262 @@ namespace nil { } }; + + // Placeholder-friendly class, KZGv2 + /** + * References: + * "Efficient polynomial commitment schemes for + * multiple points and polynomials", + * Dan Boneh, Justin Drake, Ben Fisch, + * + */ + template> + class kzg_commitment_scheme_v2 : public polys_evaluator{ + public: + using curve_type = typename KZGScheme::curve_type; + using field_type = typename KZGScheme::field_type; + using params_type = typename KZGScheme::params_type; + + // This should be marshallable and transcriptable type + using commitment_type = typename KZGScheme::commitment_type; + using verification_key_type = typename curve_type::template g2_type<>::value_type; + using transcript_type = typename KZGScheme::transcript_type; + using transcript_hash_type = typename KZGScheme::transcript_hash_type; + using poly_type = PolynomialType; + struct proof_type { + eval_storage z; + typename KZGScheme::single_commitment_type pi_1, pi_2; + }; + using endianness = nil::marshalling::option::big_endian; + private: + params_type _params; + std::map _commitments; + std::map> _ind_commitments; + std::vector _merged_points; + protected: + + // Differs from static one by input parameters + void merge_eval_points() { + std::set set; + for( auto const &it:this->_points){ + auto k = it.first; + for (std::size_t i = 0; i < this->_points[k].size(); ++i) { + set.insert(this->_points[k][i].begin(), this->_points[k][i].end()); + } + } + _merged_points = std::vector(set.begin(), set.end()); + } + + typename math::polynomial + set_difference_polynom( + std::vector merged_points, + std::vector points + ) { + std::sort(merged_points.begin(), merged_points.end()); + std::sort(points.begin(), points.end()); + std::vector result; + std::set_difference(merged_points.begin(), merged_points.end(), points.begin(), points.end(), std::back_inserter(result)); + if (result.size() == 0) { + return typename math::polynomial({{1}}); + } + BOOST_ASSERT(this->get_V(result) * this->get_V(points) == this->get_V(merged_points)); + return this->get_V(result); + } + + void update_transcript(std::size_t batch_ind, typename KZGScheme::transcript_type &transcript) { + /* The procedure of updating the transcript is subject to review and change + * #295 */ + + // Push commitments to transcript + transcript(_commitments[batch_ind]); + + // Push evaluation points to transcript + for( std::size_t i = 0; i < this->_z.get_batch_size(batch_ind); i++){ + for( std::size_t j = 0; j < this->_z.get_poly_points_number(batch_ind, i); j++ ) { + nil::marshalling::status_type status; + std::vector byteblob = + nil::marshalling::pack(this->_z.get(batch_ind, i, j), status); + BOOST_ASSERT(status == nil::marshalling::status_type::success); + transcript(byteblob); + } + } + + // Push U polynomials to transcript + for (std::size_t i = 0; i < this->_points[batch_ind].size(); i++) { + auto poly = this->get_U(batch_ind, i); + for (std::size_t j = 0; j < poly.size(); ++j) { + nil::marshalling::status_type status; + std::vector byteblob = + nil::marshalling::pack(poly[j], status); + BOOST_ASSERT(status == nil::marshalling::status_type::success); + transcript(byteblob); + } + } + } + public: + // Interface function. Isn't useful here. + void mark_batch_as_fixed(std::size_t index) { + } + + kzg_commitment_scheme_v2(params_type kzg_params) : _params(kzg_params) {} + + // Differs from static, because we pack the result into byte blob. + commitment_type commit(std::size_t index){ + this->_ind_commitments[index] = {}; + this->state_commited(index); + + std::vector result = {}; + for (std::size_t i = 0; i < this->_polys[index].size(); ++i) { + BOOST_ASSERT(this->_polys[index][i].degree() <= _params.commitment_key.size()); + auto single_commitment = nil::crypto3::zk::algorithms::commit_one(_params, this->_polys[index][i]); + this->_ind_commitments[index].push_back(single_commitment); + nil::marshalling::status_type status; + std::vector single_commitment_bytes = + nil::marshalling::pack(single_commitment, status); + BOOST_ASSERT(status == nil::marshalling::status_type::success); + result.insert(result.end(), single_commitment_bytes.begin(), single_commitment_bytes.end()); + } + _commitments[index] = result; + return result; + } + + using preprocessed_data_type = bool; + preprocessed_data_type preprocess(transcript_type& transcript) const{ + return true; + } + + void setup(transcript_type& transcript, preprocessed_data_type b = true) { + // Nothing to be done here. + } + + proof_type proof_eval(transcript_type &transcript){ + this->eval_polys(); + this->merge_eval_points(); + + for( auto const &it: this->_commitments ){ + auto k = it.first; + update_transcript(k, transcript); + } + + auto theta = transcript.template challenge(); + auto theta_i = KZGScheme::scalar_value_type::one(); + auto f = math::polynomial::zero(); + + for( auto const &it: this->_polys ){ + auto k = it.first; + for (std::size_t i = 0; i < this->_z.get_batch_size(k); ++i) { + auto diffpoly = set_difference_polynom(_merged_points, this->_points.at(k)[i]); + auto f_i = math::polynomial( this->_polys[k][i].coefficients()); + f += theta_i * (f_i - this->get_U(k, i)) * diffpoly; + theta_i *= theta; + } + } + + BOOST_ASSERT( f % this->get_V(_merged_points) == math::polynomial::zero()); + f /= this->get_V(_merged_points); + + typename KZGScheme::single_commitment_type pi_1 = nil::crypto3::zk::algorithms::commit_one(_params, f); + + nil::marshalling::status_type status; + std::vector pi1_byteblob = nil::marshalling::pack(pi_1, status); + BOOST_ASSERT(status == nil::marshalling::status_type::success); + + transcript(pi1_byteblob); + + auto theta_2 = transcript.template challenge(); + math::polynomial theta_2_vanish = { -theta_2, 1 }; + + theta_i = KZGScheme::scalar_value_type::one(); + + auto L = math::polynomial::zero(); + + for( auto const &it: this->_polys ) { + auto k = it.first; + for (std::size_t i = 0; i < this->_z.get_batch_size(k); ++i) { + auto diffpoly = set_difference_polynom(_merged_points, this->_points.at(k)[i]); + auto Z_T_S_i = diffpoly.evaluate(theta_2); + auto f_i = math::polynomial(this->_polys[k][i].coefficients()); + L += theta_i * Z_T_S_i * (f_i - this->get_U(k, i).evaluate(theta_2)); + theta_i *= theta; + } + } + + L -= this->get_V(_merged_points).evaluate(theta_2) * f; + BOOST_ASSERT( L.evaluate(theta_2) == KZGScheme::scalar_value_type::zero() ); + L /= theta_2_vanish; + + typename KZGScheme::single_commitment_type pi_2 = nil::crypto3::zk::algorithms::commit_one(_params, L); + + /* TODO: Review the necessity of sending pi_2 to transcript */ + std::vector pi2_byteblob = nil::marshalling::pack(pi_2, status); + BOOST_ASSERT(status == nil::marshalling::status_type::success); + transcript(pi2_byteblob); + + return {this->_z, pi_1, pi_2}; + } + + bool verify_eval( + const proof_type &proof, + const std::map &commitments, + transcript_type &transcript + ) { + this->merge_eval_points(); + this->_commitments = commitments; + this->_z = proof.z; + + for (auto const &it: this->_commitments) { + auto k = it.first; + update_transcript(k, transcript); + } + + auto theta = transcript.template challenge(); + nil::marshalling::status_type status; + std::vector byteblob = nil::marshalling::pack(proof.pi_1, status); + BOOST_ASSERT(status == nil::marshalling::status_type::success); + transcript(byteblob); + auto theta_2 = transcript.template challenge(); + auto theta_i = KZGScheme::scalar_value_type::one(); + + auto F = KZGScheme::single_commitment_type::zero(); + auto rsum = KZGScheme::scalar_value_type::zero(); + + for (const auto &it: this->_commitments) { + auto k = it.first; + std::size_t blob_size = this->_commitments.at(k).size() / this->_points.at(k).size(); + std::vector byteblob(blob_size); + + for (std::size_t i = 0; i < this->_points.at(k).size(); ++i) { + for (std::size_t j = 0; j < blob_size; j++) { + byteblob[j] = this->_commitments.at(k)[i * blob_size + j]; + } + nil::marshalling::status_type status; + typename curve_type::template g1_type<>::value_type + cm_i = nil::marshalling::pack(byteblob, status); + BOOST_ASSERT(status == nil::marshalling::status_type::success); + auto Z_T_S_i = set_difference_polynom(_merged_points, this->_points.at(k)[i]).evaluate(theta_2); + F += theta_i * Z_T_S_i * cm_i; + rsum += theta_i * Z_T_S_i * this->get_U(k, i).evaluate(theta_2); + + theta_i *= theta; + } + } + + F -= rsum * KZGScheme::single_commitment_type::one(); + F -= this->get_V(_merged_points).evaluate(theta_2) * proof.pi_1; + + auto left_side_pairing = nil::crypto3::algebra::pair_reduced + ( F + theta_2 * proof.pi_2, verification_key_type::one() ); + + auto right_side_pairing = nil::crypto3::algebra::pair_reduced + ( proof.pi_2, _params.verification_key[1] ); + + return left_side_pairing == right_side_pairing; + } + + const params_type& get_commitment_params() const { + return _params; + } + }; } // namespace commitments } // namespace zk } // namespace crypto3 diff --git a/test/commitment/kzg.cpp b/test/commitment/kzg.cpp index 79fcee2c..5c97a0d2 100644 --- a/test/commitment/kzg.cpp +++ b/test/commitment/kzg.cpp @@ -932,3 +932,67 @@ BOOST_AUTO_TEST_CASE(batched_kzg_placeholder_repr) { } BOOST_AUTO_TEST_SUITE_END() + + +template< + typename curve_type, + typename transcript_hash_type + > +struct placeholder_class_test_initializer { + bool run_test() { + typedef typename curve_type::scalar_field_type::value_type scalar_value_type; + + using kzg_type = zk::commitments::batched_kzg; + typedef typename kzg_type::transcript_type transcript_type; + using kzg_scheme_type = typename zk::commitments::kzg_commitment_scheme_v2; + + scalar_value_type alpha = 7; + auto params = typename kzg_type::params_type(8, 8, alpha); + kzg_scheme_type kzg(params); + + typename kzg_type::batch_of_polynomials_type polys(4); + + polys[0].template from_coefficients>({{ 1, 2, 3, 4, 5, 6, 7, 8}}); + polys[1].template from_coefficients>({{11, 12, 13, 14, 15, 16, 17, 18}}); + polys[2].template from_coefficients>({{21, 22, 23, 24, 25, 26, 27, 28}}); + polys[3].template from_coefficients>({{31, 32, 33, 34, 35, 36, 37, 38}}); + + + std::size_t batch_id = 0; + + kzg.append_to_batch(batch_id, polys); + std::map commitments; + commitments[batch_id] = kzg.commit(batch_id); + + std::set points_0 = {101, 2, 3}; + std::set points_1 = {102, 2, 3}; + std::set points_2 = { 1, 2, 3}; + std::set points_3 = {104, 2, 3}; + kzg.append_eval_points(batch_id, 0, points_0); + kzg.append_eval_points(batch_id, 1, points_1); + kzg.append_eval_points(batch_id, 2, points_2); + kzg.append_eval_points(batch_id, 3, points_3); + + transcript_type transcript; + auto proof = kzg.proof_eval(transcript); + + transcript_type transcript_verification; + bool result = kzg.verify_eval(proof, commitments, transcript_verification); + return result; + + } +}; + +BOOST_AUTO_TEST_SUITE(placeholder_class) + using TestFixtures = boost::mpl::list< + placeholder_class_test_initializer< algebra::curves::bls12_381, hashes::keccak_1600<256> >, + placeholder_class_test_initializer< algebra::curves::mnt4_298, hashes::keccak_1600<256> >, + placeholder_class_test_initializer< algebra::curves::mnt6_298, hashes::keccak_1600<256> > + >; + +BOOST_AUTO_TEST_CASE_TEMPLATE(placeholder_class_test, F, TestFixtures) { + F fixture; + BOOST_CHECK(fixture.run_test()); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/systems/plonk/placeholder/placeholder.cpp b/test/systems/plonk/placeholder/placeholder.cpp index 69a552c8..5cedde45 100644 --- a/test/systems/plonk/placeholder/placeholder.cpp +++ b/test/systems/plonk/placeholder/placeholder.cpp @@ -1226,7 +1226,6 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(prover_test, F, TestFixtures) { BOOST_AUTO_TEST_SUITE_END() - template< typename curve_type, typename merkle_hash_type, @@ -1377,6 +1376,163 @@ BOOST_AUTO_TEST_SUITE(placeholder_circuit2_kzg) */ >; +BOOST_AUTO_TEST_CASE_TEMPLATE(prover_test, F, TestFixtures) { + F fixture; + BOOST_CHECK(fixture.run_test()); +} +BOOST_AUTO_TEST_SUITE_END() + + +template< + typename curve_type, + typename merkle_hash_type, + typename transcript_hash_type, + std::size_t WitnessColumns, + std::size_t PublicInputColumns, + std::size_t ConstantColumns, + std::size_t SelectorColumns, + std::size_t usable_rows_amount, + std::size_t permutation, + bool UseGrinding = false> +struct placeholder_kzg_test_fixture_v2 : public test_initializer { + using field_type = typename curve_type::scalar_field_type; + + struct placeholder_test_params { + constexpr static const std::size_t usable_rows = usable_rows_amount; + + constexpr static const std::size_t witness_columns = WitnessColumns; + constexpr static const std::size_t public_input_columns = PublicInputColumns; + constexpr static const std::size_t constant_columns = ConstantColumns; + constexpr static const std::size_t selector_columns = SelectorColumns; + + constexpr static const std::size_t lambda = 40; + constexpr static const std::size_t m = 2; + }; + + using transcript_type = typename transcript::fiat_shamir_heuristic_sequential; + + using circuit_params = placeholder_circuit_params; + + using kzg_type = commitments::batched_kzg; + using kzg_scheme_type = typename commitments::kzg_commitment_scheme_v2; + using kzg_placeholder_params_type = nil::crypto3::zk::snark::placeholder_params; + + using policy_type = zk::snark::detail::placeholder_policy; + + using circuit_type = + circuit_description, + usable_rows_amount, permutation>; + + placeholder_kzg_test_fixture_v2() + : desc(WitnessColumns, PublicInputColumns, ConstantColumns, SelectorColumns) + { + } + + bool run_test() { + test_initializer::setup(); + typename field_type::value_type pi0 = test_global_alg_rnd_engine(); + circuit_type circuit = circuit_test_t(pi0, test_global_alg_rnd_engine); + desc.rows_amount = circuit.table_rows; + desc.usable_rows_amount = circuit.usable_rows; + std::size_t table_rows_log = std::log2(circuit.table_rows); + + typename policy_type::constraint_system_type constraint_system(circuit.gates, circuit.copy_constraints, circuit.lookup_gates); + typename policy_type::variable_assignment_type assignments = circuit.table; + + std::vector columns_with_copy_constraints = {0, 1, 2, 3}; + + bool verifier_res; + + // KZG commitment scheme + auto kzg_params = create_kzg_params(table_rows_log); + kzg_scheme_type kzg_scheme(kzg_params); + + typename placeholder_public_preprocessor::preprocessed_data_type + kzg_preprocessed_public_data = + placeholder_public_preprocessor::process( + constraint_system, assignments.public_table(), desc, kzg_scheme, columns_with_copy_constraints.size() + ); + + typename placeholder_private_preprocessor::preprocessed_data_type + kzg_preprocessed_private_data = placeholder_private_preprocessor::process( + constraint_system, assignments.private_table(), desc + ); + + auto kzg_proof = placeholder_prover::process( + kzg_preprocessed_public_data, std::move(kzg_preprocessed_private_data), desc, constraint_system, kzg_scheme + ); + + verifier_res = placeholder_verifier::process( + kzg_preprocessed_public_data, kzg_proof, desc, constraint_system, kzg_scheme + ); + test_initializer::teardown(); + return verifier_res; + } + + plonk_table_description desc; +}; + + +BOOST_AUTO_TEST_SUITE(placeholder_circuit2_kzg_v2) + + using TestFixtures = boost::mpl::list< + placeholder_kzg_test_fixture_v2< + algebra::curves::bls12_381, + hashes::keccak_1600<256>, + hashes::keccak_1600<256>, + witness_columns_t, + public_columns_t, + constant_columns_t, + selector_columns_t, + usable_rows_t, + permutation_t, true> + /* + , placeholder_kzg_test_fixture< + algebra::curves::alt_bn128_254, + hashes::keccak_1600<256>, + hashes::keccak_1600<256>, + witness_columns_t, + public_columns_t, + constant_columns_t, + selector_columns_t, + usable_rows_t, + 4, true>*/ + , placeholder_kzg_test_fixture< + algebra::curves::mnt4_298, + hashes::keccak_1600<256>, + hashes::keccak_1600<256>, + witness_columns_t, + public_columns_t, + constant_columns_t, + selector_columns_t, + usable_rows_t, + permutation_t, true> + , placeholder_kzg_test_fixture_v2< + algebra::curves::mnt6_298, + hashes::keccak_1600<256>, + hashes::keccak_1600<256>, + witness_columns_t, + public_columns_t, + constant_columns_t, + selector_columns_t, + usable_rows_t, + permutation_t, true> + /*, -- Not yet implemented + placeholder_kzg_test_fixture< + algebra::curves::mnt6_298, + hashes::poseidon>, + hashes::poseidon>, + witness_columns_t, + public_columns_t, + constant_columns_t, + selector_columns_t, + usable_rows_t, + 4, + true> + */ + >; + BOOST_AUTO_TEST_CASE_TEMPLATE(prover_test, F, TestFixtures) { F fixture; BOOST_CHECK(fixture.run_test());