Skip to content

Commit

Permalink
tests passing through gemini
Browse files Browse the repository at this point in the history
  • Loading branch information
ledwards2225 committed Aug 16, 2023
1 parent 5ef61bf commit e194f55
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 168 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -186,136 +186,7 @@ ProverOutput<Curve> GeminiProver_<Curve>::compute_fold_polynomial_evaluations(st
return { fold_poly_opening_pairs, std::move(fold_polynomials) };
};

/**
* @brief Returns univariate opening claims for the Fold polynomials to be checked later
*
* @param mle_opening_point the MLE evaluation point u
* @param batched_evaluation batched evaluation from multivariate evals at the point u
* @param batched_f batched commitment to unshifted polynomials
* @param batched_g batched commitment to to-be-shifted polynomials
* @param proof commitments to the m-1 folded polynomials, and alleged evaluations.
* @param transcript
* @return Fold polynomial opening claims: (r, A₀(r), C₀₊), (-r, A₀(-r), C₀₋), and
* (Cⱼ, Aⱼ(-r^{2ʲ}), -r^{2}), j = [1, ..., m-1]
*/

template <typename Curve>
std::vector<OpeningClaim<Curve>> GeminiVerifier_<Curve>::reduce_verification(std::span<const Fr> mle_opening_point, /* u */
const Fr batched_evaluation, /* all */
GroupElement& batched_f, /* unshifted */
GroupElement& batched_g, /* to-be-shifted */
VerifierTranscript<Fr>& transcript)
{
const size_t num_variables = mle_opening_point.size();

// Get polynomials Fold_i, i = 1,...,m-1 from transcript
std::vector<Commitment> commitments;
commitments.reserve(num_variables - 1);
for (size_t i = 0; i < num_variables - 1; ++i) {
auto commitment = transcript.template receive_from_prover<Commitment>("Gemini:FOLD_" + std::to_string(i + 1));
commitments.emplace_back(commitment);
}

// compute vector of powers of random evaluation point r
const Fr r = transcript.get_challenge("Gemini:r");
std::vector<Fr> r_squares = squares_of_r(r, num_variables);

// Get evaluations a_i, i = 0,...,m-1 from transcript
std::vector<Fr> evaluations;
evaluations.reserve(num_variables);
for (size_t i = 0; i < num_variables; ++i) {
auto eval = transcript.template receive_from_prover<Fr>("Gemini:a_" + std::to_string(i));
evaluations.emplace_back(eval);
}

// Compute evaluation A₀(r)
auto a_0_pos = compute_eval_pos(batched_evaluation, mle_opening_point, r_squares, evaluations);

// C₀_r_pos = ∑ⱼ ρʲ⋅[fⱼ] + r⁻¹⋅∑ⱼ ρᵏ⁺ʲ [gⱼ]
// C₀_r_pos = ∑ⱼ ρʲ⋅[fⱼ] - r⁻¹⋅∑ⱼ ρᵏ⁺ʲ [gⱼ]
auto [c0_r_pos, c0_r_neg] = compute_simulated_commitments(batched_f, batched_g, r);

std::vector<OpeningClaim<Curve>> fold_polynomial_opening_claims;
fold_polynomial_opening_claims.reserve(num_variables + 1);

// ( [A₀₊], r, A₀(r) )
fold_polynomial_opening_claims.emplace_back(OpeningClaim<Curve>{ { r, a_0_pos }, c0_r_pos });
// ( [A₀₋], -r, A₀(-r) )
fold_polynomial_opening_claims.emplace_back(OpeningClaim<Curve>{ { -r, evaluations[0] }, c0_r_neg });
for (size_t l = 0; l < num_variables - 1; ++l) {
// ([A₀₋], −r^{2ˡ}, Aₗ(−r^{2ˡ}) )
fold_polynomial_opening_claims.emplace_back(
OpeningClaim<Curve>{ { -r_squares[l + 1], evaluations[l + 1] }, commitments[l] });
}

return fold_polynomial_opening_claims;
};

