Skip to content

Commit

Permalink
KZGv2 implementation (#304)
Browse files Browse the repository at this point in the history
* work in progress on v2 #300

* v2 #300

* placeholder at KZGv2 draft #300

* work in progress on KZGv2 #300

* work in progress #300

* Working implementation of KZGv2 #300

* Uncomment tests for v1 on mnt curves #300

* Small KZGv2 placeholder test #300
  • Loading branch information
vo-nil authored Mar 5, 2024
1 parent 3768893 commit 8b5632c
Show file tree
Hide file tree
Showing 4 changed files with 480 additions and 3 deletions.
5 changes: 3 additions & 2 deletions include/nil/crypto3/zk/commitments/batched_commitment.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include <boost/property_tree/json_parser.hpp>

#include <nil/crypto3/math/polynomial/polynomial_dfs.hpp>
#include <nil/crypto3/math/polynomial/lagrange_interpolation.hpp>

#include <nil/crypto3/zk/transcript/fiat_shamir.hpp>
#include <nil/crypto3/zk/commitments/type_traits.hpp>
Expand Down Expand Up @@ -223,14 +224,14 @@ namespace nil {
void append_eval_points(std::size_t batch_id, std::set<typename field_type::value_type> 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<typename field_type::value_type> 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){
Expand Down
256 changes: 256 additions & 0 deletions include/nil/crypto3/zk/commitments/polynomial/kzg.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
* <https://eprint.iacr.org/2020/081.pdf>
*/
template<typename KZGScheme, typename PolynomialType = typename math::polynomial_dfs<typename KZGScheme::field_type::value_type>>
class kzg_commitment_scheme_v2 : public polys_evaluator<typename KZGScheme::params_type, typename KZGScheme::commitment_type, PolynomialType>{
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<field_type> z;
typename KZGScheme::single_commitment_type pi_1, pi_2;
};
using endianness = nil::marshalling::option::big_endian;
private:
params_type _params;
std::map<std::size_t, commitment_type> _commitments;
std::map<std::size_t, std::vector<typename KZGScheme::single_commitment_type>> _ind_commitments;
std::vector<typename KZGScheme::scalar_value_type> _merged_points;
protected:

// Differs from static one by input parameters
void merge_eval_points() {
std::set<typename KZGScheme::scalar_value_type> 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<typename KZGScheme::scalar_value_type>(set.begin(), set.end());
}

typename math::polynomial<typename KZGScheme::scalar_value_type>
set_difference_polynom(
std::vector<typename KZGScheme::scalar_value_type> merged_points,
std::vector<typename KZGScheme::scalar_value_type> points
) {
std::sort(merged_points.begin(), merged_points.end());
std::sort(points.begin(), points.end());
std::vector<typename KZGScheme::scalar_value_type> 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<typename KZGScheme::scalar_value_type>({{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<uint8_t> byteblob =
nil::marshalling::pack<endianness>(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<uint8_t> byteblob =
nil::marshalling::pack<endianness>(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<std::uint8_t> 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<KZGScheme>(_params, this->_polys[index][i]);
this->_ind_commitments[index].push_back(single_commitment);
nil::marshalling::status_type status;
std::vector<uint8_t> single_commitment_bytes =
nil::marshalling::pack<endianness>(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<typename KZGScheme::curve_type::scalar_field_type>();
auto theta_i = KZGScheme::scalar_value_type::one();
auto f = math::polynomial<typename KZGScheme::scalar_value_type>::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<typename KZGScheme::scalar_value_type>( 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<typename KZGScheme::scalar_value_type>::zero());
f /= this->get_V(_merged_points);

typename KZGScheme::single_commitment_type pi_1 = nil::crypto3::zk::algorithms::commit_one<KZGScheme>(_params, f);

nil::marshalling::status_type status;
std::vector<std::uint8_t> pi1_byteblob = nil::marshalling::pack<endianness>(pi_1, status);
BOOST_ASSERT(status == nil::marshalling::status_type::success);

transcript(pi1_byteblob);

auto theta_2 = transcript.template challenge<typename curve_type::scalar_field_type>();
math::polynomial<typename KZGScheme::scalar_value_type> theta_2_vanish = { -theta_2, 1 };

theta_i = KZGScheme::scalar_value_type::one();

auto L = math::polynomial<typename KZGScheme::scalar_value_type>::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<typename KZGScheme::scalar_value_type>(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<KZGScheme>(_params, L);

/* TODO: Review the necessity of sending pi_2 to transcript */
std::vector<uint8_t> pi2_byteblob = nil::marshalling::pack<endianness>(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<std::size_t, commitment_type> &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<typename KZGScheme::curve_type::scalar_field_type>();
nil::marshalling::status_type status;
std::vector<std::uint8_t> byteblob = nil::marshalling::pack<endianness>(proof.pi_1, status);
BOOST_ASSERT(status == nil::marshalling::status_type::success);
transcript(byteblob);
auto theta_2 = transcript.template challenge<typename KZGScheme::curve_type::scalar_field_type>();
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<std::uint8_t> 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<typename KZGScheme::curve_type>
( F + theta_2 * proof.pi_2, verification_key_type::one() );

auto right_side_pairing = nil::crypto3::algebra::pair_reduced<typename KZGScheme::curve_type>
( 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
Expand Down
64 changes: 64 additions & 0 deletions test/commitment/kzg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<curve_type, transcript_hash_type>;
typedef typename kzg_type::transcript_type transcript_type;
using kzg_scheme_type = typename zk::commitments::kzg_commitment_scheme_v2<kzg_type>;

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<std::vector<scalar_value_type>>({{ 1, 2, 3, 4, 5, 6, 7, 8}});
polys[1].template from_coefficients<std::vector<scalar_value_type>>({{11, 12, 13, 14, 15, 16, 17, 18}});
polys[2].template from_coefficients<std::vector<scalar_value_type>>({{21, 22, 23, 24, 25, 26, 27, 28}});
polys[3].template from_coefficients<std::vector<scalar_value_type>>({{31, 32, 33, 34, 35, 36, 37, 38}});


std::size_t batch_id = 0;

kzg.append_to_batch(batch_id, polys);
std::map<std::size_t, typename kzg_scheme_type::commitment_type> commitments;
commitments[batch_id] = kzg.commit(batch_id);

std::set<scalar_value_type> points_0 = {101, 2, 3};
std::set<scalar_value_type> points_1 = {102, 2, 3};
std::set<scalar_value_type> points_2 = { 1, 2, 3};
std::set<scalar_value_type> 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()
Loading

0 comments on commit 8b5632c

Please sign in to comment.