Skip to content

Commit

Permalink
feat: Clarify state in Protogalaxy 3 (#8181)
Browse files Browse the repository at this point in the history
Main goal: more explicit state by making round functions pure functions
(with const inputs).
- Exception: first round mutates instances. May handle in follow-on that
changes handling of accumulator.
- Also: get rid of several pieces of prover state (`gate_challenges`,
`relation_parameters`, `optimised_relation_parameters`, `accumulators`,
`result`)
- FYI: will likely get rid of temporary refactoring helper classes
`State` and `ProtogalaxyProverInternal` also.

Also:
- Rename `accumulator_update_round`, `preparation_round`,
`compressed_perturbator`, `OptimisedFoo`, `CombinedFoo`.
 - Combiner test does not use prover class.
 - Use `const` in a bunch of places
- Reduce amount of templating by explicitly naming instantiations of
compute_combiner
  • Loading branch information
codygunton committed Aug 30, 2024
1 parent 2203bc0 commit eb0c7be
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 150 deletions.
8 changes: 4 additions & 4 deletions barretenberg/cpp/scripts/analyze_client_ivc_bench.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,10 @@

print('\nBreakdown of ProtogalaxyProver::prove:')
protogalaxy_round_labels = [
"ProtogalaxyProver_::preparation_round(t)",
"ProtogalaxyProver_::perturbator_round(t)",
"ProtogalaxyProver_::combiner_quotient_round(t)",
"ProtogalaxyProver_::update_target_sum_and_fold(t)"
"ProtoGalaxyProver_::preparation_round(t)",
"ProtoGalaxyProver_::perturbator_round(t)",
"ProtoGalaxyProver_::combiner_quotient_round(t)",
"ProtoGalaxyProver_::update_target_sum_and_fold(t)"
]
max_label_length = max(len(label) for label in protogalaxy_round_labels)
for key in protogalaxy_round_labels:
Expand Down
8 changes: 4 additions & 4 deletions barretenberg/cpp/scripts/analyze_protogalaxy_bench.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,10 @@

print('\nBreakdown of ProtogalaxyProver::prove:')
protogalaxy_round_labels = [
"ProtogalaxyProver_::preparation_round(t)",
"ProtogalaxyProver_::perturbator_round(t)",
"ProtogalaxyProver_::combiner_quotient_round(t)",
"ProtogalaxyProver_::update_target_sum_and_fold(t)"
"ProtoGalaxyProver_::preparation_round(t)",
"ProtoGalaxyProver_::perturbator_round(t)",
"ProtoGalaxyProver_::combiner_quotient_round(t)",
"ProtoGalaxyProver_::update_target_sum_and_fold(t)"
]
max_label_length = max(len(label) for label in protogalaxy_round_labels)
for key in protogalaxy_round_labels:
Expand Down
50 changes: 25 additions & 25 deletions barretenberg/cpp/src/barretenberg/protogalaxy/combiner.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,10 @@ TEST(Protogalaxy, CombinerOn2Instances)
ProverInstances instances{ instance_data };
Fun::UnivariateRelationSeparator alphas;
alphas.fill(bb::Univariate<FF, 12>(FF(0))); // focus on the arithmetic relation only
GateSeparatorPolynomial<FF> gate_separators({ 2 }, /*log_num_monomials=*/1);
Fun::UnivariateRelationParametersNoOptimisticSkipping univariate_relation_parameters_no_skpping;
auto result_no_skipping = Fun::compute_combiner_no_optimistic_skipping(
instances, gate_separators, univariate_relation_parameters_no_skpping, alphas);
PowPolynomial<FF> pow_polynomial({ 2 }, /*log_num_monomials=*/1);
Fun::UnivariateRelationParametersNoOptimisticSkipping univariate_relation_parameters;
auto result = Fun::compute_combiner_no_optimistic_skipping(
instances, pow_polynomial, univariate_relation_parameters, alphas);
// The expected_result values are computed by running the python script combiner_example_gen.py
auto expected_result = Univariate<FF, 12>(std::array<FF, 12>{ 9704UL,
13245288UL,
Expand Down Expand Up @@ -133,13 +133,13 @@ TEST(Protogalaxy, CombinerOn2Instances)
relation value:
0 0 0 0 0 0 0 0 0 6 18 36 60 90 */

GateSeparatorPolynomial<FF> gate_separators({ 2 }, /*log_num_monomials=*/1);
Fun::UnivariateRelationParametersNoOptimisticSkipping univariate_relation_parameters_no_skpping;
Fun::UnivariateRelationParameters univariate_relation_parameters;
auto result_no_skipping = Fun::compute_combiner_no_optimistic_skipping(
instances, gate_separators, univariate_relation_parameters_no_skpping, alphas);
auto result_with_skipping =
Fun::compute_combiner(instances, gate_separators, univariate_relation_parameters, alphas);
PowPolynomial<FF> pow_polynomial({ 2 }, /*log_num_monomials=*/1);
Fun::UnivariateRelationParametersNoOptimisticSkipping univariate_relation_parameters;
Fun::UnivariateRelationParameters optimised_univariate_relation_parameters;
auto result = Fun::compute_combiner_no_optimistic_skipping(
instances, pow_polynomial, univariate_relation_parameters, alphas);
auto optimised_result =
Fun::compute_combiner(instances, pow_polynomial, optimised_univariate_relation_parameters, alphas);
auto expected_result =
Univariate<FF, 12>(std::array<FF, 12>{ 0, 0, 12, 36, 72, 120, 180, 252, 336, 432, 540, 660 });

Expand Down Expand Up @@ -193,7 +193,7 @@ TEST(Protogalaxy, CombinerOptimizationConsistency)
ProverInstances instances{ instance_data };
Fun::UnivariateRelationSeparator alphas;
alphas.fill(bb::Univariate<FF, UNIVARIATE_LENGTH>(FF(0))); // focus on the arithmetic relation only
GateSeparatorPolynomial<FF> gate_separators({ 2 }, /*log_num_monomials=*/1);
PowPolynomial<FF> pow_polynomial({ 2 }, /*log_num_monomials=*/1);

// Relation parameters are all zeroes
RelationParameters<FF> relation_parameters;
Expand Down Expand Up @@ -254,12 +254,12 @@ TEST(Protogalaxy, CombinerOptimizationConsistency)
precomputed_result[idx] = std::get<0>(accumulator)[0];
}
auto expected_result = Univariate<FF, UNIVARIATE_LENGTH>(precomputed_result);
Fun::UnivariateRelationParametersNoOptimisticSkipping univariate_relation_parameters_no_skpping;
Fun::UnivariateRelationParameters univariate_relation_parameters;
auto result_no_skipping = Fun::compute_combiner_no_optimistic_skipping(
instances, gate_separators, univariate_relation_parameters_no_skpping, alphas);
auto result_with_skipping =
Fun::compute_combiner(instances, gate_separators, univariate_relation_parameters, alphas);
Fun::UnivariateRelationParametersNoOptimisticSkipping univariate_relation_parameters;
Fun::UnivariateRelationParameters optimised_univariate_relation_parameters;
auto result = Fun::compute_combiner_no_optimistic_skipping(
instances, pow_polynomial, univariate_relation_parameters, alphas);
auto optimised_result =
Fun::compute_combiner(instances, pow_polynomial, optimised_univariate_relation_parameters, alphas);

EXPECT_EQ(result_no_skipping, expected_result);
EXPECT_EQ(result_with_skipping, expected_result);
Expand Down Expand Up @@ -325,13 +325,13 @@ TEST(Protogalaxy, CombinerOptimizationConsistency)
relation value:
0 0 0 0 0 0 0 0 0 6 18 36 60 90 */

GateSeparatorPolynomial<FF> gate_separators({ 2 }, /*log_num_monomials=*/1);
Fun::UnivariateRelationParametersNoOptimisticSkipping univariate_relation_parameters_no_skpping;
Fun::UnivariateRelationParameters univariate_relation_parameters;
auto result_no_skipping = Fun::compute_combiner_no_optimistic_skipping(
instances, gate_separators, univariate_relation_parameters_no_skpping, alphas);
auto result_with_skipping =
Fun::compute_combiner(instances, gate_separators, univariate_relation_parameters, alphas);
PowPolynomial<FF> pow_polynomial({ 2 }, /*log_num_monomials=*/1);
Fun::UnivariateRelationParametersNoOptimisticSkipping univariate_relation_parameters;
Fun::UnivariateRelationParameters optimised_univariate_relation_parameters;
auto result = Fun::compute_combiner_no_optimistic_skipping(
instances, pow_polynomial, univariate_relation_parameters, alphas);
auto optimised_result =
Fun::compute_combiner(instances, pow_polynomial, optimised_univariate_relation_parameters, alphas);
auto expected_result =
Univariate<FF, 12>(std::array<FF, 12>{ 0, 0, 12, 36, 72, 120, 180, 252, 336, 432, 540, 660 });

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ template <class ProverInstances_> class ProtogalaxyProver_ {
using FF = typename ProverInstances_::Flavor::FF;
static constexpr size_t NUM_INSTANCES = ProverInstances_::NUM;
using CombinerQuotient = Univariate<FF, ProverInstances_::BATCHED_EXTENDED_LENGTH, NUM_INSTANCES>;
using TupleOfTuplesOfUnivariatesNoOptimisticSkipping =
typename Flavor::template ProtogalaxyTupleOfTuplesOfUnivariatesNoOptimisticSkipping<NUM_INSTANCES>;
using TupleOfTuplesOfUnivariates = typename Flavor::template ProtogalaxyTupleOfTuplesOfUnivariates<NUM_INSTANCES>;
using OptimisedTupleOfTuplesOfUnivariates =
typename Flavor::template OptimisedProtogalaxyTupleOfTuplesOfUnivariates<NUM_INSTANCES>;
using UnivariateRelationParameters =
bb::RelationParameters<Univariate<FF, ProverInstances_::EXTENDED_LENGTH, 0, /*skip_count=*/NUM_INSTANCES - 1>>;
using UnivariateRelationSeparator =
Expand All @@ -40,16 +40,12 @@ template <class ProverInstances_> class ProtogalaxyProver_ {
std::shared_ptr<CommitmentKey> commitment_key;
State state;

ProtogalaxyProver_() = default;
ProtogalaxyProver_(const std::vector<std::shared_ptr<Instance>>& insts)
ProtoGalaxyProver_() = default;
ProtoGalaxyProver_(const std::vector<std::shared_ptr<Instance>>& insts)
: instances(ProverInstances_(insts))
// TODO(https://github.com/AztecProtocol/barretenberg/issues/878)
, commitment_key(instances[1]->proving_key.commitment_key){};

// Returns the accumulator, which is the first element in ProverInstances. The accumulator is assumed to have the
// FoldingParameters set and be the result of a previous round of folding.
std::shared_ptr<Instance> get_accumulator() { return instances[0]; }

/**
* @brief For each instance produced by a circuit, prior to folding, we need to complete the computation of its
* prover polynomials, commit to witnesses and generate the relation parameters as well as send the public data ϕ of
Expand Down Expand Up @@ -106,5 +102,49 @@ template <class ProverInstances_> class ProtogalaxyProver_ {
* accumulator was computed correctly.
*/
BB_PROFILE FoldingResult<Flavor> prove();

// Returns the accumulator, which is the first element in ProverInstances. The accumulator is assumed to have the
// FoldingParameters set and be the result of a previous round of folding.
std::shared_ptr<Instance> get_accumulator() { return instances[0]; }

/**
* @brief Create inputs to folding protocol (an Oink interaction).
* @details Finalise the prover instances that will be folded: complete computation of all the witness polynomials
* and compute commitments. Send commitments to the verifier and retrieve challenges.
*/
void run_oink_prover_on_each_instance();

/**
* @brief Steps 2 - 5 of the paper.
* @details Compute perturbator (F polynomial in paper). Send all but the constant coefficient to verifier.
*
* @param accumulator
* @return std::tuple<std::vector<FF>, Polynomial<FF>> deltas, perturbator
*/
std::tuple<std::vector<FF>, Polynomial<FF>> perturbator_round(const std::shared_ptr<const Instance>& accumulator);

/**
* @brief Steps 6 - 11 of the paper.
* @details Compute combiner (G polynomial in the paper) and then its quotient (K polynomial), whose coefficient
* will be sent to the verifier.
*/
/*gate_challenges, alphas, optimised_relation_parameters, perturbator_evaluation, combiner_quotient */
std::tuple<std::vector<FF>, UnivariateRelationSeparator, UnivariateRelationParameters, FF, CombinerQuotient>
combiner_quotient_round(const std::vector<FF>& gate_challenges,
const std::vector<FF>& deltas,
const ProverInstances_& instances);

/**
* @brief Steps 12 - 13 of the paper plus the prover folding work.
* @details Compute \f$ e^* \f$ plus, then update the prover accumulator by taking a Lagrange-linear combination of
* the current accumulator and the instances to be folded. In our mental model, we are doing a scalar multipliation
* of matrices whose columns are polynomials, as well as taking similar linear combinations of the relation
* parameters.
*/
FoldingResult<Flavor> update_target_sum_and_fold(const ProverInstances_& instances,
const CombinerQuotient& combiner_quotient,
const UnivariateRelationSeparator& alphas,
const UnivariateRelationParameters& univariate_relation_parameters,
const FF& perturbator_evaluation);
};
} // namespace bb
Original file line number Diff line number Diff line change
Expand Up @@ -16,110 +16,15 @@ void ProtogalaxyProver_<ProverInstances>::run_oink_prover_on_instance(std::share
oink_prover.prove();
}

template <class ProverInstances> void ProtogalaxyProver_<ProverInstances>::run_oink_prover_on_each_instance()
{
BB_OP_COUNT_TIME_NAME("ProtogalaxyProver_::run_oink_prover_on_each_instance");
auto idx = 0;
auto& instance = instances[0];
auto domain_separator = std::to_string(idx);

if (!instance->is_accumulator) {
run_oink_prover_on_instance(instance, domain_separator);
instance->target_sum = 0;
instance->gate_challenges = std::vector<FF>(instance->proving_key.log_circuit_size, 0);
}

idx++;

for (auto it = instances.begin() + 1; it != instances.end(); it++, idx++) {
auto instance = *it;
auto domain_separator = std::to_string(idx);
run_oink_prover_on_instance(instance, domain_separator);
}

state.accumulator = instances[0];
};

template <class ProverInstances>
std::tuple<std::vector<typename ProverInstances::Flavor::FF>, Polynomial<typename ProverInstances::Flavor::FF>>
ProtogalaxyProver_<ProverInstances>::perturbator_round(
const std::shared_ptr<const typename ProverInstances::Instance>& accumulator)
{
BB_OP_COUNT_TIME_NAME("ProtogalaxyProver_::perturbator_round");

using Fun = ProtogalaxyProverInternal<ProverInstances>;

const FF delta = transcript->template get_challenge<FF>("delta");
const std::vector<FF> deltas = compute_round_challenge_pows(accumulator->proving_key.log_circuit_size, delta);
// An honest prover with valid initial instances computes that the perturbator is 0 in the first round
const Polynomial<FF> perturbator = accumulator->is_accumulator
? Fun::compute_perturbator(accumulator, deltas)
: Polynomial<FF>(accumulator->proving_key.log_circuit_size + 1);
// Prover doesn't send the constant coefficient of F because this is supposed to be equal to the target sum of
// the accumulator which the folding verifier has from the previous iteration.
// TODO(https://github.com/AztecProtocol/barretenberg/issues/1087): Verifier circuit for first IVC step is
// different
if (accumulator->is_accumulator) {
for (size_t idx = 1; idx <= accumulator->proving_key.log_circuit_size; idx++) {
transcript->send_to_verifier("perturbator_" + std::to_string(idx), perturbator[idx]);
}
}

return std::make_tuple(deltas, perturbator);
};

template <class ProverInstances>
std::tuple<std::vector<typename ProverInstances::Flavor::FF>,
typename ProtogalaxyProver_<ProverInstances>::UnivariateRelationSeparator,
typename ProtogalaxyProver_<ProverInstances>::UnivariateRelationParameters,
typename ProverInstances::Flavor::FF,
typename ProtogalaxyProver_<ProverInstances>::CombinerQuotient>
ProtogalaxyProver_<ProverInstances>::combiner_quotient_round(const std::vector<FF>& gate_challenges,
const std::vector<FF>& deltas,
const ProverInstances& instances)
{
BB_OP_COUNT_TIME_NAME("ProtogalaxyProver_::combiner_quotient_round");

using Fun = ProtogalaxyProverInternal<ProverInstances>;

const FF perturbator_challenge = transcript->template get_challenge<FF>("perturbator_challenge");

const std::vector<FF> updated_gate_challenges =
update_gate_challenges(perturbator_challenge, gate_challenges, deltas);
const UnivariateRelationSeparator alphas = Fun::compute_and_extend_alphas(instances);
const GateSeparatorPolynomial<FF> gate_separators{ updated_gate_challenges,
instances[0]->proving_key.log_circuit_size };
const UnivariateRelationParameters relation_parameters =
Fun::template compute_extended_relation_parameters<UnivariateRelationParameters>(instances);

TupleOfTuplesOfUnivariates accumulators;
auto combiner = Fun::compute_combiner(instances, gate_separators, relation_parameters, alphas, accumulators);

const FF perturbator_evaluation = state.perturbator.evaluate(perturbator_challenge);
const CombinerQuotient combiner_quotient = Fun::compute_combiner_quotient(perturbator_evaluation, combiner);

for (size_t idx = ProverInstances::NUM; idx < ProverInstances::BATCHED_EXTENDED_LENGTH; idx++) {
transcript->send_to_verifier("combiner_quotient_" + std::to_string(idx), combiner_quotient.value_at(idx));
}

return std::make_tuple(
updated_gate_challenges, alphas, relation_parameters, perturbator_evaluation, combiner_quotient);
}

/**
* @brief Given the challenge \gamma, compute Z(\gamma) and {L_0(\gamma),L_1(\gamma)}
* TODO(https://github.com/AztecProtocol/barretenberg/issues/764): Generalize the vanishing polynomial formula
* and the computation of Lagrange basis for k instances
*/
template <class ProverInstances>
FoldingResult<typename ProverInstances::Flavor> ProtogalaxyProver_<ProverInstances>::update_target_sum_and_fold(
FoldingResult<typename ProverInstances::Flavor> ProtoGalaxyProver_<ProverInstances>::update_target_sum_and_fold(
const ProverInstances& instances,
const CombinerQuotient& combiner_quotient,
const UnivariateRelationSeparator& alphas,
const UnivariateRelationParameters& univariate_relation_parameters,
const FF& perturbator_evaluation)
{
BB_OP_COUNT_TIME_NAME("ProtogalaxyProver_::update_target_sum_and_fold");
BB_OP_COUNT_TIME_NAME("ProtoGalaxyProver_::update_target_sum_and_fold");
using Fun = ProtogalaxyProverInternal<ProverInstances>;

const FF combiner_challenge = transcript->template get_challenge<FF>("combiner_quotient_challenge");
Expand Down Expand Up @@ -161,6 +66,30 @@ FoldingResult<typename ProverInstances::Flavor> ProtogalaxyProver_<ProverInstanc
return result;
}

template <class ProverInstances> void ProtoGalaxyProver_<ProverInstances>::run_oink_prover_on_each_instance()
{
BB_OP_COUNT_TIME_NAME("ProtoGalaxyProver_::run_oink_prover_on_each_instance");
auto idx = 0;
auto& instance = instances[0];
auto domain_separator = std::to_string(idx);

if (!instance->is_accumulator) {
run_oink_prover_on_instance(instance, domain_separator);
instance->target_sum = 0;
instance->gate_challenges = std::vector<FF>(instance->proving_key.log_circuit_size, 0);
}

idx++;

for (auto it = instances.begin() + 1; it != instances.end(); it++, idx++) {
auto instance = *it;
auto domain_separator = std::to_string(idx);
run_oink_prover_on_instance(instance, domain_separator);
}

state.accumulator = instances[0];
};

template <class ProverInstances>
std::tuple<std::vector<typename ProverInstances::Flavor::FF>, Polynomial<typename ProverInstances::Flavor::FF>>
ProtoGalaxyProver_<ProverInstances>::perturbator_round(
Expand Down
Loading

0 comments on commit eb0c7be

Please sign in to comment.