/**
* @brief Compute the expected evaluation of the univariate commitment to the batched polynomial.
*
* @param batched_mle_eval The evaluation of the folded polynomials
* @param mle_vars MLE opening point u
* @param r_squares squares of r, r², ..., r^{2ᵐ⁻¹}
* @param fold_polynomial_evals series of Aᵢ₋₁(−r^{2ⁱ⁻¹})
* @return evaluation A₀(r)
*/
template <typename Curve>
typename Curve::ScalarField GeminiVerifier_<Curve>::compute_eval_pos(const Fr batched_mle_eval,
std::span<const Fr> mle_vars,
std::span<const Fr> r_squares,
std::span<const Fr> fold_polynomial_evals)
{
const size_t num_variables = mle_vars.size();

const auto& evals = fold_polynomial_evals;

// Initialize eval_pos with batched MLE eval v = ∑ⱼ ρʲ vⱼ + ∑ⱼ ρᵏ⁺ʲ v↺ⱼ
Fr eval_pos = batched_mle_eval;
for (size_t l = num_variables; l != 0; --l) {
const Fr r = r_squares[l - 1]; // = rₗ₋₁ = r^{2ˡ⁻¹}
const Fr eval_neg = evals[l - 1]; // = Aₗ₋₁(−r^{2ˡ⁻¹})
const Fr u = mle_vars[l - 1]; // = uₗ₋₁

// The folding property ensures that
// Aₗ₋₁(r^{2ˡ⁻¹}) + Aₗ₋₁(−r^{2ˡ⁻¹}) Aₗ₋₁(r^{2ˡ⁻¹}) - Aₗ₋₁(−r^{2ˡ⁻¹})
// Aₗ(r^{2ˡ}) = (1-uₗ₋₁) ----------------------------- + uₗ₋₁ -----------------------------
// 2 2r^{2ˡ⁻¹}
// We solve the above equation in Aₗ₋₁(r^{2ˡ⁻¹}), using the previously computed Aₗ(r^{2ˡ}) in eval_pos
// and using Aₗ₋₁(−r^{2ˡ⁻¹}) sent by the prover in the proof.
eval_pos = ((r * eval_pos * 2) - eval_neg * (r * (Fr(1) - u) - u)) / (r * (Fr(1) - u) + u);
}

return eval_pos; // return A₀(r)
};

/**
* @brief Computes two commitments to A₀ partially evaluated in r and -r.
*
* @param batched_f batched commitment to non-shifted polynomials
* @param batched_g batched commitment to to-be-shifted polynomials
* @param r evaluation point at which we have partially evaluated A₀ at r and -r.
* @return std::pair<Commitment, Commitment> c0_r_pos, c0_r_neg
*/
template <typename Curve>
std::pair<typename Curve::Element, typename Curve::Element> GeminiVerifier_<Curve>::compute_simulated_commitments(
GroupElement& batched_f, GroupElement& batched_g, Fr r)
{
// C₀ᵣ₊ = [F] + r⁻¹⋅[G]
GroupElement C0_r_pos = batched_f;
// C₀ᵣ₋ = [F] - r⁻¹⋅[G]
GroupElement C0_r_neg = batched_f;
Fr r_inv = r.invert();
if (!batched_g.is_point_at_infinity()) {
batched_g *= r_inv;
C0_r_pos += batched_g;
C0_r_neg -= batched_g;
}
return { C0_r_pos, C0_r_neg };
};

template class GeminiProver_<curve::BN254>;
template class GeminiProver_<curve::Grumpkin>;
template class GeminiVerifier_<curve::BN254>;
template class GeminiVerifier_<curve::Grumpkin>;
}; // namespace proof_system::honk::pcs::gemini
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,11 @@ template <typename Curve> struct ProverOutput {

/**
* @brief Compute powers of challenge ρ
*
* @tparam Fr
* @param rho
* @param num_powers
* @return std::vector<Fr>
*
* @tparam Fr
* @param rho
* @param num_powers
* @return std::vector<Fr>
*/
template <class Fr> inline std::vector<Fr> powers_of_rho(const Fr rho, const size_t num_powers)
{
Expand Down Expand Up @@ -107,8 +107,8 @@ template <typename Curve> class GeminiProver_ {
Polynomial&& batched_to_be_shifted);

static ProverOutput<Curve> compute_fold_polynomial_evaluations(std::span<const Fr> mle_opening_point,
std::vector<Polynomial>&& fold_polynomials,
const Fr& r_challenge);
std::vector<Polynomial>&& fold_polynomials,
const Fr& r_challenge);
}; // namespace proof_system::honk::pcs::gemini

