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: Shplonk revival in ECCVM #7164

Merged
merged 23 commits into from
Jun 25, 2024
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
4971ebe
commit
maramihali Jun 18, 2024
e7350db
modify verifiers
maramihali Jun 18, 2024
1e07311
try to share more code paths in zm test files
maramihali Jun 18, 2024
77f6d94
cleanup
maramihali Jun 18, 2024
8b4f411
Merge remote-tracking branch 'origin/master' into mm/zeromorph-pcs-se…
maramihali Jun 18, 2024
437fb3f
more cleaning
maramihali Jun 19, 2024
ae02db0
Merge remote-tracking branch 'origin/master' into mm/zeromorph-pcs-se…
maramihali Jun 19, 2024
07cd6d8
make gcc happy
maramihali Jun 19, 2024
4eea9e6
recomment asserts and pass commitments as const ref
maramihali Jun 20, 2024
8b48161
recomment asserts and pass commitments as const ref
maramihali Jun 20, 2024
2ffa927
resolve review comments
maramihali Jun 21, 2024
4cee7b7
Merge remote-tracking branch 'origin/master' into mm/zeromorph-pcs-se…
maramihali Jun 21, 2024
90460c1
Merge branch 'mm/zeromorph-pcs-separation' into mm/shplonk-refactor
maramihali Jun 21, 2024
88f1e34
Shplonk refactor and ECCVM + Shplonk integration
maramihali Jun 24, 2024
676d3e6
Merge remote-tracking branch 'origin/master' into mm/shplonk-refactor
maramihali Jun 24, 2024
704436e
remove stale files and restore deleted files
maramihali Jun 24, 2024
9d2cbde
some cleanup
maramihali Jun 24, 2024
b9414c2
fix typo
maramihali Jun 24, 2024
586b941
Merge branch 'master' into mm/shplonk-refactor
maramihali Jun 24, 2024
34dcfc5
respond to review comments
maramihali Jun 25, 2024
c4467b1
Merge remote-tracking branch 'origin/master' into mm/shplonk-refactor
maramihali Jun 25, 2024
9db7e0d
fix fuzzer
maramihali Jun 25, 2024
b7044ca
Merge branch 'master' into mm/shplonk-refactor
maramihali Jun 25, 2024
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 @@ -295,22 +295,18 @@ TEST_F(IPATest, GeminiShplonkIPAWithShift)
const auto [gemini_opening_pairs, gemini_witnesses] = GeminiProver::compute_fold_polynomial_evaluations(
mle_opening_point, std::move(gemini_polynomials), r_challenge);

std::vector<ProverOpeningClaim<Curve>> opening_claims;

for (size_t l = 0; l < log_n; ++l) {
std::string label = "Gemini:a_" + std::to_string(l);
const auto& evaluation = gemini_opening_pairs[l + 1].evaluation;
prover_transcript->send_to_verifier(label, evaluation);
opening_claims.emplace_back(gemini_witnesses[l], gemini_opening_pairs[l]);
}
opening_claims.emplace_back(gemini_witnesses[log_n], gemini_opening_pairs[log_n]);

const Fr nu_challenge = prover_transcript->template get_challenge<Fr>("Shplonk:nu");
auto batched_quotient_Q =
ShplonkProver::compute_batched_quotient(gemini_opening_pairs, gemini_witnesses, nu_challenge);
prover_transcript->send_to_verifier("Shplonk:Q", this->ck()->commit(batched_quotient_Q));

const Fr z_challenge = prover_transcript->template get_challenge<Fr>("Shplonk:z");
const auto [shplonk_opening_pair, shplonk_witness] = ShplonkProver::compute_partially_evaluated_batched_quotient(
gemini_opening_pairs, gemini_witnesses, std::move(batched_quotient_Q), nu_challenge, z_challenge);

IPA::compute_opening_proof(this->ck(), shplonk_opening_pair, shplonk_witness, prover_transcript);
const auto opening_claim = ShplonkProver::prove(this->ck(), opening_claims, prover_transcript);
IPA::compute_opening_proof(this->ck(), opening_claim.opening_pair, opening_claim.polynomial, prover_transcript);

