Skip to content

Commit

Permalink
feat: PG + Goblin (AztecProtocol#4399)
Browse files Browse the repository at this point in the history
Implements a new `ClientIvc` class that serves as the interface for
doing IVC with PG + Goblin. Adds a PoC for the architecture in new test
file. This test (and an updated one for Goblin + vanilla recursion) use
a new goblin method `merge` which is similar to the `accumulate` method
but with the IVC prover related work stripped out. This allows goblin to
be completely agnostic to the IVC scheme (recursion/folding) that it's
being used with.

---------

Co-authored-by: codygunton <codygunton@gmail.com>
  • Loading branch information
ledwards2225 and codygunton authored Feb 7, 2024
1 parent 15c06c5 commit 295cd55
Show file tree
Hide file tree
Showing 14 changed files with 384 additions and 70 deletions.
3 changes: 1 addition & 2 deletions barretenberg/barretenberg.code-workspace
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,7 @@
},
"cmake.configureArgs": [
"--preset clang16",
"-G Ninja",
"-g"
"-G Ninja"
],
"cmake.useCMakePresets": "auto",
"editor.inlayHints.enabled": "offUnlessPressed",
Expand Down
1 change: 1 addition & 0 deletions barretenberg/cpp/scripts/bb-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ IMAGE_URI=$(calculate_image_uri $REPOSITORY)
retry docker pull $IMAGE_URI

