Skip to content
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
6 changes: 3 additions & 3 deletions barretenberg/cpp/src/barretenberg/api/api_client_ivc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ void ClientIVCAPI::prove(const Flags& flags,
write_bytes_to_stdout(buf);
} else {
vinfo("writing ClientIVC proof in directory ", output_dir);
write_file(output_dir / "proof", buf);
proof.to_file_msgpack(output_dir / "proof");
}
};

Expand All @@ -290,7 +290,7 @@ bool ClientIVCAPI::verify([[maybe_unused]] const Flags& flags,
init_bn254_crs(1);
init_grumpkin_crs(1 << CONST_ECCVM_LOG_N);

const auto proof = from_buffer<ClientIVC::Proof>(read_file(proof_path));
const auto proof = ClientIVC::Proof::from_file_msgpack(proof_path);
const auto vk = from_buffer<ClientIVC::VerificationKey>(read_file(vk_path));

vk.mega->pcs_verification_key = std::make_shared<VerifierCommitmentKey<curve::BN254>>();
Expand Down Expand Up @@ -434,7 +434,7 @@ void write_arbitrary_valid_client_ivc_proof_and_vk_to_file(const std::filesystem

// Write the proof and verification keys into the working directory in 'binary' format
vinfo("writing ClientIVC proof and vk...");
write_file(output_dir / "proof", to_buffer(proof));
proof.to_file_msgpack(output_dir / "proof");

auto eccvm_vk = std::make_shared<ECCVMFlavor::VerificationKey>(ivc.goblin.get_eccvm_proving_key());
auto translator_vk = std::make_shared<TranslatorFlavor::VerificationKey>(ivc.goblin.get_translator_proving_key());
Expand Down
2 changes: 1 addition & 1 deletion barretenberg/cpp/src/barretenberg/api/prove_tube.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ void prove_tube(const std::string& output_path, const std::string& vk_path)
init_grumpkin_crs(1 << 18);

// Read the proof and verification data from given files
auto proof = from_buffer<ClientIVC::Proof>(read_file(proof_path));
auto proof = ClientIVC::Proof::from_file_msgpack(proof_path);
auto vk = from_buffer<ClientIVC::VerificationKey>(read_file(vk_path));

// We don't serialise and deserialise the Grumkin SRS so initialise with circuit_size + 1 to be able to recursively
Expand Down
56 changes: 56 additions & 0 deletions barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,62 @@ class ClientIVC {

size_t size() const { return mega_proof.size() + goblin_proof.size(); }

// TODO(https://github.com/AztecProtocol/barretenberg/issues/1299): The following msgpack methods are generic
// and should leverage some kind of shared msgpack utility.
msgpack::sbuffer to_msgpack_buffer() const
{
msgpack::sbuffer buffer;
msgpack::pack(buffer, *this);
return buffer;
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suspect that this didn't add any new headers (but also in general this should be in a cpp file as msgpack stuff that isn't our thin header include should avoid header pollution)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

yeah I definitely don't want this in here. When you're back we should discuss how to standardize things, assuming we move to more msgpack use in general. I saw you had some established patterns using msgpack::packer - maybe this can just fit into that but wasn't sure it was the right thing


class DeserializationError : public std::runtime_error {
public:
DeserializationError(const std::string& msg)
: std::runtime_error(std::string("Client IVC Proof deserialization error: ") + msg)
{}
};

static Proof from_msgpack_buffer(const msgpack::sbuffer& buffer)
{
msgpack::object_handle oh = msgpack::unpack(buffer.data(), buffer.size());
msgpack::object obj = oh.get();
Proof proof;
obj.convert(proof);
return proof;
}

void to_file_msgpack(const std::string& filename) const
{
msgpack::sbuffer buffer = to_msgpack_buffer();
std::ofstream ofs(filename, std::ios::binary);
if (!ofs.is_open()) {
throw_or_abort("Failed to open file for writing.");
}
ofs.write(buffer.data(), static_cast<std::streamsize>(buffer.size()));
ofs.close();
}

static Proof from_file_msgpack(const std::string& filename)
{
std::ifstream ifs(filename, std::ios::binary);
if (!ifs.is_open()) {
throw_or_abort("Failed to open file for reading.");
}

ifs.seekg(0, std::ios::end);
size_t file_size = static_cast<size_t>(ifs.tellg());
ifs.seekg(0, std::ios::beg);

std::vector<char> buffer(file_size);
ifs.read(buffer.data(), static_cast<std::streamsize>(file_size));
ifs.close();
msgpack::sbuffer msgpack_buffer;
msgpack_buffer.write(buffer.data(), file_size);

return Proof::from_msgpack_buffer(msgpack_buffer);
}

MSGPACK_FIELDS(mega_proof, goblin_proof);
};

Expand Down
64 changes: 64 additions & 0 deletions barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,70 @@ class ClientIVCTests : public ::testing::Test {
}
};

/**
* @brief Test methods for serializing and deserializing a proof to/from a file in msgpack format
*
*/
TEST_F(ClientIVCTests, MsgpackProofFromFile)
{
ClientIVC ivc;

ClientIVCMockCircuitProducer circuit_producer;

// Initialize the IVC with an arbitrary circuit
Builder circuit_0 = circuit_producer.create_next_circuit(ivc);
ivc.accumulate(circuit_0);

// Create another circuit and accumulate
Builder circuit_1 = circuit_producer.create_next_circuit(ivc);
ivc.accumulate(circuit_1);

const auto proof = ivc.prove();

// Serialize/deserialize the proof to/from a file as proof-of-concept
const std::string filename = "proof.msgpack";
proof.to_file_msgpack(filename);
auto proof_deserialized = ClientIVC::Proof::from_file_msgpack(filename);

EXPECT_TRUE(ivc.verify(proof_deserialized));
};

/**
* @brief Check that a CIVC proof can be serialized and deserialized via msgpack and that attempting to deserialize a
* random buffer of bytes fails gracefully with a type error
*/
TEST_F(ClientIVCTests, RandomProofBytes)
{
ClientIVC ivc;

ClientIVCMockCircuitProducer circuit_producer;

// Initialize the IVC with an arbitrary circuit
Builder circuit_0 = circuit_producer.create_next_circuit(ivc);
ivc.accumulate(circuit_0);

// Create another circuit and accumulate
Builder circuit_1 = circuit_producer.create_next_circuit(ivc);
ivc.accumulate(circuit_1);

const auto proof = ivc.prove();

// Serialize/deserialize proof to msgpack buffer, check that it verifies
msgpack::sbuffer buffer = proof.to_msgpack_buffer();
auto proof_deserialized = ClientIVC::Proof::from_msgpack_buffer(buffer);
EXPECT_TRUE(ivc.verify(proof_deserialized));

// Overwrite the buffer with random bytes for testing failure case
{
std::vector<uint8_t> random_bytes(buffer.size());
std::generate(random_bytes.begin(), random_bytes.end(), []() { return static_cast<uint8_t>(rand() % 256); });
std::copy(random_bytes.begin(), random_bytes.end(), buffer.data());
}

// Expect deserialization to fail with error msgpack::v1::type_error with description "std::bad_cast"
EXPECT_THROW(ClientIVC::Proof::from_msgpack_buffer(buffer), msgpack::v1::type_error);
};

/**
* @brief A simple-as-possible test demonstrating IVC for two mock circuits
* @details When accumulating only two circuits, only a single round of folding is performed thus no recursive
Expand Down