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: eccvm sumcheck with commitments to round univariates #11206

Draft
wants to merge 8 commits into
base: master
Choose a base branch
from
Draft
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 @@ -324,6 +324,8 @@ TYPED_TEST(KZGTest, ShpleminiKzgWithShiftAndConcatenation)
&consistency_checked,
/* libra commitments = */ {},
/* libra evaluations = */ {},
{},
{},
to_vector_of_ref_vectors(concatenation_groups_commitments),
RefVector(c_evaluations));
const auto pairing_points = KZG::reduce_verify_batch_opening_claim(batch_opening_claim, verifier_transcript);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,23 @@ template <typename Curve> class ShpleminiProver_ {
using ShplonkProver = ShplonkProver_<Curve>;
using GeminiProver = GeminiProver_<Curve>;

template <typename Transcript, size_t LENGTH = 0>
template <typename Transcript>
static OpeningClaim prove(const FF circuit_size,
RefSpan<Polynomial> f_polynomials,
RefSpan<Polynomial> g_polynomials,
std::span<FF> multilinear_challenge,
const std::shared_ptr<CommitmentKey<Curve>>& commitment_key,
const std::shared_ptr<Transcript>& transcript,
const std::array<Polynomial, NUM_LIBRA_EVALUATIONS>& libra_polynomials = {},
const std::vector<Polynomial> sumcheck_round_univariates = {},
const std::vector<std::array<FF, 3>> sumcheck_round_evaluations = {},
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_polynomials[0].size() > 0);
const bool is_eccvm = (!sumcheck_round_univariates.empty());

std::vector<OpeningClaim> opening_claims = GeminiProver::prove(circuit_size,
f_polynomials,
g_polynomials,
Expand All @@ -47,7 +51,26 @@ template <typename Curve> class ShpleminiProver_ {
has_zk);
// Create opening claims for Libra masking univariates
std::vector<OpeningClaim> libra_opening_claims;
std::vector<OpeningClaim> sumcheck_round_claims;

info(sumcheck_round_univariates.size());
OpeningClaim new_claim;
if (is_eccvm) {

const size_t log_circuit_size = numeric::get_msb(static_cast<uint32_t>(circuit_size));
for (size_t idx = 0; idx < log_circuit_size; idx++) {
const std::vector<FF> evaluation_points = { FF(0), FF(1), multilinear_challenge[idx] };
size_t eval_idx = 0;
new_claim.polynomial = std::move(sumcheck_round_univariates[idx]);

for (auto& eval_point : evaluation_points) {
new_claim.opening_pair.challenge = eval_point;
new_claim.opening_pair.evaluation = sumcheck_round_evaluations[idx][eval_idx];
sumcheck_round_claims.push_back(new_claim);
eval_idx++;
}
}
}

if (has_zk) {
static constexpr FF subgroup_generator = Curve::subgroup_generator;
Expand All @@ -66,8 +89,8 @@ template <typename Curve> class ShpleminiProver_ {
}
}

const OpeningClaim batched_claim =
ShplonkProver::prove(commitment_key, opening_claims, transcript, libra_opening_claims);
const OpeningClaim batched_claim = ShplonkProver::prove(
commitment_key, opening_claims, transcript, libra_opening_claims, sumcheck_round_claims);
return batched_claim;
};
};
Expand Down Expand Up @@ -150,6 +173,8 @@ template <typename Curve> class ShpleminiVerifier_ {
// Shplemini Refactoring: Remove bool pointer
const std::array<Commitment, NUM_LIBRA_COMMITMENTS>& libra_commitments = {},
const Fr& libra_univariate_evaluation = Fr{ 0 },
const std::vector<Commitment>& sumcheck_round_commitments = {},
const std::vector<std::array<Fr, 3>>& sumcheck_round_evaluations = {},
const std::vector<RefVector<Commitment>>& concatenation_group_commitments = {},
RefSpan<Fr> concatenated_evaluations = {})

Expand Down Expand Up @@ -327,6 +352,16 @@ template <typename Curve> class ShpleminiVerifier_ {
libra_evaluations, gemini_evaluation_challenge, multivariate_challenge, libra_univariate_evaluation);
}

