Skip to content
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
19 changes: 2 additions & 17 deletions barretenberg/cpp/src/barretenberg/commitment_schemes/claim.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,23 +27,6 @@ template <typename Curve> class OpeningPair {
bool operator==(const OpeningPair& other) const = default;
};

/**
* @brief Opening vector \f$(r,\{a_1, \dots, a_m\}, {v_1, \dots, v_m})\f$ for some witness polynomials \f$\{p_1(X),
* p_m(X)\}\f$ such that \f$\sum_i a_i p_i(r) = \sum_i a_i v_i\f$.
*
* @tparam Params for the given commitment scheme
*/
template <typename Curve> class OpeningVector {
using Fr = typename Curve::ScalarField;

public:
Fr challenge; // r
std::vector<Fr> coefficients; // (a_1, \dots, a_m)
std::vector<Fr> evaluations; // \sum_i a_i p_i(r) = \sum_i a_i v_i

bool operator==(const OpeningVector& other) const = default;
};

/**
* @brief Polynomial p and an opening pair (r,v) such that p(r) = v
*
Expand Down Expand Up @@ -162,6 +145,8 @@ template <typename Curve> class OpeningClaim {
*
* @details This structure is used in the `reduce_verify_batch_opening_claim` method of KZG or IPA.
*
* @note This structure always represents a zero evaluation claim.
*
* @tparam Curve: BN254 or Grumpkin.
*/
template <typename Curve> struct BatchOpeningClaim {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -390,40 +390,54 @@ template <typename Curve> class ShplonkVerifier_ {
}
}

/**
* Structure used to update the internal state of the Shplonk verifier. It represents a claim which is constructed
* as a linear combination of the commitments stored by the Shplonk verifier. The structure is composed of:
* - A list of indices = \f$(i_1, \dots, i_k)\f$
* - A list of scalar coefficients = \f$(a_1, \dots, a_k)\f$
* - An opening pair \f$(x, v)\f$
* The state of the Shplonk verifier is updated so to add the check:
* \f[ \sum_{j=1}^k a_j f_{i_j}(x) = v \f]
* where \f${f_i}_i\f$ are the polynomials whose commitments are stored in the Shplonk verifier
*
* @note The challenge \f$x\f$ is stored redundantly for the purpose of the `update` method, but it is useful to
* expose the method `reduce_verification_vector_claims_no_finalize`
*/
// It is composed
struct LinearCombinationOfClaims {
std::vector<size_t> indices;
std::vector<Fr> scalars;
OpeningPair<Curve> opening_pair;
};

