Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: folding acir programs #6685

Merged
merged 33 commits into from
May 28, 2024
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
8009652
WiP fails to verify with any recursive verifier
ledwards2225 May 20, 2024
5c1bdf8
basic integration test setup
ledwards2225 May 20, 2024
1e4efca
add and use program stack struct
ledwards2225 May 20, 2024
2c0b89c
integration test for program stack
ledwards2225 May 20, 2024
e328d2c
client ivc prove and verify method
ledwards2225 May 20, 2024
aaf1550
updates to inegration tests, client ivc test failing
ledwards2225 May 20, 2024
436f751
minimal test showing issue with adding RAM post
ledwards2225 May 20, 2024
5e9072f
test cleanup
ledwards2225 May 22, 2024
6a1de02
Merge branch 'master' into lde/acir_folding
ledwards2225 May 22, 2024
492b2ed
client ivc test passes
ledwards2225 May 22, 2024
6e7162f
move adding of mock ops into client ivc
ledwards2225 May 22, 2024
f3a91e0
fold and verify flow passes
ledwards2225 May 22, 2024
deb9658
add cbinds for fold and verify
ledwards2225 May 22, 2024
bfc2db9
Merge branch 'master' into lde/acir_folding
ledwards2225 May 23, 2024
5adc97a
add fold tests to CI for bb and bbjs
ledwards2225 May 23, 2024
e3088ef
Merge branch 'master' into lde/acir_folding
ledwards2225 May 23, 2024
5e5784c
update integration tests after merge
ledwards2225 May 23, 2024
248d4ba
Merge branch 'master' into lde/acir_folding
ledwards2225 May 23, 2024
adcbe99
fix binding
ledwards2225 May 23, 2024
0cacb52
fix CI setup
ledwards2225 May 23, 2024
bea3d67
clean up
ledwards2225 May 23, 2024
bba7d2d
clean up
ledwards2225 May 24, 2024
ee002d6
Merge branch 'master' into lde/acir_folding
ledwards2225 May 24, 2024
db19d39
Merge branch 'master' into lde/acir_folding
ledwards2225 May 24, 2024
233ff93
mega name fix
ledwards2225 May 24, 2024
7d03507
disable tests at risk for intermittent failure
ledwards2225 May 24, 2024
a41fe29
Address issue 1003
codygunton May 27, 2024
92fd298
Merge remote-tracking branch 'origin/master' into lde/acir_folding
codygunton May 27, 2024
e7ace4a
update mega naming
ledwards2225 May 28, 2024
c4c1843
Merge branch 'master' into lde/acir_folding
ledwards2225 May 28, 2024
922d83e
update name
ledwards2225 May 28, 2024
ffc3622
disable last integration test
ledwards2225 May 28, 2024
837de7e
Merge branch 'master' into lde/acir_folding
ledwards2225 May 28, 2024
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
3 changes: 3 additions & 0 deletions barretenberg/Earthfile
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ barretenberg-acir-tests-bb:
RUN FLOW=prove_and_verify_mega_honk ./run_acir_tests.sh 6_array
# Construct and verify a UltraHonk proof for all ACIR programs using the new witness stack workflow
RUN FLOW=prove_and_verify_ultra_honk_program ./run_acir_tests.sh
# Fold and verify an ACIR program stack using ClientIvc
# TODO(https://github.com/AztecProtocol/barretenberg/issues/1003): reinstate when ClientIvc fixed.
# RUN FLOW=fold_and_verify_program ./run_acir_tests.sh fold_basic
# This is a "full" Goblin flow. It constructs and verifies four proofs: MegaHonk, ECCVM, Translator, and merge
RUN FLOW=prove_and_verify_goblin ./run_acir_tests.sh 6_array
# Run 1_mul through native bb build, all_cmds flow, to test all cli args.
Expand Down
5 changes: 4 additions & 1 deletion barretenberg/acir_tests/Dockerfile.bb.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,11 @@ RUN BIN=../ts/dest/node/main.js FLOW=prove_then_verify_ultra_honk ./run_acir_tes
RUN BIN=../ts/dest/node/main.js FLOW=prove_and_verify ./run_acir_tests.sh poseidon_bn254_hash
# Run a single arbitrary test not involving recursion through bb.js for MegaHonk
RUN BIN=../ts/dest/node/main.js FLOW=prove_and_verify_ultra_honk ./run_acir_tests.sh closures_mut_ref
# Run a single arbitrary test for separate prove and verify for UltraHonk
# Run a single arbitrary test for separate prove and verify for MegaHonk
RUN BIN=../ts/dest/node/main.js FLOW=prove_and_verify_mega_honk ./run_acir_tests.sh 6_array
# Fold and verify an ACIR program stack
# TODO(https://github.com/AztecProtocol/barretenberg/issues/1003): reinstate when ClientIvc is fixed.
# RUN BIN=../ts/dest/node/main.js FLOW=fold_and_verify_program ./run_acir_tests.sh fold_basic
# Run a single arbitrary test not involving recursion through bb.js for full Goblin
RUN BIN=../ts/dest/node/main.js FLOW=prove_and_verify_goblin ./run_acir_tests.sh 6_array
# Run 1_mul through bb.js build, all_cmds flow, to test all cli args.
Expand Down
6 changes: 6 additions & 0 deletions barretenberg/acir_tests/flows/fold_and_verify_program.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/sh
set -eu

