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

refactor: CIVC VK #10223

Merged
merged 3 commits into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
79 changes: 28 additions & 51 deletions barretenberg/cpp/src/barretenberg/bb/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,6 @@ void client_ivc_prove_output_all_msgpack(const std::string& bytecodePath,
using Program = acir_format::AcirProgram;
using ECCVMVK = ECCVMFlavor::VerificationKey;
using TranslatorVK = TranslatorFlavor::VerificationKey;
using DeciderVerificationKey = ClientIVC::DeciderVerificationKey;

using namespace acir_format;

Expand Down Expand Up @@ -378,23 +377,17 @@ void client_ivc_prove_output_all_msgpack(const std::string& bytecodePath,

// Write the proof and verification keys into the working directory in 'binary' format (in practice it seems this
// directory is passed by bb.js)
std::string vkPath = outputDir + "/mega_vk"; // the vk of the last circuit in the stack
std::string vkPath = outputDir + "/client_ivc_vk"; // the vk of the last circuit in the stack
Copy link
Contributor

Choose a reason for hiding this comment

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

the comment is stale

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Made the change in my API PR that builds off this one

std::string proofPath = outputDir + "/client_ivc_proof";
std::string translatorVkPath = outputDir + "/translator_vk";
std::string eccVkPath = outputDir + "/ecc_vk";

auto proof = ivc.prove();
auto eccvm_vk = std::make_shared<ECCVMVK>(ivc.goblin.get_eccvm_proving_key());
auto translator_vk = std::make_shared<TranslatorVK>(ivc.goblin.get_translator_proving_key());

auto last_vk = std::make_shared<DeciderVerificationKey>(ivc.honk_vk);
vinfo("ensure valid proof: ", ivc.verify(proof));

vinfo("write proof and vk data to files..");
write_file(proofPath, to_buffer(proof));
write_file(vkPath, to_buffer(ivc.honk_vk));
write_file(translatorVkPath, to_buffer(translator_vk));
write_file(eccVkPath, to_buffer(eccvm_vk));
write_file(vkPath, to_buffer(ClientIVC::VerificationKey{ ivc.honk_vk, eccvm_vk, translator_vk }));
}

template <typename T> std::shared_ptr<T> read_to_shared_ptr(const std::filesystem::path& path)
Expand All @@ -414,24 +407,20 @@ template <typename T> std::shared_ptr<T> read_to_shared_ptr(const std::filesyste
* @param accumualtor_path Path to the file containing the serialized protogalaxy accumulator
* @return true (resp., false) if the proof is valid (resp., invalid).
*/
bool verify_client_ivc(const std::filesystem::path& proof_path,
const std::filesystem::path& mega_vk,
const std::filesystem::path& eccvm_vk_path,
const std::filesystem::path& translator_vk_path)
bool verify_client_ivc(const std::filesystem::path& proof_path, const std::filesystem::path& vk_path)
{
init_bn254_crs(1);
init_grumpkin_crs(1 << 15);

const auto proof = from_buffer<ClientIVC::Proof>(read_file(proof_path));
const auto final_vk = read_to_shared_ptr<ClientIVC::VerificationKey>(mega_vk);
final_vk->pcs_verification_key = std::make_shared<VerifierCommitmentKey<curve::BN254>>();

const auto eccvm_vk = read_to_shared_ptr<ECCVMFlavor::VerificationKey>(eccvm_vk_path);
eccvm_vk->pcs_verification_key =
std::make_shared<VerifierCommitmentKey<curve::Grumpkin>>(eccvm_vk->circuit_size + 1);
const auto translator_vk = read_to_shared_ptr<TranslatorFlavor::VerificationKey>(translator_vk_path);
translator_vk->pcs_verification_key = std::make_shared<VerifierCommitmentKey<curve::BN254>>();
const bool verified = ClientIVC::verify(proof, final_vk, eccvm_vk, translator_vk);
const auto vk = from_buffer<ClientIVC::VerificationKey>(read_file(vk_path));

vk.mega->pcs_verification_key = std::make_shared<VerifierCommitmentKey<curve::BN254>>();
vk.eccvm->pcs_verification_key =
std::make_shared<VerifierCommitmentKey<curve::Grumpkin>>(vk.eccvm->circuit_size + 1);
vk.translator->pcs_verification_key = std::make_shared<VerifierCommitmentKey<curve::BN254>>();

const bool verified = ClientIVC::verify(proof, vk);
vinfo("verified: ", verified);
return verified;
}
Expand Down Expand Up @@ -519,10 +508,8 @@ void client_ivc_prove_output_all(const std::string& bytecodePath,

// Write the proof and verification keys into the working directory in 'binary' format (in practice it seems this
// directory is passed by bb.js)
std::string vkPath = outputPath + "/mega_vk"; // the vk of the last circuit in the stack
std::string vkPath = outputPath + "/client_ivc_vk"; // the vk of the last circuit in the stack
Copy link
Contributor

Choose a reason for hiding this comment

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

stale comment

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Made the change in my API PR that builds off this one

std::string proofPath = outputPath + "/client_ivc_proof";
std::string translatorVkPath = outputPath + "/translator_vk";
std::string eccVkPath = outputPath + "/ecc_vk";

auto proof = ivc.prove();
auto eccvm_vk = std::make_shared<ECCVMVK>(ivc.goblin.get_eccvm_proving_key());
Expand All @@ -531,9 +518,7 @@ void client_ivc_prove_output_all(const std::string& bytecodePath,

vinfo("write proof and vk data to files..");
write_file(proofPath, to_buffer(proof));
write_file(vkPath, to_buffer(ivc.honk_vk)); // maybe dereference
write_file(translatorVkPath, to_buffer(translator_vk));
write_file(eccVkPath, to_buffer(eccvm_vk));
write_file(vkPath, to_buffer(ClientIVC::VerificationKey{ ivc.honk_vk, eccvm_vk, translator_vk }));
}

/**
Expand All @@ -544,37 +529,31 @@ void client_ivc_prove_output_all(const std::string& bytecodePath,
*/
void prove_tube(const std::string& output_path)
{
using ClientIVC = stdlib::recursion::honk::ClientIVCRecursiveVerifier;
using StackHonkVK = typename MegaFlavor::VerificationKey;
using ECCVMVk = ECCVMFlavor::VerificationKey;
using TranslatorVk = TranslatorFlavor::VerificationKey;
using GoblinVerifierInput = ClientIVC::GoblinVerifierInput;
using VerifierInput = ClientIVC::VerifierInput;
using namespace stdlib::recursion::honk;

using GoblinVerifierInput = ClientIVCRecursiveVerifier::GoblinVerifierInput;
using VerifierInput = ClientIVCRecursiveVerifier::VerifierInput;
using Builder = UltraCircuitBuilder;
using GrumpkinVk = bb::VerifierCommitmentKey<curve::Grumpkin>;

std::string vkPath = output_path + "/mega_vk"; // the vk of the last circuit in the stack
std::string vkPath = output_path + "/client_ivc_vk"; // the vk of the last circuit in the stack
std::string proofPath = output_path + "/client_ivc_proof";
std::string translatorVkPath = output_path + "/translator_vk";
std::string eccVkPath = output_path + "/ecc_vk";

// Note: this could be decreased once we optimise the size of the ClientIVC recursiveve rifier
init_bn254_crs(1 << 25);
init_grumpkin_crs(1 << 18);

// Read the proof and verification data from given files
auto proof = from_buffer<ClientIVC::Proof>(read_file(proofPath));
std::shared_ptr<StackHonkVK> mega_vk = std::make_shared<StackHonkVK>(from_buffer<StackHonkVK>(read_file(vkPath)));
std::shared_ptr<TranslatorVk> translator_vk =
std::make_shared<TranslatorVk>(from_buffer<TranslatorVk>(read_file(translatorVkPath)));
std::shared_ptr<ECCVMVk> eccvm_vk = std::make_shared<ECCVMVk>(from_buffer<ECCVMVk>(read_file(eccVkPath)));
auto vk = from_buffer<ClientIVC::VerificationKey>(read_file(vkPath));

// We don't serialise and deserialise the Grumkin SRS so initialise with circuit_size + 1 to be able to recursively
// IPA. The + 1 is to satisfy IPA verification key requirements.
// TODO(https://github.com/AztecProtocol/barretenberg/issues/1025)
eccvm_vk->pcs_verification_key = std::make_shared<GrumpkinVk>(eccvm_vk->circuit_size + 1);
vk.eccvm->pcs_verification_key = std::make_shared<GrumpkinVk>(vk.eccvm->circuit_size + 1);

GoblinVerifierInput goblin_verifier_input{ eccvm_vk, translator_vk };
VerifierInput input{ mega_vk, goblin_verifier_input };
GoblinVerifierInput goblin_verifier_input{ vk.eccvm, vk.translator };
VerifierInput input{ vk.mega, goblin_verifier_input };
auto builder = std::make_shared<Builder>();

// Preserve the public inputs that should be passed to the base rollup by making them public inputs to the tube
Expand All @@ -588,9 +567,9 @@ void prove_tube(const std::string& output_path)
auto offset = bb::HONK_PROOF_PUBLIC_INPUT_OFFSET;
builder->add_public_variable(proof.mega_proof[i + offset]);
}
ClientIVC verifier{ builder, input };
ClientIVCRecursiveVerifier verifier{ builder, input };

ClientIVC::Output client_ivc_rec_verifier_output = verifier.verify(proof);
ClientIVCRecursiveVerifier::Output client_ivc_rec_verifier_output = verifier.verify(proof);

PairingPointAccumulatorIndices current_aggregation_object =
stdlib::recursion::init_default_agg_obj_indices<Builder>(*builder);
Expand Down Expand Up @@ -1468,12 +1447,10 @@ int main(int argc, char* argv[])
}
if (command == "verify_client_ivc") {
std::filesystem::path output_dir = get_option(args, "-o", "./target");
std::filesystem::path client_ivc_proof_path = output_dir / "client_ivc_proof";
std::filesystem::path mega_vk_path = output_dir / "mega_vk";
std::filesystem::path eccvm_vk_path = output_dir / "ecc_vk";
std::filesystem::path translator_vk_path = output_dir / "translator_vk";
std::filesystem::path proof_path = output_dir / "client_ivc_proof";
std::filesystem::path vk_path = output_dir / "client_ivc_vk";

return verify_client_ivc(client_ivc_proof_path, mega_vk_path, eccvm_vk_path, translator_vk_path) ? 0 : 1;
return verify_client_ivc(proof_path, vk_path) ? 0 : 1;
}
if (command == "fold_and_verify_program") {
return foldAndVerifyProgram(bytecode_path, witness_path) ? 0 : 1;
Expand Down
25 changes: 12 additions & 13 deletions barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,9 @@ void ClientIVC::complete_kernel_circuit_logic(ClientCircuit& circuit)
* @param circuit
* @param precomputed_vk
*/
void ClientIVC::accumulate(ClientCircuit& circuit, const std::shared_ptr<VerificationKey>& precomputed_vk, bool mock_vk)
void ClientIVC::accumulate(ClientCircuit& circuit,
const std::shared_ptr<MegaVerificationKey>& precomputed_vk,
bool mock_vk)
{
if (auto_verify_mode && circuit.databus_propagation_data.is_kernel) {
complete_kernel_circuit_logic(circuit);
Expand Down Expand Up @@ -186,7 +188,7 @@ void ClientIVC::accumulate(ClientCircuit& circuit, const std::shared_ptr<Verific
trace_usage_tracker.update(circuit);

// Set the verification key from precomputed if available, else compute it
honk_vk = precomputed_vk ? precomputed_vk : std::make_shared<VerificationKey>(proving_key->proving_key);
honk_vk = precomputed_vk ? precomputed_vk : std::make_shared<MegaVerificationKey>(proving_key->proving_key);
if (mock_vk) {
honk_vk->set_metadata(proving_key->proving_key);
}
Expand Down Expand Up @@ -280,7 +282,7 @@ HonkProof ClientIVC::construct_and_prove_hiding_circuit()
merge_verification_queue.emplace_back(merge_proof);

auto decider_pk = std::make_shared<DeciderProvingKey>(builder, TraceSettings(), bn254_commitment_key);
honk_vk = std::make_shared<VerificationKey>(decider_pk->proving_key);
honk_vk = std::make_shared<MegaVerificationKey>(decider_pk->proving_key);
MegaProver prover(decider_pk);

HonkProof proof = prover.construct_proof();
Expand All @@ -301,18 +303,15 @@ ClientIVC::Proof ClientIVC::prove()
return { mega_proof, goblin.prove(merge_proof) };
};

bool ClientIVC::verify(const Proof& proof,
const std::shared_ptr<VerificationKey>& mega_vk,
const std::shared_ptr<ClientIVC::ECCVMVerificationKey>& eccvm_vk,
const std::shared_ptr<ClientIVC::TranslatorVerificationKey>& translator_vk)
bool ClientIVC::verify(const Proof& proof, const VerificationKey& vk)
{

// Verify the hiding circuit proof
MegaVerifier verifer{ mega_vk };
MegaVerifier verifer{ vk.mega };
bool mega_verified = verifer.verify_proof(proof.mega_proof);
vinfo("Mega verified: ", mega_verified);
// Goblin verification (final merge, eccvm, translator)
GoblinVerifier goblin_verifier{ eccvm_vk, translator_vk };
GoblinVerifier goblin_verifier{ vk.eccvm, vk.translator };
bool goblin_verified = goblin_verifier.verify(proof.goblin_proof);
vinfo("Goblin verified: ", goblin_verified);
return goblin_verified && mega_verified;
Expand All @@ -328,7 +327,7 @@ bool ClientIVC::verify(const Proof& proof)
{
auto eccvm_vk = std::make_shared<ECCVMVerificationKey>(goblin.get_eccvm_proving_key());
auto translator_vk = std::make_shared<TranslatorVerificationKey>(goblin.get_translator_proving_key());
return verify(proof, honk_vk, eccvm_vk, translator_vk);
return verify(proof, { honk_vk, eccvm_vk, translator_vk });
}

/**
Expand Down Expand Up @@ -379,12 +378,12 @@ bool ClientIVC::prove_and_verify()
* (albeit innefficient) way of separating out the cost of computing VKs from a benchmark.
*
* @param circuits A copy of the circuits to be accumulated (passing by reference would alter the original circuits)
* @return std::vector<std::shared_ptr<ClientIVC::VerificationKey>>
* @return std::vector<std::shared_ptr<MegaFlavor::VerificationKey>>
*/
std::vector<std::shared_ptr<ClientIVC::VerificationKey>> ClientIVC::precompute_folding_verification_keys(
std::vector<std::shared_ptr<MegaFlavor::VerificationKey>> ClientIVC::precompute_folding_verification_keys(
std::vector<ClientCircuit> circuits)
{
std::vector<std::shared_ptr<VerificationKey>> vkeys;
std::vector<std::shared_ptr<MegaVerificationKey>> vkeys;

for (auto& circuit : circuits) {
accumulate(circuit);
Expand Down
24 changes: 15 additions & 9 deletions barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class ClientIVC {

public:
using Flavor = MegaFlavor;
using VerificationKey = Flavor::VerificationKey;
using MegaVerificationKey = Flavor::VerificationKey;
using FF = Flavor::FF;
using FoldProof = std::vector<FF>;
using MergeProof = std::vector<FF>;
Expand Down Expand Up @@ -73,12 +73,20 @@ class ClientIVC {
MSGPACK_FIELDS(mega_proof, goblin_proof);
};

struct VerificationKey {
std::shared_ptr<MegaVerificationKey> mega;
std::shared_ptr<ECCVMVerificationKey> eccvm;
std::shared_ptr<TranslatorVerificationKey> translator;

MSGPACK_FIELDS(mega, eccvm, translator);
};

enum class QUEUE_TYPE { OINK, PG }; // for specifying type of proof in the verification queue

// An entry in the native verification queue
struct VerifierInputs {
std::vector<FF> proof; // oink or PG
std::shared_ptr<VerificationKey> honk_verification_key;
std::shared_ptr<MegaVerificationKey> honk_verification_key;
QUEUE_TYPE type;
};
using VerificationQueue = std::vector<VerifierInputs>;
Expand All @@ -89,6 +97,7 @@ class ClientIVC {
std::shared_ptr<RecursiveVerificationKey> honk_verification_key;
QUEUE_TYPE type;
};

using StdlibVerificationQueue = std::vector<StdlibVerifierInputs>;

// Utility for tracking the max size of each block across the full IVC
Expand All @@ -101,7 +110,7 @@ class ClientIVC {
ProverFoldOutput fold_output; // prover accumulator and fold proof

std::shared_ptr<DeciderVerificationKey> verifier_accumulator; // verifier accumulator
std::shared_ptr<VerificationKey> honk_vk; // honk vk to be completed and folded into the accumulator
std::shared_ptr<MegaVerificationKey> honk_vk; // honk vk to be completed and folded into the accumulator

// Set of tuples {proof, verification_key, type} to be recursively verified
VerificationQueue verification_queue;
Expand Down Expand Up @@ -158,25 +167,22 @@ class ClientIVC {
* @param mock_vk A boolean to say whether the precomputed vk shoudl have its metadata set.
*/
void accumulate(ClientCircuit& circuit,
const std::shared_ptr<VerificationKey>& precomputed_vk = nullptr,
const std::shared_ptr<MegaVerificationKey>& precomputed_vk = nullptr,
bool mock_vk = false);

Proof prove();

HonkProof construct_and_prove_hiding_circuit();

static bool verify(const Proof& proof,
const std::shared_ptr<VerificationKey>& mega_vk,
const std::shared_ptr<ClientIVC::ECCVMVerificationKey>& eccvm_vk,
const std::shared_ptr<ClientIVC::TranslatorVerificationKey>& translator_vk);
static bool verify(const Proof& proof, const VerificationKey& vk);

bool verify(const Proof& proof);

bool prove_and_verify();

HonkProof decider_prove() const;

std::vector<std::shared_ptr<VerificationKey>> precompute_folding_verification_keys(
std::vector<std::shared_ptr<MegaVerificationKey>> precompute_folding_verification_keys(
std::vector<ClientCircuit> circuits);
};
} // namespace bb
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ ClientIVC::VerifierInputs create_dummy_vkey_and_proof_oink(const TraceSettings&
const size_t num_public_inputs = 0)
{
using Flavor = MegaFlavor;
using VerificationKey = ClientIVC::VerificationKey;
using FF = bb::fr;

MegaExecutionTraceBlocks blocks;
Expand Down Expand Up @@ -89,7 +88,7 @@ ClientIVC::VerifierInputs create_dummy_vkey_and_proof_oink(const TraceSettings&
}

// Set relevant VK metadata and commitments
verifier_inputs.honk_verification_key = std::make_shared<VerificationKey>();
verifier_inputs.honk_verification_key = std::make_shared<Flavor::VerificationKey>();
verifier_inputs.honk_verification_key->circuit_size = structured_dyadic_size;
verifier_inputs.honk_verification_key->num_public_inputs = total_num_public_inputs;
verifier_inputs.honk_verification_key->pub_inputs_offset = blocks.pub_inputs.trace_offset; // must be set correctly
Expand Down Expand Up @@ -146,7 +145,7 @@ ClientIVC::MergeProof create_dummy_merge_proof()
* @param key_witness_indices
*/
void populate_dummy_vk_in_constraint(MegaCircuitBuilder& builder,
const std::shared_ptr<ClientIVC::VerificationKey>& mock_verification_key,
const std::shared_ptr<MegaFlavor::VerificationKey>& mock_verification_key,
std::vector<uint32_t>& key_witness_indices)
{
using Flavor = MegaFlavor;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ ClientIVC::VerifierInputs create_dummy_vkey_and_proof_oink(const TraceSettings&
ClientIVC::MergeProof create_dummy_merge_proof();

void populate_dummy_vk_in_constraint(MegaCircuitBuilder& builder,
const std::shared_ptr<ClientIVC::VerificationKey>& mock_verification_key,
const std::shared_ptr<MegaFlavor::VerificationKey>& mock_verification_key,
std::vector<uint32_t>& key_witness_indices);

} // namespace acir_format
Loading