if (!sumcheck_round_evaluations.empty()) {
batch_sumcheck_round_claims(log_circuit_size,
commitments,
scalars,
multivariate_challenge,
shplonk_batching_challenge,
shplonk_evaluation_challenge,
sumcheck_round_commitments,
sumcheck_round_evaluations);
}
return { commitments, scalars, shplonk_evaluation_challenge };
};
/**
Expand Down Expand Up @@ -664,5 +699,67 @@ template <typename Curve> class ShpleminiVerifier_ {
scalars.push_back(batching_scalars[1] + batching_scalars[2]);
scalars.push_back(batching_scalars[3]);
}

static void batch_sumcheck_round_claims(const size_t log_circuit_size,
std::vector<Commitment>& commitments,
std::vector<Fr>& scalars,
const std::vector<Fr>& multilinear_challenge,
const Fr& shplonk_batching_challenge,
const Fr& shplonk_evaluation_challenge,
const std::vector<Commitment>& sumcheck_round_commitments,
const std::vector<std::array<Fr, 3>>& sumcheck_round_evaluations)
{
std::vector<Commitment> round_commitments = {};
std::vector<Fr> truncated_challenge = {};
std::vector<std::array<Fr, 3>> round_evals = {};

for (size_t idx = 0; idx < log_circuit_size; idx++) {
round_commitments.emplace_back(sumcheck_round_commitments[idx]);
round_evals.emplace_back(sumcheck_round_evaluations[idx]);
truncated_challenge.emplace_back(multilinear_challenge[idx]);
}

std::vector<Fr> denominators = {};
Fr shplonk_challenge_power = Fr{ 1 };
for (size_t j = 0; j < CONST_PROOF_SIZE_LOG_N + 2 + NUM_LIBRA_COMMITMENTS + 1; ++j) {
shplonk_challenge_power *= shplonk_batching_challenge;
}

Fr& constant_term = scalars[scalars.size() - 4];

std::array<Fr, 2> const_denominators;

const_denominators[0] = Fr(1) / (shplonk_evaluation_challenge);
const_denominators[1] = Fr(1) / (shplonk_evaluation_challenge - Fr{ 1 });

for (const auto& [challenge, comm] : zip_view(truncated_challenge, round_commitments)) {
denominators.push_back(shplonk_evaluation_challenge - challenge);
commitments.push_back(comm);
}
if constexpr (!Curve::is_stdlib_type) {
Fr::batch_invert(denominators);
} else {
for (auto& denominator : denominators) {
denominator = Fr{ 1 } / denominator;
}
}
for (const auto& [eval_array, denominator] : zip_view(round_evals, denominators)) {
Fr batched_scaling_factor = Fr(0);
for (size_t idx = 0; idx < 2; idx++) {
Fr current_scaling_factor = const_denominators[idx] * shplonk_challenge_power;
batched_scaling_factor -= current_scaling_factor;
shplonk_challenge_power *= shplonk_batching_challenge;
constant_term += current_scaling_factor * eval_array[idx];
}
Fr current_scaling_factor = denominator * shplonk_challenge_power;

batched_scaling_factor -= current_scaling_factor;
shplonk_challenge_power *= shplonk_batching_challenge;

constant_term += current_scaling_factor * eval_array[2];

scalars.push_back(batched_scaling_factor);
}
};
};
} // namespace bb
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ template <typename Curve> class ShplonkProver_ {
*/
static Polynomial compute_batched_quotient(std::span<const ProverOpeningClaim<Curve>> opening_claims,
const Fr& nu,
std::span<const ProverOpeningClaim<Curve>> libra_opening_claims)
std::span<const ProverOpeningClaim<Curve>> libra_opening_claims,
std::span<const ProverOpeningClaim<Curve>> sumcheck_round_claims)
{
// Find n, the maximum size of all polynomials fⱼ(X)
size_t max_poly_size{ 0 };
Expand Down Expand Up @@ -86,6 +87,20 @@ template <typename Curve> class ShplonkProver_ {
Q.add_scaled(tmp, current_nu);
current_nu *= nu;
}
// size_t counter = 0;
for (const auto& claim : sumcheck_round_claims) {

// Compute individual claim quotient tmp = ( fⱼ(X) − vⱼ) / ( X − xⱼ )
tmp = claim.polynomial;
tmp.at(0) = tmp[0] - claim.opening_pair.evaluation;
// info("prover const term", tmp.at(0));
tmp.factor_roots(claim.opening_pair.challenge);

// Add the claim quotient to the batched quotient polynomial
Q.add_scaled(tmp, current_nu);
current_nu *= nu;
// counter++;
}
// Return batched quotient polynomial Q(X)
return Q;
};
Expand All @@ -105,7 +120,8 @@ template <typename Curve> class ShplonkProver_ {
Polynomial& batched_quotient_Q,
const Fr& nu_challenge,
const Fr& z_challenge,
std::span<const ProverOpeningClaim<Curve>> libra_opening_claims = {})
std::span<const ProverOpeningClaim<Curve>> libra_opening_claims = {},
std::span<const ProverOpeningClaim<Curve>> sumcheck_opening_claims = {})
{
const size_t num_opening_claims = opening_claims.size();

Expand All @@ -120,6 +136,11 @@ template <typename Curve> class ShplonkProver_ {
for (const auto& claim : libra_opening_claims) {
inverse_vanishing_evals.emplace_back(z_challenge - claim.opening_pair.challenge);
}

for (const auto& claim : sumcheck_opening_claims) {
inverse_vanishing_evals.emplace_back(z_challenge - claim.opening_pair.challenge);
}

Fr::batch_invert(inverse_vanishing_evals);

// G(X) = Q(X) - Q_z(X) = Q(X) - ∑ⱼ νʲ ⋅ ( fⱼ(X) − vⱼ) / ( z − xⱼ ),
Expand Down Expand Up @@ -160,6 +181,17 @@ template <typename Curve> class ShplonkProver_ {
idx++;
current_nu *= nu_challenge;
}

for (const auto& claim : sumcheck_opening_claims) {
tmp = claim.polynomial;
tmp.at(0) = tmp[0] - claim.opening_pair.evaluation;
Fr scaling_factor = current_nu * inverse_vanishing_evals[idx]; // = νʲ / (z − xⱼ )

// Add the claim quotient to the batched quotient polynomial
G.add_scaled(tmp, -scaling_factor);
idx++;
current_nu *= nu_challenge;
}
// Return opening pair (z, 0) and polynomial G(X) = Q(X) - Q_z(X)
return { .polynomial = G, .opening_pair = { .challenge = z_challenge, .evaluation = Fr::zero() } };
};
Expand All @@ -177,15 +209,17 @@ template <typename Curve> class ShplonkProver_ {
static ProverOpeningClaim<Curve> prove(const std::shared_ptr<CommitmentKey<Curve>>& commitment_key,
std::span<const ProverOpeningClaim<Curve>> opening_claims,
const std::shared_ptr<Transcript>& transcript,
std::span<const ProverOpeningClaim<Curve>> libra_opening_claims = {})
std::span<const ProverOpeningClaim<Curve>> libra_opening_claims = {},
std::span<const ProverOpeningClaim<Curve>> sumcheck_round_claims = {})
{
const Fr nu = transcript->template get_challenge<Fr>("Shplonk:nu");
auto batched_quotient = compute_batched_quotient(opening_claims, nu, libra_opening_claims);
auto batched_quotient =
compute_batched_quotient(opening_claims, nu, libra_opening_claims, sumcheck_round_claims);
auto batched_quotient_commitment = commitment_key->commit(batched_quotient);
transcript->send_to_verifier("Shplonk:Q", batched_quotient_commitment);
const Fr z = transcript->template get_challenge<Fr>("Shplonk:z");
return compute_partially_evaluated_batched_quotient(
opening_claims, batched_quotient, nu, z, libra_opening_claims);
opening_claims, batched_quotient, nu, z, libra_opening_claims, sumcheck_round_claims);
}
};