VFLAG=${VERBOSE:+-v}

$BIN fold_and_verify_program $VFLAG -c $CRS_PATH -b ./target/program.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/sh
set -eu

VFLAG=${VERBOSE:+-v}

$BIN prove_and_verify_goblin_ultra_honk_program $VFLAG -c $CRS_PATH -b ./target/program.json
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rename file and flow to mega?

1 change: 1 addition & 0 deletions barretenberg/cpp/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ include(GNUInstallDirs)
message(STATUS "Compiling all-in-one barretenberg archive")

set(BARRETENBERG_TARGET_OBJECTS
$<TARGET_OBJECTS:client_ivc_objects>
$<TARGET_OBJECTS:commitment_schemes_objects>
$<TARGET_OBJECTS:common_objects>
$<TARGET_OBJECTS:client_ivc_objects>
Expand Down
35 changes: 35 additions & 0 deletions barretenberg/cpp/src/barretenberg/bb/main.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "barretenberg/bb/file_io.hpp"
#include "barretenberg/client_ivc/client_ivc.hpp"
#include "barretenberg/common/serialize.hpp"
#include "barretenberg/dsl/acir_format/acir_format.hpp"
#include "barretenberg/dsl/types.hpp"
Expand Down Expand Up @@ -219,6 +220,34 @@ bool proveAndVerifyHonkProgram(const std::string& bytecodePath, const std::strin
return true;
}

bool foldAndVerifyProgram(const std::string& bytecodePath, const std::string& witnessPath)
{
using Flavor = MegaFlavor; // This is the only option
using Builder = Flavor::CircuitBuilder;

init_bn254_crs(1 << 18);
init_grumpkin_crs(1 << 14);

ClientIVC ivc;
ivc.structured_flag = true;

auto program_stack = acir_format::get_acir_program_stack(bytecodePath, witnessPath);

// Accumulate the entire program stack into the IVC
while (!program_stack.empty()) {
auto stack_item = program_stack.back();

// Construct a bberg circuit from the acir representation
auto circuit = acir_format::create_circuit<Builder>(
stack_item.constraints, 0, stack_item.witness, false, ivc.goblin.op_queue);

ivc.accumulate(circuit);

program_stack.pop_back();
}
return ivc.prove_and_verify();
}

/**
* @brief Proves and Verifies an ACIR circuit
*
Expand Down Expand Up @@ -832,6 +861,12 @@ int main(int argc, char* argv[])
if (command == "prove_and_verify_ultra_honk_program") {
return proveAndVerifyHonkProgram<UltraFlavor>(bytecode_path, witness_path) ? 0 : 1;
}
if (command == "prove_and_verify_goblin_ultra_honk_program") {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rename

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks

return proveAndVerifyHonkProgram<MegaFlavor>(bytecode_path, witness_path) ? 0 : 1;
}
if (command == "fold_and_verify_program") {
return foldAndVerifyProgram(bytecode_path, witness_path) ? 0 : 1;
}
if (command == "prove_and_verify_goblin") {
return proveAndVerifyGoblin(bytecode_path, witness_path) ? 0 : 1;
}
Expand Down
14 changes: 14 additions & 0 deletions barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,4 +117,18 @@ std::vector<std::shared_ptr<ClientIVC::VerificationKey>> ClientIVC::precompute_f
return vkeys;
}

/**
* @brief Construct and verify a proof for the IVC
* @note Use of this method only makes sense when the prover and verifier are the same entity, e.g. in
* development/testing.
*
*/
bool ClientIVC::prove_and_verify()
{
auto proof = prove();

auto verifier_inst = std::make_shared<VerifierInstance>(this->instance_vk);
return verify(proof, { this->verifier_accumulator, verifier_inst });
}

} // namespace bb
2 changes: 2 additions & 0 deletions barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ class ClientIVC {

bool verify(Proof& proof, const std::vector<std::shared_ptr<VerifierInstance>>& verifier_instances);

bool prove_and_verify();

HonkProof decider_prove() const;

std::vector<std::shared_ptr<VerificationKey>> precompute_folding_verification_keys(std::vector<ClientCircuit>);
Expand Down
1 change: 1 addition & 0 deletions barretenberg/cpp/src/barretenberg/dsl/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ barretenberg_module(
dsl
plonk
ultra_honk
client_ivc
stdlib_sha256
stdlib_aes128
stdlib_keccak
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,8 @@ template <>
UltraCircuitBuilder create_circuit(const AcirFormat& constraint_system,
size_t size_hint,
WitnessVector const& witness,
bool honk_recursion)
bool honk_recursion,
[[maybe_unused]] std::shared_ptr<ECCOpQueue>)
{
Builder builder{
size_hint, witness, constraint_system.public_inputs, constraint_system.varnum, constraint_system.recursive
Expand All @@ -365,10 +366,10 @@ template <>
MegaCircuitBuilder create_circuit(const AcirFormat& constraint_system,
[[maybe_unused]] size_t size_hint,
WitnessVector const& witness,
bool honk_recursion)
bool honk_recursion,
std::shared_ptr<ECCOpQueue> op_queue)
{
// Construct a builder using the witness and public input data from acir and with the goblin-owned op_queue
auto op_queue = std::make_shared<ECCOpQueue>(); // instantiate empty op_queue
auto builder = MegaCircuitBuilder{ op_queue, witness, constraint_system.public_inputs, constraint_system.varnum };

// Populate constraints in the builder via the data in constraint_system
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,11 @@ struct AcirProgramStack {
std::vector<AcirFormat> constraint_systems;
WitnessVectorStack witness_stack;

AcirProgramStack(std::vector<AcirFormat>& constraint_systems_in, WitnessVectorStack& witness_stack_in)
: constraint_systems(constraint_systems_in)
, witness_stack(witness_stack_in)
{}

size_t size() const { return witness_stack.size(); }
bool empty() const { return witness_stack.empty(); }

Expand All @@ -138,7 +143,8 @@ template <typename Builder = UltraCircuitBuilder>
Builder create_circuit(const AcirFormat& constraint_system,
size_t size_hint = 0,
WitnessVector const& witness = {},
bool honk_recursion = false);
bool honk_recursion = false,
std::shared_ptr<ECCOpQueue> op_queue = std::make_shared<ECCOpQueue>());

template <typename Builder>
void build_constraints(Builder& builder,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include "barretenberg/client_ivc/client_ivc.hpp"
#ifndef __wasm__
#include "barretenberg/bb/exec_pipe.hpp"
#include "barretenberg/common/streams.hpp"
Expand Down Expand Up @@ -53,11 +54,6 @@ class AcirIntegrationTest : public ::testing::Test {
using VerificationKey = Flavor::VerificationKey;

Prover prover{ builder };
// builder.blocks.summarize();
// info("num gates = ", builder.get_num_gates());
// info("total circuit size = ", builder.get_total_circuit_size());
// info("circuit size = ", prover.instance->proving_key.circuit_size);
// info("log circuit size = ", prover.instance->proving_key.log_circuit_size);
auto proof = prover.construct_proof();

// Verify Honk proof
Expand All @@ -66,16 +62,49 @@ class AcirIntegrationTest : public ::testing::Test {

return verifier.verify_proof(proof);
}
};

class AcirIntegrationSingleTest : public AcirIntegrationTest, public testing::WithParamInterface<std::string> {
void add_some_simple_RAM_gates(auto& circuit)
{
std::array<uint32_t, 3> ram_values{ circuit.add_variable(5),
circuit.add_variable(10),
circuit.add_variable(20) };

size_t ram_id = circuit.create_RAM_array(3);

for (size_t i = 0; i < 3; ++i) {
circuit.init_RAM_element(ram_id, i, ram_values[i]);
}

auto val_idx_1 = circuit.read_RAM_array(ram_id, circuit.add_variable(1));
auto val_idx_2 = circuit.read_RAM_array(ram_id, circuit.add_variable(2));
auto val_idx_3 = circuit.read_RAM_array(ram_id, circuit.add_variable(0));

circuit.create_big_add_gate({
val_idx_1,
val_idx_2,
val_idx_3,
circuit.zero_idx,
1,
1,
1,
0,
-35,
});
}

protected:
static void SetUpTestSuite() { srs::init_crs_factory("../srs_db/ignition"); }
};

class AcirIntegrationSingleTest : public AcirIntegrationTest, public testing::WithParamInterface<std::string> {};

class AcirIntegrationFoldingTest : public AcirIntegrationTest, public testing::WithParamInterface<std::string> {
protected:
static void SetUpTestSuite() { srs::init_crs_factory("../srs_db/ignition"); }
static void SetUpTestSuite()
{
srs::init_crs_factory("../srs_db/ignition");
srs::init_grumpkin_crs_factory("../srs_db/grumpkin");
}
};

TEST_P(AcirIntegrationSingleTest, ProveAndVerifyProgram)
Expand Down Expand Up @@ -322,14 +351,73 @@ TEST_P(AcirIntegrationFoldingTest, ProveAndVerifyProgramStack)
}
}

// TODO(https://github.com/AztecProtocol/barretenberg/issues/1003): Reinstate when ClientIvc is fixed.
TEST_P(AcirIntegrationFoldingTest, DISABLED_FoldAndVerifyProgramStack)
{
using Flavor = MegaFlavor;
using Builder = Flavor::CircuitBuilder;

std::string test_name = GetParam();
auto program_stack = get_program_stack_data_from_test_file(test_name);

ClientIVC ivc;
ivc.structured_flag = true;

while (!program_stack.empty()) {
auto program = program_stack.back();

// Construct a bberg circuit from the acir representation
auto circuit =
acir_format::create_circuit<Builder>(program.constraints, 0, program.witness, false, ivc.goblin.op_queue);

ivc.accumulate(circuit);

CircuitChecker::check(circuit);
// EXPECT_TRUE(prove_and_verify_honk<Flavor>(ivc.prover_instance));

program_stack.pop_back();
}

EXPECT_TRUE(ivc.prove_and_verify());
}

INSTANTIATE_TEST_SUITE_P(AcirTests,
AcirIntegrationFoldingTest,
testing::Values("fold_after_inlined_calls",
"fold_basic",
"fold_basic_nested_call",
"fold_call_witness_condition",
"fold_complex_outputs",
"fold_distinct_return",
"fold_fibonacci",
"fold_numeric_generic_poseidon"));
#endif
testing::Values("fold_basic", "fold_basic_nested_call"));

/**
* @brief Ensure that adding gates post-facto to a circuit generated from acir still results in a valid circuit
* @details This is a pattern required by e.g. ClientIvc which appends recursive verifiers to acir-generated circuits
*
*/
TEST_F(AcirIntegrationTest, UpdateAcirCircuit)
{
using Flavor = MegaFlavor;
using Builder = Flavor::CircuitBuilder;

std::string test_name = "6_array"; // arbitrary program with RAM gates
auto acir_program = get_program_data_from_test_file(test_name);

// Construct a bberg circuit from the acir representation
auto circuit = acir_format::create_circuit<Builder>(acir_program.constraints, 0, acir_program.witness);

EXPECT_TRUE(CircuitChecker::check(circuit));

// Now append some RAM gates onto the circuit generated from acir and confirm that its still valid. (First, check
// that the RAM operations constitute a valid independent circuit).
{
Builder circuit;
add_some_simple_RAM_gates(circuit);
EXPECT_TRUE(CircuitChecker::check(circuit));
EXPECT_TRUE(prove_and_verify_honk<Flavor>(circuit));
}

// Now manually append the simple RAM circuit to the circuit generated from acir
add_some_simple_RAM_gates(circuit);

// Confirm that the result is still valid
EXPECT_TRUE(CircuitChecker::check(circuit));
EXPECT_TRUE(prove_and_verify_honk<Flavor>(circuit));
}

#endif
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ AcirFormat circuit_buf_to_acir_format(std::vector<uint8_t> const& buf);
* @brief Converts from the ACIR-native `WitnessMap` format to Barretenberg's internal `WitnessVector` format.
*
* @param buf Serialized representation of a `WitnessMap`.
* @return A `WitnessVector` equivalent to the passed `WitnessMap`.xo
* @return A `WitnessVector` equivalent to the passed `WitnessMap`.
* @note This transformation results in all unassigned witnesses within the `WitnessMap` being assigned the value 0.
* Converting the `WitnessVector` back to a `WitnessMap` is unlikely to return the exact same `WitnessMap`.
*/
Expand Down
28 changes: 28 additions & 0 deletions barretenberg/cpp/src/barretenberg/dsl/acir_proofs/c_bind.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "c_bind.hpp"
#include "../acir_format/acir_to_constraint_buf.hpp"
#include "acir_composer.hpp"
#include "barretenberg/client_ivc/client_ivc.hpp"
#include "barretenberg/common/mem.hpp"
#include "barretenberg/common/net.hpp"
#include "barretenberg/common/serialize.hpp"
Expand Down Expand Up @@ -78,6 +79,33 @@ WASM_EXPORT void acir_prove_and_verify_ultra_honk(uint8_t const* acir_vec, uint8
*result = verifier.verify_proof(proof);
}

WASM_EXPORT void acir_fold_and_verify_program_stack(uint8_t const* acir_vec, uint8_t const* witness_vec, bool* result)
{
using ProgramStack = acir_format::AcirProgramStack;
using Builder = MegaCircuitBuilder;

auto constraint_systems = acir_format::program_buf_to_acir_format(from_buffer<std::vector<uint8_t>>(acir_vec));
auto witness_stack = acir_format::witness_buf_to_witness_stack(from_buffer<std::vector<uint8_t>>(witness_vec));

ProgramStack program_stack{ constraint_systems, witness_stack };

ClientIVC ivc;
ivc.structured_flag = true;

while (!program_stack.empty()) {
auto stack_item = program_stack.back();

// Construct a bberg circuit from the acir representation
auto builder = acir_format::create_circuit<Builder>(
stack_item.constraints, 0, stack_item.witness, false, ivc.goblin.op_queue);

ivc.accumulate(builder);

program_stack.pop_back();
}
*result = ivc.prove_and_verify();
}

WASM_EXPORT void acir_prove_and_verify_mega_honk(uint8_t const* acir_vec, uint8_t const* witness_vec, bool* result)
{
auto constraint_system = acir_format::circuit_buf_to_acir_format(from_buffer<std::vector<uint8_t>>(acir_vec));
Expand Down
Loading
Loading