Skip to content

Commit

Permalink
feat: Verify ClientIVC proofs through Bb binary (#7407)
Browse files Browse the repository at this point in the history
Exposes a function to verify ClientIVC proofs through the Bb binary
  • Loading branch information
codygunton authored Jul 11, 2024
1 parent e4abe1d commit 3760c64
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 26 deletions.
2 changes: 2 additions & 0 deletions barretenberg/Earthfile
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ barretenberg-acir-tests-bb:
RUN FLOW=prove_and_verify_mega_honk_program ./run_acir_tests.sh
# Fold and verify an ACIR program stack using ClientIvc
RUN FLOW=fold_and_verify_program ./run_acir_tests.sh fold_basic
# Fold and verify an ACIR program stack using ClientIvc, then natively verify the ClientIVC proof.
RUN FLOW=prove_then_verify_client_ivc ./run_acir_tests.sh fold_basic
# Fold and verify an ACIR program stack using ClientIvc, recursively verify as part of the Tube circuit and produce and verify a Honk proof
RUN FLOW=prove_then_verify_tube ./run_acir_tests.sh fold_basic
# Construct and separately verify a UltraHonk proof for a single program that recursively verifies a Honk proof
Expand Down
9 changes: 9 additions & 0 deletions barretenberg/acir_tests/flows/prove_then_verify_client_ivc.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/sh
set -eu

VFLAG=${VERBOSE:+-v}
BFLAG="-b ./target/program.json"
FLAGS="-c $CRS_PATH $VFLAG"

$BIN client_ivc_prove_output_all $FLAGS $BFLAG
$BIN verify_client_ivc $FLAGS
80 changes: 67 additions & 13 deletions barretenberg/cpp/src/barretenberg/bb/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ std::vector<uint8_t> decompressedBuffer(uint8_t* bytes, size_t size)

void client_ivc_prove_output_all_msgpack(const std::string& bytecodePath,
const std::string& witnessPath,
const std::string& outputPath)
const std::string& outputDir)
{
using Flavor = MegaFlavor; // This is the only option
using Builder = Flavor::CircuitBuilder;
Expand Down Expand Up @@ -361,11 +361,11 @@ 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 = outputPath + "/inst_vk"; // the vk of the last instance
std::string accPath = outputPath + "/pg_acc";
std::string proofPath = outputPath + "/client_ivc_proof";
std::string translatorVkPath = outputPath + "/translator_vk";
std::string eccVkPath = outputPath + "/ecc_vk";
std::string vkPath = outputDir + "/inst_vk"; // the vk of the last instance
std::string accPath = outputDir + "/pg_acc";
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());
Expand All @@ -382,6 +382,48 @@ void client_ivc_prove_output_all_msgpack(const std::string& bytecodePath,
write_file(eccVkPath, to_buffer(eccvm_vk));
}

template <typename T> std::shared_ptr<T> read_to_shared_ptr(const std::filesystem::path& path)
{
return std::make_shared<T>(from_buffer<T>(read_file(path)));
};

