diff --git a/include/nil/crypto3/zk/commitments/polynomial/kzg.hpp b/include/nil/crypto3/zk/commitments/polynomial/kzg.hpp index c55d5bed1..15540eb29 100644 --- a/include/nil/crypto3/zk/commitments/polynomial/kzg.hpp +++ b/include/nil/crypto3/zk/commitments/polynomial/kzg.hpp @@ -51,6 +51,9 @@ namespace nil { namespace crypto3 { namespace zk { namespace commitments { + template + struct kzg_commitment; + template struct kzg_commitment { @@ -66,8 +69,13 @@ namespace nil { using proof_type = commitment_type; struct kzg_params_type { + std::size_t n; //max polynomial degree scalar_value_type alpha; //secret key - std::size_t n; //max polynomial degree + kzg_params_type(std::size_t _n, scalar_value_type _alpha) : n(_n), alpha(_alpha) {} + kzg_params_type(std::size_t _n) { + alpha = scalar_value_type::random_element(); + n = _n; + } }; struct srs_type { @@ -93,7 +101,7 @@ namespace nil { static commitment_type commit(const srs_type &srs, const polynomial &f) { - BOOST_ASSERT(f.size() <= srs.commitment_key.size()); + // assert(f.size() <= srs.commitment_key.size()); return algebra::multiexp(srs.commitment_key.begin(), srs.commitment_key.begin() + f.size(), f.begin(), f.end(), 1); } @@ -105,22 +113,22 @@ namespace nil { } static proof_type proof_eval(srs_type srs, + const polynomial &f, scalar_value_type i, - const polynomial &f) { + scalar_value_type eval) { const polynomial denominator_polynom = {-i, 1}; const polynomial q = - (f - polynomial{f.evaluate(i)}) / denominator_polynom; + (f - polynomial{eval}) / denominator_polynom; - proof_type p = commit(srs, q); - return p; + return commit(srs, q); } static bool verify_eval(srs_type srs, + proof_type p, commitment_type C_f, scalar_value_type i, - scalar_value_type eval, - proof_type p) { + scalar_value_type eval) { auto A_1 = algebra::precompute_g1(p); auto A_2 = algebra::precompute_g2(srs.verification_key - @@ -135,6 +143,129 @@ namespace nil { return gt_4 == gt_value_type::one(); } }; + + template + struct kzg_batched_commitment : public kzg_commitment { + + typedef CurveType curve_type; + typedef algebra::pairing::pairing_policy pairing_policy; + typedef typename curve_type::gt_type::value_type gt_value_type; + + using multiexp_method = typename algebra::policies::multiexp_method_BDLO12; + using scalar_value_type = typename curve_type::scalar_field_type::value_type; + using commitment_key_type = std::vector::value_type>; + using verification_key_type = typename curve_type::template g2_type<>::value_type; + using commitment_type = typename curve_type::template g1_type<>::value_type; + + using kzg = kzg_commitment; + using kzg_params_type = typename kzg::kzg_params_type; + using srs_type = typename kzg::srs_type; + + struct evals_type { + std::vector evals_at_z0; + std::vector evals_at_z1; + evals_type(const std::vector &e1, const std::vector &e2) + : evals_at_z0(e1), evals_at_z1(e2) {} + }; + + struct batched_proof_type { + commitment_type commit0; + commitment_type commit1; + batched_proof_type(commitment_type c0, commitment_type c1) : commit0(c0), commit1(c1) {} + }; + + static polynomial accumulate(const std::vector> &polys, + const scalar_value_type &factor) { + std::size_t num = polys.size(); + if (num == 1) return polys[0]; + + polynomial result = polys[num - 1]; + for (int i = num - 2; i >= 0; --i) { + result = result * factor + polys[i]; + } + return result; + } + + static evals_type evaluate_polynomials(const std::vector> &polys0, + const std::vector> &polys1, + scalar_value_type z0, scalar_value_type z1) { + std::vector evals_at_z0; + for (const auto &poly : polys0) { + evals_at_z0.emplace_back(poly.evaluate(z0)); + } + + std::vector evals_at_z1; + for (const auto &poly : polys1) { + evals_at_z1.emplace_back(poly.evaluate(z1)); + } + + return evals_type(evals_at_z0, evals_at_z1); + } + + static std::vector commit(const srs_type &srs, + const std::vector> &polys) { + std::vector commitments; + for (const auto &poly : polys) { + commitments.emplace_back(kzg::commit(srs, poly)); + } + return commitments; + } + + static batched_proof_type proof_eval(const srs_type &srs, + const std::vector> &polys0, + const std::vector> &polys1, + const evals_type &evals, + scalar_value_type z0, scalar_value_type z1, + scalar_value_type gamma0, scalar_value_type gamma1) { + + auto accum0 = accumulate(polys0, gamma0); + auto accum_eval0 = polynomial{evals.evals_at_z0}.evaluate(gamma0); + typename kzg::proof_type proof0 = kzg::proof_eval(srs, accum0, z0, accum_eval0); + + auto accum1 = accumulate(polys1, gamma1); + auto accum_eval1 = polynomial{evals.evals_at_z1}.evaluate(gamma1); + typename kzg::proof_type proof1 = kzg::proof_eval(srs, accum1, z1, accum_eval1); + + return batched_proof_type(proof0, proof1); + } + + static bool verify_eval(srs_type srs, + const batched_proof_type &proof, + const evals_type &evals, + const std::vector &commits0, + const std::vector &commits1, + scalar_value_type z0, scalar_value_type z1, + scalar_value_type gamma0, scalar_value_type gamma1, + scalar_value_type r) { + + auto eval0_accum = evals.evals_at_z0.back(); + auto comm0_accum = commits0.back(); + for (int i = commits0.size() - 2; i >= 0; --i) { + comm0_accum = (gamma0 * comm0_accum) + commits0[i]; + eval0_accum = (eval0_accum * gamma0) + evals.evals_at_z0[i]; + } + + auto eval1_accum = evals.evals_at_z1.back(); + auto comm1_accum = commits1.back(); + for (int i = commits1.size() - 2; i >= 0; --i) { + comm1_accum = (gamma1 * comm1_accum) + commits1[i]; + eval1_accum = (eval1_accum * gamma1) + evals.evals_at_z1[i]; + } + + auto F = (comm0_accum - eval0_accum * curve_type::template g1_type<>::value_type::one()) + + r * (comm1_accum - eval1_accum * curve_type::template g1_type<>::value_type::one()); + + auto A_1 = algebra::precompute_g1(F + z0 * proof.commit0 + z1 * r * proof.commit1); + auto A_2 = algebra::precompute_g2(curve_type::template g2_type<>::value_type::one()); + auto B_1 = algebra::precompute_g1(-proof.commit0 - r * proof.commit1); + auto B_2 = algebra::precompute_g2(srs.verification_key); + + gt_value_type gt3 = algebra::double_miller_loop(A_1, A_2, B_1, B_2); + gt_value_type gt_4 = algebra::final_exponentiation(gt3); + + return gt_4 == gt_value_type::one(); + } + }; }; // namespace commitments } // namespace zk } // namespace crypto3 diff --git a/test/commitment/kzg.cpp b/test/commitment/kzg.cpp index e36abaa16..8f694e982 100644 --- a/test/commitment/kzg.cpp +++ b/test/commitment/kzg.cpp @@ -33,9 +33,18 @@ #include #include -#include #include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include + #include #include #include @@ -61,7 +70,7 @@ BOOST_AUTO_TEST_CASE(kzg_basic_test) { std::size_t n = 16; const polynomial f = {-1, 1, 2, 3}; - auto srs = kzg_type::setup({alpha, n}); + auto srs = kzg_type::setup({n, alpha}); BOOST_CHECK(curve_type::template g1_type<>::value_type::one() == srs.commitment_key[0]); BOOST_CHECK(10 * curve_type::template g1_type<>::value_type::one() == srs.commitment_key[1]); BOOST_CHECK(100 * curve_type::template g1_type<>::value_type::one() == srs.commitment_key[2]); @@ -72,11 +81,11 @@ BOOST_AUTO_TEST_CASE(kzg_basic_test) { BOOST_CHECK(3209 * curve_type::template g1_type<>::value_type::one() == commit); auto eval = f.evaluate(i); - auto proof = kzg_type::proof_eval(srs, i, f); + auto proof = kzg_type::proof_eval(srs, f, i, eval); BOOST_CHECK(33 * scalar_value_type::one() == eval); BOOST_CHECK(397 * curve_type::template g1_type<>::value_type::one() == proof); - BOOST_CHECK(kzg_type::verify_eval(srs, commit, i, eval, proof)); + BOOST_CHECK(kzg_type::verify_eval(srs, proof, commit, i, eval)); } BOOST_AUTO_TEST_CASE(kzg_random_test) { @@ -93,12 +102,197 @@ BOOST_AUTO_TEST_CASE(kzg_random_test) { std::size_t n = 298; const polynomial f = {-1, 1, 2, 3, 5, -15}; - auto srs = kzg_type::setup({alpha, n}); + auto srs = kzg_type::setup({n, alpha}); auto commit = kzg_type::commit(srs, f); auto eval = f.evaluate(i); - auto proof = kzg_type::proof_eval(srs, i, f); + auto proof = kzg_type::proof_eval(srs, f, i, eval); + + BOOST_CHECK(kzg_type::verify_eval(srs, proof, commit, i, eval)); +} + +BOOST_AUTO_TEST_CASE(kzg_batched_accumulate_test) { + + typedef algebra::curves::mnt4<298> curve_type; + typedef typename curve_type::base_field_type::value_type base_value_type; + typedef typename curve_type::base_field_type base_field_type; + typedef typename curve_type::scalar_field_type scalar_field_type; + typedef typename curve_type::scalar_field_type::value_type scalar_value_type; + typedef zk::commitments::kzg_batched_commitment kzg_type; + + { + const std::vector> polynomials = {{ + {1, 2, 3, 4}, // 1 + 2x + 2x^2 + 3x^3 + }}; + const scalar_value_type beta = 29; + + const polynomial expect_result = {1, 2, 3, 4}; + + BOOST_CHECK(expect_result == kzg_type::accumulate(polynomials, beta)); + } + + { + const std::vector> polynomials = {{ + {1, 2, 3, 4}, // 1 + 2x + 2x^2 + 3x^3 + {5, 6, 7}, + {8, 9, 10, 11, 12}, + }}; + const scalar_value_type beta = 29; + + const polynomial expect_result = { + 1 + beta * 5 + beta * beta * 8, + 2 + beta * 6 + beta * beta * 9, + 3 + beta * 7 + beta * beta * 10, + 4 + beta * 0 + beta * beta * 11, + 0 + beta * 0 + beta * beta * 12 + }; + + BOOST_CHECK(expect_result == kzg_type::accumulate(polynomials, beta)); + } + + { + const std::vector> f_set{ + {1, 2, 3, 4, 5, 6, 7, 8}, + {11, 12, 0, 14, 15, 16, 17}, + }; + const scalar_value_type beta = 29; + + const polynomial expect{ + 1 + beta * 11, + 2 + beta * 12, + 3 + beta * 0, + 4 + beta * 14, + 5 + beta * 15, + 6 + beta * 16, + 7 + beta * 17, + 8 + beta * 0}; + + const polynomial actual = + kzg_type::accumulate(f_set, beta); + + BOOST_CHECK(expect == actual); + } +} + +BOOST_AUTO_TEST_CASE(kzg_batched_basic_test) { + + typedef algebra::curves::bls12<381> curve_type; + typedef typename curve_type::base_field_type::value_type base_value_type; + typedef typename curve_type::base_field_type base_field_type; + typedef typename curve_type::scalar_field_type scalar_field_type; + typedef typename curve_type::scalar_field_type::value_type scalar_value_type; + typedef zk::commitments::kzg_batched_commitment kzg_type; + + scalar_value_type alpha = 7; + std::size_t n = 8; + const std::vector> fs{{ + {{1, 2, 3, 4, 5, 6, 7, 8}}, + {{11, 12, 13, 14, 15, 16, 17, 18}}, + {{21, 22, 23, 24, 25, 26, 27, 28}}, + {{31, 32, 33, 34, 35, 36, 37, 38}}, + }}; + + const std::vector> gs{{ + {{71, 72, 73, 74, 75, 76, 77, 78}}, + {{81, 82, 83, 84, 85, 86, 87, 88}}, + {{91, 92, 93, 94, 95, 96, 97, 98}}, + }}; + + scalar_value_type z0 = 123; + scalar_value_type z1 = 456; + auto evals = kzg_type::evaluate_polynomials(fs, gs, z0, z1); + + auto srs = kzg_type::setup({n, alpha}); + + scalar_value_type gamma0 = 54321; + scalar_value_type gamma1 = 98760; + + auto proof = kzg_type::proof_eval(srs, fs, gs, evals, z0, z1, gamma0, gamma1); + + { + scalar_value_type h0_x = scalar_value_type::zero(); + for (size_t i = 0; i < fs.size(); ++i) { + const polynomial &f_i = fs[i]; + const scalar_value_type f_x_minus_f_z0 = f_i.evaluate(alpha) - f_i.evaluate(z0); + const scalar_value_type gamma_power = gamma0.pow(i); + h0_x += gamma_power * f_x_minus_f_z0 * ((alpha - z0).inversed()); + } + BOOST_CHECK(h0_x * curve_type::template g1_type<>::value_type::one() == proof.commit0); + + scalar_value_type h1_x = scalar_value_type::zero(); + for (size_t i = 0; i < gs.size(); ++i) { + const polynomial &g_i = gs[i]; + const scalar_value_type g_x_minus_g_z1 = g_i.evaluate(alpha) - g_i.evaluate(z1); + const scalar_value_type gamma_power = gamma1.pow(i); + h1_x += gamma_power * g_x_minus_g_z1 * ((alpha - z1).inversed()); + } + BOOST_CHECK(h1_x * curve_type::template g1_type<>::value_type::one() == proof.commit1); + } + + scalar_value_type r = 23546; + auto c0 = kzg_type::commit(srs, fs); + auto c1 = kzg_type::commit(srs, gs); + BOOST_CHECK(kzg_type::verify_eval(srs, proof, evals, c0, c1, z0, z1, gamma0, gamma1, r)); +} + +BOOST_AUTO_TEST_CASE(kzg_batched_random_test) { + + typedef algebra::curves::bls12<381> curve_type; + typedef typename curve_type::base_field_type::value_type base_value_type; + typedef typename curve_type::base_field_type base_field_type; + typedef typename curve_type::scalar_field_type scalar_field_type; + typedef typename curve_type::scalar_field_type::value_type scalar_value_type; + typedef zk::commitments::kzg_batched_commitment kzg_type; + + scalar_value_type alpha = algebra::random_element(); + std::size_t n = 298; + const std::vector> fs{{ + {{1, 2, 3, 4, 5, 6, 7, 8}}, + {{11, 12, 13, 14, 15, 16, 17}}, + {{21, 22, 23, 24, 25, 26, 27, 28}}, + {{31, 32, 33, 34, 35, 36, 37, 38, 39}}, + }}; + + const std::vector> gs{{ + {{71, 72}}, + {{81, 82, 83, 85, 86, 87, 88}}, + {{91, 92, 93, 94, 95, 96, 97, 98, 99, 100}}, + }}; + + scalar_value_type z0 = algebra::random_element(); + scalar_value_type z1 = algebra::random_element(); + auto evals = kzg_type::evaluate_polynomials(fs, gs, z0, z1); + + auto srs = kzg_type::setup({n, alpha}); + + scalar_value_type gamma0 = algebra::random_element(); + scalar_value_type gamma1 = algebra::random_element(); + + auto proof = kzg_type::proof_eval(srs, fs, gs, evals, z0, z1, gamma0, gamma1); + + { + scalar_value_type h0_x = scalar_value_type::zero(); + for (size_t i = 0; i < fs.size(); ++i) { + const polynomial &f_i = fs[i]; + const scalar_value_type f_x_minus_f_z0 = f_i.evaluate(alpha) - f_i.evaluate(z0); + const scalar_value_type gamma_power = gamma0.pow(i); + h0_x += gamma_power * f_x_minus_f_z0 * ((alpha - z0).inversed()); + } + BOOST_CHECK(h0_x * curve_type::template g1_type<>::value_type::one() == proof.commit0); + + scalar_value_type h1_x = scalar_value_type::zero(); + for (size_t i = 0; i < gs.size(); ++i) { + const polynomial &g_i = gs[i]; + const scalar_value_type g_x_minus_g_z1 = g_i.evaluate(alpha) - g_i.evaluate(z1); + const scalar_value_type gamma_power = gamma1.pow(i); + h1_x += gamma_power * g_x_minus_g_z1 * ((alpha - z1).inversed()); + } + BOOST_CHECK(h1_x * curve_type::template g1_type<>::value_type::one() == proof.commit1); + } - BOOST_CHECK(kzg_type::verify_eval(srs, commit, i, eval, proof)); + scalar_value_type r = algebra::random_element(); + auto c0 = kzg_type::commit(srs, fs); + auto c1 = kzg_type::commit(srs, gs); + BOOST_CHECK(kzg_type::verify_eval(srs, proof, evals, c0, c1, z0, z1, gamma0, gamma1, r)); } BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file