Skip to content

Commit

Permalink
Lde/split gemini (#256)
Browse files Browse the repository at this point in the history
* adding adrians new transcript classes

* building with some failing tests

* tests passing

* tests added for transcript and new manifest concept

* improvements to the manifest concept

* prover now operating on split gemini fuctionality

* make shplonk test independent of Gemini

* gemini and kzg tests updated; reduce prove removed from gemini

* general cleanup

* woops, fix gcc build

* minor rebase fix

* make gemini method return fold polys per Adrians suggestion

* fix bad move
  • Loading branch information
ledwards2225 authored Mar 30, 2023
1 parent 2dbe41b commit b9df01e
Show file tree
Hide file tree
Showing 13 changed files with 176 additions and 172 deletions.
6 changes: 3 additions & 3 deletions cpp/src/barretenberg/honk/pcs/claim.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ template <typename Params> class OpeningPair {
using Fr = typename Params::Fr;

public:
Fr query; // r
Fr challenge; // r
Fr evaluation; // v = p(r)

bool operator==(const OpeningPair& other) const = default;
Expand All @@ -31,7 +31,7 @@ template <typename Params> class OpeningClaim {
using Fr = typename Params::Fr;

public:
// (query r, evaluation v = p(r))
// (challenge r, evaluation v = p(r))
OpeningPair<Params> opening_pair;
// commitment to univariate polynomial p(X)
CommitmentAffine commitment;
Expand All @@ -46,7 +46,7 @@ template <typename Params> class OpeningClaim {
*/
bool verify(CK* ck, const barretenberg::Polynomial<Fr>& polynomial) const
{
Fr real_eval = polynomial.evaluate(opening_pair.query);
Fr real_eval = polynomial.evaluate(opening_pair.challenge);
if (real_eval != opening_pair.evaluation) {
return false;
}
Expand Down
150 changes: 53 additions & 97 deletions cpp/src/barretenberg/honk/pcs/gemini/gemini.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
* v = ∑ ρʲ⋅vⱼ + ∑ ρᵏ⁺ʲ⋅v↺ⱼ = F(u) + G↺(u)
*
* The prover then creates the folded polynomials A₀, ..., Aₘ₋₁,
* commits and opens them at different points, as univariates.
* and opens them at different points, as univariates.
*
* We open A₀ as univariate at r and -r.
* Since A₀ = F + G↺, but the verifier only has commitments to the gⱼs,
Expand All @@ -48,30 +48,6 @@
*/
namespace honk::pcs::gemini {

/**
* @brief A Gemini proof contains the m-1 commitments to the
* folded univariates, and corresponding evaluations
* at -r, -r², …, r^{2ᵐ⁻¹}.
*
* The evaluations allow the verifier to reconstruct the evaluation of A₀(r).
*
* @tparam Params CommitmentScheme parameters
*/
template <typename Params> struct Proof {
/** @brief Commitments to folded polynomials (size = m-1)
*
* [ C₁, …, Cₘ₋₁], where Cₗ = commit(Aₗ(X)) of size 2ᵐ⁻ˡ
*/
std::vector<typename Params::Commitment> commitments;

/**
* @brief Evaluations of batched and folded polynomials (size m)
*
* [A₀(-r) , ..., Aₘ₋₁(-r^{2ᵐ⁻¹})]
*/
std::vector<typename Params::Fr> evaluations;
};

/**
* @brief Prover output (evalutation pair, witness) that can be passed on to Shplonk batch opening.
* @details Evaluation pairs {r, A₀₊(r)}, {-r, A₀₋(-r)}, {-r^{2^j}, Aⱼ(-r^{2^j)}, j = [1, ..., m-1]
Expand Down Expand Up @@ -100,35 +76,30 @@ template <typename Params> class MultilinearReductionScheme {

public:
/**
* @brief reduces claims about multiple (shifted) MLE evaluation
*
* @param ck is the commitment key for creating the new commitments
* @param mle_opening_point u = (u₀,...,uₘ₋₁) is the MLE opening point
* @param batched_shifted batch polynomial constructed from the unshifted multivariates
* @param batched_to_be_shifted batch polynomial constructed from the to-be-shifted multivariates
* @param transcript
* @return Output (opening pairs, folded_witness_polynomials)
* @brief Computes d-1 fold polynomials Fold_i, i = 1, ..., d-1
*
* @param mle_opening_point multilinear opening point 'u'
* @param batched_unshifted F(X) = ∑ⱼ ρʲ fⱼ(X)
* @param batched_to_be_shifted G(X) = ∑ⱼ ρᵏ⁺ʲ gⱼ(X)
* @return std::vector<Polynomial>
*/
static ProverOutput<Params> reduce_prove(std::shared_ptr<CK> ck,
std::span<const Fr> mle_opening_point,
const Polynomial&& batched_shifted, /* unshifted */
const Polynomial&& batched_to_be_shifted, /* to-be-shifted */
ProverTranscript<Fr>& transcript)
static std::vector<Polynomial> compute_fold_polynomials(std::span<const Fr> mle_opening_point,
Polynomial&& batched_unshifted,
Polynomial&& batched_to_be_shifted)
{
const size_t num_variables = mle_opening_point.size(); // m

// Allocate space for m+1 Fold polynomials
//
// At the end, the first two will contain the batched polynomial
// partially evaluated at the challenges r,-r.
// The other m-1 polynomials correspond to the foldings of A₀
// The first two are populated here with the batched unshifted and to-be-shifted polynomial respectively.
// They will eventually contain the full batched polynomial A₀ partially evaluated at the challenges r,-r.
// This function populates the other m-1 polynomials with the foldings of A₀.
std::vector<Polynomial> fold_polynomials;
fold_polynomials.reserve(num_variables + 1);
// F(X) = ∑ⱼ ρʲ fⱼ(X)
Polynomial& batched_F = fold_polynomials.emplace_back(batched_shifted);
// G(X) = ∑ⱼ ρᵏ⁺ʲ gⱼ(X)
Polynomial& batched_G = fold_polynomials.emplace_back(batched_to_be_shifted);

// F(X) = ∑ⱼ ρʲ fⱼ(X) and G(X) = ∑ⱼ ρᵏ⁺ʲ gⱼ(X)
Polynomial& batched_F = fold_polynomials.emplace_back(std::move(batched_unshifted));
Polynomial& batched_G = fold_polynomials.emplace_back(std::move(batched_to_be_shifted));

// A₀(X) = F(X) + G↺(X) = F(X) + G(X)/X.
Polynomial A_0(batched_F);
Expand Down Expand Up @@ -163,79 +134,64 @@ template <typename Params> class MultilinearReductionScheme {
A_l = A_l_fold;
}

/*
* Create commitments C₁,…,Cₘ₋₁ to polynomials FOLD_i, i = 1,...,d-1 and add to transcript
*/
std::vector<CommitmentAffine> commitments;
commitments.reserve(num_variables - 1);
for (size_t l = 0; l < num_variables - 1; ++l) {
commitments.emplace_back(ck->commit(fold_polynomials[l + 2]));
transcript.send_to_verifier("Gemini:FOLD_" + std::to_string(l + 1), commitments[l]);
}
return fold_polynomials;
};

/*
* Generate evaluation challenge r, and compute rₗ = r^{2ˡ} for l = 0, 1, ..., m-1
*/
const Fr r_challenge = transcript.get_challenge("Gemini:r");
std::vector<Fr> r_squares = squares_of_r(r_challenge, num_variables);
/**
* @brief Computes/aggragates d+1 Fold polynomials and their opening pairs (challenge, evaluation)
*
* @details This function assumes that, upon input, last d-1 entries in fold_polynomials are Fold_i.
* The first two entries are assumed to be, respectively, the batched unshifted and batched to-be-shifted
* polynomials F(X) = ∑ⱼ ρʲfⱼ(X) and G(X) = ∑ⱼ ρᵏ⁺ʲ gⱼ(X). This function completes the computation
* of the first two Fold polynomials as F + G/r and F - G/r. It then evaluates each of the d+1
* fold polynomials at, respectively, the points r, rₗ = r^{2ˡ} for l = 0, 1, ..., d-1.
*
* @param mle_opening_point u = (u₀,...,uₘ₋₁) is the MLE opening point
* @param fold_polynomials vector of polynomials whose first two elements are F(X) = ∑ⱼ ρʲfⱼ(X)
* and G(X) = ∑ⱼ ρᵏ⁺ʲ gⱼ(X), and the next d-1 elements are Fold_i, i = 1, ..., d-1.
* @param r_challenge univariate opening challenge
*/
static ProverOutput<Params> compute_fold_polynomial_evaluations(std::span<const Fr> mle_opening_point,
std::vector<Polynomial>&& fold_polynomials,
const Fr& r_challenge)
{
const size_t num_variables = mle_opening_point.size(); // m

/*
* Compute the witness polynomials for the resulting claim
*
*
* We are batching all polynomials together, and linearly combining them with
* powers of ρ
*/
Polynomial& batched_F = fold_polynomials[0]; // F(X) = ∑ⱼ ρʲ fⱼ(X)
Polynomial& batched_G = fold_polynomials[1]; // G(X) = ∑ⱼ ρᵏ⁺ʲ gⱼ(X)

// 2 simulated polynomials and (m-1) polynomials from this round
// Compute univariate opening queries rₗ = r^{2ˡ} for l = 0, 1, ..., m-1
std::vector<Fr> r_squares = squares_of_r(r_challenge, num_variables);

// Compute G/r
Fr r_inv = r_challenge.invert();
// G(X) *= r⁻¹
batched_G *= r_inv;

// To avoid an extra allocation, we reuse the following polynomials
// but rename them to represent the result.
// tmp = A₀(X) (&tmp == &A_0)
// A_0_pos = F(X) (&A_0_pos == &batched_F)
Polynomial& tmp = A_0;
// Construct A₀₊ = F + G/r and A₀₋ = F - G/r in place in fold_polynomials
Polynomial tmp = batched_F;
Polynomial& A_0_pos = fold_polynomials[0];

tmp = batched_F;
// A₀₊(X) = F(X) + G(X)/r, s.t. A₀₊(r) = A₀(r)
A_0_pos += batched_G;

// Perform a swap so that tmp = G(X)/r and A_0_neg = F(X)
std::swap(tmp, batched_G);
// After the swap, we have
// tmp = G(X)/r
// A_0_neg = F(X) (since &batched_F == &A_0_neg)
Polynomial& A_0_neg = fold_polynomials[1];

// A₀₋(X) = F(X) - G(X)/r, s.t. A₀₋(-r) = A₀(-r)
A_0_neg -= tmp;

/*
* Compute the m+1 evaluations Aₗ(−r^{2ˡ}), l = 0, ..., m-1.
* Add them to the transcript
*/
std::vector<Fr> fold_polynomial_evals;
fold_polynomial_evals.reserve(num_variables);
for (size_t l = 0; l < num_variables; ++l) {
const Polynomial& A_l = fold_polynomials[l + 1];

fold_polynomial_evals.emplace_back(A_l.evaluate(-r_squares[l]));
transcript.send_to_verifier("Gemini:a_" + std::to_string(l), fold_polynomial_evals[l]);
}

// Compute evaluation A₀(r)
auto a_0_pos = fold_polynomials[0].evaluate(r_challenge);

std::vector<OpeningPair<Params>> fold_poly_opening_pairs;
fold_poly_opening_pairs.reserve(num_variables + 1);

// ( r, A₀(r) )
fold_poly_opening_pairs.emplace_back(OpeningPair<Params>{ r_challenge, a_0_pos });
// (-r, Aₗ(−r^{2ˡ}) )
// Compute first opening pair {r, A₀(r)}
fold_poly_opening_pairs.emplace_back(
OpeningPair<Params>{ r_challenge, fold_polynomials[0].evaluate(r_challenge) });

// Compute the remaining m opening pairs {−r^{2ˡ}, Aₗ(−r^{2ˡ})}, l = 0, ..., m-1.
for (size_t l = 0; l < num_variables; ++l) {
fold_poly_opening_pairs.emplace_back(OpeningPair<Params>{ -r_squares[l], fold_polynomial_evals[l] });
fold_poly_opening_pairs.emplace_back(
OpeningPair<Params>{ -r_squares[l], fold_polynomials[l + 1].evaluate(-r_squares[l]) });
}

return { fold_poly_opening_pairs, std::move(fold_polynomials) };
Expand Down
24 changes: 19 additions & 5 deletions cpp/src/barretenberg/honk/pcs/gemini/gemini.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,25 @@ template <class Params> class GeminiTest : public CommitmentTest<Params> {
// Compute:
// - (d+1) opening pairs: {r, \hat{a}_0}, {-r^{2^i}, a_i}, i = 0, ..., d-1
// - (d+1) Fold polynomials Fold_{r}^(0), Fold_{-r}^(0), and Fold^(i), i = 0, ..., d-1
auto prover_output = Gemini::reduce_prove(this->ck(),
multilinear_evaluation_point,
std::move(batched_unshifted),
std::move(batched_to_be_shifted),
prover_transcript);
auto fold_polynomials = Gemini::compute_fold_polynomials(
multilinear_evaluation_point, std::move(batched_unshifted), std::move(batched_to_be_shifted));

for (size_t l = 0; l < log_n - 1; ++l) {
std::string label = "FOLD_" + std::to_string(l + 1);
auto commitment = this->ck()->commit(fold_polynomials[l + 2]);
prover_transcript.send_to_verifier(label, commitment);
}

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

auto prover_output = Gemini::compute_fold_polynomial_evaluations(
multilinear_evaluation_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 = prover_output.opening_pairs[l + 1].evaluation;
prover_transcript.send_to_verifier(label, evaluation);
}

// Check that the Fold polynomials have been evaluated correctly in the prover
this->verify_batch_opening_pair(prover_output.opening_pairs, prover_output.witnesses);
Expand Down
4 changes: 2 additions & 2 deletions cpp/src/barretenberg/honk/pcs/kzg/kzg.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ template <typename Params> class BilinearAccumulator {
*/
BilinearAccumulator(const OpeningClaim<Params>& claim, const Commitment& proof)
: lhs(claim.commitment - (Commitment::one() * claim.opening_pair.evaluation) +
(proof * claim.opening_pair.query))
(proof * claim.opening_pair.challenge))
, rhs(-proof)
{}

Expand Down Expand Up @@ -73,7 +73,7 @@ template <typename Params> class UnivariateOpeningScheme {
{
Polynomial quotient(polynomial);
quotient[0] -= opening_pair.evaluation;
quotient.factor_roots(opening_pair.query);
quotient.factor_roots(opening_pair.challenge);
CommitmentAffine quotient_commitment = ck->commit(quotient);

transcript.send_to_verifier("KZG:W", quotient_commitment);
Expand Down
36 changes: 25 additions & 11 deletions cpp/src/barretenberg/honk/pcs/kzg/kzg.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ TYPED_TEST(BilinearAccumulationTest, single)

auto witness = this->random_polynomial(n);
auto commitment = this->commit(witness);
auto query = Fr::random_element();
auto evaluation = witness.evaluate(query);
auto opening_pair = OpeningPair<TypeParam>{ query, evaluation };
auto challenge = Fr::random_element();
auto evaluation = witness.evaluate(challenge);
auto opening_pair = OpeningPair<TypeParam>{ challenge, evaluation };
auto opening_claim = OpeningClaim<TypeParam>{ opening_pair, commitment };

auto prover_transcript = ProverTranscript<Fr>::init_empty();
Expand Down Expand Up @@ -112,14 +112,28 @@ TYPED_TEST(BilinearAccumulationTest, GeminiShplonkKzgWithShift)

// Run the full prover PCS protocol:

// Gemini prover output:
// - opening pairs: d+1 pairs (r, a_0_pos) and (-r^{2^l}, a_l), l = 0:d-1
// - witness: the d+1 polynomials Fold_{r}^(0), Fold_{-r}^(0), Fold^(l), l = 1:d-1
auto gemini_prover_output = Gemini::reduce_prove(this->ck(),
mle_opening_point,
std::move(batched_unshifted),
std::move(batched_to_be_shifted),
prover_transcript);
// Compute:
// - (d+1) opening pairs: {r, \hat{a}_0}, {-r^{2^i}, a_i}, i = 0, ..., d-1
// - (d+1) Fold polynomials Fold_{r}^(0), Fold_{-r}^(0), and Fold^(i), i = 0, ..., d-1
auto fold_polynomials = Gemini::compute_fold_polynomials(
mle_opening_point, std::move(batched_unshifted), std::move(batched_to_be_shifted));

for (size_t l = 0; l < log_n - 1; ++l) {
std::string label = "FOLD_" + std::to_string(l + 1);
auto commitment = this->ck()->commit(fold_polynomials[l + 2]);
prover_transcript.send_to_verifier(label, commitment);
}

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

auto gemini_prover_output =
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;
prover_transcript.send_to_verifier(label, evaluation);
}

// Shplonk prover output:
// - opening pair: (z_challenge, 0)
Expand Down
2 changes: 1 addition & 1 deletion cpp/src/barretenberg/honk/pcs/shplonk/shplonk.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ template <typename Params> using OutputWitness = barretenberg::Polynomial<typena
* @tparam Params CommitmentScheme parameters
*/
template <typename Params> struct ProverOutput {
OpeningPair<Params> opening_pair; // single opening pair (query, G(query) = 0)
OpeningPair<Params> opening_pair; // single opening pair (challenge, evaluation)
OutputWitness<Params> witness; // single polynomial G(X)
};

Expand Down
Loading

0 comments on commit b9df01e

Please sign in to comment.