Skip to content

Commit

Permalink
Lde/split gemini (AztecProtocol/barretenberg#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 cc7889f commit 6d6afb1
Show file tree
Hide file tree
Showing 13 changed files with 176 additions and 172 deletions.
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
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
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
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
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
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 6d6afb1

Please sign in to comment.