template <typename Curve> class GeminiVerifier_ {
Expand All @@ -117,26 +117,136 @@ template <typename Curve> class GeminiVerifier_ {
using Commitment = typename Curve::AffineElement;

public:
/**
* @brief Returns univariate opening claims for the Fold polynomials to be checked later
*
* @param mle_opening_point the MLE evaluation point u
* @param batched_evaluation batched evaluation from multivariate evals at the point u
* @param batched_f batched commitment to unshifted polynomials
* @param batched_g batched commitment to to-be-shifted polynomials
* @param proof commitments to the m-1 folded polynomials, and alleged evaluations.
* @param transcript
* @return Fold polynomial opening claims: (r, A₀(r), C₀₊), (-r, A₀(-r), C₀₋), and
* (Cⱼ, Aⱼ(-r^{2ʲ}), -r^{2}), j = [1, ..., m-1]
*/
static std::vector<OpeningClaim<Curve>> reduce_verification(std::span<const Fr> mle_opening_point, /* u */
const Fr batched_evaluation, /* all */
GroupElement& batched_f, /* unshifted */
GroupElement& batched_g, /* to-be-shifted */
VerifierTranscript<Fr>& transcript);
const Fr batched_evaluation, /* all */
GroupElement& batched_f, /* unshifted */
GroupElement& batched_g, /* to-be-shifted */
auto& transcript)
{
const size_t num_variables = mle_opening_point.size();

// Get polynomials Fold_i, i = 1,...,m-1 from transcript
std::vector<Commitment> commitments;
commitments.reserve(num_variables - 1);
for (size_t i = 0; i < num_variables - 1; ++i) {
auto commitment =
transcript.template receive_from_prover<Commitment>("Gemini:FOLD_" + std::to_string(i + 1));
commitments.emplace_back(commitment);
}

// compute vector of powers of random evaluation point r
const Fr r = transcript.get_challenge("Gemini:r");
std::vector<Fr> r_squares = squares_of_r(r, num_variables);

// Get evaluations a_i, i = 0,...,m-1 from transcript
std::vector<Fr> evaluations;
evaluations.reserve(num_variables);
for (size_t i = 0; i < num_variables; ++i) {
auto eval = transcript.template receive_from_prover<Fr>("Gemini:a_" + std::to_string(i));
evaluations.emplace_back(eval);
}

// Compute evaluation A₀(r)
auto a_0_pos = compute_eval_pos(batched_evaluation, mle_opening_point, r_squares, evaluations);

// C₀_r_pos = ∑ⱼ ρʲ⋅[fⱼ] + r⁻¹⋅∑ⱼ ρᵏ⁺ʲ [gⱼ]
// C₀_r_pos = ∑ⱼ ρʲ⋅[fⱼ] - r⁻¹⋅∑ⱼ ρᵏ⁺ʲ [gⱼ]
auto [c0_r_pos, c0_r_neg] = compute_simulated_commitments(batched_f, batched_g, r);

std::vector<OpeningClaim<Curve>> fold_polynomial_opening_claims;
fold_polynomial_opening_claims.reserve(num_variables + 1);

// ( [A₀₊], r, A₀(r) )
fold_polynomial_opening_claims.emplace_back(OpeningClaim<Curve>{ { r, a_0_pos }, c0_r_pos });
// ( [A₀₋], -r, A₀(-r) )
fold_polynomial_opening_claims.emplace_back(OpeningClaim<Curve>{ { -r, evaluations[0] }, c0_r_neg });
for (size_t l = 0; l < num_variables - 1; ++l) {
// ([A₀₋], −r^{2ˡ}, Aₗ(−r^{2ˡ}) )
fold_polynomial_opening_claims.emplace_back(
OpeningClaim<Curve>{ { -r_squares[l + 1], evaluations[l + 1] }, commitments[l] });
}

return fold_polynomial_opening_claims;
}

private:
/**
* @brief Compute the expected evaluation of the univariate commitment to the batched polynomial.
*
* @param batched_mle_eval The evaluation of the folded polynomials
* @param mle_vars MLE opening point u
* @param r_squares squares of r, r², ..., r^{2ᵐ⁻¹}
* @param fold_polynomial_evals series of Aᵢ₋₁(−r^{2ⁱ⁻¹})
* @return evaluation A₀(r)
*/
static Fr compute_eval_pos(const Fr batched_mle_eval,
std::span<const Fr> mle_vars,
std::span<const Fr> r_squares,
std::span<const Fr> fold_polynomial_evals);
std::span<const Fr> fold_polynomial_evals)
{
const size_t num_variables = mle_vars.size();

const auto& evals = fold_polynomial_evals;

// Initialize eval_pos with batched MLE eval v = ∑ⱼ ρʲ vⱼ + ∑ⱼ ρᵏ⁺ʲ v↺ⱼ
Fr eval_pos = batched_mle_eval;
for (size_t l = num_variables; l != 0; --l) {
const Fr r = r_squares[l - 1]; // = rₗ₋₁ = r^{2ˡ⁻¹}
const Fr eval_neg = evals[l - 1]; // = Aₗ₋₁(−r^{2ˡ⁻¹})
const Fr u = mle_vars[l - 1]; // = uₗ₋₁

// The folding property ensures that
// Aₗ₋₁(r^{2ˡ⁻¹}) + Aₗ₋₁(−r^{2ˡ⁻¹}) Aₗ₋₁(r^{2ˡ⁻¹}) - Aₗ₋₁(−r^{2ˡ⁻¹})
// Aₗ(r^{2ˡ}) = (1-uₗ₋₁) ----------------------------- + uₗ₋₁ -----------------------------
// 2 2r^{2ˡ⁻¹}
// We solve the above equation in Aₗ₋₁(r^{2ˡ⁻¹}), using the previously computed Aₗ(r^{2ˡ}) in eval_pos
// and using Aₗ₋₁(−r^{2ˡ⁻¹}) sent by the prover in the proof.
eval_pos = ((r * eval_pos * 2) - eval_neg * (r * (Fr(1) - u) - u)) / (r * (Fr(1) - u) + u);
}

return eval_pos; // return A₀(r)
}

