From 004e170d8656c8670f10d1482a91acd5f4d406d2 Mon Sep 17 00:00:00 2001 From: Cody Date: Wed, 11 Dec 2024 15:12:44 +0000 Subject: [PATCH] Revert "feat: unified create circuit from acir (#10440)" This reverts commit a4dfe13c1c0af3d527f5c9b2fcc38fe059e9bc38. --- .../src/barretenberg/bb/api_client_ivc.hpp | 102 +++++--- barretenberg/cpp/src/barretenberg/bb/main.cpp | 113 ++++----- .../dsl/acir_format/acir_format.cpp | 218 +++++++++--------- .../dsl/acir_format/acir_format.hpp | 42 ++-- .../dsl/acir_format/acir_format.test.cpp | 14 +- .../dsl/acir_format/acir_integration.test.cpp | 30 +-- .../dsl/acir_format/block_constraint.cpp | 1 + .../dsl/acir_format/block_constraint.test.cpp | 34 +-- .../acir_format/ivc_recursion_constraint.cpp | 22 +- .../acir_format/ivc_recursion_constraint.hpp | 6 +- .../ivc_recursion_constraint.test.cpp | 149 ++++++------ .../barretenberg/dsl/acir_proofs/c_bind.cpp | 111 ++++----- 12 files changed, 436 insertions(+), 406 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/bb/api_client_ivc.hpp b/barretenberg/cpp/src/barretenberg/bb/api_client_ivc.hpp index 8d0705b91c0..8576f918d40 100644 --- a/barretenberg/cpp/src/barretenberg/bb/api_client_ivc.hpp +++ b/barretenberg/cpp/src/barretenberg/bb/api_client_ivc.hpp @@ -125,38 +125,79 @@ class ClientIVCAPI : public API { return folding_stack; }; - static std::shared_ptr _accumulate(std::vector& folding_stack, - bool auto_verify = false) + static ClientIVC _accumulate(std::vector& folding_stack) { using Builder = MegaCircuitBuilder; using Program = acir_format::AcirProgram; - using namespace acir_format; - vinfo("performing accumulation with auto-verify = ", auto_verify); + using namespace acir_format; - TraceSettings trace_settings{ E2E_FULL_TEST_STRUCTURE }; - auto ivc = std::make_shared(trace_settings, auto_verify); + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1163) set these dynamically + init_bn254_crs(1 << 20); + init_grumpkin_crs(1 << 15); - const ProgramMetadata metadata{ ivc }; + // TODO(#7371) dedupe this with the rest of the similar code + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1101): remove use of auto_verify_mode + ClientIVC ivc{ { E2E_FULL_TEST_STRUCTURE }, /*auto_verify_mode=*/true }; // Accumulate the entire program stack into the IVC // TODO(https://github.com/AztecProtocol/barretenberg/issues/1116): remove manual setting of is_kernel bool is_kernel = false; for (Program& program : folding_stack) { // Construct a bberg circuit from the acir representation then accumulate it into the IVC - Builder circuit = acir_format::create_circuit(program, metadata); + Builder circuit = acir_format::create_circuit( + program.constraints, true, 0, program.witness, false, ivc.goblin.op_queue); // Set the internal is_kernel flag based on the local mechanism only if it has not already been set to true - if (ivc->auto_verify_mode) { - if (!circuit.databus_propagation_data.is_kernel) { - circuit.databus_propagation_data.is_kernel = is_kernel; - } - is_kernel = !is_kernel; + if (!circuit.databus_propagation_data.is_kernel) { + circuit.databus_propagation_data.is_kernel = is_kernel; } + is_kernel = !is_kernel; // Do one step of ivc accumulator or, if there is only one circuit in the stack, prove that circuit. In this // case, no work is added to the Goblin opqueue, but VM proofs for trivials inputs are produced. - ivc->accumulate(circuit, /*one_circuit=*/folding_stack.size() == 1); + ivc.accumulate(circuit, /*one_circuit=*/folding_stack.size() == 1); + } + + return ivc; + }; + + static ClientIVC _accumulate_without_auto_verify(std::vector& folding_stack) + { + using Builder = MegaCircuitBuilder; + using Program = acir_format::AcirProgram; + + using namespace acir_format; + + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1163) set these dynamically + init_bn254_crs(1 << 20); + init_grumpkin_crs(1 << 15); + + // TODO(#7371) dedupe this with the rest of the similar code + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1101): remove use of auto_verify_mode + ClientIVC ivc{ { E2E_FULL_TEST_STRUCTURE }, /*auto_verify_mode=*/false }; + + // Accumulate the entire program stack into the IVC + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1116): remove manual setting of is_kernel once + // databus has been integrated into noir kernel programs + bool is_kernel = false; + for (Program& program : folding_stack) { + + Builder circuit; + + is_kernel = !program.constraints.ivc_recursion_constraints.empty(); + if (is_kernel) { + vinfo("Accumulating KERNEL."); + circuit = create_kernel_circuit(program.constraints, ivc, program.witness); + } else { + vinfo("Accumulating APP."); + circuit = create_circuit( + program.constraints, /*recursive=*/false, 0, program.witness, false, ivc.goblin.op_queue); + } + + // Do one step of ivc accumulator or, if there is only one circuit in the stack, prove that circuit. In this + // case, no work is added to the Goblin opqueue, but VM proofs for trivial inputs are produced. + ivc.accumulate(circuit, /*one_circuit=*/folding_stack.size() == 1); } return ivc; @@ -176,27 +217,33 @@ class ClientIVCAPI : public API { throw_or_abort("No input_type or input_type not supported"); } + std::vector folding_stack = + _build_folding_stack(*flags.input_type, bytecode_path, witness_path); + // TODO(https://github.com/AztecProtocol/barretenberg/issues/1163) set these dynamically init_bn254_crs(1 << 20); init_grumpkin_crs(1 << 15); - std::vector folding_stack = - _build_folding_stack(*flags.input_type, bytecode_path, witness_path); - - bool auto_verify = !flags.no_auto_verify; - std::shared_ptr ivc = _accumulate(folding_stack, auto_verify); - ClientIVC::Proof proof = ivc->prove(); + ClientIVC ivc; + if (flags.no_auto_verify) { + vinfo("performing accumulation WITHOUT auto-verify"); + ivc = _accumulate_without_auto_verify(folding_stack); + } else { + vinfo("performing accumulation with auto-verify"); + ivc = _accumulate(folding_stack); + } + ClientIVC::Proof proof = ivc.prove(); // Write the proof and verification keys into the working directory in 'binary' format (in practice it seems // this directory is passed by bb.js) vinfo("writing ClientIVC proof and vk..."); write_file(output_dir / "client_ivc_proof", to_buffer(proof)); - auto eccvm_vk = std::make_shared(ivc->goblin.get_eccvm_proving_key()); + auto eccvm_vk = std::make_shared(ivc.goblin.get_eccvm_proving_key()); auto translator_vk = - std::make_shared(ivc->goblin.get_translator_proving_key()); + std::make_shared(ivc.goblin.get_translator_proving_key()); write_file(output_dir / "client_ivc_vk", - to_buffer(ClientIVC::VerificationKey{ ivc->honk_vk, eccvm_vk, translator_vk })); + to_buffer(ClientIVC::VerificationKey{ ivc.honk_vk, eccvm_vk, translator_vk })); }; /** @@ -239,15 +286,10 @@ class ClientIVCAPI : public API { if (!flags.input_type || !(*flags.input_type == "compiletime_stack" || *flags.input_type == "runtime_stack")) { throw_or_abort("No input_type or input_type not supported"); } - - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1163) set these dynamically - init_bn254_crs(1 << 20); - init_grumpkin_crs(1 << 15); - std::vector folding_stack = _build_folding_stack(*flags.input_type, bytecode_path, witness_path); - std::shared_ptr ivc = _accumulate(folding_stack, /*auto_verify=*/true); - const bool verified = ivc->prove_and_verify(); + ClientIVC ivc = _accumulate(folding_stack); + const bool verified = ivc.prove_and_verify(); return verified; }; diff --git a/barretenberg/cpp/src/barretenberg/bb/main.cpp b/barretenberg/cpp/src/barretenberg/bb/main.cpp index eb1200e7f8e..0ff6e1363db 100644 --- a/barretenberg/cpp/src/barretenberg/bb/main.cpp +++ b/barretenberg/cpp/src/barretenberg/bb/main.cpp @@ -110,15 +110,21 @@ bool proveAndVerify(const std::string& bytecodePath, const bool recursive, const } template -bool proveAndVerifyHonkAcirFormat(acir_format::AcirProgram program, acir_format::ProgramMetadata metadata) +bool proveAndVerifyHonkAcirFormat(acir_format::AcirFormat constraint_system, + const bool recursive, + acir_format::WitnessVector witness) { using Builder = Flavor::CircuitBuilder; using Prover = UltraProver_; using Verifier = UltraVerifier_; using VerificationKey = Flavor::VerificationKey; + bool honk_recursion = false; + if constexpr (IsAnyOf) { + honk_recursion = true; + } // Construct a bberg circuit from the acir representation - auto builder = acir_format::create_circuit(program, metadata); + auto builder = acir_format::create_circuit(constraint_system, recursive, 0, witness, honk_recursion); // Construct Honk proof Prover prover{ builder }; @@ -143,15 +149,15 @@ bool proveAndVerifyHonkAcirFormat(acir_format::AcirProgram program, acir_format: template bool proveAndVerifyHonk(const std::string& bytecodePath, const bool recursive, const std::string& witnessPath) { - constexpr bool honk_recursion = IsAnyOf; - const acir_format::ProgramMetadata metadata{ .recursive = recursive, .honk_recursion = honk_recursion }; - + bool honk_recursion = false; + if constexpr (IsAnyOf) { + honk_recursion = true; + } // Populate the acir constraint system and witness from gzipped data - acir_format::AcirProgram program; - program.constraints = get_constraint_system(bytecodePath, metadata.honk_recursion); - program.witness = get_witness(witnessPath); + auto constraint_system = get_constraint_system(bytecodePath, honk_recursion); + auto witness = get_witness(witnessPath); - return proveAndVerifyHonkAcirFormat(program, metadata); + return proveAndVerifyHonkAcirFormat(constraint_system, recursive, witness); } /** @@ -165,14 +171,14 @@ bool proveAndVerifyHonk(const std::string& bytecodePath, const bool recursive, c template bool proveAndVerifyHonkProgram(const std::string& bytecodePath, const bool recursive, const std::string& witnessPath) { - constexpr bool honk_recursion = IsAnyOf; - const acir_format::ProgramMetadata metadata{ .recursive = recursive, .honk_recursion = honk_recursion }; - - auto program_stack = acir_format::get_acir_program_stack(bytecodePath, witnessPath, metadata.honk_recursion); - + bool honk_recursion = false; + if constexpr (IsAnyOf) { + honk_recursion = true; + } + auto program_stack = acir_format::get_acir_program_stack(bytecodePath, witnessPath, honk_recursion); while (!program_stack.empty()) { - auto program = program_stack.back(); - if (!proveAndVerifyHonkAcirFormat(program, metadata)) { + auto stack_item = program_stack.back(); + if (!proveAndVerifyHonkAcirFormat(stack_item.constraints, recursive, stack_item.witness)) { return false; } program_stack.pop_back(); @@ -323,29 +329,25 @@ void gateCount(const std::string& bytecodePath, bool recursive, bool honk_recurs // All circuit reports will be built into the string below std::string functions_string = "{\"functions\": [\n "; auto constraint_systems = get_constraint_systems(bytecodePath, honk_recursion); - - const acir_format::ProgramMetadata metadata{ .recursive = recursive, - .honk_recursion = honk_recursion, - .collect_gates_per_opcode = true }; size_t i = 0; - for (const auto& constraint_system : constraint_systems) { - acir_format::AcirProgram program{ constraint_system }; - auto builder = acir_format::create_circuit(program, metadata); + for (auto constraint_system : constraint_systems) { + auto builder = acir_format::create_circuit( + constraint_system, recursive, 0, {}, honk_recursion, std::make_shared(), true); builder.finalize_circuit(/*ensure_nonzero=*/true); size_t circuit_size = builder.num_gates; vinfo("Calculated circuit size in gateCount: ", circuit_size); // Build individual circuit report std::string gates_per_opcode_str; - for (size_t j = 0; j < program.constraints.gates_per_opcode.size(); j++) { - gates_per_opcode_str += std::to_string(program.constraints.gates_per_opcode[j]); - if (j != program.constraints.gates_per_opcode.size() - 1) { + for (size_t j = 0; j < constraint_system.gates_per_opcode.size(); j++) { + gates_per_opcode_str += std::to_string(constraint_system.gates_per_opcode[j]); + if (j != constraint_system.gates_per_opcode.size() - 1) { gates_per_opcode_str += ","; } } auto result_string = format("{\n \"acir_opcodes\": ", - program.constraints.num_acir_opcodes, + constraint_system.num_acir_opcodes, ",\n \"circuit_size\": ", circuit_size, ",\n \"gates_per_opcode\": [", @@ -711,15 +713,17 @@ UltraProver_ compute_valid_prover(const std::string& bytecodePath, using Builder = Flavor::CircuitBuilder; using Prover = UltraProver_; - constexpr bool honk_recursion = IsAnyOf; - const acir_format::ProgramMetadata metadata{ .recursive = recursive, .honk_recursion = honk_recursion }; - - acir_format::AcirProgram program{ get_constraint_system(bytecodePath, metadata.honk_recursion) }; + bool honk_recursion = false; + if constexpr (IsAnyOf) { + honk_recursion = true; + } + auto constraint_system = get_constraint_system(bytecodePath, honk_recursion); + acir_format::WitnessVector witness = {}; if (!witnessPath.empty()) { - program.witness = get_witness(witnessPath); + witness = get_witness(witnessPath); } - auto builder = acir_format::create_circuit(program, metadata); + auto builder = acir_format::create_circuit(constraint_system, recursive, 0, witness, honk_recursion); auto prover = Prover{ builder }; init_bn254_crs(prover.proving_key->proving_key.circuit_size); return std::move(prover); @@ -842,23 +846,28 @@ void write_vk_for_ivc(const std::string& bytecodePath, const std::string& output using Prover = ClientIVC::MegaProver; using DeciderProvingKey = ClientIVC::DeciderProvingKey; using VerificationKey = ClientIVC::MegaVerificationKey; - using Program = acir_format::AcirProgram; - using ProgramMetadata = acir_format::ProgramMetadata; // TODO(https://github.com/AztecProtocol/barretenberg/issues/1163) set these dynamically init_bn254_crs(1 << 20); init_grumpkin_crs(1 << 15); - Program program{ get_constraint_system(bytecodePath, /*honk_recursion=*/false), /*witness=*/{} }; - auto& ivc_constraints = program.constraints.ivc_recursion_constraints; + auto constraints = get_constraint_system(bytecodePath, /*honk_recursion=*/false); + acir_format::WitnessVector witness = {}; TraceSettings trace_settings{ E2E_FULL_TEST_STRUCTURE }; - const ProgramMetadata metadata{ .ivc = ivc_constraints.empty() - ? nullptr - : create_mock_ivc_from_constraints(ivc_constraints, trace_settings) }; - Builder builder = acir_format::create_circuit(program, metadata); + // The presence of ivc recursion constraints determines whether or not the program is a kernel + bool is_kernel = !constraints.ivc_recursion_constraints.empty(); + Builder builder; + if (is_kernel) { + // Create a mock IVC instance based on the IVC recursion constraints in the kernel program + ClientIVC mock_ivc = create_mock_ivc_from_constraints(constraints.ivc_recursion_constraints, trace_settings); + builder = acir_format::create_kernel_circuit(constraints, mock_ivc, witness); + } else { + builder = acir_format::create_circuit( + constraints, /*recursive=*/false, 0, witness, /*honk_recursion=*/false); + } // Add public inputs corresponding to pairing point accumulator builder.add_pairing_point_accumulator(stdlib::recursion::init_default_agg_obj_indices(builder)); @@ -898,12 +907,10 @@ void write_recursion_inputs_honk(const std::string& bytecodePath, using VerificationKey = Flavor::VerificationKey; using FF = Flavor::FF; - const acir_format::ProgramMetadata metadata{ .recursive = recursive, .honk_recursion = true }; - - acir_format::AcirProgram program; - program.constraints = get_constraint_system(bytecodePath, metadata.honk_recursion); - program.witness = get_witness(witnessPath); - auto builder = acir_format::create_circuit(program, metadata); + bool honk_recursion = true; + auto constraints = get_constraint_system(bytecodePath, honk_recursion); + auto witness = get_witness(witnessPath); + auto builder = acir_format::create_circuit(constraints, recursive, 0, witness, honk_recursion); // Construct Honk proof and verification key Prover prover{ builder }; @@ -1051,13 +1058,15 @@ void prove_honk_output_all(const std::string& bytecodePath, using Prover = UltraProver_; using VerificationKey = Flavor::VerificationKey; - constexpr bool honk_recursion = IsAnyOf; - const acir_format::ProgramMetadata metadata{ .recursive = recursive, .honk_recursion = honk_recursion }; + bool honk_recursion = false; + if constexpr (IsAnyOf) { + honk_recursion = true; + } - acir_format::AcirProgram program{ get_constraint_system(bytecodePath, metadata.honk_recursion), - get_witness(witnessPath) }; + auto constraint_system = get_constraint_system(bytecodePath, honk_recursion); + auto witness = get_witness(witnessPath); - auto builder = acir_format::create_circuit(program, metadata); + auto builder = acir_format::create_circuit(constraint_system, recursive, 0, witness, honk_recursion); // Construct Honk proof Prover prover{ builder }; diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp index 1a8f5d7f43f..a4a864625ca 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp @@ -19,12 +19,12 @@ template class DSLBigInts; template class DSLBigInts; template -void build_constraints(Builder& builder, AcirProgram& program, const ProgramMetadata& metadata) +void build_constraints(Builder& builder, + AcirFormat& constraint_system, + bool has_valid_witness_assignments, + bool honk_recursion, + bool collect_gates_per_opcode) { - bool has_valid_witness_assignments = !program.witness.empty(); - bool collect_gates_per_opcode = metadata.collect_gates_per_opcode; - AcirFormat& constraint_system = program.constraints; - if (collect_gates_per_opcode) { constraint_system.gates_per_opcode.resize(constraint_system.num_acir_opcodes, 0); } @@ -231,9 +231,6 @@ void build_constraints(Builder& builder, AcirProgram& program, const ProgramMeta if (!constraint_system.avm_recursion_constraints.empty()) { info("WARNING: this circuit contains unhandled avm_recursion_constraints!"); } - if (!constraint_system.ivc_recursion_constraints.empty()) { - process_ivc_recursion_constraints(builder, constraint_system, metadata.ivc, has_valid_witness_assignments); - } } else { process_plonk_recursion_constraints(builder, constraint_system, has_valid_witness_assignments, gate_counter); PairingPointAccumulatorIndices current_aggregation_object = @@ -249,9 +246,9 @@ void build_constraints(Builder& builder, AcirProgram& program, const ProgramMeta // default one if the circuit is recursive and honk_recursion is true. if (!constraint_system.honk_recursion_constraints.empty() || !constraint_system.avm_recursion_constraints.empty()) { - ASSERT(metadata.honk_recursion); + ASSERT(honk_recursion); builder.add_pairing_point_accumulator(current_aggregation_object); - } else if (metadata.honk_recursion && builder.is_recursive_circuit) { + } else if (honk_recursion && builder.is_recursive_circuit) { // Make sure the verification key records the public input indices of the // final recursion output. builder.add_pairing_point_accumulator(current_aggregation_object); @@ -395,59 +392,6 @@ PairingPointAccumulatorIndices process_honk_recursion_constraints( return current_aggregation_object; } -void process_ivc_recursion_constraints(MegaCircuitBuilder& builder, - AcirFormat& constraints, - const std::shared_ptr& ivc, - bool has_valid_witness_assignments) -{ - using StdlibVerificationKey = ClientIVC::RecursiveVerificationKey; - - // We expect the length of the internal verification queue to match the number of ivc recursion constraints - if (constraints.ivc_recursion_constraints.size() != ivc->verification_queue.size()) { - info("WARNING: Mismatch in number of recursive verifications during kernel creation!"); - ASSERT(false); - } - - // If no witness is provided, populate the VK and public inputs in the recursion constraint with dummy values so - // that the present kernel circuit is constructed correctly. (Used for constructing VKs without witnesses). - if (!has_valid_witness_assignments) { - // Create stdlib representations of each {proof, vkey} pair to be recursively verified - for (auto [constraint, queue_entry] : - zip_view(constraints.ivc_recursion_constraints, ivc->verification_queue)) { - populate_dummy_vk_in_constraint(builder, queue_entry.honk_verification_key, constraint.key); - } - } - - // Construct a stdlib verification key for each constraint based on the verification key witness indices therein - std::vector> stdlib_verification_keys; - stdlib_verification_keys.reserve(constraints.ivc_recursion_constraints.size()); - for (const auto& constraint : constraints.ivc_recursion_constraints) { - stdlib_verification_keys.push_back(std::make_shared( - StdlibVerificationKey::from_witness_indices(builder, constraint.key))); - } - // Create stdlib representations of each {proof, vkey} pair to be recursively verified - ivc->instantiate_stdlib_verification_queue(builder, stdlib_verification_keys); - - // Connect the public_input witnesses in each constraint to the corresponding public input witnesses in the internal - // verification queue. This ensures that the witnesses utlized in constraints generated based on acir are properly - // connected to the constraints generated herein via the ivc scheme (e.g. recursive verifications). - for (auto [constraint, queue_entry] : - zip_view(constraints.ivc_recursion_constraints, ivc->stdlib_verification_queue)) { - - // Get the witness indices for the public inputs contained within the proof in the verification queue - std::vector public_input_indices = ProofSurgeon::get_public_inputs_witness_indices_from_proof( - queue_entry.proof, constraint.public_inputs.size()); - - // Assert equality between the internal public input witness indices and those in the acir constraint - for (auto [witness_idx, constraint_witness_idx] : zip_view(public_input_indices, constraint.public_inputs)) { - builder.assert_equal(witness_idx, constraint_witness_idx); - } - } - - // Complete the kernel circuit with all required recursive verifications, databus consistency checks etc. - ivc->complete_kernel_circuit_logic(builder); -} - #ifndef DISABLE_AZTEC_VM PairingPointAccumulatorIndices process_avm_recursion_constraints( Builder& builder, @@ -470,19 +414,28 @@ PairingPointAccumulatorIndices process_avm_recursion_constraints( #endif // DISABLE_AZTEC_VM /** - * @brief Specialization for creating an Ultra circuit from an acir program + * @brief Specialization for creating Ultra circuit from acir constraints and optionally a witness * - * @param program constraints and optionally a witness - * @param metadata additional data needed to construct the circuit + * @tparam Builder + * @param constraint_system + * @param size_hint + * @param witness + * @return Builder */ -template <> UltraCircuitBuilder create_circuit(AcirProgram& program, const ProgramMetadata& metadata) +template <> +UltraCircuitBuilder create_circuit(AcirFormat& constraint_system, + bool recursive, + const size_t size_hint, + const WitnessVector& witness, + bool honk_recursion, + [[maybe_unused]] std::shared_ptr, + bool collect_gates_per_opcode) { - AcirFormat& constraints = program.constraints; - WitnessVector& witness = program.witness; - - Builder builder{ metadata.size_hint, witness, constraints.public_inputs, constraints.varnum, metadata.recursive }; + Builder builder{ size_hint, witness, constraint_system.public_inputs, constraint_system.varnum, recursive }; - build_constraints(builder, program, metadata); + bool has_valid_witness_assignments = !witness.empty(); + build_constraints( + builder, constraint_system, has_valid_witness_assignments, honk_recursion, collect_gates_per_opcode); vinfo("created circuit"); @@ -490,59 +443,114 @@ template <> UltraCircuitBuilder create_circuit(AcirProgram& program, const Progr }; /** - * @brief Specialization for creating a Mega circuit from an acir program + * @brief Specialization for creating Mega circuit from acir constraints and optionally a witness * - * @param program constraints and optionally a witness - * @param metadata additional data needed to construct the circuit + * @tparam Builder + * @param constraint_system + * @param size_hint + * @param witness + * @return Builder */ -template <> MegaCircuitBuilder create_circuit(AcirProgram& program, const ProgramMetadata& metadata) +template <> +MegaCircuitBuilder create_circuit(AcirFormat& constraint_system, + [[maybe_unused]] bool recursive, + [[maybe_unused]] const size_t size_hint, + const WitnessVector& witness, + bool honk_recursion, + std::shared_ptr op_queue, + bool collect_gates_per_opcode) { - AcirFormat& constraints = program.constraints; - WitnessVector& witness = program.witness; - - auto op_queue = (metadata.ivc == nullptr) ? std::make_shared() : metadata.ivc->goblin.op_queue; - // Construct a builder using the witness and public input data from acir and with the goblin-owned op_queue - auto builder = MegaCircuitBuilder{ op_queue, witness, constraints.public_inputs, constraints.varnum }; + auto builder = MegaCircuitBuilder{ op_queue, witness, constraint_system.public_inputs, constraint_system.varnum }; // Populate constraints in the builder via the data in constraint_system - build_constraints(builder, program, metadata); + bool has_valid_witness_assignments = !witness.empty(); + acir_format::build_constraints( + builder, constraint_system, has_valid_witness_assignments, honk_recursion, collect_gates_per_opcode); return builder; }; /** - * @brief Specialization for creating Ultra circuit from acir constraints and optionally a witness + * @brief Create a kernel circuit from a constraint system and an IVC instance + * @details This method processes ivc_recursion_constraints using the kernel completion logic contained in ClientIVC. + * Since verification keys are known at the time of acir generation, the verification key witnesses contained in the + * constraints are used directly to instantiate the recursive verifiers. On the other hand, the proof witnesses + * contained in the constraints are generally 'dummy' values since proofs are not known during acir generation (with the + * exception of public inputs). This is remedied by connecting the dummy proof witnesses to the genuine proof witnesses, + * known internally to the IVC class, via copy constraints. * - * @tparam Builder - * @param constraint_system + * @param constraint_system AcirFormat constraint system possibly containing IVC recursion constraints + * @param ivc An IVC instance containing internal data about proofs to be verified * @param size_hint * @param witness - * @return Builder + * @return MegaCircuitBuilder */ -template <> -UltraCircuitBuilder create_circuit(AcirFormat& constraint_system, - bool recursive, - const size_t size_hint, - const WitnessVector& witness, - bool honk_recursion, - [[maybe_unused]] std::shared_ptr, - bool collect_gates_per_opcode) +MegaCircuitBuilder create_kernel_circuit(AcirFormat& constraint_system, + ClientIVC& ivc, + const WitnessVector& witness, + const size_t size_hint) { - Builder builder{ size_hint, witness, constraint_system.public_inputs, constraint_system.varnum, recursive }; + using StdlibVerificationKey = ClientIVC::RecursiveVerificationKey; - AcirProgram program{ constraint_system, witness }; - const ProgramMetadata metadata{ .recursive = recursive, - .honk_recursion = honk_recursion, - .collect_gates_per_opcode = collect_gates_per_opcode, - .size_hint = size_hint }; - build_constraints(builder, program, metadata); + // Construct the main kernel circuit logic excluding recursive verifiers + auto circuit = create_circuit(constraint_system, + /*recursive=*/false, + size_hint, + witness, + /*honk_recursion=*/false, + ivc.goblin.op_queue, + /*collect_gates_per_opcode=*/false); - vinfo("created circuit"); + // We expect the length of the internal verification queue to match the number of ivc recursion constraints + if (constraint_system.ivc_recursion_constraints.size() != ivc.verification_queue.size()) { + info("WARNING: Mismatch in number of recursive verifications during kernel creation!"); + ASSERT(false); + } - return builder; + // If no witness is provided, populate the VK and public inputs in the recursion constraint with dummy values so + // that the present kernel circuit is constructed correctly. (Used for constructing VKs without witnesses). + if (witness.empty()) { + // Create stdlib representations of each {proof, vkey} pair to be recursively verified + for (auto [constraint, queue_entry] : + zip_view(constraint_system.ivc_recursion_constraints, ivc.verification_queue)) { + + populate_dummy_vk_in_constraint(circuit, queue_entry.honk_verification_key, constraint.key); + } + } + + // Construct a stdlib verification key for each constraint based on the verification key witness indices therein + std::vector> stdlib_verification_keys; + stdlib_verification_keys.reserve(constraint_system.ivc_recursion_constraints.size()); + for (const auto& constraint : constraint_system.ivc_recursion_constraints) { + stdlib_verification_keys.push_back(std::make_shared( + StdlibVerificationKey::from_witness_indices(circuit, constraint.key))); + } + // Create stdlib representations of each {proof, vkey} pair to be recursively verified + ivc.instantiate_stdlib_verification_queue(circuit, stdlib_verification_keys); + + // Connect the public_input witnesses in each constraint to the corresponding public input witnesses in the internal + // verification queue. This ensures that the witnesses utlized in constraints generated based on acir are properly + // connected to the constraints generated herein via the ivc scheme (e.g. recursive verifications). + for (auto [constraint, queue_entry] : + zip_view(constraint_system.ivc_recursion_constraints, ivc.stdlib_verification_queue)) { + + // Get the witness indices for the public inputs contained within the proof in the verification queue + std::vector public_input_indices = ProofSurgeon::get_public_inputs_witness_indices_from_proof( + queue_entry.proof, constraint.public_inputs.size()); + + // Assert equality between the internal public input witness indices and those in the acir constraint + for (auto [witness_idx, constraint_witness_idx] : zip_view(public_input_indices, constraint.public_inputs)) { + circuit.assert_equal(witness_idx, constraint_witness_idx); + } + } + + // Complete the kernel circuit with all required recursive verifications, databus consistency checks etc. + ivc.complete_kernel_circuit_logic(circuit); + + return circuit; }; -template void build_constraints(MegaCircuitBuilder&, AcirProgram&, const ProgramMetadata&); +template void build_constraints(MegaCircuitBuilder&, AcirFormat&, bool, bool, bool); } // namespace acir_format diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.hpp index 6a6c6efd7da..aaa7d40ac0b 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.hpp @@ -160,7 +160,7 @@ using WitnessVectorStack = std::vector>; struct AcirProgram { AcirFormat constraints; - WitnessVector witness = {}; + WitnessVector witness; }; /** @@ -193,27 +193,6 @@ struct AcirProgramStack { void pop_back() { witness_stack.pop_back(); } }; -struct ProgramMetadata { - - // An IVC instance; needed to construct a circuit from IVC recursion constraints - std::shared_ptr ivc = nullptr; - - bool recursive = false; // Specifies whether a prover that produces SNARK recursion friendly proofs should be used. - // The proof produced when this flag is true should be friendly for recursive verification - // inside of another SNARK. For example, a recursive friendly proof may use Blake3Pedersen - // for hashing in its transcript, while we still want a prove that uses Keccak for its - // transcript in order to be able to verify SNARKs on Ethereum. - bool honk_recursion = false; // honk_recursion means we will honk to recursively verify this - // circuit. This distinction is needed to not add the default - // aggregation object when we're not using the honk RV. - bool collect_gates_per_opcode = false; - size_t size_hint = 0; -}; - -// TODO(https://github.com/AztecProtocol/barretenberg/issues/1161) Refactor this function -template -Builder create_circuit(AcirProgram& program, const ProgramMetadata& metadata = ProgramMetadata{}); - // TODO(https://github.com/AztecProtocol/barretenberg/issues/1161) Refactor this function template Builder create_circuit(AcirFormat& constraint_system, @@ -229,8 +208,20 @@ Builder create_circuit(AcirFormat& constraint_system, std::shared_ptr op_queue = std::make_shared(), bool collect_gates_per_opcode = false); +MegaCircuitBuilder create_kernel_circuit(AcirFormat& constraint_system, + ClientIVC& ivc, + const WitnessVector& witness = {}, + const size_t size_hint = 0); + template -void build_constraints(Builder& builder, AcirProgram& program, const ProgramMetadata& metadata); +void build_constraints( + Builder& builder, + AcirFormat& constraint_system, + bool has_valid_witness_assignments, + bool honk_recursion = false, + bool collect_gates_per_opcode = false); // honk_recursion means we will honk to recursively verify this + // circuit. This distinction is needed to not add the default + // aggregation object when we're not using the honk RV. /** * @brief Utility class for tracking the gate count of acir constraints @@ -276,11 +267,6 @@ void process_honk_recursion_constraints(Builder& builder, bool has_valid_witness_assignments, GateCounter& gate_counter); -void process_ivc_recursion_constraints(MegaCircuitBuilder& builder, - AcirFormat& constraints, - ClientIVC* ivc, - bool has_valid_witness_assignments); - #ifndef DISABLE_AZTEC_VM void process_avm_recursion_constraints(Builder& builder, AcirFormat& constraint_system, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp index c2f9d7d997e..87e95cbcd8a 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp @@ -341,11 +341,15 @@ TEST_F(AcirFormatTests, TestCollectsGateCounts) }; mock_opcode_indices(constraint_system); WitnessVector witness{ 5, 27, 32 }; - AcirProgram program{ constraint_system, witness }; - const ProgramMetadata metadata{ .collect_gates_per_opcode = true }; - auto builder = create_circuit(program, metadata); - - EXPECT_EQ(program.constraints.gates_per_opcode, std::vector({ 2, 1 })); + auto builder = create_circuit(constraint_system, + /*recursive*/ false, + /*size_hint*/ 0, + witness, + false, + std::make_shared(), + true); + + EXPECT_EQ(constraint_system.gates_per_opcode, std::vector({ 2, 1 })); } TEST_F(AcirFormatTests, TestBigAdd) diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_integration.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_integration.test.cpp index 3ed1f1df1c8..45bf0703edb 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_integration.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_integration.test.cpp @@ -154,7 +154,8 @@ TEST_P(AcirIntegrationSingleTest, DISABLED_ProveAndVerifyProgram) false); // TODO(https://github.com/AztecProtocol/barretenberg/issues/1013): Assumes Flavor is not UltraHonk // Construct a bberg circuit from the acir representation - Builder builder = acir_format::create_circuit(acir_program); + Builder builder = + acir_format::create_circuit(acir_program.constraints, /*recursive*/ false, 0, acir_program.witness); // Construct and verify Honk proof if constexpr (IsPlonkFlavor) { @@ -379,7 +380,8 @@ TEST_P(AcirIntegrationFoldingTest, DISABLED_ProveAndVerifyProgramStack) auto program = program_stack.back(); // Construct a bberg circuit from the acir representation - auto builder = acir_format::create_circuit(program); + auto builder = + acir_format::create_circuit(program.constraints, /*recursive*/ false, 0, program.witness); // Construct and verify Honk proof for the individidual circuit EXPECT_TRUE(prove_and_verify_honk(builder)); @@ -398,18 +400,16 @@ TEST_P(AcirIntegrationFoldingTest, DISABLED_FoldAndVerifyProgramStack) test_name, /*honk_recursion=*/false); // TODO(https://github.com/AztecProtocol/barretenberg/issues/1013): // Assumes Flavor is not UltraHonk - TraceSettings trace_settings{ SMALL_TEST_STRUCTURE }; - auto ivc = std::make_shared(trace_settings, /*auto_verify_mode=*/true); - - const acir_format::ProgramMetadata metadata{ ivc }; + ClientIVC ivc{ { SMALL_TEST_STRUCTURE }, /*auto_verify_mode=*/true }; while (!program_stack.empty()) { auto program = program_stack.back(); // Construct a bberg circuit from the acir representation - auto circuit = acir_format::create_circuit(program, metadata); + auto circuit = acir_format::create_circuit( + program.constraints, /*recursive*/ false, 0, program.witness, false, ivc.goblin.op_queue); - ivc->accumulate(circuit); + ivc.accumulate(circuit); CircuitChecker::check(circuit); // EXPECT_TRUE(prove_and_verify_honk(circuit)); @@ -417,7 +417,7 @@ TEST_P(AcirIntegrationFoldingTest, DISABLED_FoldAndVerifyProgramStack) program_stack.pop_back(); } - EXPECT_TRUE(ivc->prove_and_verify()); + EXPECT_TRUE(ivc.prove_and_verify()); } INSTANTIATE_TEST_SUITE_P(AcirTests, @@ -438,7 +438,8 @@ TEST_F(AcirIntegrationTest, DISABLED_Databus) acir_format::AcirProgram acir_program = get_program_data_from_test_file(test_name); // Construct a bberg circuit from the acir representation - Builder builder = acir_format::create_circuit(acir_program); + Builder builder = + acir_format::create_circuit(acir_program.constraints, /*recursive*/ false, 0, acir_program.witness); // This prints a summary of the types of gates in the circuit builder.blocks.summarize(); @@ -462,7 +463,8 @@ TEST_F(AcirIntegrationTest, DISABLED_DatabusTwoCalldata) acir_format::AcirProgram acir_program = get_program_data_from_test_file(test_name); // Construct a bberg circuit from the acir representation - Builder builder = acir_format::create_circuit(acir_program); + Builder builder = + acir_format::create_circuit(acir_program.constraints, /*recursive*/ false, 0, acir_program.witness); // Check that the databus columns in the builder have been populated as expected const auto& calldata = builder.get_calldata(); @@ -516,7 +518,8 @@ TEST_F(AcirIntegrationTest, DISABLED_UpdateAcirCircuit) // Assumes Flavor is not UltraHonk // Construct a bberg circuit from the acir representation - Builder circuit = acir_format::create_circuit(acir_program); + auto circuit = + acir_format::create_circuit(acir_program.constraints, /*recursive*/ false, 0, acir_program.witness); EXPECT_TRUE(CircuitChecker::check(circuit)); @@ -555,7 +558,8 @@ TEST_F(AcirIntegrationTest, DISABLED_HonkRecursion) /*honk_recursion=*/false); // Construct a bberg circuit from the acir representation - Builder circuit = acir_format::create_circuit(acir_program); + auto circuit = + acir_format::create_circuit(acir_program.constraints, /*recursive*/ false, 0, acir_program.witness); EXPECT_TRUE(CircuitChecker::check(circuit)); EXPECT_TRUE(prove_and_verify_honk(circuit)); diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/block_constraint.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/block_constraint.cpp index b39d9e33882..d6bf0d93323 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/block_constraint.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/block_constraint.cpp @@ -87,6 +87,7 @@ void create_block_constraints(MegaCircuitBuilder& builder, // The presence of calldata is used to indicate that the present circuit is a kernel. This is needed in the // databus consistency checks to indicate that the corresponding return data belongs to a kernel (else an app). // TODO(https://github.com/AztecProtocol/barretenberg/issues/1165): is_kernel must be known prior to this stage + // since we must determine whether to use create_circuit or create_kernel_circuit. Resolve. builder.databus_propagation_data.is_kernel = true; } break; case BlockType::ReturnData: { diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/block_constraint.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/block_constraint.test.cpp index 53ae075c146..6eed50bf027 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/block_constraint.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/block_constraint.test.cpp @@ -136,9 +136,9 @@ size_t generate_block_constraint(BlockConstraint& constraint, WitnessVector& wit TEST_F(UltraPlonkRAM, TestBlockConstraint) { BlockConstraint block; - AcirProgram program; - size_t num_variables = generate_block_constraint(block, program.witness); - program.constraints = { + WitnessVector witness_values; + size_t num_variables = generate_block_constraint(block, witness_values); + AcirFormat constraint_system{ .varnum = static_cast(num_variables), .num_acir_opcodes = 7, .public_inputs = {}, @@ -169,9 +169,9 @@ TEST_F(UltraPlonkRAM, TestBlockConstraint) .block_constraints = { block }, .original_opcode_indices = create_empty_original_opcode_indices(), }; - mock_opcode_indices(program.constraints); + mock_opcode_indices(constraint_system); - auto builder = create_circuit(program); + auto builder = create_circuit(constraint_system, /*recursive*/ false, /*size_hint*/ 0, witness_values); auto composer = Composer(); auto prover = composer.create_prover(builder); @@ -184,11 +184,11 @@ TEST_F(UltraPlonkRAM, TestBlockConstraint) TEST_F(MegaHonk, Databus) { BlockConstraint block; - AcirProgram program; - size_t num_variables = generate_block_constraint(block, program.witness); + WitnessVector witness_values; + size_t num_variables = generate_block_constraint(block, witness_values); block.type = BlockType::CallData; - program.constraints = { + AcirFormat constraint_system{ .varnum = static_cast(num_variables), .num_acir_opcodes = 1, .public_inputs = {}, @@ -219,10 +219,10 @@ TEST_F(MegaHonk, Databus) .block_constraints = { block }, .original_opcode_indices = create_empty_original_opcode_indices(), }; - mock_opcode_indices(program.constraints); + mock_opcode_indices(constraint_system); // Construct a bberg circuit from the acir representation - auto circuit = create_circuit(program); + auto circuit = acir_format::create_circuit(constraint_system, /*recursive*/ false, 0, witness_values); EXPECT_TRUE(prove_and_verify(circuit)); } @@ -230,8 +230,8 @@ TEST_F(MegaHonk, Databus) TEST_F(MegaHonk, DatabusReturn) { BlockConstraint block; - AcirProgram program; - size_t num_variables = generate_block_constraint(block, program.witness); + WitnessVector witness_values; + size_t num_variables = generate_block_constraint(block, witness_values); block.type = BlockType::CallData; poly_triple rd_index{ @@ -244,7 +244,7 @@ TEST_F(MegaHonk, DatabusReturn) .q_o = 0, .q_c = 0, }; - program.witness.emplace_back(0); + witness_values.emplace_back(0); ++num_variables; auto fr_five = fr(5); poly_triple rd_read{ @@ -257,7 +257,7 @@ TEST_F(MegaHonk, DatabusReturn) .q_o = 0, .q_c = 0, }; - program.witness.emplace_back(fr_five); + witness_values.emplace_back(fr_five); poly_triple five{ .a = 0, .b = 0, @@ -293,7 +293,7 @@ TEST_F(MegaHonk, DatabusReturn) .q_c = 0, }; - program.constraints = { + AcirFormat constraint_system{ .varnum = static_cast(num_variables), .num_acir_opcodes = 2, .public_inputs = {}, @@ -324,10 +324,10 @@ TEST_F(MegaHonk, DatabusReturn) .block_constraints = { block }, .original_opcode_indices = create_empty_original_opcode_indices(), }; - mock_opcode_indices(program.constraints); + mock_opcode_indices(constraint_system); // Construct a bberg circuit from the acir representation - auto circuit = create_circuit(program); + auto circuit = acir_format::create_circuit(constraint_system, /*recursive*/ false, 0, witness_values); EXPECT_TRUE(prove_and_verify(circuit)); } diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp index 7a6bc5e8864..f815610631e 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.cpp @@ -29,10 +29,10 @@ using namespace bb; * @param trace_settings * @return ClientIVC */ -std::shared_ptr create_mock_ivc_from_constraints(const std::vector& constraints, - const TraceSettings& trace_settings) +ClientIVC create_mock_ivc_from_constraints(const std::vector& constraints, + const TraceSettings& trace_settings) { - auto ivc = std::make_shared(trace_settings); + ClientIVC ivc{ trace_settings }; uint32_t oink_type = static_cast(PROOF_TYPE::OINK); uint32_t pg_type = static_cast(PROOF_TYPE::PG); @@ -47,7 +47,7 @@ std::shared_ptr create_mock_ivc_from_constraints(const std::vectorverifier_accumulator = create_mock_decider_vk(); + ivc.verifier_accumulator = create_mock_decider_vk(); mock_ivc_accumulation(ivc, ClientIVC::QUEUE_TYPE::PG, /*is_kernel=*/true); return ivc; } @@ -55,14 +55,14 @@ std::shared_ptr create_mock_ivc_from_constraints(const std::vectorverifier_accumulator = create_mock_decider_vk(); + ivc.verifier_accumulator = create_mock_decider_vk(); mock_ivc_accumulation(ivc, ClientIVC::QUEUE_TYPE::PG, /*is_kernel=*/true); mock_ivc_accumulation(ivc, ClientIVC::QUEUE_TYPE::PG, /*is_kernel=*/false); return ivc; } ASSERT(false && "WARNING: Invalid set of IVC recursion constraints!"); - return ivc; + return ClientIVC{}; } /** @@ -72,13 +72,13 @@ std::shared_ptr create_mock_ivc_from_constraints(const std::vector& ivc, ClientIVC::QUEUE_TYPE type, const bool is_kernel) +void mock_ivc_accumulation(ClientIVC& ivc, ClientIVC::QUEUE_TYPE type, const bool is_kernel) { ClientIVC::VerifierInputs entry = - acir_format::create_mock_verification_queue_entry(type, ivc->trace_settings, is_kernel); - ivc->verification_queue.emplace_back(entry); - ivc->merge_verification_queue.emplace_back(acir_format::create_dummy_merge_proof()); - ivc->initialized = true; + acir_format::create_mock_verification_queue_entry(type, ivc.trace_settings, is_kernel); + ivc.verification_queue.emplace_back(entry); + ivc.merge_verification_queue.emplace_back(acir_format::create_dummy_merge_proof()); + ivc.initialized = true; } /** diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.hpp index ec36ed6f90f..8d89c6ecfc5 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.hpp @@ -11,10 +11,10 @@ using namespace bb; // TODO(https://github.com/AztecProtocol/barretenberg/issues/1148): logic in this file is incomplete. See issue for // details. -std::shared_ptr create_mock_ivc_from_constraints(const std::vector& constraints, - const TraceSettings& trace_settings); +ClientIVC create_mock_ivc_from_constraints(const std::vector& constraints, + const TraceSettings& trace_settings); -void mock_ivc_accumulation(const std::shared_ptr& ivc, ClientIVC::QUEUE_TYPE type, const bool is_kernel); +void mock_ivc_accumulation(ClientIVC& ivc, ClientIVC::QUEUE_TYPE type, const bool is_kernel); std::vector create_mock_oink_proof(const size_t dyadic_size, const size_t num_public_inputs, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.test.cpp index 283f675e59a..1cd9d5b5595 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ivc_recursion_constraint.test.cpp @@ -30,9 +30,9 @@ class IvcRecursionConstraintTest : public ::testing::Test { * @brief Constuct a simple arbitrary circuit to represent a mock app circuit * */ - static Builder construct_mock_app_circuit(const std::shared_ptr& ivc) + static Builder construct_mock_app_circuit(ClientIVC& ivc) { - Builder circuit{ ivc->goblin.op_queue }; + Builder circuit{ ivc.goblin.op_queue }; GoblinMockCircuits::add_some_ecc_op_gates(circuit); MockCircuits::add_arithmetic_gates(circuit); @@ -113,11 +113,11 @@ class IvcRecursionConstraintTest : public ::testing::Test { AcirProgram& program, const TraceSettings& trace_settings) { // Create a mock IVC instance from the IVC recursion constraints in the kernel program - auto mock_ivc = create_mock_ivc_from_constraints(program.constraints.ivc_recursion_constraints, trace_settings); + ClientIVC mock_ivc = + create_mock_ivc_from_constraints(program.constraints.ivc_recursion_constraints, trace_settings); // Create kernel circuit from kernel program and the mocked IVC (empty witness mimics VK construction context) - const ProgramMetadata metadata{ mock_ivc }; - Builder kernel = acir_format::create_circuit(program, metadata); + Builder kernel = acir_format::create_kernel_circuit(program.constraints, mock_ivc, /*witness=*/{}); // Note: adding pairing point normally happens in accumulate() kernel.add_pairing_point_accumulator(stdlib::recursion::init_default_agg_obj_indices(kernel)); @@ -142,25 +142,22 @@ class IvcRecursionConstraintTest : public ::testing::Test { */ TEST_F(IvcRecursionConstraintTest, AccumulateTwo) { - TraceSettings trace_settings{ SMALL_TEST_STRUCTURE }; - auto ivc = std::make_shared(trace_settings); + ClientIVC ivc{ { SMALL_TEST_STRUCTURE } }; // construct a mock app_circuit Builder app_circuit = construct_mock_app_circuit(ivc); // Complete instance and generate an oink proof - ivc->accumulate(app_circuit); + ivc.accumulate(app_circuit); - // Construct kernel consisting only of the kernel completion logic - AcirProgram program = construct_mock_kernel_program(ivc->verification_queue); + // Construct kernel_0 consisting only of the kernel completion logic + AcirProgram program_0 = construct_mock_kernel_program(ivc.verification_queue); + Builder kernel_0 = acir_format::create_kernel_circuit(program_0.constraints, ivc, program_0.witness); - const ProgramMetadata metadata{ ivc }; - Builder kernel = acir_format::create_circuit(program, metadata); + EXPECT_TRUE(CircuitChecker::check(kernel_0)); + ivc.accumulate(kernel_0); - EXPECT_TRUE(CircuitChecker::check(kernel)); - ivc->accumulate(kernel); - - EXPECT_TRUE(ivc->prove_and_verify()); + EXPECT_TRUE(ivc.prove_and_verify()); } /** @@ -169,32 +166,29 @@ TEST_F(IvcRecursionConstraintTest, AccumulateTwo) */ TEST_F(IvcRecursionConstraintTest, AccumulateFour) { - TraceSettings trace_settings{ SMALL_TEST_STRUCTURE }; - auto ivc = std::make_shared(trace_settings); + ClientIVC ivc{ { SMALL_TEST_STRUCTURE } }; // construct a mock app_circuit Builder app_circuit_0 = construct_mock_app_circuit(ivc); - ivc->accumulate(app_circuit_0); - - const ProgramMetadata metadata{ ivc }; + ivc.accumulate(app_circuit_0); // Construct kernel_0; consists of a single oink recursive verification for app (plus databus/merge logic) - AcirProgram program_0 = construct_mock_kernel_program(ivc->verification_queue); - Builder kernel_0 = acir_format::create_circuit(program_0, metadata); - ivc->accumulate(kernel_0); + AcirProgram program_0 = construct_mock_kernel_program(ivc.verification_queue); + Builder kernel_0 = acir_format::create_kernel_circuit(program_0.constraints, ivc, program_0.witness); + ivc.accumulate(kernel_0); // construct a mock app_circuit Builder app_circuit_1 = construct_mock_app_circuit(ivc); - ivc->accumulate(app_circuit_1); + ivc.accumulate(app_circuit_1); // Construct kernel_1; consists of two PG recursive verifications for kernel_0 and app_1 (plus databus/merge logic) - AcirProgram program_1 = construct_mock_kernel_program(ivc->verification_queue); - Builder kernel_1 = acir_format::create_circuit(program_1, metadata); + AcirProgram program_1 = construct_mock_kernel_program(ivc.verification_queue); + Builder kernel_1 = acir_format::create_kernel_circuit(program_1.constraints, ivc, program_1.witness); EXPECT_TRUE(CircuitChecker::check(kernel_1)); - ivc->accumulate(kernel_1); + ivc.accumulate(kernel_1); - EXPECT_TRUE(ivc->prove_and_verify()); + EXPECT_TRUE(ivc.prove_and_verify()); } // Test generation of "init" kernel VK via dummy IVC data @@ -205,31 +199,29 @@ TEST_F(IvcRecursionConstraintTest, GenerateVK) // First, construct the kernel VK by running the full IVC (accumulate one app and one kernel) std::shared_ptr expected_kernel_vk; { - auto ivc = std::make_shared(trace_settings); + ClientIVC ivc{ trace_settings }; // Construct and accumulate mock app_circuit Builder app_circuit = construct_mock_app_circuit(ivc); - ivc->accumulate(app_circuit); + ivc.accumulate(app_circuit); // Construct and accumulate kernel consisting only of the kernel completion logic - AcirProgram program = construct_mock_kernel_program(ivc->verification_queue); - const ProgramMetadata metadata{ ivc }; - Builder kernel = acir_format::create_circuit(program, metadata); - ivc->accumulate(kernel); - expected_kernel_vk = ivc->verification_queue.back().honk_verification_key; + AcirProgram program = construct_mock_kernel_program(ivc.verification_queue); + Builder kernel = acir_format::create_kernel_circuit(program.constraints, ivc, program.witness); + ivc.accumulate(kernel); + expected_kernel_vk = ivc.verification_queue.back().honk_verification_key; } // Now, construct the kernel VK by mocking the post app accumulation state of the IVC std::shared_ptr kernel_vk; { - auto ivc = std::make_shared(trace_settings); + ClientIVC ivc{ trace_settings }; acir_format::mock_ivc_accumulation(ivc, ClientIVC::QUEUE_TYPE::OINK, /*is_kernel=*/false); // Construct kernel consisting only of the kernel completion logic - AcirProgram program = construct_mock_kernel_program(ivc->verification_queue); - const ProgramMetadata metadata{ ivc }; - Builder kernel = acir_format::create_circuit(program, metadata); + AcirProgram program = construct_mock_kernel_program(ivc.verification_queue); + Builder kernel = acir_format::create_kernel_circuit(program.constraints, ivc); // Note that this would normally happen in accumulate() kernel.add_pairing_point_accumulator(stdlib::recursion::init_default_agg_obj_indices(kernel)); @@ -253,29 +245,28 @@ TEST_F(IvcRecursionConstraintTest, GenerateInitKernelVKFromConstraints) // First, construct the kernel VK by running the full IVC (accumulate one app and one kernel) std::shared_ptr expected_kernel_vk; { - auto ivc = std::make_shared(trace_settings); + ClientIVC ivc{ trace_settings }; // Construct and accumulate mock app_circuit Builder app_circuit = construct_mock_app_circuit(ivc); - ivc->accumulate(app_circuit); + ivc.accumulate(app_circuit); // Construct and accumulate kernel consisting only of the kernel completion logic - AcirProgram program = construct_mock_kernel_program(ivc->verification_queue); - const ProgramMetadata metadata{ ivc }; - Builder kernel = acir_format::create_circuit(program, metadata); + AcirProgram program = construct_mock_kernel_program(ivc.verification_queue); + Builder kernel = acir_format::create_kernel_circuit(program.constraints, ivc, program.witness); - ivc->accumulate(kernel); - expected_kernel_vk = ivc->verification_queue.back().honk_verification_key; + ivc.accumulate(kernel); + expected_kernel_vk = ivc.verification_queue.back().honk_verification_key; } // Now, construct the kernel VK by mocking the post app accumulation state of the IVC std::shared_ptr kernel_vk; { - auto ivc = std::make_shared(trace_settings); + ClientIVC ivc{ trace_settings }; // Construct kernel consisting only of the kernel completion logic acir_format::mock_ivc_accumulation(ivc, ClientIVC::QUEUE_TYPE::OINK, /*is_kernel=*/false); - AcirProgram program = construct_mock_kernel_program(ivc->verification_queue); + AcirProgram program = construct_mock_kernel_program(ivc.verification_queue); kernel_vk = construct_kernel_vk_from_acir_program(program, trace_settings); } @@ -296,39 +287,37 @@ TEST_F(IvcRecursionConstraintTest, GenerateResetKernelVKFromConstraints) // First, construct the kernel VK by running the full IVC (accumulate one app and one kernel) std::shared_ptr expected_kernel_vk; { - auto ivc = std::make_shared(trace_settings); - - const ProgramMetadata metadata{ ivc }; + ClientIVC ivc{ trace_settings }; // Construct and accumulate mock app_circuit Builder app_circuit = construct_mock_app_circuit(ivc); - ivc->accumulate(app_circuit); + ivc.accumulate(app_circuit); { // Construct and accumulate a mock INIT kernel (oink recursion for app accumulation) - AcirProgram program = construct_mock_kernel_program(ivc->verification_queue); - Builder kernel = acir_format::create_circuit(program, metadata); - ivc->accumulate(kernel); + AcirProgram program = construct_mock_kernel_program(ivc.verification_queue); + Builder kernel = acir_format::create_kernel_circuit(program.constraints, ivc, program.witness); + ivc.accumulate(kernel); } { // Construct and accumulate a mock RESET kernel (PG recursion for kernel accumulation) - EXPECT_TRUE(ivc->verification_queue.size() == 1); - EXPECT_TRUE(ivc->verification_queue[0].type == bb::ClientIVC::QUEUE_TYPE::PG); - AcirProgram program = construct_mock_kernel_program(ivc->verification_queue); - Builder kernel = acir_format::create_circuit(program, metadata); - ivc->accumulate(kernel); + EXPECT_TRUE(ivc.verification_queue.size() == 1); + EXPECT_TRUE(ivc.verification_queue[0].type == bb::ClientIVC::QUEUE_TYPE::PG); + AcirProgram program = construct_mock_kernel_program(ivc.verification_queue); + Builder kernel = acir_format::create_kernel_circuit(program.constraints, ivc, program.witness); + ivc.accumulate(kernel); } - expected_kernel_vk = ivc->verification_queue.back().honk_verification_key; + expected_kernel_vk = ivc.verification_queue.back().honk_verification_key; } // Now, construct the kernel VK by mocking the IVC state prior to kernel construction std::shared_ptr kernel_vk; { - auto ivc = std::make_shared(trace_settings); + ClientIVC ivc{ trace_settings }; // Construct kernel consisting only of the kernel completion logic acir_format::mock_ivc_accumulation(ivc, ClientIVC::QUEUE_TYPE::PG, /*is_kernel=*/true); - AcirProgram program = construct_mock_kernel_program(ivc->verification_queue); + AcirProgram program = construct_mock_kernel_program(ivc.verification_queue); kernel_vk = construct_kernel_vk_from_acir_program(program, trace_settings); } @@ -349,47 +338,45 @@ TEST_F(IvcRecursionConstraintTest, GenerateInnerKernelVKFromConstraints) // First, construct the kernel VK by running the full IVC (accumulate one app and one kernel) std::shared_ptr expected_kernel_vk; { - auto ivc = std::make_shared(trace_settings); - - const ProgramMetadata metadata{ ivc }; + ClientIVC ivc{ trace_settings }; { // Construct and accumulate mock app_circuit Builder app_circuit = construct_mock_app_circuit(ivc); - ivc->accumulate(app_circuit); + ivc.accumulate(app_circuit); } { // Construct and accumulate a mock INIT kernel (oink recursion for app accumulation) - AcirProgram program = construct_mock_kernel_program(ivc->verification_queue); - Builder kernel = acir_format::create_circuit(program, metadata); - ivc->accumulate(kernel); + AcirProgram program = construct_mock_kernel_program(ivc.verification_queue); + Builder kernel = acir_format::create_kernel_circuit(program.constraints, ivc, program.witness); + ivc.accumulate(kernel); } { // Construct and accumulate a second mock app_circuit Builder app_circuit = construct_mock_app_circuit(ivc); - ivc->accumulate(app_circuit); + ivc.accumulate(app_circuit); } { // Construct and accumulate a mock RESET kernel (PG recursion for kernel accumulation) - EXPECT_TRUE(ivc->verification_queue.size() == 2); - EXPECT_TRUE(ivc->verification_queue[0].type == bb::ClientIVC::QUEUE_TYPE::PG); - EXPECT_TRUE(ivc->verification_queue[1].type == bb::ClientIVC::QUEUE_TYPE::PG); - AcirProgram program = construct_mock_kernel_program(ivc->verification_queue); - Builder kernel = acir_format::create_circuit(program, metadata); - ivc->accumulate(kernel); + EXPECT_TRUE(ivc.verification_queue.size() == 2); + EXPECT_TRUE(ivc.verification_queue[0].type == bb::ClientIVC::QUEUE_TYPE::PG); + EXPECT_TRUE(ivc.verification_queue[1].type == bb::ClientIVC::QUEUE_TYPE::PG); + AcirProgram program = construct_mock_kernel_program(ivc.verification_queue); + Builder kernel = acir_format::create_kernel_circuit(program.constraints, ivc, program.witness); + ivc.accumulate(kernel); } - expected_kernel_vk = ivc->verification_queue.back().honk_verification_key; + expected_kernel_vk = ivc.verification_queue.back().honk_verification_key; } // Now, construct the kernel VK by mocking the IVC state prior to kernel construction std::shared_ptr kernel_vk; { - auto ivc = std::make_shared(trace_settings); + ClientIVC ivc{ trace_settings }; // Construct kernel consisting only of the kernel completion logic acir_format::mock_ivc_accumulation(ivc, ClientIVC::QUEUE_TYPE::PG, /*is_kernel=*/true); acir_format::mock_ivc_accumulation(ivc, ClientIVC::QUEUE_TYPE::PG, /*is_kernel=*/false); - AcirProgram program = construct_mock_kernel_program(ivc->verification_queue); + AcirProgram program = construct_mock_kernel_program(ivc.verification_queue); kernel_vk = construct_kernel_vk_from_acir_program(program, trace_settings); } diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/c_bind.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/c_bind.cpp index 817e772ade1..4ae4f09c296 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/c_bind.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/c_bind.cpp @@ -17,12 +17,9 @@ WASM_EXPORT void acir_get_circuit_sizes( uint8_t const* acir_vec, bool const* recursive, bool const* honk_recursion, uint32_t* total, uint32_t* subgroup) { - const acir_format::ProgramMetadata metadata{ .recursive = *recursive, - .honk_recursion = *honk_recursion, - .size_hint = 1 << 19 }; - acir_format::AcirProgram program{ acir_format::circuit_buf_to_acir_format( - from_buffer>(acir_vec), *honk_recursion) }; - auto builder = acir_format::create_circuit(program, metadata); + auto constraint_system = + acir_format::circuit_buf_to_acir_format(from_buffer>(acir_vec), *honk_recursion); + auto builder = acir_format::create_circuit(constraint_system, recursive, 1 << 19, {}, *honk_recursion); builder.finalize_circuit(/*ensure_nonzero=*/true); *total = htonl((uint32_t)builder.get_finalized_total_circuit_size()); *subgroup = htonl((uint32_t)builder.get_circuit_subgroup_size(builder.get_finalized_total_circuit_size())); @@ -68,13 +65,12 @@ WASM_EXPORT void acir_prove_and_verify_ultra_honk(uint8_t const* acir_vec, uint8_t const* witness_vec, bool* result) { - const acir_format::ProgramMetadata metadata{ .recursive = *recursive, .honk_recursion = true }; - acir_format::AcirProgram program{ - acir_format::circuit_buf_to_acir_format(from_buffer>(acir_vec), metadata.honk_recursion), - acir_format::witness_buf_to_witness_data(from_buffer>(witness_vec)) - }; + auto constraint_system = + acir_format::circuit_buf_to_acir_format(from_buffer>(acir_vec), /*honk_recursion=*/true); + auto witness = acir_format::witness_buf_to_witness_data(from_buffer>(witness_vec)); - auto builder = acir_format::create_circuit(program, metadata); + auto builder = acir_format::create_circuit( + constraint_system, *recursive, 0, witness, /*honk_recursion=*/true); UltraProver prover{ builder }; auto proof = prover.construct_proof(); @@ -100,26 +96,28 @@ WASM_EXPORT void acir_fold_and_verify_program_stack(uint8_t const* acir_vec, ProgramStack program_stack{ constraint_systems, witness_stack }; - TraceSettings trace_settings{ SMALL_TEST_STRUCTURE }; - auto ivc = std::make_shared(trace_settings, /*auto_verify_mode=*/true); - - const acir_format::ProgramMetadata metadata{ ivc, *recursive }; + ClientIVC ivc{ { SMALL_TEST_STRUCTURE }, /*auto_verify_mode=*/true }; bool is_kernel = false; while (!program_stack.empty()) { - auto program = program_stack.back(); + auto stack_item = program_stack.back(); // Construct a bberg circuit from the acir representation - auto builder = acir_format::create_circuit(program, metadata); + auto builder = acir_format::create_circuit(stack_item.constraints, + *recursive, + 0, + stack_item.witness, + /*honk_recursion=*/false, + ivc.goblin.op_queue); builder.databus_propagation_data.is_kernel = is_kernel; is_kernel = !is_kernel; // toggle on/off so every second circuit is intepreted as a kernel - ivc->accumulate(builder); + ivc.accumulate(builder); program_stack.pop_back(); } - *result = ivc->prove_and_verify(); + *result = ivc.prove_and_verify(); info("acir_fold_and_verify_program_stack result: ", *result); } @@ -128,14 +126,12 @@ WASM_EXPORT void acir_prove_and_verify_mega_honk(uint8_t const* acir_vec, uint8_t const* witness_vec, bool* result) { - const acir_format::ProgramMetadata metadata{ .recursive = *recursive, .honk_recursion = false }; - - acir_format::AcirProgram program{ - acir_format::circuit_buf_to_acir_format(from_buffer>(acir_vec), metadata.honk_recursion), - acir_format::witness_buf_to_witness_data(from_buffer>(witness_vec)) - }; + auto constraint_system = + acir_format::circuit_buf_to_acir_format(from_buffer>(acir_vec), /*honk_recursion=*/false); + auto witness = acir_format::witness_buf_to_witness_data(from_buffer>(witness_vec)); - auto builder = acir_format::create_circuit(program, metadata); + auto builder = acir_format::create_circuit( + constraint_system, *recursive, 0, witness, /*honk_recursion=*/false); MegaProver prover{ builder }; auto proof = prover.construct_proof(); @@ -239,10 +235,7 @@ WASM_EXPORT void acir_prove_and_verify_aztec_client(uint8_t const* acir_stack, } // TODO(#7371) dedupe this with the rest of the similar code // TODO(https://github.com/AztecProtocol/barretenberg/issues/1101): remove use of auto_verify_mode - TraceSettings trace_settings{ E2E_FULL_TEST_STRUCTURE }; - auto ivc = std::make_shared(trace_settings, /*auto_verify_mode=*/true); - - const acir_format::ProgramMetadata metadata{ ivc }; + ClientIVC ivc{ { E2E_FULL_TEST_STRUCTURE }, /*auto_verify_mode=*/true }; // Accumulate the entire program stack into the IVC // TODO(https://github.com/AztecProtocol/barretenberg/issues/1116): remove manual setting of is_kernel once databus @@ -252,7 +245,8 @@ WASM_EXPORT void acir_prove_and_verify_aztec_client(uint8_t const* acir_stack, for (Program& program : folding_stack) { // Construct a bberg circuit from the acir representation then accumulate it into the IVC vinfo("constructing circuit..."); - auto circuit = acir_format::create_circuit(program, metadata); + auto circuit = acir_format::create_circuit( + program.constraints, false, 0, program.witness, false, ivc.goblin.op_queue); // Set the internal is_kernel flag based on the local mechanism only if it has not already been set to true if (!circuit.databus_propagation_data.is_kernel) { @@ -261,7 +255,7 @@ WASM_EXPORT void acir_prove_and_verify_aztec_client(uint8_t const* acir_stack, is_kernel = !is_kernel; vinfo("done constructing circuit. calling ivc.accumulate..."); - ivc->accumulate(circuit); + ivc.accumulate(circuit); vinfo("done accumulating."); } auto end = std::chrono::steady_clock::now(); @@ -269,7 +263,7 @@ WASM_EXPORT void acir_prove_and_verify_aztec_client(uint8_t const* acir_stack, vinfo("time to construct and accumulate all circuits: ", diff.count()); vinfo("calling ivc.prove_and_verify..."); - bool result = ivc->prove_and_verify(); + bool result = ivc.prove_and_verify(); info("verified?: ", result); end = std::chrono::steady_clock::now(); @@ -296,11 +290,9 @@ WASM_EXPORT void acir_prove_aztec_client(uint8_t const* acir_stack, acir_format::circuit_buf_to_acir_format(bincode, /*honk_recursion=*/false); folding_stack.push_back(Program{ constraints, witness }); } + // TODO(#7371) dedupe this with the rest of the similar code // TODO(https://github.com/AztecProtocol/barretenberg/issues/1101): remove use of auto_verify_mode - TraceSettings trace_settings{ E2E_FULL_TEST_STRUCTURE }; - auto ivc = std::make_shared(trace_settings, /*auto_verify_mode=*/true); - - const acir_format::ProgramMetadata metadata{ ivc }; + ClientIVC ivc{ { E2E_FULL_TEST_STRUCTURE }, /*auto_verify_mode=*/true }; // Accumulate the entire program stack into the IVC // TODO(https://github.com/AztecProtocol/barretenberg/issues/1116): remove manual setting of is_kernel once databus @@ -310,7 +302,8 @@ WASM_EXPORT void acir_prove_aztec_client(uint8_t const* acir_stack, for (Program& program : folding_stack) { // Construct a bberg circuit from the acir representation then accumulate it into the IVC vinfo("constructing circuit..."); - auto circuit = acir_format::create_circuit(program, metadata); + auto circuit = acir_format::create_circuit( + program.constraints, false, 0, program.witness, false, ivc.goblin.op_queue); // Set the internal is_kernel flag based on the local mechanism only if it has not already been set to true if (!circuit.databus_propagation_data.is_kernel) { @@ -319,7 +312,7 @@ WASM_EXPORT void acir_prove_aztec_client(uint8_t const* acir_stack, is_kernel = !is_kernel; vinfo("done constructing circuit. calling ivc.accumulate..."); - ivc->accumulate(circuit); + ivc.accumulate(circuit); vinfo("done accumulating."); } auto end = std::chrono::steady_clock::now(); @@ -327,7 +320,7 @@ WASM_EXPORT void acir_prove_aztec_client(uint8_t const* acir_stack, vinfo("time to construct and accumulate all circuits: ", diff.count()); vinfo("calling ivc.prove ..."); - ClientIVC::Proof proof = ivc->prove(); + ClientIVC::Proof proof = ivc.prove(); end = std::chrono::steady_clock::now(); diff = std::chrono::duration_cast(end - start); vinfo("time to construct, accumulate, prove all circuits: ", diff.count()); @@ -339,9 +332,9 @@ WASM_EXPORT void acir_prove_aztec_client(uint8_t const* acir_stack, vinfo("time to serialize proof: ", diff.count()); start = std::chrono::steady_clock::now(); - auto eccvm_vk = std::make_shared(ivc->goblin.get_eccvm_proving_key()); - auto translator_vk = std::make_shared(ivc->goblin.get_translator_proving_key()); - *out_vk = to_heap_buffer(to_buffer(ClientIVC::VerificationKey{ ivc->honk_vk, eccvm_vk, translator_vk })); + auto eccvm_vk = std::make_shared(ivc.goblin.get_eccvm_proving_key()); + auto translator_vk = std::make_shared(ivc.goblin.get_translator_proving_key()); + *out_vk = to_heap_buffer(to_buffer(ClientIVC::VerificationKey{ ivc.honk_vk, eccvm_vk, translator_vk })); end = std::chrono::steady_clock::now(); diff = std::chrono::duration_cast(end - start); vinfo("time to serialize vk: ", diff.count()); @@ -366,14 +359,12 @@ WASM_EXPORT void acir_prove_ultra_honk(uint8_t const* acir_vec, uint8_t const* witness_vec, uint8_t** out) { - const acir_format::ProgramMetadata metadata{ .recursive = *recursive, .honk_recursion = true }; - - acir_format::AcirProgram program{ - acir_format::circuit_buf_to_acir_format(from_buffer>(acir_vec), metadata.honk_recursion), - acir_format::witness_buf_to_witness_data(from_buffer>(witness_vec)) - }; + auto constraint_system = + acir_format::circuit_buf_to_acir_format(from_buffer>(acir_vec), /*honk_recursion=*/true); + auto witness = acir_format::witness_buf_to_witness_data(from_buffer>(witness_vec)); - auto builder = acir_format::create_circuit(program, metadata); + auto builder = acir_format::create_circuit( + constraint_system, *recursive, 0, witness, /*honk_recursion=*/true); UltraProver prover{ builder }; auto proof = prover.construct_proof(); @@ -432,11 +423,10 @@ WASM_EXPORT void acir_write_vk_ultra_honk(uint8_t const* acir_vec, bool const* r using DeciderProvingKey = DeciderProvingKey_; using VerificationKey = UltraFlavor::VerificationKey; - const acir_format::ProgramMetadata metadata{ .recursive = *recursive, .honk_recursion = true }; - - acir_format::AcirProgram program{ acir_format::circuit_buf_to_acir_format( - from_buffer>(acir_vec), metadata.honk_recursion) }; - auto builder = acir_format::create_circuit(program, metadata); + auto constraint_system = + acir_format::circuit_buf_to_acir_format(from_buffer>(acir_vec), /*honk_recursion=*/true); + auto builder = + acir_format::create_circuit(constraint_system, *recursive, 0, {}, /*honk_recursion=*/true); DeciderProvingKey proving_key(builder); VerificationKey vk(proving_key.proving_key); @@ -448,11 +438,10 @@ WASM_EXPORT void acir_write_vk_ultra_keccak_honk(uint8_t const* acir_vec, bool c using DeciderProvingKey = DeciderProvingKey_; using VerificationKey = UltraKeccakFlavor::VerificationKey; - const acir_format::ProgramMetadata metadata{ .recursive = *recursive, .honk_recursion = true }; - - acir_format::AcirProgram program{ acir_format::circuit_buf_to_acir_format( - from_buffer>(acir_vec), metadata.honk_recursion) }; - auto builder = acir_format::create_circuit(program, metadata); + auto constraint_system = + acir_format::circuit_buf_to_acir_format(from_buffer>(acir_vec), /*honk_recursion=*/true); + auto builder = + acir_format::create_circuit(constraint_system, *recursive, 0, {}, /*honk_recursion=*/true); DeciderProvingKey proving_key(builder); VerificationKey vk(proving_key.proving_key);