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

chore: create a Gemini prover #8622

Merged
merged 6 commits into from
Sep 18, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
2 changes: 1 addition & 1 deletion barretenberg/cpp/CMakePresets.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@
"displayName": "Debugging build with Clang-16",
"description": "Build with globally installed Clang-16 in debug mode",
"inherits": "clang16",
"binaryDir": "build-debug",
"binaryDir": "build",
"environment": {
"CMAKE_BUILD_TYPE": "Debug",
"CFLAGS": "-gdwarf-4",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,14 +139,12 @@ template <typename Curve> class CommitmentTest : public ::testing::Test {
* @brief Ensures that a set of opening pairs is correct by checking that evaluations are
* correct by recomputing them from each witness polynomial.
*/
void verify_batch_opening_pair(std::span<const OpeningPair<Curve>> opening_pairs,
std::span<const Polynomial> witnesses)
void verify_batch_opening_pair(std::vector<ProverOpeningClaim<Curve>> opening_claims)
{
const size_t num_pairs = opening_pairs.size();
ASSERT_EQ(witnesses.size(), num_pairs);

for (size_t j = 0; j < num_pairs; ++j) {
this->verify_opening_pair(opening_pairs[j], witnesses[j]);
for (auto claim : opening_claims) {
auto& [x, y] = claim.opening_pair;
Fr y_expected = claim.polynomial.evaluate(x);
EXPECT_EQ(y, y_expected) << "OpeningPair: evaluations mismatch";
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@

#include "gemini.hpp"
#include "barretenberg/common/thread.hpp"

#include <bit>
#include <memory>
#include <vector>

/**
* @brief Protocol for opening several multi-linear polynomials at the same point.
Expand All @@ -16,7 +14,7 @@
* f₀, …, fₖ₋₁ = multilinear polynomials,
* g₀, …, gₕ₋₁ = shifted multilinear polynomial,
* Each gⱼ is the left-shift of some f↺ᵢ, and gⱼ points to the same memory location as fᵢ.
* v₀, …, vₖ₋₁, v↺₀, …, v↺ₕ₋₁ = multilinear evalutions s.t. fⱼ(u) = vⱼ, and gⱼ(u) = f↺ⱼ(u) = v↺ⱼ
* v₀, …, vₖ₋₁, v↺₀, …, v↺ₕ₋₁ = multilinear evalutions s.t. fⱼ(u) = vⱼ, and gⱼ(u) = f↺ⱼ(u) = v↺ⱼ
*
* We use a challenge ρ to create a random linear combination of all fⱼ,
* and actually define A₀ = F + G↺, where
Expand All @@ -43,6 +41,59 @@
* since they are linear-combinations of the commitments [fⱼ] and [gⱼ].
*/
namespace bb {
template <typename Curve>
std::vector<typename GeminiProver_<Curve>::Claim> GeminiProver_<Curve>::prove(
maramihali marked this conversation as resolved.
Show resolved Hide resolved
const std::shared_ptr<CommitmentKey<Curve>>& commitment_key,
std::span<Fr> multilinear_challenge,
std::span<Fr> multilinear_evaluations, /* u */
RefSpan<Polynomial> f_polynomials, // unshifted
RefSpan<Polynomial> g_polynomials, // to-be-shifted
std::shared_ptr<NativeTranscript>& transcript)
{
ASSERT(multilinear_evaluations.size() == f_polynomials.size() + g_polynomials.size());
Fr rho = transcript->template get_challenge<Fr>("rho");
std::vector<Fr> rhos = gemini::powers_of_rho(rho, multilinear_evaluations.size());

// Compute batched multivariate evaluation
Fr batched_evaluation = Fr::zero();
for (size_t i = 0; i < rhos.size(); ++i) {
batched_evaluation += multilinear_evaluations[i] * rhos[i];
}

size_t log_n = multilinear_challenge.size();
size_t n = 1 << log_n;
// Compute batched polynomials
Polynomial batched_unshifted(n);
// TODO(mara): use shiftable, after you understand how it works
Polynomial batched_to_be_shifted = Polynomial::shiftable(1 << log_n);

const size_t num_unshifted = f_polynomials.size();
const size_t num_to_be_shifted = g_polynomials.size();
for (size_t i = 0; i < num_unshifted; i++) {
batched_unshifted.add_scaled(f_polynomials[i], rhos[i]);
}
for (size_t i = 0; i < num_to_be_shifted; i++) {
batched_to_be_shifted.add_scaled(g_polynomials[i], rhos[num_unshifted + i]);
}

// log_n + 2
auto fold_polynomials =
compute_fold_polynomials(multilinear_challenge, std::move(batched_unshifted), std::move(batched_to_be_shifted));

// Commit to the folded polynomials (except the first two, explain why the first two are left out) and send the
// commitment to the verifier
for (size_t l = 0; l < log_n - 1; l++) {
transcript->send_to_verifier("Gemini:FOLD_" + std::to_string(l + 1),
commitment_key->commit(fold_polynomials[l + 2]));
}
const Fr r_challenge = transcript->template get_challenge<Fr>("Gemini:r");
std::vector<Claim> claims =
compute_fold_polynomial_evaluations(multilinear_challenge, std::move(fold_polynomials), r_challenge);
for (size_t l = 1; l <= log_n; l++) {
transcript->send_to_verifier("Gemini:a_" + std::to_string(l), claims[l].opening_pair.evaluation);
}
return claims;
};

/**
* @brief Computes d-1 fold polynomials Fold_i, i = 1, ..., d-1
Expand All @@ -53,9 +104,10 @@ namespace bb {
* @return std::vector<Polynomial>
*/
template <typename Curve>
std::vector<typename GeminiProver_<Curve>::Polynomial> GeminiProver_<Curve>::compute_gemini_polynomials(
std::vector<typename GeminiProver_<Curve>::Polynomial> GeminiProver_<Curve>::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

const size_t num_threads = get_num_cpus_pow2();
Expand Down Expand Up @@ -141,13 +193,13 @@ std::vector<typename GeminiProver_<Curve>::Polynomial> GeminiProver_<Curve>::com
* @param r_challenge univariate opening challenge
*/
template <typename Curve>
GeminiProverOutput<Curve> GeminiProver_<Curve>::compute_fold_polynomial_evaluations(
std::span<const Fr> mle_opening_point, std::vector<Polynomial>&& gemini_polynomials, const Fr& r_challenge)
std::vector<typename GeminiProver_<Curve>::Claim> GeminiProver_<Curve>::compute_fold_polynomial_evaluations(
std::span<const Fr> mle_opening_point, std::vector<Polynomial>&& fold_polynomials, const Fr& r_challenge)
maramihali marked this conversation as resolved.
Show resolved Hide resolved
{
const size_t num_variables = mle_opening_point.size(); // m

Polynomial& batched_F = gemini_polynomials[0]; // F(X) = ∑ⱼ ρʲ fⱼ(X)
Polynomial& batched_G = gemini_polynomials[1]; // G(X) = ∑ⱼ ρᵏ⁺ʲ gⱼ(X)
Polynomial& batched_F = fold_polynomials[0]; // F(X) = ∑ⱼ ρʲ fⱼ(X)
Polynomial& batched_G = fold_polynomials[1]; // G(X) = ∑ⱼ ρᵏ⁺ʲ gⱼ(X)

// Compute univariate opening queries rₗ = r^{2ˡ} for l = 0, 1, ..., m-1
std::vector<Fr> r_squares = gemini::powers_of_evaluation_challenge(r_challenge, num_variables);
Expand All @@ -156,36 +208,35 @@ GeminiProverOutput<Curve> GeminiProver_<Curve>::compute_fold_polynomial_evaluati
Fr r_inv = r_challenge.invert();
batched_G *= r_inv;

// Construct A₀₊ = F + G/r and A₀₋ = F - G/r in place in gemini_polynomials
// Construct A₀₊ = F + G/r and A₀₋ = F - G/r in place in fold_polynomials
Polynomial tmp = batched_F;
Polynomial& A_0_pos = gemini_polynomials[0];
Polynomial& A_0_pos = fold_polynomials[0];

// 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);
Polynomial& A_0_neg = gemini_polynomials[1];
Polynomial& A_0_neg = fold_polynomials[1];

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

std::vector<OpeningPair<Curve>> fold_poly_opening_pairs;
fold_poly_opening_pairs.reserve(num_variables + 1);
std::vector<Claim> opening_claims;
opening_claims.reserve(num_variables + 1);

// Compute first opening pair {r, A₀(r)}
fold_poly_opening_pairs.emplace_back(
OpeningPair<Curve>{ r_challenge, gemini_polynomials[0].evaluate(r_challenge) });

Fr evaluation = fold_polynomials[0].evaluate(r_challenge);
opening_claims.emplace_back(
Claim{ fold_polynomials[0], { 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<Curve>{ -r_squares[l], gemini_polynomials[l + 1].evaluate(-r_squares[l]) });
evaluation = fold_polynomials[l + 1].evaluate(-r_squares[l]);
opening_claims.emplace_back(Claim{ fold_polynomials[l + 1], { -r_squares[l], evaluation } });
}

return { fold_poly_opening_pairs, std::move(gemini_polynomials) };
return opening_claims;
};

template class GeminiProver_<curve::BN254>;
template class GeminiProver_<curve::Grumpkin>;
}; // namespace bb
} // namespace bb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#pragma once

#include "../claim.hpp"
#include "barretenberg/commitment_schemes/claim.hpp"
#include "barretenberg/polynomials/polynomial.hpp"
#include "barretenberg/transcript/transcript.hpp"

Expand Down Expand Up @@ -57,10 +57,6 @@ namespace bb {
* ]
* @tparam Curve CommitmentScheme parameters
*/
template <typename Curve> struct GeminiProverOutput {
std::vector<OpeningPair<Curve>> opening_pairs;
std::vector<Polynomial<typename Curve::ScalarField>> witnesses;
};

namespace gemini {
/**
Expand Down Expand Up @@ -102,15 +98,24 @@ template <class Fr> inline std::vector<Fr> powers_of_evaluation_challenge(const
template <typename Curve> class GeminiProver_ {
using Fr = typename Curve::ScalarField;
using Polynomial = bb::Polynomial<Fr>;
using Claim = ProverOpeningClaim<Curve>;
maramihali marked this conversation as resolved.
Show resolved Hide resolved

public:
static std::vector<Polynomial> compute_gemini_polynomials(std::span<const Fr> mle_opening_point,
Polynomial&& batched_unshifted,
Polynomial&& batched_to_be_shifted);
static std::vector<Polynomial> compute_fold_polynomials(std::span<const Fr> multilinear_evaluations,
Polynomial&& batched_unshifted,
Polynomial&& batched_to_be_shifted);

static std::vector<Claim> compute_fold_polynomial_evaluations(std::span<const Fr> multilinear_evaluations,
std::vector<Polynomial>&& gemini_polynomials,
const Fr& r_challenge);

static GeminiProverOutput<Curve> compute_fold_polynomial_evaluations(std::span<const Fr> mle_opening_point,
std::vector<Polynomial>&& gemini_polynomials,
const Fr& r_challenge);
// TODO(Mara): consider if we should template this by transcript to use with a test transcript
static std::vector<Claim> prove(const std::shared_ptr<CommitmentKey<Curve>>& commitment_key,
std::span<Fr> multilinear_challenge,
std::span<Fr> multilinear_evaluations,
RefSpan<Polynomial> f_polynomials,
RefSpan<Polynomial> g_polynomials,
std::shared_ptr<NativeTranscript>& transcript);
}; // namespace bb

template <typename Curve> class GeminiVerifier_ {
Expand All @@ -122,22 +127,42 @@ template <typename Curve> class GeminiVerifier_ {
/**
* @brief Returns univariate opening claims for the Fold polynomials to be checked later
*
* @param mle_opening_point the MLE evaluation point u
* @param multilinear_evaluations 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 batched_commitment_unshifted batched commitment to unshifted polynomials
* @param batched_commitment_to_be_shifted 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 */
Fr& batched_evaluation, /* all */
GroupElement& batched_f, /* unshifted */
GroupElement& batched_g, /* to-be-shifted */
static std::vector<OpeningClaim<Curve>> reduce_verification(std::span<Fr> multilinear_challenge,
std::span<Fr> multilinear_evaluations, /* u */
RefSpan<GroupElement> unshifted_commitments,
RefSpan<GroupElement> to_be_shifted_commitments,
auto& transcript)
{
const size_t num_variables = mle_opening_point.size();
const size_t num_variables = multilinear_challenge.size();

Fr rho = transcript->template get_challenge<Fr>("rho");
std::vector<Fr> rhos = gemini::powers_of_rho(rho, multilinear_evaluations.size());

GroupElement batched_commitment_unshifted = GroupElement::zero();
GroupElement batched_commitment_to_be_shifted = GroupElement::zero();

Fr batched_evaluation = Fr::zero();
for (size_t i = 0; i < multilinear_evaluations.size(); ++i) {
batched_evaluation += multilinear_evaluations[i] * rhos[i];
}

const size_t num_unshifted = unshifted_commitments.size();
const size_t num_to_be_shifted = to_be_shifted_commitments.size();
for (size_t i = 0; i < num_unshifted; i++) {
batched_commitment_unshifted += unshifted_commitments[i] * rhos[i];
}
for (size_t i = 0; i < num_to_be_shifted; i++) {
batched_commitment_to_be_shifted += to_be_shifted_commitments[i] * rhos[num_unshifted + i];
}

// Get polynomials Fold_i, i = 1,...,m-1 from transcript
const std::vector<Commitment> commitments = get_gemini_commitments(num_variables, transcript);
Expand All @@ -149,12 +174,13 @@ template <typename Curve> class GeminiVerifier_ {
// Get evaluations a_i, i = 0,...,m-1 from transcript
const std::vector<Fr> evaluations = get_gemini_evaluations(num_variables, transcript);
// Compute evaluation A₀(r)
auto a_0_pos =
compute_gemini_batched_univariate_evaluation(batched_evaluation, mle_opening_point, r_squares, evaluations);
auto a_0_pos = compute_gemini_batched_univariate_evaluation(
batched_evaluation, multilinear_challenge, 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);
auto [c0_r_pos, c0_r_neg] =
compute_simulated_commitments(batched_commitment_unshifted, batched_commitment_to_be_shifted, r);

std::vector<OpeningClaim<Curve>> fold_polynomial_opening_claims;
fold_polynomial_opening_claims.reserve(num_variables + 1);
Expand Down Expand Up @@ -246,14 +272,13 @@ template <typename Curve> class GeminiVerifier_ {
/**
* @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 batched_commitment_unshifted batched commitment to non-shifted polynomials
* @param batched_commitment_to_be_shifted 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)
static std::pair<GroupElement, GroupElement> compute_simulated_commitments(
GroupElement& batched_commitment_unshifted, GroupElement& batched_commitment_to_be_shifted, Fr r)
{
// C₀ᵣ₊ = [F] + r⁻¹⋅[G]
GroupElement C0_r_pos;
Expand All @@ -265,7 +290,7 @@ template <typename Curve> class GeminiVerifier_ {
// TODO(#673): The following if-else represents the stldib/native code paths. Once the "native" verifier is
// achieved through a builder Simulator, the stdlib codepath should become the only codepath.
if constexpr (Curve::is_stdlib_type) {
std::vector<GroupElement> commitments = { batched_f, batched_g };
std::vector<GroupElement> commitments = { batched_commitment_unshifted, batched_commitment_to_be_shifted };
auto builder = r.get_context();
auto one = Fr(builder, 1);
// TODO(#707): these batch muls include the use of 1 as a scalar. This is handled appropriately as a non-mul
Expand All @@ -274,12 +299,12 @@ template <typename Curve> class GeminiVerifier_ {
C0_r_pos = GroupElement::batch_mul(commitments, { one, r_inv });
C0_r_neg = GroupElement::batch_mul(commitments, { one, -r_inv });
} else {
C0_r_pos = batched_f;
C0_r_neg = batched_f;
if (!batched_g.is_point_at_infinity()) {
batched_g = batched_g * r_inv;
C0_r_pos += batched_g;
C0_r_neg -= batched_g;
C0_r_pos = batched_commitment_unshifted;
C0_r_neg = batched_commitment_unshifted;
if (!batched_commitment_to_be_shifted.is_point_at_infinity()) {
batched_commitment_to_be_shifted = batched_commitment_to_be_shifted * r_inv;
C0_r_pos += batched_commitment_to_be_shifted;
C0_r_neg -= batched_commitment_to_be_shifted;
}
}

Expand Down
Loading
Loading