/**
* @brief Computes two commitments to A₀ partially evaluated in r and -r.
*
* @param batched_f batched commitment to non-shifted polynomials
* @param batched_g batched commitment to to-be-shifted polynomials
* @param r evaluation point at which we have partially evaluated A₀ at r and -r.
* @return std::pair<Commitment, Commitment> c0_r_pos, c0_r_neg
*/
static std::pair<GroupElement, GroupElement> compute_simulated_commitments(GroupElement& batched_f,
GroupElement& batched_g,
Fr r);
Fr r)
{
// C₀ᵣ₊ = [F] + r⁻¹⋅[G]
GroupElement C0_r_pos = batched_f;
// C₀ᵣ₋ = [F] - r⁻¹⋅[G]
GroupElement C0_r_neg = batched_f;
Fr r_inv = r.invert();
// WORKTODO: reinstate some kind of !batched_g.is_point_at_infinity() check for stdlib?
// if (!batched_g.is_point_at_infinity()) {
batched_g = batched_g * r_inv;
C0_r_pos += batched_g;
C0_r_neg -= batched_g;
// }
return { C0_r_pos, C0_r_neg };
}

}; // namespace proof_system::honk::pcs::gemini

extern template class GeminiProver_<curve::BN254>;
extern template class GeminiProver_<curve::Grumpkin>;
extern template class GeminiVerifier_<curve::BN254>;
extern template class GeminiVerifier_<curve::Grumpkin>;

} // namespace proof_system::honk::pcs::gemini
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ template <typename Flavor> bool UltraRecursiveVerifier_<Flavor>::verify_proof(co
using FF = typename Flavor::FF;
using GroupElement = typename Flavor::GroupElement;
using Commitment = typename Flavor::Commitment;
// using Curve = typename Flavor::Curve;
// using PCS = typename Flavor::PCS;
// using Gemini = ::proof_system::honk::pcs::gemini::GeminiVerifier_<Curve>;
using Curve = typename Flavor::Curve;
using Gemini = ::proof_system::honk::pcs::gemini::GeminiVerifier_<Curve>;
// using Shplonk = pcs::shplonk::ShplonkVerifier_<PCSParams>;
// using PCS = typename Flavor::PCS;
using VerifierCommitments = typename Flavor::VerifierCommitments;
using CommitmentLabels = typename Flavor::CommitmentLabels;

Expand Down Expand Up @@ -133,20 +133,10 @@ template <typename Flavor> bool UltraRecursiveVerifier_<Flavor>::verify_proof(co
if (!sumcheck_output.has_value()) {
return false;
}
// else {
// return true;
// }

// Extract multivariate opening point u = (u_0, ..., u_{d-1}) and purported multivariate evaluations at u
auto [multivariate_challenge, purported_evaluations] = *sumcheck_output;

// Execute Gemini/Shplonk verification:

// Construct inputs for Gemini verifier:
// - Multivariate opening point u = (u_0, ..., u_{d-1})
// - batched unshifted and to-be-shifted polynomial commitments
// auto batched_commitment_unshifted = GroupElement(GroupElement::NativeGroup::zero());
// auto batched_commitment_to_be_shifted = GroupElement(0);

// Compute powers of batching challenge rho
FF rho = transcript.get_challenge("rho");
std::vector<FF> rhos = ::proof_system::honk::pcs::gemini::powers_of_rho(rho, Flavor::NUM_ALL_ENTITIES);
Expand Down Expand Up @@ -175,20 +165,22 @@ template <typename Flavor> bool UltraRecursiveVerifier_<Flavor>::verify_proof(co
// do something silly like set it to rho.pow(0) in the fctn to make it work both native and stdlib?
scalars_unshifted[0] = FF::from_witness(builder, 1);

// Batch the commitments to the unshifted and to-be-shifted polynomials using powers of rho
auto batched_commitment_unshifted = GroupElement::batch_mul(commitments.get_unshifted(), scalars_unshifted);
auto batched_commitment_to_be_shifted =
GroupElement::batch_mul(commitments.get_to_be_shifted(), scalars_to_be_shifted);
(void)batched_commitment_unshifted;
(void)batched_commitment_to_be_shifted;

// Produce a Gemini claim consisting of:
// - d+1 commitments [Fold_{r}^(0)], [Fold_{-r}^(0)], and [Fold^(l)], l = 1:d-1
// - d+1 evaluations a_0_pos, and a_l, l = 0:d-1
// auto gemini_claim = Gemini::reduce_verification(multivariate_challenge,
// batched_evaluation,
// batched_commitment_unshifted,
// batched_commitment_to_be_shifted,
// transcript);
auto gemini_claim = Gemini::reduce_verification(multivariate_challenge,
batched_evaluation,
batched_commitment_unshifted,
batched_commitment_to_be_shifted,
transcript);

// Note(luke): Temporary. Done only to complete manifest through Gemini. Delete once we proceed to Shplonk.
[[maybe_unused]] FF nu = transcript.get_challenge("Shplonk:nu");

// DEBUG!
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,11 @@ template <typename OuterComposer> class RecursiveVerifierTest : public testing::
auto recursive_manifest = verifier.transcript.get_manifest();
auto native_manifest = native_verifier.transcript.get_manifest();
// Note: Recursive manifest currently goes only though sumcheck
recursive_manifest.print();
native_manifest.print();
for (size_t i = 0; i < recursive_manifest.size(); ++i) {
EXPECT_EQ(recursive_manifest[i], native_manifest[i]);
}
recursive_manifest.print();
native_manifest.print();
};

public:
Expand Down

0 comments on commit e194f55

Please sign in to comment.