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: ClientIvc recursive verifier #6721

Merged
merged 19 commits into from
May 31, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
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
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ void ClientIVC::accumulate(ClientCircuit& circuit, const std::shared_ptr<Verific
// If a previous fold proof exists, add a recursive folding verification to the circuit
if (!fold_output.proof.empty()) {
BB_OP_COUNT_TIME_NAME("construct_circuits");
FoldingRecursiveVerifier verifier{ &circuit, verifier_accumulator, { instance_vk } };
FoldingRecursiveVerifier verifier{ &circuit, { verifier_accumulator, { instance_vk } } };
auto verifier_accum = verifier.verify_folding_proof(fold_output.proof);
verifier_accumulator = std::make_shared<VerifierInstance>(verifier_accum->get_value());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ barretenberg_module(
ultra_honk
stdlib_poseidon2
protogalaxy
client_ivc
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#include "client_ivc_recursive_verifier.hpp"

namespace bb::stdlib::recursion::honk {

void ClientIvcRecursiveVerifier_::verify(const ClientIVC::Proof& proof, VerifierInput& data)
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we settle on either IVC or Ivc when it comes to naming

Copy link
Contributor Author

Choose a reason for hiding this comment

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

updated to IVC

{
// WORKTODO: Perform Goblin recursive verification here

// Perform recursive folding verification
FoldingVerifier folding_verifier{ builder, data };
auto recursive_verifier_accumulator = folding_verifier.verify_folding_proof(proof.folding_proof);
auto native_verifier_acc = std::make_shared<VerifierInput::Instance>(recursive_verifier_accumulator->get_value());
Copy link
Contributor

Choose a reason for hiding this comment

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

thinking out loud: if these two would share the same builder we wouldn't have to call get_value here. But probably not worth investing time atm, especially since we're not sure what's gonna happen when adding ZK

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah not a top priority but I agree, might make sense to have these two more integrated. Currently we might be duplicating the final accumulator in the witness doing it this way


// Perform recursive decider verification
DeciderVerifier decider{ builder, native_verifier_acc };
decider.verify_proof(proof.decider_proof);
}

} // namespace bb::stdlib::recursion::honk
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#pragma once
#include "barretenberg/client_ivc/client_ivc.hpp"
#include "barretenberg/stdlib/honk_recursion/verifier/decider_recursive_verifier.hpp"

namespace bb::stdlib::recursion::honk {
class ClientIvcRecursiveVerifier_ {
Copy link
Contributor

Choose a reason for hiding this comment

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

I wonder whether we should template this by builder.. unlikely we're going to use MegaCircuitBuilder but it's worth having the mechanism to quickly switch

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think this is worth doing, at least not until we need it. Using mega requires using Goblin so it changes the whole dynamic of what this class does

using Builder = UltraCircuitBuilder; // The circuit will be an Ultra circuit
using RecursiveFlavor = MegaRecursiveFlavor_<Builder>; // The verifier algorithms are Mega
using RecursiveVerifierInstances = RecursiveVerifierInstances_<RecursiveFlavor, 2>;

Builder* builder;

public:
using DeciderVerifier = DeciderRecursiveVerifier_<RecursiveFlavor>;
using FoldingVerifier = ProtoGalaxyRecursiveVerifier_<RecursiveVerifierInstances>;
using VerifierInput = FoldingVerifier::VerifierInput;

ClientIvcRecursiveVerifier_(Builder* builder)
: builder(builder){};

void verify(const ClientIVC::Proof&, VerifierInput&);
};
} // namespace bb::stdlib::recursion::honk
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#include "barretenberg/stdlib/honk_recursion/verifier/client_ivc_recursive_verifier.hpp"
#include "barretenberg/circuit_checker/circuit_checker.hpp"
#include "barretenberg/client_ivc/client_ivc.hpp"
#include "barretenberg/common/test.hpp"

namespace bb::stdlib::recursion::honk {
class ClientIvcRecursionTests : public testing::Test {
public:
using Builder = UltraCircuitBuilder;
using ClientIvcVerifier = ClientIvcRecursiveVerifier_;
using VerifierInput = ClientIvcVerifier::FoldingVerifier::VerifierInput;
using VerifierInstance = VerifierInput::Instance;

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

struct ClientIvcProverOutput {
ClientIVC::Proof proof;
VerifierInput verifier_input;
};

/**
* @brief Construct a genuine ClientIvc prover output based on accumulation of an arbitrary set of mock circuits
*
*/
static ClientIvcProverOutput construct_client_ivc_prover_output(ClientIVC& ivc)
{
using Builder = ClientIVC::ClientCircuit;

size_t NUM_CIRCUITS = 3;
for (size_t idx = 0; idx < NUM_CIRCUITS; ++idx) {
Builder circuit{ ivc.goblin.op_queue };
GoblinMockCircuits::construct_mock_function_circuit(circuit);
ivc.accumulate(circuit);
}

return { ivc.prove(), { ivc.verifier_accumulator, { ivc.instance_vk } } };
}
};

/**
* @brief Ensure the ClientIvc proof used herein can be natively verified
*
*/
TEST_F(ClientIvcRecursionTests, NativeVerification)
{
ClientIVC ivc;
auto [proof, verifier_input] = construct_client_ivc_prover_output(ivc);

// Construct the set of native verifier instances to be processed by the folding verifier
std::vector<std::shared_ptr<VerifierInstance>> instances{ verifier_input.accumulator };
for (auto vk : verifier_input.instance_vks) {
instances.emplace_back(std::make_shared<VerifierInstance>(vk));
}

// Confirm that the IVC proof can be natively verified
EXPECT_TRUE(ivc.verify(proof, instances));
}

/**
* @brief Construct and Check a recursive ClientIvc verification circuit
*
*/
TEST_F(ClientIvcRecursionTests, Basic)
{
// Generate a genuine ClientIvc prover output
ClientIVC ivc;
auto [proof, verifier_input] = construct_client_ivc_prover_output(ivc);

// Construct the ClientIvc recursive verifier
Builder builder;
ClientIvcVerifier verifier{ &builder };

// Generate the recursive verification circuit
verifier.verify(proof, verifier_input);

EXPECT_TRUE(CircuitChecker::check(builder));
Copy link
Contributor

Choose a reason for hiding this comment

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

can you also make sure we can do full proving and verification of the client ivc recursive verifier in this test

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I can but ideally we won't do full proof construction in these test since it'll be very time consuming. CheckCircuit should be nearly just as good and a couple orders of magnitude faster

}

} // namespace bb::stdlib::recursion::honk
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ template <class VerifierInstances> class ProtoGalaxyRecursiveVerifier_ {
static constexpr size_t NUM = VerifierInstances::NUM;
using Transcript = bb::BaseTranscript<bb::stdlib::recursion::honk::StdlibTranscriptParams<Builder>>;

struct VerifierInput {
using Instance = NativeInstance;
std::shared_ptr<Instance> accumulator;
std::vector<std::shared_ptr<NativeVerificationKey>> instance_vks;
};

static constexpr size_t NUM_SUBRELATIONS = Flavor::NUM_SUBRELATIONS;

CommitmentLabels commitment_labels;
Expand All @@ -35,11 +41,9 @@ template <class VerifierInstances> class ProtoGalaxyRecursiveVerifier_ {
std::shared_ptr<Transcript> transcript;
VerifierInstances instances;

ProtoGalaxyRecursiveVerifier_(Builder* builder,
std::shared_ptr<NativeInstance>& accumulator,
const std::vector<std::shared_ptr<NativeVerificationKey>>& native_inst_vks)
ProtoGalaxyRecursiveVerifier_(Builder* builder, const VerifierInput& input_data)
: builder(builder)
, instances(VerifierInstances(builder, accumulator, native_inst_vks)){};
, instances(VerifierInstances(builder, input_data.accumulator, input_data.instance_vks)){};

/**
* @brief Given a new round challenge δ for each iteration of the full ProtoGalaxy protocol, compute the vector
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,8 +193,8 @@ template <typename RecursiveFlavor> class ProtoGalaxyRecursiveTests : public tes

// Create a recursive folding verifier circuit for the folding proof of the two instances
OuterBuilder folding_circuit;
auto verifier =
FoldingRecursiveVerifier(&folding_circuit, verifier_instance_1, { verifier_instance_2->verification_key });
auto verifier = FoldingRecursiveVerifier(&folding_circuit,
{ verifier_instance_1, { verifier_instance_2->verification_key } });
verifier.verify_folding_proof(folding_proof.proof);
info("Folding Recursive Verifier: num gates = ", folding_circuit.num_gates);
EXPECT_EQ(folding_circuit.failed(), false) << folding_circuit.err();
Expand Down Expand Up @@ -257,8 +257,8 @@ template <typename RecursiveFlavor> class ProtoGalaxyRecursiveTests : public tes

// Create a recursive folding verifier circuit for the folding proof of the two instances
OuterBuilder folding_circuit;
auto verifier =
FoldingRecursiveVerifier(&folding_circuit, verifier_instance_1, { verifier_instance_2->verification_key });
auto verifier = FoldingRecursiveVerifier(&folding_circuit,
{ verifier_instance_1, { verifier_instance_2->verification_key } });
auto recursive_verifier_accumulator = verifier.verify_folding_proof(folding_proof.proof);
auto native_verifier_acc = std::make_shared<InnerVerifierInstance>(recursive_verifier_accumulator->get_value());
info("Folding Recursive Verifier: num gates = ", folding_circuit.num_gates);
Expand Down Expand Up @@ -357,8 +357,7 @@ template <typename RecursiveFlavor> class ProtoGalaxyRecursiveTests : public tes
// commitments
OuterBuilder folding_circuit;
FoldingRecursiveVerifier verifier{ &folding_circuit,
verifier_accumulator,
{ verifier_inst->verification_key } };
{ verifier_accumulator, { verifier_inst->verification_key } } };
auto recursive_verifier_acc = verifier.verify_folding_proof(folding_proof.proof);
// Validate that the target sum between prover and verifier is now different
EXPECT_FALSE(folding_proof.accumulator->target_sum == recursive_verifier_acc->target_sum.get_value());
Expand Down
Loading