/**
* @brief Verifies a client ivc proof and writes the result to stdout
*
* Communication:
* - proc_exit: A boolean value is returned indicating whether the proof is valid.
* an exit code of 0 will be returned for success and 1 for failure.
*
* @param proof_path Path to the file containing the serialized proof
* @param vk_path Path to the file containing the serialized verification key of the final mega honk instance
* @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& accumulator_path,
const std::filesystem::path& final_vk_path,
const std::filesystem::path& eccvm_vk_path,
const std::filesystem::path& translator_vk_path)
{
init_bn254_crs(1 << 24);
init_grumpkin_crs(1 << 14);

const auto proof = from_buffer<ClientIVC::Proof>(read_file(proof_path));
const auto accumulator = read_to_shared_ptr<ClientIVC::VerifierInstance>(accumulator_path);
accumulator->verification_key->pcs_verification_key = std::make_shared<VerifierCommitmentKey<curve::BN254>>();
const auto final_vk = read_to_shared_ptr<ClientIVC::VerificationKey>(final_vk_path);
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, accumulator, std::make_shared<ClientIVC::VerifierInstance>(final_vk), eccvm_vk, translator_vk);
vinfo("verified: ", verified);
return verified;
}

bool foldAndVerifyProgram(const std::string& bytecodePath, const std::string& witnessPath)
{
using Flavor = MegaFlavor; // This is the only option
Expand Down Expand Up @@ -534,8 +576,7 @@ void prove_tube(const std::string& output_path)
ClientIVC verifier{ builder, input };

verifier.verify(proof);
info("num gates: ", builder->get_num_gates());
info("generating proof");
info("num gates in tube circuit: ", builder->get_num_gates());
using Prover = UltraProver_<UltraFlavor>;
using Verifier = UltraVerifier_<UltraFlavor>;
Prover tube_prover{ *builder };
Expand Down Expand Up @@ -1269,10 +1310,23 @@ int main(int argc, char* argv[])
// TODO(https://github.com/AztecProtocol/barretenberg/issues/1050) we need a verify_client_ivc bb cli command
// TODO(#7371): remove this
if (command == "client_ivc_prove_output_all_msgpack") {
std::string output_path = get_option(args, "-o", "./proofs/proof");
client_ivc_prove_output_all_msgpack(bytecode_path, witness_path, output_path);
std::filesystem::path output_dir = get_option(args, "-o", "./target");
client_ivc_prove_output_all_msgpack(bytecode_path, witness_path, output_dir);
return 0;
}
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 accumulator_path = output_dir / "pg_acc";
std::filesystem::path final_vk_path = output_dir / "inst_vk";
std::filesystem::path eccvm_vk_path = output_dir / "ecc_vk";
std::filesystem::path translator_vk_path = output_dir / "translator_vk";

return verify_client_ivc(
client_ivc_proof_path, accumulator_path, final_vk_path, eccvm_vk_path, translator_vk_path)
? 0
: 1;
}
if (command == "fold_and_verify_program") {
return foldAndVerifyProgram(bytecode_path, witness_path) ? 0 : 1;
}
Expand All @@ -1290,13 +1344,13 @@ int main(int argc, char* argv[])
std::string output_path = get_option(args, "-o", "./proofs");
prove_honk_output_all<MegaFlavor>(bytecode_path, witness_path, output_path);
} else if (command == "client_ivc_prove_output_all") {
std::string output_path = get_option(args, "-o", "./proofs");
std::string output_path = get_option(args, "-o", "./target");
client_ivc_prove_output_all(bytecode_path, witness_path, output_path);
} else if (command == "prove_tube") {
std::string output_path = get_option(args, "-o", "./proofs");
std::string output_path = get_option(args, "-o", "./target");
prove_tube(output_path);
} else if (command == "verify_tube") {
std::string output_path = get_option(args, "-o", "./proofs");
std::string output_path = get_option(args, "-o", "./target");
auto tube_proof_path = output_path + "/proof";
auto tube_vk_path = output_path + "/vk";
return verify_honk<UltraFlavor>(tube_proof_path, tube_vk_path) ? 0 : 1;
Expand Down
33 changes: 21 additions & 12 deletions barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,31 +58,40 @@ ClientIVC::Proof ClientIVC::prove()
{
max_block_sizes.print(); // print minimum structured sizes for each block
return { fold_output.proof, decider_prove(), goblin.prove() };
}
};

/**
* @brief Verify a full proof of the IVC
*
* @param proof
* @return bool
*/
bool ClientIVC::verify(Proof& proof, const std::vector<std::shared_ptr<VerifierInstance>>& verifier_instances)
bool ClientIVC::verify(const Proof& proof,
const std::shared_ptr<VerifierInstance>& accumulator,
const std::shared_ptr<VerifierInstance>& final_verifier_instance,
const std::shared_ptr<ClientIVC::ECCVMVerificationKey>& eccvm_vk,
const std::shared_ptr<ClientIVC::TranslatorVerificationKey>& translator_vk)
{
// Goblin verification (merge, eccvm, translator)
auto eccvm_vkey = std::make_shared<ECCVMVerificationKey>(goblin.get_eccvm_proving_key());
auto translator_vkey = std::make_shared<TranslatorVerificationKey>(goblin.get_translator_proving_key());
GoblinVerifier goblin_verifier{ eccvm_vkey, translator_vkey };
GoblinVerifier goblin_verifier{ eccvm_vk, translator_vk };
bool goblin_verified = goblin_verifier.verify(proof.goblin_proof);

// Decider verification
ClientIVC::FoldingVerifier folding_verifier({ verifier_instances[0], verifier_instances[1] });
ClientIVC::FoldingVerifier folding_verifier({ accumulator, final_verifier_instance });
auto verifier_accumulator = folding_verifier.verify_folding_proof(proof.folding_proof);

ClientIVC::DeciderVerifier decider_verifier(verifier_accumulator);
bool decision = decider_verifier.verify_proof(proof.decider_proof);
return goblin_verified && decision;
}

/**
* @brief Verify a full proof of the IVC
*
* @param proof
* @return bool
*/
bool ClientIVC::verify(Proof& proof, const std::vector<std::shared_ptr<VerifierInstance>>& verifier_instances)
{
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, verifier_instances[0], verifier_instances[1], eccvm_vk, translator_vk);
}

/**
* @brief Internal method for constructing a decider proof
*
Expand Down
6 changes: 6 additions & 0 deletions barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,12 @@ class ClientIVC {

Proof prove();

static bool verify(const Proof& proof,
const std::shared_ptr<VerifierInstance>& accumulator,
const std::shared_ptr<VerifierInstance>& final_verifier_instance,
const std::shared_ptr<ClientIVC::ECCVMVerificationKey>& eccvm_vk,
const std::shared_ptr<ClientIVC::TranslatorVerificationKey>& translator_vk);

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

bool prove_and_verify();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -691,8 +691,23 @@ template <typename Curve> class ZeroMorphVerifier_ {
* @brief Utility for native batch multiplication of group elements
* @note This is used only for native verification and is not optimized for efficiency
*/
static Commitment batch_mul_native(const std::vector<Commitment>& points, const std::vector<FF>& scalars)
static Commitment batch_mul_native(const std::vector<Commitment>& _points, const std::vector<FF>& _scalars)
{
std::vector<Commitment> points;
std::vector<FF> scalars;
for (auto [point, scalar] : zip_view(_points, _scalars)) {
// TODO(https://github.com/AztecProtocol/barretenberg/issues/866) Special handling of point at infinity here
// due to incorrect serialization.
if (!scalar.is_zero() && !point.is_point_at_infinity() && !point.y.is_zero()) {
points.emplace_back(point);
scalars.emplace_back(scalar);
}
}

if (points.empty()) {
return Commitment::infinity();
}

auto result = points[0] * scalars[0];
for (size_t idx = 1; idx < scalars.size(); ++idx) {
result = result + points[idx] * scalars[idx];
Expand Down

0 comments on commit 3760c64

Please sign in to comment.