Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: zk shplemini #9830

Merged
merged 10 commits into from
Nov 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,8 @@ template <typename Curve> class GeminiProver_ {
const std::shared_ptr<CommitmentKey<Curve>>& commitment_key,
const std::shared_ptr<Transcript>& transcript,
RefSpan<Polynomial> concatenated_polynomials = {},
const std::vector<RefVector<Polynomial>>& groups_to_be_concatenated = {});
const std::vector<RefVector<Polynomial>>& groups_to_be_concatenated = {},
bool has_zk = false);

}; // namespace bb

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,19 +49,37 @@ std::vector<typename GeminiProver_<Curve>::Claim> GeminiProver_<Curve>::prove(
const std::shared_ptr<CommitmentKey<Curve>>& commitment_key,
const std::shared_ptr<Transcript>& transcript,
RefSpan<Polynomial> concatenated_polynomials,
const std::vector<RefVector<Polynomial>>& groups_to_be_concatenated)
const std::vector<RefVector<Polynomial>>& groups_to_be_concatenated,
bool has_zk)

{
size_t log_n = numeric::get_msb(static_cast<uint32_t>(circuit_size));
size_t n = 1 << log_n;

Fr rho = transcript->template get_challenge<Fr>("rho");

// Compute batched polynomials
Polynomial batched_unshifted(n);
Polynomial batched_to_be_shifted = Polynomial::shiftable(1 << log_n);
Polynomial batched_to_be_shifted = Polynomial::shiftable(n);

// To achieve ZK, we mask the batched polynomial by a random polynomial of the same size
if (has_zk) {
batched_unshifted = Polynomial::random(n);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Before: initialize poly to zero then start to accumulate f_polynomials[0]:
More efficient: initialize with f_polynomials[0] and start the loop at index 1.

After: initialize poly to zero then start to accumulate f_polynomials[0] OR overwrite with random.
More efficient: conditionally initialize as in

Polynomial batched_unshifted =  has_zk ?  Polynomial::random(n) : f_polynomials[0];
size_t starting_idx = has_zk ? 0 : 1;
...
for (size_t i = starting_idx; i < f_polynomials.size(); i++) {
...

But then you have to similarly define a conditional starting point for the loop. Anyway, you're not making things worse so don't worry about it, just remarking.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for the suggestion! it breaks some edge case tests in Gemini though, namely when we open shifts without unshifted (quite unrealistic). adding another check (f_polynomials.size()>0) would be somewhat ugly

transcript->send_to_verifier("Gemini:masking_poly_comm", commitment_key->commit(batched_unshifted));
// In the provers, the size of multilinear_challenge is CONST_PROOF_SIZE_LOG_N, but we need to evaluate the
// hiding polynomial as multilinear in log_n variables
std::vector<Fr> multilinear_challenge_resized(multilinear_challenge.begin(), multilinear_challenge.end());
multilinear_challenge_resized.resize(log_n);
transcript->send_to_verifier("Gemini:masking_poly_eval",
batched_unshifted.evaluate_mle(multilinear_challenge_resized));
}

// Get the batching challenge
const Fr rho = transcript->template get_challenge<Fr>("rho");

Fr rho_challenge{ 1 };
if (has_zk) {
// ρ⁰ is used to batch the hiding polynomial
rho_challenge *= rho;
}
for (size_t i = 0; i < f_polynomials.size(); i++) {
batched_unshifted.add_scaled(f_polynomials[i], rho_challenge);
rho_challenge *= rho;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,17 @@ template <typename Curve> class ShpleminiProver_ {
RefSpan<Polynomial> concatenated_polynomials = {},
const std::vector<RefVector<Polynomial>>& groups_to_be_concatenated = {})
{
// While Shplemini is not templated on Flavor, we derive ZK flag this way
const bool has_zk = !libra_evaluations.empty();
std::vector<OpeningClaim> opening_claims = GeminiProver::prove(circuit_size,
f_polynomials,
g_polynomials,
multilinear_challenge,
commitment_key,
transcript,
concatenated_polynomials,
groups_to_be_concatenated);
groups_to_be_concatenated,
has_zk);
// Create opening claims for Libra masking univariates
std::vector<OpeningClaim> libra_opening_claims;
size_t idx = 0;
Expand All @@ -51,7 +54,7 @@ template <typename Curve> class ShpleminiProver_ {
libra_opening_claims.push_back(new_claim);
idx++;
}
OpeningClaim batched_claim =
const OpeningClaim batched_claim =
ShplonkProver::prove(commitment_key, opening_claims, transcript, libra_opening_claims);
return batched_claim;
};
Expand Down Expand Up @@ -144,6 +147,17 @@ template <typename Curve> class ShpleminiVerifier_ {
log_circuit_size = numeric::get_msb(static_cast<uint32_t>(N));
}

Fr batched_evaluation = Fr{ 0 };

// While Shplemini is not templated on Flavor, we derive ZK flag this way
const bool has_zk = !libra_univariate_evaluations.empty();
Commitment hiding_polynomial_commitment;
if (has_zk) {
hiding_polynomial_commitment =
transcript->template receive_from_prover<Commitment>("Gemini:masking_poly_comm");
batched_evaluation += transcript->template receive_from_prover<Fr>("Gemini:masking_poly_eval");
}

// Get the challenge ρ to batch commitments to multilinear polynomials and their shifts
const Fr multivariate_batching_challenge = transcript->template get_challenge<Fr>("rho");

Expand Down Expand Up @@ -224,9 +238,13 @@ template <typename Curve> class ShpleminiVerifier_ {
}
}

if (has_zk) {
commitments.emplace_back(hiding_polynomial_commitment);
scalars.emplace_back(-unshifted_scalar); // corresponds to ρ⁰
}

// Place the commitments to prover polynomials in the commitments vector. Compute the evaluation of the
// batched multilinear polynomial. Populate the vector of scalars for the final batch mul
Fr batched_evaluation = Fr(0);
batch_multivariate_opening_claims(unshifted_commitments,
shifted_commitments,
unshifted_evaluations,
Expand All @@ -237,6 +255,7 @@ template <typename Curve> class ShpleminiVerifier_ {
commitments,
scalars,
batched_evaluation,
has_zk,
concatenation_scalars,
concatenation_group_commitments,
concatenated_evaluations);
Expand Down Expand Up @@ -271,7 +290,7 @@ template <typename Curve> class ShpleminiVerifier_ {

// For ZK flavors, the sumcheck output contains the evaluations of Libra univariates that submitted to the
// ShpleminiVerifier, otherwise this argument is set to be empty
if (!libra_univariate_evaluations.empty()) {
if (has_zk) {
add_zk_data(commitments,
scalars,
libra_univariate_commitments,
Expand Down Expand Up @@ -345,11 +364,18 @@ template <typename Curve> class ShpleminiVerifier_ {
std::vector<Commitment>& commitments,
std::vector<Fr>& scalars,
Fr& batched_evaluation,
const bool has_zk = false,
std::vector<Fr> concatenated_scalars = {},
const std::vector<RefVector<Commitment>>& concatenation_group_commitments = {},
RefSpan<Fr> concatenated_evaluations = {})
{
Fr current_batching_challenge = Fr(1);

if (has_zk) {
// ρ⁰ is used to batch the hiding polynomial
current_batching_challenge *= multivariate_batching_challenge;
}

for (auto [unshifted_commitment, unshifted_evaluation] :
zip_view(unshifted_commitments, unshifted_evaluations)) {
// Move unshifted commitments to the 'commitments' vector
Expand Down
8 changes: 8 additions & 0 deletions barretenberg/cpp/src/barretenberg/eccvm/eccvm_flavor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -940,6 +940,8 @@ class ECCVMFlavor {
std::vector<bb::Univariate<FF, BATCHED_RELATION_PARTIAL_LENGTH>> sumcheck_univariates;
std::vector<FF> libra_evaluations;
std::array<FF, NUM_ALL_ENTITIES> sumcheck_evaluations;
Commitment hiding_polynomial_commitment;
FF hiding_polynomial_eval;
std::vector<Commitment> gemini_fold_comms;
std::vector<FF> gemini_fold_evals;
Commitment shplonk_q_comm;
Expand Down Expand Up @@ -1161,6 +1163,10 @@ class ECCVMFlavor {
}
sumcheck_evaluations = NativeTranscript::template deserialize_from_buffer<std::array<FF, NUM_ALL_ENTITIES>>(
NativeTranscript::proof_data, num_frs_read);
hiding_polynomial_commitment =
deserialize_from_buffer<Commitment>(NativeTranscript::proof_data, num_frs_read);
hiding_polynomial_eval = deserialize_from_buffer<FF>(NativeTranscript::proof_data, num_frs_read);

for (size_t i = 0; i < CONST_PROOF_SIZE_LOG_N - 1; ++i) {
gemini_fold_comms.push_back(deserialize_from_buffer<Commitment>(proof_data, num_frs_read));
}
Expand Down Expand Up @@ -1318,6 +1324,8 @@ class ECCVMFlavor {
NativeTranscript::template serialize_to_buffer(libra_evaluations[i], NativeTranscript::proof_data);
}
NativeTranscript::template serialize_to_buffer(sumcheck_evaluations, NativeTranscript::proof_data);
NativeTranscript::template serialize_to_buffer(hiding_polynomial_commitment, NativeTranscript::proof_data);
NativeTranscript::template serialize_to_buffer(hiding_polynomial_eval, NativeTranscript::proof_data);
for (size_t i = 0; i < CONST_PROOF_SIZE_LOG_N - 1; ++i) {
NativeTranscript::template serialize_to_buffer(gemini_fold_comms[i], proof_data);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,8 @@ class ECCVMTranscriptTests : public ::testing::Test {
// manifest_expected.add_entry(round, "Libra:evaluation", log_n * frs_per_Fr);

manifest_expected.add_entry(round, "Sumcheck:evaluations", frs_per_evals);
manifest_expected.add_entry(round, "Gemini:masking_poly_comm", frs_per_G);
manifest_expected.add_entry(round, "Gemini:masking_poly_eval", frs_per_Fr);

manifest_expected.add_challenge(round, "rho");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ class MegaZKFlavor : public bb::MegaFlavor {
std::vector<bb::Univariate<FF, BATCHED_RELATION_PARTIAL_LENGTH>> sumcheck_univariates;
std::vector<FF> libra_evaluations;
std::array<FF, NUM_ALL_ENTITIES> sumcheck_evaluations;
Commitment hiding_polynomial_commitment;
FF hiding_polynomial_eval;
std::vector<Commitment> gemini_fold_comms;
std::vector<FF> gemini_fold_evals;
Commitment shplonk_q_comm;
Expand Down Expand Up @@ -131,6 +133,8 @@ class MegaZKFlavor : public bb::MegaFlavor {
NativeTranscript::template deserialize_from_buffer<FF>(NativeTranscript::proof_data, num_frs_read));
}
sumcheck_evaluations = deserialize_from_buffer<std::array<FF, NUM_ALL_ENTITIES>>(proof_data, num_frs_read);
hiding_polynomial_commitment = deserialize_from_buffer<Commitment>(proof_data, num_frs_read);
hiding_polynomial_eval = deserialize_from_buffer<FF>(NativeTranscript::proof_data, num_frs_read);
for (size_t i = 0; i < CONST_PROOF_SIZE_LOG_N - 1; ++i) {
gemini_fold_comms.push_back(deserialize_from_buffer<Commitment>(proof_data, num_frs_read));
}
Expand Down Expand Up @@ -191,6 +195,8 @@ class MegaZKFlavor : public bb::MegaFlavor {
}

serialize_to_buffer(sumcheck_evaluations, proof_data);
serialize_to_buffer(hiding_polynomial_commitment, NativeTranscript::proof_data);
serialize_to_buffer(hiding_polynomial_eval, NativeTranscript::proof_data);
for (size_t i = 0; i < CONST_PROOF_SIZE_LOG_N - 1; ++i) {
serialize_to_buffer(gemini_fold_comms[i], proof_data);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,12 @@ template <typename Flavor> class MegaTranscriptTests : public ::testing::Test {
}

manifest_expected.add_entry(round, "Sumcheck:evaluations", frs_per_evals);

if constexpr (Flavor::HasZK) {
manifest_expected.add_entry(round, "Gemini:masking_poly_comm", frs_per_G);
manifest_expected.add_entry(round, "Gemini:masking_poly_eval", frs_per_Fr);
}

manifest_expected.add_challenge(round, "rho");

round++;
Expand Down
Loading