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

Split shplonk in prep for work queue #321

Merged
merged 2 commits into from
Apr 7, 2023
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
15 changes: 10 additions & 5 deletions cpp/src/barretenberg/honk/pcs/kzg/kzg.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,24 +126,29 @@ TYPED_TEST(BilinearAccumulationTest, GeminiShplonkKzgWithShift)

const Fr r_challenge = prover_transcript.get_challenge("Gemini:r");

auto gemini_prover_output =
const auto [gemini_opening_pairs, gemini_witnesses] =
Gemini::compute_fold_polynomial_evaluations(mle_opening_point, std::move(fold_polynomials), r_challenge);

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

// Shplonk prover output:
// - opening pair: (z_challenge, 0)
// - witness: polynomial Q - Q_z
auto shplonk_prover_output = Shplonk::reduce_prove(
this->ck(), gemini_prover_output.opening_pairs, gemini_prover_output.witnesses, prover_transcript);
const Fr nu_challenge = prover_transcript.get_challenge("Shplonk:nu");
auto batched_quotient_Q = Shplonk::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.get_challenge("Shplonk:z");
const auto [shplonk_opening_pair, shplonk_witness] = Shplonk::compute_partially_evaluated_batched_quotient(
gemini_opening_pairs, gemini_witnesses, std::move(batched_quotient_Q), nu_challenge, z_challenge);

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

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

Expand Down
9 changes: 7 additions & 2 deletions cpp/src/barretenberg/honk/pcs/shplonk/shplonk.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,13 @@ TYPED_TEST(ShplonkTest, ShplonkSimple)
std::vector<Polynomial> polynomials = { poly1, poly2 };

// Execute the shplonk prover functionality
const auto [prover_opening_pair, shplonk_prover_witness] =
Shplonk::reduce_prove(this->ck(), opening_pairs, polynomials, prover_transcript);
const Fr nu_challenge = prover_transcript.get_challenge("Shplonk:nu");
auto batched_quotient_Q = Shplonk::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.get_challenge("Shplonk:z");
const auto [prover_opening_pair, shplonk_prover_witness] = Shplonk::compute_partially_evaluated_batched_quotient(
opening_pairs, polynomials, std::move(batched_quotient_Q), nu_challenge, z_challenge);