TESTS=(
client_ivc_tests
commitment_schemes_tests
crypto_aes128_tests
crypto_blake2s_tests
Expand Down
1 change: 1 addition & 0 deletions barretenberg/cpp/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ else()
endif()

add_subdirectory(barretenberg/bb)
add_subdirectory(barretenberg/client_ivc)
add_subdirectory(barretenberg/commitment_schemes)
add_subdirectory(barretenberg/common)
add_subdirectory(barretenberg/crypto)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
barretenberg_module(client_ivc goblin)
79 changes: 79 additions & 0 deletions barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#include "barretenberg/client_ivc/client_ivc.hpp"

namespace bb {

ClientIVC::ClientIVC()
{
// TODO(https://github.com/AztecProtocol/barretenberg/issues/723):
GoblinMockCircuits::perform_op_queue_interactions_for_mock_first_circuit(goblin.op_queue);
}

/**
* @brief Initialize the IVC with a first circuit
* @details Initializes the accumulator and performs the initial goblin merge
*
* @param circuit
*/
void ClientIVC::initialize(ClientCircuit& circuit)
{
goblin.merge(circuit); // Construct new merge proof
Composer composer;
fold_output.accumulator = composer.create_instance(circuit);
}

/**
* @brief Accumulate a circuit into the IVC scheme
* @details Performs goblin merge, generates circuit instance, folds into accumulator and constructs a folding proof
*
* @param circuit Circuit to be accumulated/folded
* @return FoldProof
*/
ClientIVC::FoldProof ClientIVC::accumulate(ClientCircuit& circuit)
{
goblin.merge(circuit); // Add recursive merge verifier and construct new merge proof
Composer composer;
auto instance = composer.create_instance(circuit);
std::vector<std::shared_ptr<Instance>> instances{ fold_output.accumulator, instance };
auto folding_prover = composer.create_folding_prover(instances);
fold_output = folding_prover.fold_instances();
return fold_output.folding_data;
}

/**
* @brief Construct a proof for the IVC, which, if verified, fully establishes its correctness
*
* @return Proof
*/
ClientIVC::Proof ClientIVC::prove()
{
// Construct Goblin proof (merge, eccvm, translator)
auto goblin_proof = goblin.prove();

// Construct decider proof for the final accumulator
Composer composer;
auto decider_prover = composer.create_decider_prover(fold_output.accumulator);
auto decider_proof = decider_prover.construct_proof();
return { goblin_proof, fold_output.folding_data, decider_proof };
}

/**
* @brief Verify a full proof of the IVC
*
* @param proof
* @return bool
*/
bool ClientIVC::verify(Proof& proof)
{
// Goblin verification (merge, eccvm, translator)
bool goblin_verified = goblin.verify(proof.goblin_proof);

// Decider verification
Composer composer;
auto folding_verifier = composer.create_folding_verifier();
bool folding_verified = folding_verifier.verify_folding_proof(proof.fold_proof);
// NOTE: Use of member accumulator here will go away with removal of vkey from ProverInstance
auto decider_verifier = composer.create_decider_verifier(fold_output.accumulator);
bool decision = decider_verifier.verify_proof(proof.decider_proof);
return goblin_verified && folding_verified && decision;
}
} // namespace bb
50 changes: 50 additions & 0 deletions barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#pragma once

#include "barretenberg/goblin/goblin.hpp"
#include "barretenberg/goblin/mock_circuits.hpp"
#include "barretenberg/ultra_honk/ultra_composer.hpp"

namespace bb {

/**
* @brief The IVC interface to be used by the aztec client for private function execution
* @details Combines Protogalaxy with Goblin to accumulate one circuit instance at a time with efficient EC group
* operations
*
*/
class ClientIVC {

public:
using Flavor = GoblinUltraFlavor;
using FF = Flavor::FF;
using FoldProof = std::vector<FF>;
using Accumulator = std::shared_ptr<ProverInstance_<Flavor>>;
using ClientCircuit = GoblinUltraCircuitBuilder; // can only be GoblinUltra

// A full proof for the IVC scheme
struct Proof {
Goblin::Proof goblin_proof;
FoldProof fold_proof; // final fold proof
HonkProof decider_proof;
};

private:
using FoldingOutput = FoldingResult<Flavor>;
using Instance = ProverInstance_<GoblinUltraFlavor>;
using Composer = GoblinUltraComposer;

public:
Goblin goblin;
FoldingOutput fold_output;

ClientIVC();

void initialize(ClientCircuit& circuit);

FoldProof accumulate(ClientCircuit& circuit);

Proof prove();

bool verify(Proof& proof);
};
} // namespace bb
120 changes: 120 additions & 0 deletions barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
#include "barretenberg/client_ivc/client_ivc.hpp"
#include "barretenberg/goblin/goblin.hpp"
#include "barretenberg/goblin/mock_circuits.hpp"
#include "barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp"
#include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp"
#include "barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.hpp"
#include "barretenberg/ultra_honk/ultra_composer.hpp"

#include <gtest/gtest.h>
using namespace bb;

class ClientIVCTests : public ::testing::Test {
protected:
static void SetUpTestSuite()
{
srs::init_crs_factory("../srs_db/ignition");
srs::init_grumpkin_crs_factory("../srs_db/grumpkin");
}

using Flavor = ClientIVC::Flavor;
using FF = typename Flavor::FF;
using Builder = ClientIVC::ClientCircuit;
using Composer = GoblinUltraComposer;
using Accumulator = ClientIVC::Accumulator;
using FoldProof = ClientIVC::FoldProof;

using GURecursiveFlavor = GoblinUltraRecursiveFlavor_<Builder>;
using RecursiveVerifierInstances = ::bb::VerifierInstances_<GURecursiveFlavor, 2>;
using FoldingRecursiveVerifier =
bb::stdlib::recursion::honk::ProtoGalaxyRecursiveVerifier_<RecursiveVerifierInstances>;

/**
* @brief Construct mock circuit with arithmetic gates and goblin ops
* @details Currently default sized to 2^16 to match kernel. (Note: op gates will bump size to next power of 2)
*
*/
static Builder create_mock_circuit(ClientIVC& ivc, size_t num_gates = 1 << 15)
{
Builder circuit{ ivc.goblin.op_queue };
GoblinMockCircuits::construct_arithmetic_circuit(circuit, num_gates);
GoblinMockCircuits::construct_goblin_ecc_op_circuit(circuit);
return circuit;
}

/**
* @brief Construct mock kernel consisting of two recursive folding verifiers
*
* @param builder
* @param fctn_fold_proof
* @param kernel_fold_proof
*/
static void construct_mock_folding_kernel(Builder& builder,
FoldProof& fctn_fold_proof,
FoldProof& kernel_fold_proof)
{
FoldingRecursiveVerifier verifier_1{ &builder };
verifier_1.verify_folding_proof(fctn_fold_proof);

FoldingRecursiveVerifier verifier_2{ &builder };
verifier_2.verify_folding_proof(kernel_fold_proof);
}

/**
* @brief Perform native fold verification and run decider prover/verifier
*
*/
static void EXPECT_FOLDING_AND_DECIDING_VERIFIED(const Accumulator& accumulator, const FoldProof& fold_proof)
{
// Verify fold proof
Composer composer;
auto folding_verifier = composer.create_folding_verifier();
bool folding_verified = folding_verifier.verify_folding_proof(fold_proof);
EXPECT_TRUE(folding_verified);

// Run decider
auto decider_prover = composer.create_decider_prover(accumulator);
auto decider_verifier = composer.create_decider_verifier(accumulator);
auto decider_proof = decider_prover.construct_proof();
bool decision = decider_verifier.verify_proof(decider_proof);
EXPECT_TRUE(decision);
}
};

/**
* @brief A full Goblin test using PG that mimicks the basic aztec client architecture
*
*/
TEST_F(ClientIVCTests, Full)
{
ClientIVC ivc;

// Initialize IVC with function circuit
Builder function_circuit = create_mock_circuit(ivc);
ivc.initialize(function_circuit);

// Accumulate kernel circuit (first kernel mocked as simple circuit since no folding proofs yet)
Builder kernel_circuit = create_mock_circuit(ivc);
FoldProof kernel_fold_proof = ivc.accumulate(kernel_circuit);
EXPECT_FOLDING_AND_DECIDING_VERIFIED(ivc.fold_output.accumulator, kernel_fold_proof);

size_t NUM_CIRCUITS = 1;
for (size_t circuit_idx = 0; circuit_idx < NUM_CIRCUITS; ++circuit_idx) {
// Accumulate function circuit
Builder function_circuit = create_mock_circuit(ivc);
FoldProof function_fold_proof = ivc.accumulate(function_circuit);
EXPECT_FOLDING_AND_DECIDING_VERIFIED(ivc.fold_output.accumulator, function_fold_proof);

// Accumulate kernel circuit
Builder kernel_circuit{ ivc.goblin.op_queue };
construct_mock_folding_kernel(kernel_circuit, function_fold_proof, kernel_fold_proof);
FoldProof kernel_fold_proof = ivc.accumulate(kernel_circuit);
EXPECT_FOLDING_AND_DECIDING_VERIFIED(ivc.fold_output.accumulator, kernel_fold_proof);
}

// Constuct four proofs: merge, eccvm, translator, decider
auto proof = ivc.prove();

// Verify all four proofs
EXPECT_TRUE(ivc.verify(proof));
}

This file was deleted.

25 changes: 25 additions & 0 deletions barretenberg/cpp/src/barretenberg/goblin/goblin.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,31 @@ class Goblin {
return { ultra_proof, instance->verification_key };
};

/**
* @brief Add a recursive merge verifier to input circuit and construct a merge proof for the updated op queue
* @details When this method is used, the "prover" functionality of the IVC scheme must be performed explicitly, but
* this method has to be called first so that the recursive merge verifier can be "appended" to the circuit being
* accumulated
*
* @param circuit_builder
*/
void merge(GoblinUltraCircuitBuilder& circuit_builder)
{
// Complete the circuit logic by recursively verifying previous merge proof if it exists
if (merge_proof_exists) {
RecursiveMergeVerifier merge_verifier{ &circuit_builder };
[[maybe_unused]] auto pairing_points = merge_verifier.verify_proof(merge_proof);
}

// Construct and store the merge proof to be recursively verified on the next call to accumulate
MergeProver merge_prover{ op_queue };
merge_proof = merge_prover.construct_proof();

if (!merge_proof_exists) {
merge_proof_exists = true;
}
};

/**
* @brief Construct an ECCVM proof and the translation polynomial evaluations
*
Expand Down
Loading

0 comments on commit 295cd55

Please sign in to comment.