Skip to content

Commit

Permalink
feat: recursive folding and decider verifier for Protogalaxy (#4156)
Browse files Browse the repository at this point in the history
Implements the recursive folding verifier and recursive decider verifier
resembling the native ones as closely as possible. Tests follow the
example of the other recursive honk verifiers and native protogalaxy
tests.

Additionally, I introduced a function that sequentially computes
polynomials in coefficient form in the `ProtoGalaxyRecursiveVerifier` to
avoid having to instantiate the entire `Polynomial` class on
`stdlib::bn254`.

Closes AztecProtocol/barretenberg#789.
Closes AztecProtocol/barretenberg#834.
  • Loading branch information
maramihali authored Jan 24, 2024
1 parent 8c3efba commit 9342048
Show file tree
Hide file tree
Showing 18 changed files with 1,060 additions and 131 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ void fold_one(State& state) noexcept
std::shared_ptr<Instance> instance_1 = construct_instance();
std::shared_ptr<Instance> instance_2 = construct_instance();

auto folding_prover = composer.create_folding_prover({ instance_1, instance_2 }, composer.commitment_key);
auto folding_prover = composer.create_folding_prover({ instance_1, instance_2 });

for (auto _ : state) {
auto proof = folding_prover.fold_instances();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,13 @@ template <class Params_> struct alignas(32) field {
*this = field(value);
}

constexpr explicit operator bool() const
{
field out = from_montgomery_form();
ASSERT(out.data[0] == 0 || out.data[0] == 1);
return static_cast<bool>(out.data[0]);
}

constexpr explicit operator uint32_t() const
{
field out = from_montgomery_form();
Expand Down
67 changes: 18 additions & 49 deletions barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ class GoblinUltra {

// GoblinUltra needs to expose more public classes than most flavors due to GoblinUltraRecursive reuse, but these
// are internal:
private:
public:
// WireEntities for basic witness entities
template <typename DataType> class WireEntities {
public:
Expand Down Expand Up @@ -418,42 +418,8 @@ class GoblinUltra {
template <typename Commitment, typename VerificationKey>
class VerifierCommitments_ : public AllEntities<Commitment> {
public:
VerifierCommitments_(const std::shared_ptr<VerificationKey>& verification_key)
{
this->q_m = verification_key->q_m;
this->q_l = verification_key->q_l;
this->q_r = verification_key->q_r;
this->q_o = verification_key->q_o;
this->q_4 = verification_key->q_4;
this->q_c = verification_key->q_c;
this->q_arith = verification_key->q_arith;
this->q_sort = verification_key->q_sort;
this->q_elliptic = verification_key->q_elliptic;
this->q_aux = verification_key->q_aux;
this->q_lookup = verification_key->q_lookup;
this->q_busread = verification_key->q_busread;
this->q_poseidon2_external = verification_key->q_poseidon2_external;
this->q_poseidon2_internal = verification_key->q_poseidon2_internal;
this->sigma_1 = verification_key->sigma_1;
this->sigma_2 = verification_key->sigma_2;
this->sigma_3 = verification_key->sigma_3;
this->sigma_4 = verification_key->sigma_4;
this->id_1 = verification_key->id_1;
this->id_2 = verification_key->id_2;
this->id_3 = verification_key->id_3;
this->id_4 = verification_key->id_4;
this->table_1 = verification_key->table_1;
this->table_2 = verification_key->table_2;
this->table_3 = verification_key->table_3;
this->table_4 = verification_key->table_4;
this->lagrange_first = verification_key->lagrange_first;
this->lagrange_last = verification_key->lagrange_last;
this->lagrange_ecc_op = verification_key->lagrange_ecc_op;
this->databus_id = verification_key->databus_id;
}

VerifierCommitments_(const std::shared_ptr<VerificationKey>& verification_key,
const WitnessCommitments& witness_commitments)
const std::optional<WitnessEntities<Commitment>>& witness_commitments = std::nullopt)
{
this->q_m = verification_key->q_m;
this->q_l = verification_key->q_l;
Expand Down Expand Up @@ -486,19 +452,22 @@ class GoblinUltra {
this->lagrange_ecc_op = verification_key->lagrange_ecc_op;
this->databus_id = verification_key->databus_id;

this->w_l = witness_commitments.w_l;
this->w_r = witness_commitments.w_r;
this->w_o = witness_commitments.w_o;
this->sorted_accum = witness_commitments.sorted_accum;
this->w_4 = witness_commitments.w_4;
this->z_perm = witness_commitments.z_perm;
this->z_lookup = witness_commitments.z_lookup;
this->ecc_op_wire_1 = witness_commitments.ecc_op_wire_1;
this->ecc_op_wire_2 = witness_commitments.ecc_op_wire_2;
this->ecc_op_wire_3 = witness_commitments.ecc_op_wire_3;
this->calldata = witness_commitments.calldata;
this->calldata = witness_commitments.calldata_read_counts;
this->lookup_inverses = witness_commitments.lookup_inverses;
if (witness_commitments.has_value()) {
auto commitments = witness_commitments.value();
this->w_l = commitments.w_l;
this->w_r = commitments.w_r;
this->w_o = commitments.w_o;
this->sorted_accum = commitments.sorted_accum;
this->w_4 = commitments.w_4;
this->z_perm = commitments.z_perm;
this->z_lookup = commitments.z_lookup;
this->ecc_op_wire_1 = commitments.ecc_op_wire_1;
this->ecc_op_wire_2 = commitments.ecc_op_wire_2;
this->ecc_op_wire_3 = commitments.ecc_op_wire_3;
this->calldata = commitments.calldata;
this->calldata = commitments.calldata_read_counts;
this->lookup_inverses = commitments.lookup_inverses;
}
}
};
// Specialize for GoblinUltra (general case used in GoblinUltraRecursive).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,14 @@ template <typename BuilderType> class GoblinUltraRecursive_ {
using Relations = GoblinUltra::Relations_<FF>;

static constexpr size_t MAX_PARTIAL_RELATION_LENGTH = compute_max_partial_relation_length<Relations>();
static constexpr size_t MAX_TOTAL_RELATION_LENGTH = compute_max_total_relation_length<Relations>();

// BATCHED_RELATION_PARTIAL_LENGTH = algebraic degree of sumcheck relation *after* multiplying by the `pow_zeta`
// random polynomial e.g. For \sum(x) [A(x) * B(x) + C(x)] * PowZeta(X), relation length = 2 and random relation
// length = 3
static constexpr size_t BATCHED_RELATION_PARTIAL_LENGTH = MAX_PARTIAL_RELATION_LENGTH + 1;
static constexpr size_t NUM_RELATIONS = std::tuple_size<Relations>::value;
static constexpr size_t BATCHED_RELATION_TOTAL_LENGTH = MAX_TOTAL_RELATION_LENGTH + 1;
static constexpr size_t NUM_RELATIONS = std::tuple_size_v<Relations>;

// For instances of this flavour, used in folding, we need a unique sumcheck batching challenge for each
// subrelation. This is because using powers of alpha would increase the degree of Protogalaxy polynomial $G$ (the
Expand Down Expand Up @@ -104,6 +106,12 @@ template <typename BuilderType> class GoblinUltraRecursive_ {
*/
class VerificationKey : public VerificationKey_<GoblinUltra::PrecomputedEntities<Commitment>> {
public:
VerificationKey(const size_t circuit_size, const size_t num_public_inputs)
{
this->circuit_size = circuit_size;
this->log_circuit_size = numeric::get_msb(circuit_size);
this->num_public_inputs = num_public_inputs;
};
/**
* @brief Construct a new Verification Key with stdlib types from a provided native verification
* key
Expand All @@ -112,9 +120,10 @@ template <typename BuilderType> class GoblinUltraRecursive_ {
* @param native_key Native verification key from which to extract the precomputed commitments
*/
VerificationKey(CircuitBuilder* builder, const std::shared_ptr<NativeVerificationKey>& native_key)
: VerificationKey_<GoblinUltra::PrecomputedEntities<Commitment>>(native_key->circuit_size,
native_key->num_public_inputs)
{
this->circuit_size = native_key->circuit_size;
this->log_circuit_size = numeric::get_msb(this->circuit_size);
this->num_public_inputs = native_key->num_public_inputs;
this->q_m = Commitment::from_witness(builder, native_key->q_m);
this->q_l = Commitment::from_witness(builder, native_key->q_l);
this->q_r = Commitment::from_witness(builder, native_key->q_r);
Expand Down Expand Up @@ -148,6 +157,11 @@ template <typename BuilderType> class GoblinUltraRecursive_ {
};
};

/**
* @brief A container for the witness commitments.
*/
using WitnessCommitments = GoblinUltra::WitnessEntities<Commitment>;

using CommitmentLabels = GoblinUltra::CommitmentLabels;
// Reuse the VerifierCommitments from GoblinUltra
using VerifierCommitments = GoblinUltra::VerifierCommitments_<Commitment, VerificationKey>;
Expand Down
48 changes: 11 additions & 37 deletions barretenberg/cpp/src/barretenberg/flavor/ultra.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -412,37 +412,8 @@ class Ultra {
*/
class VerifierCommitments : public AllEntities<Commitment> {
public:
VerifierCommitments(const std::shared_ptr<VerificationKey>& verification_key)
{
q_m = verification_key->q_m;
q_c = verification_key->q_c;
q_l = verification_key->q_l;
q_r = verification_key->q_r;
q_o = verification_key->q_o;
q_4 = verification_key->q_4;
q_arith = verification_key->q_arith;
q_sort = verification_key->q_sort;
q_elliptic = verification_key->q_elliptic;
q_aux = verification_key->q_aux;
q_lookup = verification_key->q_lookup;
sigma_1 = verification_key->sigma_1;
sigma_2 = verification_key->sigma_2;
sigma_3 = verification_key->sigma_3;
sigma_4 = verification_key->sigma_4;
id_1 = verification_key->id_1;
id_2 = verification_key->id_2;
id_3 = verification_key->id_3;
id_4 = verification_key->id_4;
table_1 = verification_key->table_1;
table_2 = verification_key->table_2;
table_3 = verification_key->table_3;
table_4 = verification_key->table_4;
lagrange_first = verification_key->lagrange_first;
lagrange_last = verification_key->lagrange_last;
}

VerifierCommitments(const std::shared_ptr<VerificationKey>& verification_key,
const WitnessCommitments& witness_commitments)
const std::optional<WitnessCommitments>& witness_commitments = std::nullopt)
{
q_m = verification_key->q_m;
q_c = verification_key->q_c;
Expand Down Expand Up @@ -470,13 +441,16 @@ class Ultra {
lagrange_first = verification_key->lagrange_first;
lagrange_last = verification_key->lagrange_last;

w_l = witness_commitments.w_l;
w_r = witness_commitments.w_r;
w_o = witness_commitments.w_o;
sorted_accum = witness_commitments.sorted_accum;
w_4 = witness_commitments.w_4;
z_perm = witness_commitments.z_perm;
z_lookup = witness_commitments.z_lookup;
if (witness_commitments.has_value()) {
auto commitments = witness_commitments.value();
this->w_l = commitments.w_l;
this->w_r = commitments.w_r;
this->w_o = commitments.w_o;
this->sorted_accum = commitments.sorted_accum;
this->w_4 = commitments.w_4;
this->z_perm = commitments.z_perm;
this->z_lookup = commitments.z_lookup;
}
}
};

Expand Down
96 changes: 68 additions & 28 deletions barretenberg/cpp/src/barretenberg/flavor/ultra_recursive.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,15 @@ template <typename BuilderType> class UltraRecursive_ {
bb::AuxiliaryRelation<FF>>;

static constexpr size_t MAX_PARTIAL_RELATION_LENGTH = compute_max_partial_relation_length<Relations>();
static_assert(MAX_PARTIAL_RELATION_LENGTH == 6);
static constexpr size_t MAX_TOTAL_RELATION_LENGTH = compute_max_total_relation_length<Relations>();
static_assert(MAX_TOTAL_RELATION_LENGTH == 12);

// BATCHED_RELATION_PARTIAL_LENGTH = algebraic degree of sumcheck relation *after* multiplying by the `pow_zeta`
// random polynomial e.g. For \sum(x) [A(x) * B(x) + C(x)] * PowZeta(X), relation length = 2 and random relation
// length = 3
static constexpr size_t BATCHED_RELATION_PARTIAL_LENGTH = MAX_PARTIAL_RELATION_LENGTH + 1;
static constexpr size_t BATCHED_RELATION_TOTAL_LENGTH = MAX_TOTAL_RELATION_LENGTH + 1;
static constexpr size_t NUM_RELATIONS = std::tuple_size<Relations>::value;

// For instances of this flavour, used in folding, we need a unique sumcheck batching challenges for each
Expand Down Expand Up @@ -161,6 +165,12 @@ template <typename BuilderType> class UltraRecursive_ {
RefVector<DataType> get_wires() { return { w_l, w_r, w_o, w_4 }; };
};

public:
/**
* @brief A container for the witness commitments.
*/
using WitnessCommitments = WitnessEntities<Commitment>;

/**
* @brief A base class labelling all entities (for instance, all of the polynomials used by the prover during
* sumcheck) in this Honk variant along with particular subsets of interest
Expand Down Expand Up @@ -229,6 +239,17 @@ template <typename BuilderType> class UltraRecursive_ {

};
};
RefVector<DataType> get_precomputed()
{
return { q_m, q_c, q_l, q_r, q_o, q_4, q_arith, q_sort,
q_elliptic, q_aux, q_lookup, sigma_1, sigma_2, sigma_3, sigma_4, id_1,
id_2, id_3, id_4, table_1, table_2, table_3, table_4, lagrange_first,
lagrange_last

};
}

RefVector<DataType> get_witness() { return { w_l, w_r, w_o, w_4, sorted_accum, z_perm, z_lookup }; };
RefVector<DataType> get_to_be_shifted()
{
return { table_1, table_2, table_3, table_4, w_l, w_r, w_o, w_4, sorted_accum, z_perm, z_lookup };
Expand All @@ -251,15 +272,23 @@ template <typename BuilderType> class UltraRecursive_ {
*/
class VerificationKey : public VerificationKey_<PrecomputedEntities<Commitment>> {
public:
VerificationKey(const size_t circuit_size, const size_t num_public_inputs)
{
this->circuit_size = circuit_size;
this->log_circuit_size = numeric::get_msb(circuit_size);
this->num_public_inputs = num_public_inputs;
};
/**
* @brief Construct a new Verification Key with stdlib types from a provided native verification key
*
* @param builder
* @param native_key Native verification key from which to extract the precomputed commitments
*/
VerificationKey(CircuitBuilder* builder, const std::shared_ptr<NativeVerificationKey>& native_key)
: VerificationKey_<PrecomputedEntities<Commitment>>(native_key->circuit_size, native_key->num_public_inputs)
{
this->circuit_size = native_key->circuit_size;
this->log_circuit_size = numeric::get_msb(this->circuit_size);
this->num_public_inputs = native_key->num_public_inputs;
this->q_m = Commitment::from_witness(builder, native_key->q_m);
this->q_l = Commitment::from_witness(builder, native_key->q_l);
this->q_r = Commitment::from_witness(builder, native_key->q_r);
Expand Down Expand Up @@ -317,38 +346,38 @@ template <typename BuilderType> class UltraRecursive_ {
this->z_lookup = "Z_LOOKUP";
this->sorted_accum = "SORTED_ACCUM";

// The ones beginning with "__" are only used for debugging
this->q_c = "__Q_C";
this->q_l = "__Q_L";
this->q_r = "__Q_R";
this->q_o = "__Q_O";
this->q_4 = "__Q_4";
this->q_m = "__Q_M";
this->q_arith = "__Q_ARITH";
this->q_sort = "__Q_SORT";
this->q_elliptic = "__Q_ELLIPTIC";
this->q_aux = "__Q_AUX";
this->q_lookup = "__Q_LOOKUP";
this->sigma_1 = "__SIGMA_1";
this->sigma_2 = "__SIGMA_2";
this->sigma_3 = "__SIGMA_3";
this->sigma_4 = "__SIGMA_4";
this->id_1 = "__ID_1";
this->id_2 = "__ID_2";
this->id_3 = "__ID_3";
this->id_4 = "__ID_4";
this->table_1 = "__TABLE_1";
this->table_2 = "__TABLE_2";
this->table_3 = "__TABLE_3";
this->table_4 = "__TABLE_4";
this->lagrange_first = "__LAGRANGE_FIRST";
this->lagrange_last = "__LAGRANGE_LAST";
this->q_c = "Q_C";
this->q_l = "Q_L";
this->q_r = "Q_R";
this->q_o = "Q_O";
this->q_4 = "Q_4";
this->q_m = "Q_M";
this->q_arith = "Q_ARITH";
this->q_sort = "Q_SORT";
this->q_elliptic = "Q_ELLIPTIC";
this->q_aux = "Q_AUX";
this->q_lookup = "Q_LOOKUP";
this->sigma_1 = "SIGMA_1";
this->sigma_2 = "SIGMA_2";
this->sigma_3 = "SIGMA_3";
this->sigma_4 = "SIGMA_4";
this->id_1 = "ID_1";
this->id_2 = "ID_2";
this->id_3 = "ID_3";
this->id_4 = "ID_4";
this->table_1 = "TABLE_1";
this->table_2 = "TABLE_2";
this->table_3 = "TABLE_3";
this->table_4 = "TABLE_4";
this->lagrange_first = "LAGRANGE_FIRST";
this->lagrange_last = "LAGRANGE_LAST";
};
};

class VerifierCommitments : public AllEntities<Commitment> {
public:
VerifierCommitments(const std::shared_ptr<VerificationKey>& verification_key)
VerifierCommitments(const std::shared_ptr<VerificationKey>& verification_key,
const std::optional<WitnessCommitments>& witness_commitments = std::nullopt)
{
this->q_m = verification_key->q_m;
this->q_l = verification_key->q_l;
Expand All @@ -375,6 +404,17 @@ template <typename BuilderType> class UltraRecursive_ {
this->table_4 = verification_key->table_4;
this->lagrange_first = verification_key->lagrange_first;
this->lagrange_last = verification_key->lagrange_last;

if (witness_commitments.has_value()) {
auto commitments = witness_commitments.value();
this->w_l = commitments.w_l;
this->w_r = commitments.w_r;
this->w_o = commitments.w_o;
this->sorted_accum = commitments.sorted_accum;
this->w_4 = commitments.w_4;
this->z_perm = commitments.z_perm;
this->z_lookup = commitments.z_lookup;
}
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -269,14 +269,10 @@ std::shared_ptr<typename ProverInstances::Instance> ProtoGalaxyProver_<ProverIns
return next_accumulator;
}

// TODO(#https://github.com/AztecProtocol/barretenberg/issues/689): finalise implementation this function
template <class ProverInstances>
FoldingResult<typename ProverInstances::Flavor> ProtoGalaxyProver_<ProverInstances>::fold_instances()
{
prepare_for_folding();

// TODO(#https://github.com/AztecProtocol/barretenberg/issues/740): Handle the case where we are folding for the
// first time and accumulator is 0
FF delta = transcript->get_challenge("delta");

auto accumulator = get_accumulator();
Expand Down
Loading

0 comments on commit 9342048

Please sign in to comment.