Skip to content

Commit

Permalink
refactor: Protogalaxy verifier matches prover 2 (#8477)
Browse files Browse the repository at this point in the history
This PR reorganizes the native folding verifier to better match the
folding prover. This amounts to encapsulating some logic in functions
and a mild reshuffling. It's tempting to also implement the verifier as
a series of pure-ish round functions, but I don't do that for lack of
time.
  • Loading branch information
codygunton authored Sep 13, 2024
1 parent 68a2226 commit 58882b1
Show file tree
Hide file tree
Showing 10 changed files with 205 additions and 141 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -593,7 +593,6 @@ template <typename Curve_> class IPA {
static OpeningClaim<Curve> reduce_batch_opening_claim(
const BatchOpeningClaim<Curve>& batch_opening_claim)
{
using Utils = CommitmentSchemesUtils<Curve>;
// Extract batch_mul arguments from the accumulator
const auto& commitments = batch_opening_claim.commitments;
const auto& scalars = batch_opening_claim.scalars;
Expand All @@ -604,7 +603,7 @@ template <typename Curve_> class IPA {
shplonk_output_commitment =
GroupElement::batch_mul(commitments, scalars, /*max_num_bits=*/0, /*with_edgecases=*/true);
} else {
shplonk_output_commitment = Utils::batch_mul_native(commitments, scalars);
shplonk_output_commitment = batch_mul_native(commitments, scalars);
}
// Output an opening claim to be verified by the IPA opening protocol
return { { shplonk_eval_challenge, Fr(0) }, shplonk_output_commitment };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,6 @@ template <typename Curve_> class KZG {
static VerifierAccumulator reduce_verify_batch_opening_claim(BatchOpeningClaim<Curve> batch_opening_claim,
const std::shared_ptr<Transcript>& transcript)
{
using Utils = CommitmentSchemesUtils<Curve>;
auto quotient_commitment = transcript->template receive_from_prover<Commitment>("KZG:W");

// The pairing check can be expressed as
Expand All @@ -125,7 +124,7 @@ template <typename Curve_> class KZG {
/*max_num_bits=*/0,
/*with_edgecases=*/true);
} else {
P_0 = Utils::batch_mul_native(batch_opening_claim.commitments, batch_opening_claim.scalars);
P_0 = batch_mul_native(batch_opening_claim.commitments, batch_opening_claim.scalars);
}
auto P_1 = -quotient_commitment;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
#include "barretenberg/commitment_schemes/commitment_key.hpp"
#include "barretenberg/commitment_schemes/gemini/gemini.hpp"
#include "barretenberg/commitment_schemes/shplonk/shplonk.hpp"
#include "barretenberg/commitment_schemes/utils/batch_mul_native.hpp"
#include "barretenberg/commitment_schemes/verification_key.hpp"
#include "barretenberg/transcript/transcript.hpp"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ TYPED_TEST(ShpleminiTest, CorrectnessOfMultivariateClaimBatching)
using GroupElement = typename TypeParam::Element;
using Commitment = typename TypeParam::AffineElement;
using Polynomial = typename bb::Polynomial<Fr>;
using Utils = CommitmentSchemesUtils<TypeParam>;

const size_t n = 16;
const size_t log_n = 4;
Expand Down Expand Up @@ -111,7 +110,7 @@ TYPED_TEST(ShpleminiTest, CorrectnessOfMultivariateClaimBatching)
verifier_batched_evaluation);

// Final pairing check
GroupElement shplemini_result = Utils::batch_mul_native(commitments, scalars);
GroupElement shplemini_result = batch_mul_native(commitments, scalars);

EXPECT_EQ(commitments.size(), unshifted_commitments.size() + shifted_commitments.size());
EXPECT_EQ(batched_evaluation, verifier_batched_evaluation);
Expand All @@ -127,7 +126,6 @@ TYPED_TEST(ShpleminiTest, CorrectnessOfGeminiClaimBatching)
using GroupElement = typename TypeParam::Element;
using Commitment = typename TypeParam::AffineElement;
using Polynomial = typename bb::Polynomial<Fr>;
using Utils = CommitmentSchemesUtils<TypeParam>;

const size_t n = 16;
const size_t log_n = 4;
Expand Down Expand Up @@ -221,7 +219,7 @@ TYPED_TEST(ShpleminiTest, CorrectnessOfGeminiClaimBatching)

EXPECT_EQ(commitments.size(), prover_commitments.size());
// Compute the group element using the output of Shplemini method
GroupElement shplemini_result = Utils::batch_mul_native(commitments, scalars);
GroupElement shplemini_result = batch_mul_native(commitments, scalars);

EXPECT_EQ(shplemini_result, expected_result);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,40 +4,48 @@
#include <vector>

namespace bb {
template <typename Curve> class CommitmentSchemesUtils {
/**
* @brief Utility for native batch multiplication of group elements
* @note This is used only for native verification and is not optimized for efficiency
*/
template <typename Commitment, typename FF>
static Commitment batch_mul_native(const std::vector<Commitment>& _points, const std::vector<FF>& _scalars)
{
std::vector<Commitment> points;
std::vector<FF> scalars;
for (size_t i = 0; i < _points.size(); ++i) {
const auto& point = _points[i];
const auto& scalar = _scalars[i];

public:
using Commitment = typename Curve::AffineElement;
using FF = typename Curve::ScalarField;

/**
* @brief Utility for native batch multiplication of group elements
* @note This is used only for native verification and is not optimized for efficiency
*/
static Commitment batch_mul_native(const std::vector<Commitment>& _points, const std::vector<FF>& _scalars)
{
std::vector<Commitment> points;
std::vector<FF> scalars;
for (size_t i = 0; i < _points.size(); ++i) {
const auto& point = _points[i];
const auto& scalar = _scalars[i];

// TODO: Special handling of point at infinity here due to incorrect serialization.
if (!scalar.is_zero() && !point.is_point_at_infinity() && !point.y.is_zero()) {
points.emplace_back(point);
scalars.emplace_back(scalar);
}
// TODO: Special handling of point at infinity here due to incorrect serialization.
if (!scalar.is_zero() && !point.is_point_at_infinity() && !point.y.is_zero()) {
points.emplace_back(point);
scalars.emplace_back(scalar);
}
}

if (points.empty()) {
return Commitment::infinity();
}
if (points.empty()) {
return Commitment::infinity();
}

auto result = points[0] * scalars[0];
for (size_t idx = 1; idx < scalars.size(); ++idx) {
result = result + points[idx] * scalars[idx];
}
return result;
auto result = points[0] * scalars[0];
for (size_t idx = 1; idx < scalars.size(); ++idx) {
result = result + points[idx] * scalars[idx];
}
return result;
}

/**
* @brief Utility for native batch multiplication of group elements
* @note This is used only for native verification and is not optimized for efficiency
*/
template <typename FF> static FF linear_combination(const std::vector<FF>& as, const std::vector<FF>& bs)
{
FF result = as[0] * bs[0];
for (size_t idx = 1; idx < as.size(); ++idx) {
result += as[idx] * bs[idx];
}
};
} // namespace bb
return result;
}

} // namespace bb
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,6 @@ template <typename Curve> class ZeroMorphProver_ {
template <typename Curve> class ZeroMorphVerifier_ {
using FF = typename Curve::ScalarField;
using Commitment = typename Curve::AffineElement;
using Utils = CommitmentSchemesUtils<Curve>;

public:
/**
Expand Down Expand Up @@ -549,7 +548,7 @@ template <typename Curve> class ZeroMorphVerifier_ {
return Commitment::batch_mul(commitments, scalars);
}
} else {
return Utils::batch_mul_native(commitments, scalars);
return batch_mul_native(commitments, scalars);
}
}

Expand Down Expand Up @@ -705,7 +704,7 @@ template <typename Curve> class ZeroMorphVerifier_ {
return Commitment::batch_mul(commitments, scalars);
}
} else {
return Utils::batch_mul_native(commitments, scalars);
return batch_mul_native(commitments, scalars);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,11 +125,9 @@ FoldingResult<typename DeciderProvingKeys::Flavor> ProtogalaxyProver_<DeciderPro
const FF combiner_challenge = transcript->template get_challenge<FF>("combiner_quotient_challenge");

FoldingResult<Flavor> result{ .accumulator = keys[0], .proof = std::move(transcript->proof_data) };

// TODO(https://github.com/AztecProtocol/barretenberg/issues/881): bad pattern
result.accumulator->is_accumulator = true;

// Compute the next target sum
// Compute the next target sum (for its own use; verifier must compute its own values)
auto [vanishing_polynomial_at_challenge, lagranges] =
Fun::compute_vanishing_polynomial_and_lagranges(combiner_challenge);
result.accumulator->target_sum = perturbator_evaluation * lagranges[0] +
Expand Down
146 changes: 65 additions & 81 deletions barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "protogalaxy_verifier.hpp"
#include "barretenberg/commitment_schemes/utils/batch_mul_native.hpp"
#include "barretenberg/plonk_honk_shared/library/grand_product_delta.hpp"
#include "barretenberg/protogalaxy/prover_verifier_shared.hpp"
#include "barretenberg/ultra_honk/oink_verifier.hpp"
Expand Down Expand Up @@ -35,123 +36,106 @@ void ProtogalaxyVerifier_<DeciderVerificationKeys>::run_oink_verifier_on_each_in
}
}

template <typename FF, size_t NUM>
std::tuple<FF, std::vector<FF>> compute_vanishing_polynomial_and_lagrange_evaluations(const FF& combiner_challenge)
{
static_assert(NUM < 5);
static constexpr FF inverse_two = FF(2).invert();

std::vector<FF> lagranges(NUM);
FF vanishing_polynomial_at_challenge;
if constexpr (NUM == 2) {
vanishing_polynomial_at_challenge = combiner_challenge * (combiner_challenge - FF(1));
lagranges = { FF(1) - combiner_challenge, combiner_challenge };
} else if constexpr (NUM == 3) {
vanishing_polynomial_at_challenge =
combiner_challenge * (combiner_challenge - FF(1)) * (combiner_challenge - FF(2));
lagranges = { (FF(1) - combiner_challenge) * (FF(2) - combiner_challenge) * inverse_two,
combiner_challenge * (FF(2) - combiner_challenge),
combiner_challenge * (combiner_challenge - FF(1)) * inverse_two };
} else if constexpr (NUM == 4) {
static constexpr FF inverse_six = FF(6).invert();
vanishing_polynomial_at_challenge = combiner_challenge * (combiner_challenge - FF(1)) *
(combiner_challenge - FF(2)) * (combiner_challenge - FF(3));
lagranges = { (FF(1) - combiner_challenge) * (FF(2) - combiner_challenge) * (FF(3) - combiner_challenge) *
inverse_six,
combiner_challenge * (FF(2) - combiner_challenge) * (FF(3) - combiner_challenge) * inverse_two,
combiner_challenge * (combiner_challenge - FF(1)) * (FF(3) - combiner_challenge) * inverse_two,
combiner_challenge * (combiner_challenge - FF(1)) * (combiner_challenge - FF(2)) * inverse_six };
}
return std::make_tuple(vanishing_polynomial_at_challenge, lagranges);
}

template <class DeciderVerificationKeys>
std::shared_ptr<typename DeciderVerificationKeys::DeciderVK> ProtogalaxyVerifier_<
DeciderVerificationKeys>::verify_folding_proof(const std::vector<FF>& proof)
{
static constexpr size_t BATCHED_EXTENDED_LENGTH = DeciderVerificationKeys::BATCHED_EXTENDED_LENGTH;
static constexpr size_t NUM_KEYS = DeciderVerificationKeys::NUM;

const std::shared_ptr<const DeciderVK>& accumulator = keys_to_fold[0];
const size_t log_circuit_size = static_cast<size_t>(accumulator->verification_key->log_circuit_size);

run_oink_verifier_on_each_incomplete_key(proof);

// Perturbator round
const FF delta = transcript->template get_challenge<FF>("delta");
const std::shared_ptr<const DeciderVK>& accumulator = keys_to_fold[0]; // WORKTODO: move

const size_t log_circuit_size = static_cast<size_t>(accumulator->verification_key->log_circuit_size);
const std::vector<FF> deltas = compute_round_challenge_pows(log_circuit_size, delta);

std::vector<FF> perturbator_coeffs(log_circuit_size + 1, 0);
if (accumulator->is_accumulator) {
for (size_t idx = 1; idx <= log_circuit_size; idx++) {
perturbator_coeffs[idx] =
transcript->template receive_from_prover<FF>("perturbator_" + std::to_string(idx));
}
}
const FF perturbator_challenge = transcript->template get_challenge<FF>("perturbator_challenge");

// Combiner quotient round
perturbator_coeffs[0] = accumulator->target_sum;
const Polynomial<FF> perturbator(perturbator_coeffs);
const FF perturbator_challenge = transcript->template get_challenge<FF>("perturbator_challenge");
const FF perturbator_evaluation = perturbator.evaluate(perturbator_challenge);

// The degree of K(X) is dk - k - 1 = k(d - 1) - 1. Hence we need k(d - 1) evaluations to represent it.
std::array<FF, DeciderVerificationKeys::BATCHED_EXTENDED_LENGTH - DeciderVerificationKeys::NUM>
combiner_quotient_evals;
for (size_t idx = 0; idx < DeciderVerificationKeys::BATCHED_EXTENDED_LENGTH - DeciderVerificationKeys::NUM; idx++) {
combiner_quotient_evals[idx] = transcript->template receive_from_prover<FF>(
"combiner_quotient_" + std::to_string(idx + DeciderVerificationKeys::NUM));
std::array<FF, BATCHED_EXTENDED_LENGTH - NUM_KEYS>
combiner_quotient_evals; // The degree of the combiner quotient (K in the paper) is dk - k - 1 = k(d - 1) - 1.
// Hence we need k(d - 1) evaluations to represent it.
for (size_t idx = DeciderVerificationKeys::NUM; auto& val : combiner_quotient_evals) {
val = transcript->template receive_from_prover<FF>("combiner_quotient_" + std::to_string(idx++));
}
const Univariate<FF, DeciderVerificationKeys::BATCHED_EXTENDED_LENGTH, DeciderVerificationKeys::NUM>
combiner_quotient(combiner_quotient_evals);

// Folding
const FF combiner_challenge = transcript->template get_challenge<FF>("combiner_quotient_challenge");
const Univariate<FF, BATCHED_EXTENDED_LENGTH, NUM_KEYS> combiner_quotient(combiner_quotient_evals);
const FF combiner_quotient_evaluation = combiner_quotient.evaluate(combiner_challenge);

constexpr FF inverse_two = FF(2).invert();
FF vanishing_polynomial_at_challenge;
std::array<FF, DeciderVerificationKeys::NUM> lagranges;
if constexpr (DeciderVerificationKeys::NUM == 2) {
vanishing_polynomial_at_challenge = combiner_challenge * (combiner_challenge - FF(1));
lagranges = { FF(1) - combiner_challenge, combiner_challenge };
} else if constexpr (DeciderVerificationKeys::NUM == 3) {
vanishing_polynomial_at_challenge =
combiner_challenge * (combiner_challenge - FF(1)) * (combiner_challenge - FF(2));
lagranges = { (FF(1) - combiner_challenge) * (FF(2) - combiner_challenge) * inverse_two,
combiner_challenge * (FF(2) - combiner_challenge),
combiner_challenge * (combiner_challenge - FF(1)) * inverse_two };
} else if constexpr (DeciderVerificationKeys::NUM == 4) {
constexpr FF inverse_six = FF(6).invert();
vanishing_polynomial_at_challenge = combiner_challenge * (combiner_challenge - FF(1)) *
(combiner_challenge - FF(2)) * (combiner_challenge - FF(3));
lagranges = { (FF(1) - combiner_challenge) * (FF(2) - combiner_challenge) * (FF(3) - combiner_challenge) *
inverse_six,
combiner_challenge * (FF(2) - combiner_challenge) * (FF(3) - combiner_challenge) * inverse_two,
combiner_challenge * (combiner_challenge - FF(1)) * (FF(3) - combiner_challenge) * inverse_two,
combiner_challenge * (combiner_challenge - FF(1)) * (combiner_challenge - FF(2)) * inverse_six };
}
static_assert(DeciderVerificationKeys::NUM < 5);

// TODO(https://github.com/AztecProtocol/barretenberg/issues/881): bad pattern
auto next_accumulator = std::make_shared<DeciderVK>();
next_accumulator->verification_key = std::make_shared<VerificationKey>(*accumulator->verification_key);
next_accumulator->is_accumulator = true;

size_t commitment_idx = 0;
for (auto& expected_vk : next_accumulator->verification_key->get_all()) {
size_t vk_idx = 0;
expected_vk = Commitment::infinity();
for (auto& key : keys_to_fold) {
expected_vk = expected_vk + key->verification_key->get_all()[commitment_idx] * lagranges[vk_idx];
vk_idx++;
}
commitment_idx++;
}

// Compute next folding parameters
const auto [vanishing_polynomial_at_challenge, lagranges] =
compute_vanishing_polynomial_and_lagrange_evaluations<FF, NUM_KEYS>(combiner_challenge);
next_accumulator->target_sum =
perturbator_evaluation * lagranges[0] + vanishing_polynomial_at_challenge * combiner_quotient_evaluation;
next_accumulator->gate_challenges =
next_accumulator->gate_challenges = // note: known already in previous round
update_gate_challenges(perturbator_challenge, accumulator->gate_challenges, deltas);

// Compute ϕ
auto& acc_witness_commitments = next_accumulator->witness_commitments;
commitment_idx = 0;
for (auto& comm : acc_witness_commitments.get_all()) {
comm = Commitment::infinity();
size_t vk_idx = 0;
for (auto& key : keys_to_fold) {
comm = comm + key->witness_commitments.get_all()[commitment_idx] * lagranges[vk_idx];
vk_idx++;
}
commitment_idx++;
// // Fold the commitments
for (auto [combination, to_combine] :
zip_view(next_accumulator->verification_key->get_all(), keys_to_fold.get_precomputed_commitments())) {
combination = batch_mul_native(to_combine, lagranges);
}
for (auto [combination, to_combine] :
zip_view(next_accumulator->witness_commitments.get_all(), keys_to_fold.get_witness_commitments())) {
combination = batch_mul_native(to_combine, lagranges);
}

size_t alpha_idx = 0;
for (auto& alpha : next_accumulator->alphas) {
alpha = FF(0);
size_t vk_idx = 0;
for (auto& key : keys_to_fold) {
alpha += key->alphas[alpha_idx] * lagranges[vk_idx];
vk_idx++;
}
alpha_idx++;
// Fold the relation parameters
for (auto [combination, to_combine] : zip_view(next_accumulator->alphas, keys_to_fold.get_alphas())) {
combination = linear_combination(to_combine, lagranges);
}
auto& expected_parameters = next_accumulator->relation_parameters;
for (size_t vk_idx = 0; vk_idx < DeciderVerificationKeys::NUM; vk_idx++) {
auto& key = keys_to_fold[vk_idx];
expected_parameters.eta += key->relation_parameters.eta * lagranges[vk_idx];
expected_parameters.eta_two += key->relation_parameters.eta_two * lagranges[vk_idx];
expected_parameters.eta_three += key->relation_parameters.eta_three * lagranges[vk_idx];
expected_parameters.beta += key->relation_parameters.beta * lagranges[vk_idx];
expected_parameters.gamma += key->relation_parameters.gamma * lagranges[vk_idx];
expected_parameters.public_input_delta += key->relation_parameters.public_input_delta * lagranges[vk_idx];
expected_parameters.lookup_grand_product_delta +=
key->relation_parameters.lookup_grand_product_delta * lagranges[vk_idx];
for (auto [combination, to_combine] :
zip_view(next_accumulator->relation_parameters.get_to_fold(), keys_to_fold.get_relation_parameters())) {
combination = linear_combination(to_combine, lagranges);
}

return next_accumulator;
Expand Down
Loading

0 comments on commit 58882b1

Please sign in to comment.