Skip to content

Commit

Permalink
feat: Execution Trace (#4623)
Browse files Browse the repository at this point in the history
Introduces an `ExecutionTrace` class responsible for translating raw
circuit data into the "execution trace polynomials", which I define as
the wire, selector and permutation argument polynomials (sigma/id). This
work was previously split across several different methods in the
Composers/ProverInstance and much of the logic was duplicated between
Plonk and Honk. That core logic is now shared across Plonk/Honk for all
flavors. It is encapsulated into a single call of the form
`Trace::generate(circuit, proving_key);` which takes the raw circuit
data contained in `circuit` and populates the provided `proving_key`
with wire, selector and sigma/id polynomials.

The main work of the `ExecutionTrace` is to "sort" the relatively
un-ordered raw circuit data. For example, for GUH, the ordering of the
execution trace is (1) zero row, (2) goblin ecc op gates, (3) public
inputs, and (4) conventional gates. Each one of these can be described
as an `ExecutionTraceBlock` which is a {`wires`, `selectors`} pair. E.g.
the conventional gates block is just the existing {`builder.wires`,
`builder.selectors`}. The public inputs block has all of its selectors
equal to zero, the first two wires equal to `builder.public_inputs`, and
the remaining wires identically zero. And so on. Eventually, each gate
type will have its own `ExecutionTraceBlock`. (I've rephrased the goblin
ecc op gates as an ExecutionTraceBlock as an example). These blocks are
constructed by the builder and "sorting" is achieved in `ExecutionTrace`
by simply arranging the blocks as desired then constructing polynomials.

From here, achieving a sorted execution trace should amount to
introducing one `ExecutionTraceBlock` for each gate type in the
builders, populating the appropriate block in each gate construction
function (instead of piling everything into a single `wires`,
`selectors`), then arranging those blocks to define the execution trace
polynomials in `ExecutionTrace`.



Closes AztecProtocol/barretenberg#808
Closes AztecProtocol/barretenberg#859

---------

Co-authored-by: ludamad <[email protected]>
  • Loading branch information
ledwards2225 and ludamad0 authored Feb 21, 2024
1 parent e84759f commit 07ac589
Show file tree
Hide file tree
Showing 27 changed files with 771 additions and 1,186 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,21 +32,6 @@ plonk::Prover provers[NUM_CIRCUITS];
plonk::Verifier verifiers[NUM_CIRCUITS];
plonk::proof proofs[NUM_CIRCUITS];

void construct_witnesses_bench(State& state) noexcept
{
for (auto _ : state) {
state.PauseTiming();
auto builder = Builder(static_cast<size_t>(state.range(0)));
generate_test_plonk_circuit(builder, static_cast<size_t>(state.range(0)));
auto composer = Composer();
composer.compute_proving_key(builder);
state.ResumeTiming();

composer.compute_witness(builder);
}
}
BENCHMARK(construct_witnesses_bench)->RangeMultiplier(2)->Range(START, MAX_GATES);

void construct_proving_keys_bench(State& state) noexcept
{
for (auto _ : state) {
Expand Down
10 changes: 10 additions & 0 deletions barretenberg/cpp/src/barretenberg/common/ref_array.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,18 @@ template <typename T, std::size_t N> class RefArray {

T& operator[](std::size_t idx) const
{
// GCC has a bug where it has trouble analyzing zip_view
// this is likely due to this bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104165
// We disable this - if GCC was right, we would have caught this at runtime
#if !defined(__clang__) && defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Warray-bounds"
#endif
ASSERT(idx < N);
return *storage[idx];
#if !defined(__clang__) && defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
}

/**
Expand Down
4 changes: 4 additions & 0 deletions barretenberg/cpp/src/barretenberg/flavor/flavor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ class ProvingKey_ : public PrecomputedPolynomials, public WitnessPolynomials {
auto get_all() { return concatenate(get_precomputed_polynomials(), get_witness_polynomials()); }
auto get_witness_polynomials() { return WitnessPolynomials::get_all(); }
auto get_precomputed_polynomials() { return PrecomputedPolynomials::get_all(); }
auto get_selectors() { return PrecomputedPolynomials::get_selectors(); }
ProvingKey_() = default;
ProvingKey_(const size_t circuit_size, const size_t num_public_inputs)
{
Expand Down Expand Up @@ -285,6 +286,9 @@ namespace bb {
template <typename T>
concept IsPlonkFlavor = IsAnyOf<T, plonk::flavor::Standard, plonk::flavor::Ultra>;

template <typename T>
concept IsUltraPlonkFlavor = IsAnyOf<T, plonk::flavor::Ultra>;

template <typename T>
concept IsHonkFlavor = IsAnyOf<T, UltraFlavor, GoblinUltraFlavor>;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ Prover new_join_split_prover(join_split_tx const& tx, bool mock)

info("public inputs: ", builder.public_inputs.size());

Composer composer(proving_key, nullptr);
Composer composer;
if (!mock) {
info("composer gates: ", builder.get_num_gates());
return composer.create_prover(builder);
Expand Down
33 changes: 0 additions & 33 deletions barretenberg/cpp/src/barretenberg/plonk/composer/composer_lib.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,39 +10,6 @@ struct SelectorProperties {
bool requires_lagrange_base_polynomial = false;
};

/**
* @brief Initilalize proving key and load the crs
*
* @param circuit_constructor Object containing the circuit
* @param crs_factory Produces the prover's reference string
* @param minimum_circuit_size The minimum size of polynomials without randomized elements
* @param num_randomized_gates Number of gates with randomized witnesses
* @param circuit_type This is passed in the case of Plonk since we use flavor-independent proving and verification keys
* in that case.
* @return std::shared_ptr<typename Flavor::ProvingKey>
*/
std::shared_ptr<plonk::proving_key> initialize_proving_key(const auto& circuit_constructor,
bb::srs::factories::CrsFactory<curve::BN254>* crs_factory,
const size_t minimum_circuit_size,
const size_t num_randomized_gates,
CircuitType circuit_type)
{
const size_t num_gates = circuit_constructor.num_gates;

const size_t num_public_inputs = circuit_constructor.public_inputs.size();
const size_t num_constraints = num_gates + num_public_inputs;
const size_t total_num_constraints = std::max(minimum_circuit_size, num_constraints);
const size_t subgroup_size =
circuit_constructor.get_circuit_subgroup_size(total_num_constraints + num_randomized_gates); // next power of 2

auto crs = crs_factory->get_prover_crs(subgroup_size + 1);

// Differentiate between Honk and Plonk here since Plonk pkey requires crs whereas Honk pkey does not
auto proving_key = std::make_shared<plonk::proving_key>(subgroup_size, num_public_inputs, crs, circuit_type);

return proving_key;
}

/**
* @brief Fill the last index of each selector polynomial in lagrange form with a non-zero value
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,39 +14,6 @@

namespace bb::plonk {

/**
* Compute witness polynomials (w_1, w_2, w_3, w_4).
*
* @details Fills 3 or 4 witness polynomials w_1, w_2, w_3, w_4 with the values of in-circuit variables. The beginning
* of w_1, w_2 polynomials is filled with public_input values.
* @return Witness with computed witness polynomials.
*
* @tparam Program settings needed to establish if w_4 is being used.
* */
void StandardComposer::compute_witness(const CircuitBuilder& circuit_constructor, const size_t minimum_circuit_size)
{

if (computed_witness) {
return;
}
const size_t num_gates = circuit_constructor.num_gates;
const size_t num_public_inputs = circuit_constructor.public_inputs.size();

const size_t num_constraints = std::max(minimum_circuit_size, num_gates + num_public_inputs);

const size_t subgroup_size = circuit_constructor.get_circuit_subgroup_size(num_constraints + NUM_RESERVED_GATES);

auto wire_polynomial_evaluations =
construct_wire_polynomials_base<StandardComposer::Flavor>(circuit_constructor, subgroup_size);

for (size_t j = 0; j < program_width; ++j) {
std::string index = std::to_string(j + 1);
circuit_proving_key->polynomial_store.put("w_" + index + "_lagrange",
std::move(wire_polynomial_evaluations[j]));
}
computed_witness = true;
}

/**
* Compute proving key
*
Expand All @@ -63,27 +30,30 @@ std::shared_ptr<plonk::proving_key> StandardComposer::compute_proving_key(const
if (circuit_proving_key) {
return circuit_proving_key;
}
const size_t minimum_circuit_size = 0;
const size_t num_randomized_gates = NUM_RESERVED_GATES;
// Initialize circuit_proving_key
// TODO(#392)(Kesha): replace composer types.
circuit_proving_key = initialize_proving_key(
circuit_constructor, crs_factory_.get(), minimum_circuit_size, num_randomized_gates, CircuitType::STANDARD);
// Compute lagrange selectors
construct_selector_polynomials<Flavor>(circuit_constructor, circuit_proving_key.get());

const size_t total_num_gates =
circuit_constructor.num_gates + circuit_constructor.public_inputs.size() + NUM_RESERVED_GATES;
const size_t subgroup_size = circuit_constructor.get_circuit_subgroup_size(total_num_gates); // next power of 2

auto crs = srs::get_crs_factory()->get_prover_crs(subgroup_size + 1);
// TODO(https://github.com/AztecProtocol/barretenberg/issues/392): Composer type
circuit_proving_key = std::make_shared<plonk::proving_key>(
subgroup_size, circuit_constructor.public_inputs.size(), crs, CircuitType::STANDARD);

// Construct and add to proving key the wire, selector and copy constraint polynomials
Trace::generate(circuit_constructor, circuit_proving_key);

// Make all selectors nonzero
enforce_nonzero_selector_polynomials(circuit_constructor, circuit_proving_key.get());
// Compute selectors in monomial form
compute_monomial_and_coset_selector_forms(circuit_proving_key.get(), standard_selector_properties());

// Compute sigma polynomials (we should update that late)
compute_standard_plonk_sigma_permutations<Flavor>(circuit_constructor, circuit_proving_key.get());

circuit_proving_key->recursive_proof_public_input_indices =
std::vector<uint32_t>(circuit_constructor.recursive_proof_public_input_indices.begin(),
circuit_constructor.recursive_proof_public_input_indices.end());
// What does this line do exactly?

circuit_proving_key->contains_recursive_proof = circuit_constructor.contains_recursive_proof;

return circuit_proving_key;
}

Expand Down Expand Up @@ -144,12 +114,8 @@ plonk::Verifier StandardComposer::create_verifier(const CircuitBuilder& circuit_
* */
plonk::Prover StandardComposer::create_prover(const CircuitBuilder& circuit_constructor)
{
// Compute q_l, etc. and sigma polynomials.
compute_proving_key(circuit_constructor);

// Compute witness polynomials.
compute_witness(circuit_constructor);

plonk::Prover output_state(circuit_proving_key, create_manifest(circuit_constructor.public_inputs.size()));

std::unique_ptr<plonk::ProverPermutationWidget<3, false>> permutation_widget =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "barretenberg/plonk/proof_system/verification_key/verification_key.hpp"
#include "barretenberg/plonk/proof_system/verifier/verifier.hpp"
#include "barretenberg/proof_system/circuit_builder/standard_circuit_builder.hpp"
#include "barretenberg/proof_system/execution_trace/execution_trace.hpp"
#include "barretenberg/srs/factories/file_crs_factory.hpp"
#include <utility>

Expand All @@ -16,6 +17,7 @@ class StandardComposer {
using Flavor = plonk::flavor::Standard;

using CircuitBuilder = StandardCircuitBuilder;
using Trace = ExecutionTrace_<Flavor>;

static constexpr std::string_view NAME_STRING = "StandardPlonk";
static constexpr size_t NUM_RESERVED_GATES = 4; // equal to the number of evaluations leaked
Expand Down Expand Up @@ -60,7 +62,6 @@ class StandardComposer {
plonk::Verifier create_verifier(const CircuitBuilder& circuit_constructor);
plonk::Prover create_prover(const CircuitBuilder& circuit_constructor);

void compute_witness(const CircuitBuilder& circuit_constructor, const size_t minimum_circuit_size = 0);
/**
* Create a manifest, which specifies proof rounds, elements and who supplies them.
*
Expand Down
Loading

0 comments on commit 07ac589

Please sign in to comment.