/**
* @brief Update the internal state of the Shplonk verifier
*
* @details Given a list of indices = \f$(i_1, \dots, i_k)\f$, a list of coefficients = \f$(a_1, \dots, a_k)\f$, an
* evaluation challenge = \f$x\f$, and a series of evaluations = \f$(v_1, \dots, v_k)\f$, update the internal
* state of the Shplonk verifier so to add the check
* \f[ \sum_{j=1}^k a_j f_{i_j}(x) = \sum_{j=1}^k a_j v_j \f]
* This amounts to update:
* @details Given a list of indices = \f$(i_1, \dots, i_k)\f$, a list of scalar coefficients = \f$(a_1, \dots,
* a_k)\f$, an opening pair $\f(x,v)\f$, and the inverse vanishing eval \f$\frac{1}{z - x}\f$, update the internal
* state of the Shplonk verifier so to add the check \f[ \sum_{j=1}^k a_j f_{i_j}(x) = v \f] This amounts to update:
* - \f$s_{i_j} -= \frac{\nu^{i-1} * a_j}{z - x}\f$
* - \f$\theta += \sum_{j=1}^k \nu^{i-1} \frac{a_j v_j}{z - x}\f$
* - \f$\theta += \nu^{i-1} \frac{v}{z - x}\f$
*
* @param indices
* @param coefficients
* @param evaluations
* @param update_data
* @param inverse_vanishing_eval
*/
void update(const std::vector<size_t>& indices,
const std::vector<Fr>& coefficients,
const std::vector<Fr>& evaluations,
const Fr& inverse_vanishing_eval)
void update(const LinearCombinationOfClaims& update_data, const Fr& inverse_vanishing_eval)
{

// Compute \nu^{i-1} / (z - x)
auto scalar_factor = pows_of_nu[pow_idx] * inverse_vanishing_eval;

for (const auto& [index, coefficient, evaluation] : zip_view(indices, coefficients, evaluations)) {
for (const auto& [index, coefficient] : zip_view(update_data.indices, update_data.scalars)) {
// \nu^{i-1} * a_j / (z - x)
auto scaling_factor = scalar_factor * coefficient;
// s_{i_j} -= \nu^{i-1} * a_j / (z - x)
scalars[index + 1] -= scaling_factor;
// \theta += \nu^{i-1} * a_j * v_j / (z - x)
identity_scalar_coefficient += scaling_factor * evaluation;
}

// \theta += \nu^{i-1} * v / (z - x)
identity_scalar_coefficient += scalar_factor * update_data.opening_pair.evaluation;

// Update `pow_idx`
pow_idx += 1;
}
Expand Down Expand Up @@ -478,7 +492,7 @@ template <typename Curve> class ShplonkVerifier_ {
/**
* @brief Instantiate a Shplonk verifier and update its state with the provided claims.
*
* @param claims list of opening claims \f$(C_j, x_j, v_j)\f$ for a witness polynomial \f$f_j(X)\f$, s.t.
* @param claims List of opening claims \f$(C_j, x_j, v_j)\f$ for a witness polynomial \f$f_j(X)\f$, s.t.
* \f$f_j(x_j) = v_j\f$.
* @param transcript
*/
Expand Down Expand Up @@ -510,22 +524,21 @@ template <typename Curve> class ShplonkVerifier_ {
}

for (size_t idx = 0; idx < claims.size(); idx++) {
verifier.update({ idx }, { Fr(1) }, { claims[idx].opening_pair.evaluation }, inverse_vanishing_evals[idx]);
verifier.update({ { idx }, { Fr(1) }, claims[idx].opening_pair }, inverse_vanishing_evals[idx]);
}

return verifier;
};

/**
* @brief Instantiate a Shplonk verifier and update its state with the provided opening vectors.
* @brief Instantiate a Shplonk verifier and update its state with the provided data.
*
* @param indices List \f${ (i_{j_1}, \dots, i_{j_k}) }_k \f$ of indices
* @param claims List of opening vectors \f$\{ (r, (a_{j_1}, \dots, a_{j_k}), (v_1, \dots, v_{j_k})) \}_k\f$ s.t.
* \f[ \sum_{l=1}^k a_{j_l} f_{j_l}(r) = \sum_{l=1}^k a_{j_l} v_{j_r} \f]
* where \f$f_1, \dots, f_m\f$ are the polynomials whose commitments are held by the Shplonk verifier.
* @param claims List of LinearCombinationOfClaims \f$\{ ( (i_{j_1}, \dots, i_{j_k}), (a_{j_1}, \dots, a_{j_k}),
* (r_k, v_k) )
* \}_k\f$ s.t. \f[ \sum_{l=1}^k a_{j_l} f_{j_l}(r_k) = v_k \f] where \f$f_1, \dots, f_m\f$ are the polynomials
* whose commitments are held by the Shplonk verifier.
*/
void reduce_verification_vector_claims_no_finalize(std::span<const std::vector<size_t>> indices,
std::span<const OpeningVector<Curve>> claims)
void reduce_verification_vector_claims_no_finalize(std::span<const LinearCombinationOfClaims> claims)
{
const size_t num_claims = claims.size();

Expand All @@ -534,17 +547,17 @@ template <typename Curve> class ShplonkVerifier_ {
inverse_vanishing_evals.reserve(num_claims);
if constexpr (Curve::is_stdlib_type) {
for (const auto& claim : claims) {
inverse_vanishing_evals.emplace_back((this->z_challenge - claim.challenge).invert());
inverse_vanishing_evals.emplace_back((this->z_challenge - claim.opening_pair.challenge).invert());
}
} else {
for (const auto& claim : claims) {
inverse_vanishing_evals.emplace_back(this->z_challenge - claim.challenge);
inverse_vanishing_evals.emplace_back(this->z_challenge - claim.opening_pair.challenge);
}
Fr::batch_invert(inverse_vanishing_evals);
}

for (const auto& [idx, claim, inv] : zip_view(indices, claims, inverse_vanishing_evals)) {
this->update(idx, claim.coefficients, claim.evaluations, inv);
for (const auto& [claim, inv] : zip_view(claims, inverse_vanishing_evals)) {
this->update(claim, inv);
}
}

Expand All @@ -553,16 +566,15 @@ template <typename Curve> class ShplonkVerifier_ {
* the challenge r. No verification happens so this function always succeeds.
*
* @param g1_identity the identity element for the Curve
* @param indices List \f${ (i_{j_1}, \dots, i_{j_k}) }_k \f$ of indices
* @param claims List of opening vectors \f$\{ (r, (a_{j_1}, \dots, a_{j_k}), (v_1, \dots, v_{j_k})) \}_k\f$ s.t.
* \f[ \sum_{l=1}^k a_{j_l} f_{j_l}(r) = \sum_{l=1}^k a_{j_l} v_{j_r} \f]
* where \f$f_1, \dots, f_m\f$ are the polynomials whose commitments are held by the Shplonk verifier.
* @param claims List of LinearCombinationOfClaims \f$\{ ( (i_{j_1}, \dots, i_{j_k}), (a_{j_1}, \dots, a_{j_k}),
* (r_k, v_k) )
* \}_k\f$ s.t. \f[ \sum_{l=1}^k a_{j_l} f_{j_l}(r_k) = v_k \f] where \f$f_1, \dots, f_m\f$ are the polynomials
* whose commitments are held by the Shplonk verifier.
*/
OpeningClaim<Curve> reduce_vector_claims_verification(Commitment g1_identity,
std::span<const std::vector<size_t>> indices,
std::span<const OpeningVector<Curve>> claims)
OpeningClaim<Curve> reduce_verification_vector_claims(Commitment g1_identity,
std::span<const LinearCombinationOfClaims> claims)
{
this->reduce_verification_vector_claims_no_finalize(indices, claims);
this->reduce_verification_vector_claims_no_finalize(claims);
return this->finalize(g1_identity);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ TYPED_TEST(ShplonkTest, ShplonkLinearlyDependent)
using ShplonkProver = ShplonkProver_<TypeParam>;
using ShplonkVerifier = ShplonkVerifier_<TypeParam>;
using Fr = typename TypeParam::ScalarField;
using OpeningVector = OpeningVector<TypeParam>;

auto prover_transcript = NativeTranscript::prover_init_empty();

Expand All @@ -74,22 +73,17 @@ TYPED_TEST(ShplonkTest, ShplonkLinearlyDependent)

// Shplonk verification
auto verifier_opening_claims = ClaimData::verifier_opening_claims(setup);
std::vector<OpeningVector> opening_vectors = {
{ verifier_opening_claims[0].opening_pair.challenge,
{ Fr(1) },
{ verifier_opening_claims[0].opening_pair.evaluation } },
{ verifier_opening_claims[1].opening_pair.challenge,
{ Fr(1) },
{ verifier_opening_claims[1].opening_pair.evaluation } },
{ verifier_opening_claims[2].opening_pair.challenge, coefficients, evals }
std::vector<typename ShplonkVerifier::LinearCombinationOfClaims> update_data = {
{ { 0 }, { Fr(1) }, verifier_opening_claims[0].opening_pair },
{ { 1 }, { Fr(1) }, verifier_opening_claims[1].opening_pair },
{ { 0, 1 }, coefficients, verifier_opening_claims[2].opening_pair },
};
std::vector<std::vector<size_t>> indices = { { 0 }, { 1 }, { 0, 1 } };
auto verifier_transcript = NativeTranscript::verifier_init_empty(prover_transcript);
ShplonkVerifier verifier(commitments, verifier_transcript, verifier_opening_claims.size());

// Execute the shplonk verifier functionality
const auto batched_verifier_claim =
verifier.reduce_vector_claims_verification(this->vk().get_g1_identity(), indices, opening_vectors);
verifier.reduce_verification_vector_claims(this->vk().get_g1_identity(), update_data);

this->verify_opening_claim(batched_verifier_claim, batched_opening_claim.polynomial);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,6 @@ TYPED_TEST(ShplonkRecursionTest, LineralyDependent)
using GroupElement = Curve::Element;
using Commitment = typename Curve::AffineElement;
using OpeningClaim = OpeningClaim<Curve>;
using OpeningVector = OpeningVector<Curve>;
using Transcript = bb::BaseTranscript<stdlib::recursion::honk::StdlibTranscriptParams<Builder>>;
using StdlibProof = stdlib::Proof<Builder>;

Expand Down Expand Up @@ -145,8 +144,12 @@ TYPED_TEST(ShplonkRecursionTest, LineralyDependent)
// Compute last commitment as it would happen in a circuit
Commitment commit = GroupElement::batch_mul(
{ stdlib_opening_claims[0].commitment, stdlib_opening_claims[1].commitment }, { coeff1, coeff2 });

// Opening pair for the linear combination as it would be received by the Verifier from the Prover
Fr r = Fr::from_witness(&builder, native_opening_claims[2].opening_pair.challenge);
Fr eval = Fr::from_witness(&builder, native_opening_claims[2].opening_pair.evaluation);

// Opening claim for the linear combination
stdlib_opening_claims.emplace_back(OpeningClaim({ r, eval }, commit));

auto verifier_transcript = std::make_shared<Transcript>();
Expand Down Expand Up @@ -178,16 +181,18 @@ TYPED_TEST(ShplonkRecursionTest, LineralyDependent)
auto [stdlib_commitments, stdlib_opening_pairs] = this->native_to_stdlib_pairs_and_commitments(
&builder, native_opening_claims, native_opening_claims.size() - 1);

// Shplonk verifier functionality - cheap way
std::vector<OpeningVector> opening_vectors = {
{ stdlib_opening_pairs[0].challenge, { Fr(1) }, { stdlib_opening_pairs[0].evaluation } },
{ stdlib_opening_pairs[1].challenge, { Fr(1) }, { stdlib_opening_pairs[1].evaluation } },
{ Fr::from_witness(&builder, native_opening_claims[2].opening_pair.challenge),
{ coeff1, coeff2 },
{ Fr::from_witness(&builder, evals[0]), Fr::from_witness(&builder, evals[1]) } }
// Opening pair for the linear combination as it would be received by the Verifier from the Prover
Fr r = Fr::from_witness(&builder, native_opening_claims[2].opening_pair.challenge);
Fr eval = Fr::from_witness(&builder, native_opening_claims[2].opening_pair.evaluation);

// Update data
std::vector<typename ShplonkVerifier::LinearCombinationOfClaims> update_data = {
{ { 0 }, { Fr(1) }, stdlib_opening_pairs[0] },
{ { 1 }, { Fr(1) }, stdlib_opening_pairs[1] },
{ { 0, 1 }, { coeff1, coeff2 }, { r, eval } }
};
std::vector<std::vector<size_t>> indices = { { 0 }, { 1 }, { 0, 1 } };

// Shplonk verifier functionality - cheap way
auto verifier_transcript = std::make_shared<Transcript>();
verifier_transcript->load_proof(stdlib_proof);
[[maybe_unused]] auto _ = verifier_transcript->template receive_from_prover<Fr>("Init");
Expand All @@ -196,7 +201,7 @@ TYPED_TEST(ShplonkRecursionTest, LineralyDependent)

// Execute the shplonk verifier functionality
[[maybe_unused]] auto batched_verifier_claim =
verifier.reduce_vector_claims_verification(this->vk().get_g1_identity(), indices, opening_vectors);
verifier.reduce_verification_vector_claims(this->vk().get_g1_identity(), update_data);

EXPECT_TRUE(CircuitChecker::check(builder));

Expand Down
Loading