Expand Down
7 changes: 5 additions & 2 deletions barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ void ECCVMProver::execute_relation_check_rounds()

zk_sumcheck_data = ZKData(key->log_circuit_size, transcript, key->commitment_key);

sumcheck_output = sumcheck.prove(key->polynomials, relation_parameters, alpha, gate_challenges, zk_sumcheck_data);
sumcheck_output = sumcheck.prove(
key->polynomials, relation_parameters, alpha, gate_challenges, zk_sumcheck_data, key->commitment_key);
}

/**
Expand Down Expand Up @@ -136,7 +137,9 @@ void ECCVMProver::execute_pcs_rounds()
sumcheck_output.challenge,
key->commitment_key,
transcript,
small_subgroup_ipa_prover.get_witness_polynomials());
small_subgroup_ipa_prover.get_witness_polynomials(),
sumcheck_output.round_univariates,
sumcheck_output.round_univariate_evaluations);

// Get the challenge at which we evaluate all transcript polynomials as univariates
evaluation_challenge_x = transcript->template get_challenge<FF>("Translation:evaluation_challenge_x");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,9 @@ TEST_F(ECCVMTranscriptTests, VerifierManifestConsistency)
// Check consistency between the manifests generated by the prover and verifier
auto prover_manifest = prover.transcript->get_manifest();
auto verifier_manifest = verifier.transcript->get_manifest();
prover_manifest.print();
info("========");
verifier_manifest.print();

// Note: a manifest can be printed using manifest.print()
// The last challenge generated by the ECCVM Prover is the translation univariate batching challenge and, on the
Expand Down
19 changes: 10 additions & 9 deletions barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,13 @@ bool ECCVMVerifier::verify_proof(const ECCVMProof& proof)

libra_commitments[0] = transcript->template receive_from_prover<Commitment>("Libra:concatenation_commitment");

auto [multivariate_challenge, claimed_evaluations, libra_evaluation, sumcheck_verified] =
sumcheck.verify(relation_parameters, alpha, gate_challenges);
auto sumcheck_output = sumcheck.verify(relation_parameters, alpha, gate_challenges);

libra_commitments[1] = transcript->template receive_from_prover<Commitment>("Libra:big_sum_commitment");
libra_commitments[2] = transcript->template receive_from_prover<Commitment>("Libra:quotient_commitment");

// If Sumcheck did not verify, return false
if (sumcheck_verified.has_value() && !sumcheck_verified.value()) {
if (!sumcheck_output.verified) {
vinfo("eccvm sumcheck failed");
return false;
}
Expand All @@ -77,16 +76,18 @@ bool ECCVMVerifier::verify_proof(const ECCVMProof& proof)
Shplemini::compute_batch_opening_claim(circuit_size,
commitments.get_unshifted(),
commitments.get_to_be_shifted(),
claimed_evaluations.get_unshifted(),
claimed_evaluations.get_shifted(),
multivariate_challenge,
sumcheck_output.claimed_evaluations.get_unshifted(),
sumcheck_output.claimed_evaluations.get_shifted(),
sumcheck_output.challenge,
key->pcs_verification_key->get_g1_identity(),
transcript,
Flavor::REPEATED_COMMITMENTS,
Flavor::HasZK,
&consistency_checked,
libra_commitments,
libra_evaluation);
sumcheck_output.claimed_libra_evaluation,
sumcheck_output.round_univariate_commitments,
sumcheck_output.round_univariate_evaluations);

// Reduce the accumulator to a single opening claim
const OpeningClaim multivariate_to_univariate_opening_claim =
Expand Down Expand Up @@ -134,8 +135,8 @@ bool ECCVMVerifier::verify_proof(const ECCVMProof& proof)

const bool batched_opening_verified =
PCS::reduce_verify(key->pcs_verification_key, batch_opening_claim, ipa_transcript);
vinfo("eccvm sumcheck verified?: ", sumcheck_verified.value());
vinfo("eccvm sumcheck verified?: ", sumcheck_output.verified.value());
vinfo("batch opening verified?: ", batched_opening_verified);
return sumcheck_verified.value() && batched_opening_verified && consistency_checked;
return sumcheck_output.verified && batched_opening_verified && consistency_checked;
}
} // namespace bb
Loading
Loading