auto verifier_transcript = NativeTranscript::verifier_init_empty(prover_transcript);

Expand All @@ -321,7 +317,7 @@ TEST_F(IPATest, GeminiShplonkIPAWithShift)
verifier_transcript);

const auto shplonk_verifier_claim =
ShplonkVerifier::reduce_verification(this->vk(), gemini_verifier_claim, verifier_transcript);
ShplonkVerifier::reduce_verification(this->vk()->get_g1_identity(), gemini_verifier_claim, verifier_transcript);
auto result = IPA::reduce_verify(this->vk(), shplonk_verifier_claim, verifier_transcript);

EXPECT_EQ(result, true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,27 +130,23 @@ TYPED_TEST(KZGTest, GeminiShplonkKzgWithShift)
const auto [gemini_opening_pairs, gemini_witnesses] = GeminiProver::compute_fold_polynomial_evaluations(
mle_opening_point, std::move(gemini_polynomials), r_challenge);

std::vector<ProverOpeningClaim<TypeParam>> opening_claims;
for (size_t l = 0; l < log_n; ++l) {
std::string label = "Gemini:a_" + std::to_string(l);
const auto& evaluation = gemini_opening_pairs[l + 1].evaluation;
prover_transcript->send_to_verifier(label, evaluation);
opening_claims.emplace_back(gemini_witnesses[l], gemini_opening_pairs[l]);
}
opening_claims.emplace_back(gemini_witnesses[log_n], gemini_opening_pairs[log_n]);

// Shplonk prover output:
// - opening pair: (z_challenge, 0)
// - witness: polynomial Q - Q_z
const Fr nu_challenge = prover_transcript->template get_challenge<Fr>("Shplonk:nu");
auto batched_quotient_Q =
ShplonkProver::compute_batched_quotient(gemini_opening_pairs, gemini_witnesses, nu_challenge);
prover_transcript->send_to_verifier("Shplonk:Q", this->ck()->commit(batched_quotient_Q));

const Fr z_challenge = prover_transcript->template get_challenge<Fr>("Shplonk:z");
const auto [shplonk_opening_pair, shplonk_witness] = ShplonkProver::compute_partially_evaluated_batched_quotient(
gemini_opening_pairs, gemini_witnesses, std::move(batched_quotient_Q), nu_challenge, z_challenge);
const auto opening_claim = ShplonkProver::prove(this->ck(), opening_claims, prover_transcript);

// KZG prover:
// - Adds commitment [W] to transcript
KZG::compute_opening_proof(this->ck(), shplonk_opening_pair, shplonk_witness, prover_transcript);
KZG::compute_opening_proof(this->ck(), opening_claim.opening_pair, opening_claim.polynomial, prover_transcript);

// Run the full verifier PCS protocol with genuine opening claims (genuine commitment, genuine evaluation)

Expand All @@ -166,7 +162,7 @@ TYPED_TEST(KZGTest, GeminiShplonkKzgWithShift)

// Shplonk verifier claim: commitment [Q] - [Q_z], opening point (z_challenge, 0)
const auto shplonk_verifier_claim =
ShplonkVerifier::reduce_verification(this->vk(), gemini_verifier_claim, verifier_transcript);
ShplonkVerifier::reduce_verification(this->vk()->get_g1_identity(), gemini_verifier_claim, verifier_transcript);

// KZG verifier:
// aggregates inputs [Q] - [Q_z] and [W] into an 'accumulator' (can perform pairing check on result)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,6 @@
*/
namespace bb {

/**
* @brief Polynomial G(X) = Q(X) - ∑ₖ ẑₖ(r)⋅( Bₖ(X) − Tₖ(z) ), where Q(X) = ∑ₖ ( Bₖ(X) − Tₖ(X) ) / zₖ(X)
*
* @tparam Curve EC parameters
*/
template <typename Curve> using OutputWitness = bb::Polynomial<typename Curve::ScalarField>;

/**
* @brief Prover output (claim=([G], r, 0), witness = G(X), proof = [Q])
* that can be passed on to a univariate opening protocol.
*
* @tparam Curve EC parameters
*/
template <typename Curve> struct ShplonkProverOutput {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

duplicate of ProverOutputClaim

OpeningPair<Curve> opening_pair; // single opening pair (challenge, evaluation)
OutputWitness<Curve> witness; // single polynomial G(X)
};

/**
* @brief Shplonk Prover
*
Expand All @@ -51,34 +33,31 @@ template <typename Curve> class ShplonkProver_ {
/**
* @brief Compute batched quotient polynomial Q(X) = ∑ⱼ ρʲ ⋅ ( fⱼ(X) − vⱼ) / ( X − xⱼ )
*
* @param opening_pairs list of opening pairs (xⱼ, vⱼ) for a witness polynomial fⱼ(X), s.t. fⱼ(xⱼ) = vⱼ.
* @param witness_polynomials list of polynomials fⱼ(X).
* @param nu
* @param opening_claims list of prover opening claims {fⱼ(X), (xⱼ, vⱼ)} for a witness polynomial fⱼ(X), s.t. fⱼ(xⱼ)
* = vⱼ.
* @param nu batching challenge
* @return Polynomial Q(X)
*/
static Polynomial compute_batched_quotient(std::span<const OpeningPair<Curve>> opening_pairs,
std::span<const Polynomial> witness_polynomials,
const Fr& nu)
static Polynomial compute_batched_quotient(std::span<const ProverOpeningClaim<Curve>> opening_claims, const Fr& nu)
{
// Find n, the maximum size of all polynomials fⱼ(X)
size_t max_poly_size{ 0 };
for (const auto& poly : witness_polynomials) {
max_poly_size = std::max(max_poly_size, poly.size());
for (const auto& claim : opening_claims) {
max_poly_size = std::max(max_poly_size, claim.polynomial.size());
}
// Q(X) = ∑ⱼ ρʲ ⋅ ( fⱼ(X) − vⱼ) / ( X − xⱼ )
Polynomial Q(max_poly_size);
Polynomial tmp(max_poly_size);

Fr current_nu = Fr::one();
for (size_t j = 0; j < opening_pairs.size(); ++j) {
// (Cⱼ, xⱼ, vⱼ)
const auto& [challenge, evaluation] = opening_pairs[j];
for (const auto& claim : opening_claims) {

// tmp = ρʲ ⋅ ( fⱼ(X) − vⱼ) / ( X − xⱼ )
tmp = witness_polynomials[j];
tmp[0] -= evaluation;
tmp.factor_roots(challenge);
// Compute individual claim quotient tmp = ( fⱼ(X) − vⱼ) / ( X − xⱼ )
tmp = claim.polynomial;
tmp[0] -= claim.opening_pair.evaluation;
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;
}
Expand All @@ -97,48 +76,67 @@ template <typename Curve> class ShplonkProver_ {
* @param z_challenge
* @return Output{OpeningPair, Polynomial}
*/
static ShplonkProverOutput<Curve> compute_partially_evaluated_batched_quotient(
std::span<const OpeningPair<Curve>> opening_pairs,
std::span<const Polynomial> witness_polynomials,
Polynomial&& batched_quotient_Q,
static ProverOpeningClaim<Curve> compute_partially_evaluated_batched_quotient(
std::span<const ProverOpeningClaim<Curve>> opening_claims,
Polynomial& batched_quotient_Q,
const Fr& nu_challenge,
const Fr& z_challenge)
{
const size_t num_opening_pairs = opening_pairs.size();
const size_t num_opening_claims = opening_claims.size();

// {ẑⱼ(r)}ⱼ , where ẑⱼ(r) = 1/zⱼ(r) = 1/(r - xⱼ)
std::vector<Fr> inverse_vanishing_evals;
inverse_vanishing_evals.reserve(num_opening_pairs);
for (const auto& pair : opening_pairs) {
inverse_vanishing_evals.emplace_back(z_challenge - pair.challenge);
inverse_vanishing_evals.reserve(num_opening_claims);
for (const auto& claim : 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ⱼ) / ( r − xⱼ ),
// s.t. G(r) = 0
Polynomial G(std::move(batched_quotient_Q)); // G(X) = Q(X)
Polynomial G(batched_quotient_Q); // G(X) = Q(X)
maramihali marked this conversation as resolved.
Show resolved Hide resolved

// G₀ = ∑ⱼ ρʲ ⋅ vⱼ / ( r − xⱼ )
Fr current_nu = Fr::one();
Polynomial tmp(G.size());
for (size_t j = 0; j < num_opening_pairs; ++j) {
// (Cⱼ, xⱼ, vⱼ)
const auto& [challenge, evaluation] = opening_pairs[j];

size_t idx = 0;
for (const auto& claim : opening_claims) {
// tmp = ρʲ ⋅ ( fⱼ(X) − vⱼ) / ( r − xⱼ )
tmp = witness_polynomials[j];
tmp[0] -= evaluation;
Fr scaling_factor = current_nu * inverse_vanishing_evals[j]; // = ρʲ / ( r − xⱼ )
tmp = claim.polynomial;
tmp[0] -= claim.opening_pair.evaluation;
Fr scaling_factor = current_nu * inverse_vanishing_evals[idx]; // = ρʲ / ( r − xⱼ )

// G -= ρʲ ⋅ ( fⱼ(X) − vⱼ) / ( r − xⱼ )
G.add_scaled(tmp, -scaling_factor);

current_nu *= nu_challenge;
idx++;
}

// Return opening pair (z, 0) and polynomial G(X) = Q(X) - Q_z(X)
return { .opening_pair = { .challenge = z_challenge, .evaluation = Fr::zero() }, .witness = std::move(G) };
return { .polynomial = G, .opening_pair = { .challenge = z_challenge, .evaluation = Fr::zero() } };
};

/**
* @brief Returns a batched opening claim equivalent to a set of opening claims consisting of polynomials, each
* opened at a single point.
*
* @param commitment_key
* @param opening_claims
* @param transcript
* @return ProverOpeningClaim<Curve>
*/
static ProverOpeningClaim<Curve> prove(const std::shared_ptr<CommitmentKey<Curve>>& commitment_key,
maramihali marked this conversation as resolved.
Show resolved Hide resolved
std::span<ProverOpeningClaim<Curve>> opening_claims,
auto& transcript)
{
const Fr nu = transcript->template get_challenge<Fr>("Shplonk:nu");
auto batched_quotient = compute_batched_quotient(opening_claims, nu);
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);
}
};

/**
Expand All @@ -156,12 +154,12 @@ template <typename Curve> class ShplonkVerifier_ {
* @brief Recomputes the new claim commitment [G] given the proof and
* the challenge r. No verification happens so this function always succeeds.
*
* @param g1_identity the identity element for the Curve
* @param claims list of opening claims (Cⱼ, xⱼ, vⱼ) for a witness polynomial fⱼ(X), s.t. fⱼ(xⱼ) = vⱼ.
* @param proof [Q(X)] = [ ∑ⱼ ρʲ ⋅ ( fⱼ(X) − vⱼ) / ( X − xⱼ ) ]
* @param transcript
* @return OpeningClaim
*/
static OpeningClaim<Curve> reduce_verification(std::shared_ptr<VK> vk,
static OpeningClaim<Curve> reduce_verification(Commitment g1_identity,
std::span<const OpeningClaim<Curve>> claims,
auto& transcript)
{
Expand Down Expand Up @@ -227,7 +225,7 @@ template <typename Curve> class ShplonkVerifier_ {
scalars.emplace_back(-scaling_factor);
}

commitments.emplace_back(GroupElement::one(builder));
commitments.emplace_back(g1_identity);
scalars.emplace_back(G_commitment_constant);

// [G] += G₀⋅[1] = [G] + (∑ⱼ ρʲ ⋅ vⱼ / ( r − xⱼ ))⋅[1]
Expand Down Expand Up @@ -264,7 +262,7 @@ template <typename Curve> class ShplonkVerifier_ {
}

// [G] += G₀⋅[1] = [G] + (∑ⱼ ρʲ ⋅ vⱼ / ( r − xⱼ ))⋅[1]
G_commitment += vk->get_g1_identity() * G_commitment_constant;
G_commitment += g1_identity * G_commitment_constant;
}

// Return opening pair (z, 0) and commitment [G]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ TYPED_TEST(ShplonkTest, ShplonkSimple)
using ShplonkProver = ShplonkProver_<TypeParam>;
using ShplonkVerifier = ShplonkVerifier_<TypeParam>;
using Fr = typename TypeParam::ScalarField;
using Polynomial = typename bb::Polynomial<Fr>;
using OpeningPair = bb::OpeningPair<TypeParam>;
using ProverOpeningClaim = ProverOpeningClaim<TypeParam>;

using OpeningClaim = OpeningClaim<TypeParam>;

const size_t n = 16;
Expand All @@ -43,32 +43,23 @@ TYPED_TEST(ShplonkTest, ShplonkSimple)
const auto commitment2 = this->commit(poly2);

// Aggregate polynomials and their opening pairs
std::vector<OpeningPair> opening_pairs = { { r1, eval1 }, { r2, eval2 } };
std::vector<Polynomial> polynomials = { poly1.share(), poly2.share() };
std::vector<ProverOpeningClaim> prover_opening_claims = { { poly1, { r1, eval1 } }, { poly2, { r2, eval2 } } };

// Execute the shplonk prover functionality
const Fr nu_challenge = prover_transcript->template get_challenge<Fr>("Shplonk:nu");
auto batched_quotient_Q = ShplonkProver::compute_batched_quotient(opening_pairs, polynomials, nu_challenge);
prover_transcript->send_to_verifier("Shplonk:Q", this->ck()->commit(batched_quotient_Q));

const Fr z_challenge = prover_transcript->template get_challenge<Fr>("Shplonk:z");
const auto [prover_opening_pair, shplonk_prover_witness] =
ShplonkProver::compute_partially_evaluated_batched_quotient(
opening_pairs, polynomials, std::move(batched_quotient_Q), nu_challenge, z_challenge);

const auto batched_opening_claim = ShplonkProver::prove(this->ck(), prover_opening_claims, prover_transcript);
// An intermediate check to confirm the opening of the shplonk prover witness Q
this->verify_opening_pair(prover_opening_pair, shplonk_prover_witness);
this->verify_opening_pair(batched_opening_claim.opening_pair, batched_opening_claim.polynomial);

// Aggregate polynomial commitments and their opening pairs
std::vector<OpeningClaim> opening_claims;
opening_claims.emplace_back(OpeningClaim{ opening_pairs[0], commitment1 });
opening_claims.emplace_back(OpeningClaim{ opening_pairs[1], commitment2 });
std::vector<OpeningClaim> verifier_opening_claims = { { { r1, eval1 }, commitment1 },
{ { r2, eval2 }, commitment2 } };

auto verifier_transcript = NativeTranscript::verifier_init_empty(prover_transcript);

// Execute the shplonk verifier functionality
const auto verifier_claim = ShplonkVerifier::reduce_verification(this->vk(), opening_claims, verifier_transcript);
const auto batched_verifier_claim = ShplonkVerifier::reduce_verification(
this->vk()->get_g1_identity(), verifier_opening_claims, verifier_transcript);

this->verify_opening_claim(verifier_claim, shplonk_prover_witness);
this->verify_opening_claim(batched_verifier_claim, batched_opening_claim.polynomial);
}
} // namespace bb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

using namespace bb;

class ECCVMComposerTests : public ::testing::Test {
class ECCVMTests : public ::testing::Test {
protected:
void SetUp() override { srs::init_grumpkin_crs_factory("../srs_db/grumpkin"); };
};
Expand Down Expand Up @@ -60,7 +60,7 @@ ECCVMCircuitBuilder generate_circuit(numeric::RNG* engine = nullptr)
return builder;
}

TEST_F(ECCVMComposerTests, BaseCase)
TEST_F(ECCVMTests, BaseCase)
{
ECCVMCircuitBuilder builder = generate_circuit(&engine);
ECCVMProver prover(builder);
Expand All @@ -71,7 +71,7 @@ TEST_F(ECCVMComposerTests, BaseCase)
ASSERT_TRUE(verified);
}

TEST_F(ECCVMComposerTests, EqFails)
TEST_F(ECCVMTests, EqFails)
{
auto builder = generate_circuit(&engine);
// Tamper with the eq op such that the expected value is incorect
Expand Down
Loading
Loading