// An intermediate check to confirm the opening of the shplonk prover witness Q
this->verify_opening_pair(prover_opening_pair, shplonk_prover_witness);
Expand Down
54 changes: 32 additions & 22 deletions cpp/src/barretenberg/honk/pcs/shplonk/shplonk_single.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,24 +22,17 @@ template <typename Params> class SingleBatchOpeningScheme {

public:
/**
* @brief Batches several single-point 'OpeningClaim' into a single 'OpeningClaim' suitable for
* a univariate polynomial opening scheme.
* @brief Compute batched quotient polynomial Q(X) = ∑ⱼ ρʲ ⋅ ( fⱼ(X) − vⱼ) / ( X − xⱼ )
*
* @param ck CommitmentKey
* @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 transcript
* @return Output{OpeningClaim, WitnessPolynomial, Proof}
* @param nu
* @return Polynomial Q(X)
*/
static ProverOutput<Params> reduce_prove(std::shared_ptr<CK> ck,
std::span<const OpeningPair<Params>> opening_pairs,
std::span<const Polynomial> witness_polynomials,
ProverTranscript<Fr>& transcript)
static Polynomial compute_batched_quotient(std::span<const OpeningPair<Params>> opening_pairs,
std::span<const Polynomial> witness_polynomials,
const Fr& nu)
{
Fr nu = transcript.get_challenge("Shplonk:nu");

const size_t num_opening_pairs = opening_pairs.size();

// Find n, the maximum size of all polynomials fⱼ(X)
size_t max_poly_size{ 0 };
for (const auto& poly : witness_polynomials) {
Expand All @@ -50,7 +43,7 @@ template <typename Params> class SingleBatchOpeningScheme {
Polynomial tmp(max_poly_size);

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

Expand All @@ -63,12 +56,28 @@ template <typename Params> class SingleBatchOpeningScheme {
current_nu *= nu;
}

// commit to Q(X) and add [Q] to the transcript
auto Q_commitment = ck->commit(Q);
transcript.send_to_verifier("Shplonk:Q", Q_commitment);
// Return batched quotient polynomial Q(X)
return Q;
};

// generate random evaluation challenge zeta_challenge
const Fr z_challenge = transcript.get_challenge("Shplonk:z");
/**
* @brief Compute partially evaluated batched quotient polynomial difference Q(X) - Q_z(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 batched_quotient_Q Q(X) = ∑ⱼ ρʲ ⋅ ( fⱼ(X) − vⱼ) / ( X − xⱼ )
* @param nu_challenge
* @param z_challenge
* @return Output{OpeningPair, Polynomial}
*/
static ProverOutput<Params> compute_partially_evaluated_batched_quotient(
std::span<const OpeningPair<Params>> opening_pairs,
std::span<const Polynomial> witness_polynomials,
Polynomial&& batched_quotient_Q,
const Fr& nu_challenge,
const Fr& z_challenge)
{
const size_t num_opening_pairs = opening_pairs.size();

// {ẑⱼ(r)}ⱼ , where ẑⱼ(r) = 1/zⱼ(r) = 1/(r - xⱼ)
std::vector<Fr> inverse_vanishing_evals;
Expand All @@ -80,10 +89,11 @@ template <typename Params> class SingleBatchOpeningScheme {

// G(X) = Q(X) - Q_z(X) = Q(X) - ∑ⱼ ρʲ ⋅ ( fⱼ(X) − vⱼ) / ( r − xⱼ ),
// s.t. G(r) = 0
Polynomial& G = Q;
Polynomial G(std::move(batched_quotient_Q)); // G(X) = Q(X)

// G₀ = ∑ⱼ ρʲ ⋅ vⱼ / ( r − xⱼ )
current_nu = Fr::one();
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];
Expand All @@ -96,7 +106,7 @@ template <typename Params> class SingleBatchOpeningScheme {
// G -= ρʲ ⋅ ( fⱼ(X) − vⱼ) / ( r − xⱼ )
G.add_scaled(tmp, -scaling_factor);

current_nu *= nu;
current_nu *= nu_challenge;
}

// Return opening pair (z, 0) and polynomial G(X) = Q(X) - Q_z(X)
Expand Down
24 changes: 20 additions & 4 deletions cpp/src/barretenberg/honk/proof_system/prover.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -239,13 +239,28 @@ template <typename settings> void Prover<settings>::execute_pcs_evaluation_round
/**
* - Do Fiat-Shamir to get "nu" challenge.
* - Compute commitment [Q]_1
* */
template <typename settings> void Prover<settings>::execute_shplonk_batched_quotient_round()
{
nu_challenge = transcript.get_challenge("Shplonk:nu");

batched_quotient_Q =
Shplonk::compute_batched_quotient(gemini_output.opening_pairs, gemini_output.witnesses, nu_challenge);

// commit to Q(X) and add [Q] to the transcript
auto Q_commitment = commitment_key->commit(batched_quotient_Q);
transcript.send_to_verifier("Shplonk:Q", Q_commitment);
}

/**
* - Do Fiat-Shamir to get "z" challenge.
* - Compute polynomial Q(X) - Q_z(X)
* */
template <typename settings> void Prover<settings>::execute_shplonk_round()
template <typename settings> void Prover<settings>::execute_shplonk_partial_evaluation_round()
{
shplonk_output =
Shplonk::reduce_prove(commitment_key, gemini_output.opening_pairs, gemini_output.witnesses, transcript);
const Fr z_challenge = transcript.get_challenge("Shplonk:z");
shplonk_output = Shplonk::compute_partially_evaluated_batched_quotient(
gemini_output.opening_pairs, gemini_output.witnesses, std::move(batched_quotient_Q), nu_challenge, z_challenge);
}

/**
Expand Down Expand Up @@ -302,7 +317,8 @@ template <typename settings> plonk::proof& Prover<settings>::construct_proof()

// Fiat-Shamir: nu
// Compute Shplonk batched quotient commitment
execute_shplonk_round();
execute_shplonk_batched_quotient_round();
execute_shplonk_partial_evaluation_round();
// queue.process_queue(); // NOTE: Don't remove; we may reinstate the queue

// Fiat-Shamir: z
Expand Down
6 changes: 5 additions & 1 deletion cpp/src/barretenberg/honk/proof_system/prover.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ template <typename settings> class Prover {
void execute_relation_check_rounds();
void execute_univariatization_round();
void execute_pcs_evaluation_round();
void execute_shplonk_round();
void execute_shplonk_batched_quotient_round();
void execute_shplonk_partial_evaluation_round();
void execute_kzg_round();

void compute_wire_commitments();
Expand Down Expand Up @@ -71,6 +72,9 @@ template <typename settings> class Prover {
// Container for d + 1 Fold polynomials produced by Gemini
std::vector<Polynomial> fold_polynomials;

Polynomial batched_quotient_Q;
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I wonder if a more proper way to handle this would be to have a std::shared_ptr<Polynomial>, rather than moving it and leaving an empty poly behind. Not a huge deal but curious about best practice here. Thoughts @adr1anh?

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe an optional here could more explicitly indicate whether the entry is used?

Copy link
Contributor

Choose a reason for hiding this comment

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

Shared pointer wouldn't make much sense since it's not actually shared anywhere. It also has a bit of overhead from having to do reference counting.

Copy link
Contributor

Choose a reason for hiding this comment

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

A unique pointer might make sense, but the main point it in checking that the element is null or not, in which case an optional is more explicit

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@adr1anh I'm sure I'm clear on what you mean -- I haven't seen optional applied to a class member before, only an input/output to a function. Is this an option or am I misunderstanding you? Either way, I'll leave it as is for now since it's hardly dangerous and I'm guessing this gets refactored soon anyway :)

Fr nu_challenge;

// Honk only needs a small portion of the functionality but may be fine to use existing work_queue
// NOTE: this is not currently in use, but it may well be used in the future.
// TODO(Adrian): Uncomment when we need this again.
Expand Down