From 6417188956f0e5079dec4a8eff85040437bfc047 Mon Sep 17 00:00:00 2001 From: AztecBot Date: Sat, 21 Mar 2026 21:56:49 +0000 Subject: [PATCH 1/2] feat: add many_from_buffer_exact for strict buffer size validation Adds many_from_buffer_exact which validates that binary buffer sizes are exact multiples of sizeof(T) before deserializing, giving clear error messages when files have trailing bytes. Applied to UltraHonk proof and public inputs deserialization. --- .../src/barretenberg/api/api_ultra_honk.cpp | 4 +-- .../cpp/src/barretenberg/api/file_io.hpp | 12 +++++++++ .../cpp/src/barretenberg/api/file_io.test.cpp | 25 +++++++++++++++++++ 3 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 barretenberg/cpp/src/barretenberg/api/file_io.test.cpp diff --git a/barretenberg/cpp/src/barretenberg/api/api_ultra_honk.cpp b/barretenberg/cpp/src/barretenberg/api/api_ultra_honk.cpp index 0e51705b34ee..345b65b02fe1 100644 --- a/barretenberg/cpp/src/barretenberg/api/api_ultra_honk.cpp +++ b/barretenberg/cpp/src/barretenberg/api/api_ultra_honk.cpp @@ -121,14 +121,14 @@ bool UltraHonkAPI::verify(const Flags& flags, if (auto json = try_parse_json(public_inputs_content)) { public_inputs = PublicInputsJson::parse(*json); } else { - public_inputs = many_from_buffer(public_inputs_content); + public_inputs = many_from_buffer_exact(public_inputs_content, "UltraHonk public inputs file"); } auto proof_content = read_file(proof_path); if (auto json = try_parse_json(proof_content)) { proof = ProofJson::parse(*json); } else { - proof = many_from_buffer(proof_content); + proof = many_from_buffer_exact(proof_content, "UltraHonk proof file"); } auto vk_content = read_file(vk_path); diff --git a/barretenberg/cpp/src/barretenberg/api/file_io.hpp b/barretenberg/cpp/src/barretenberg/api/file_io.hpp index 42cbaf6ab05f..a61de3098c06 100644 --- a/barretenberg/cpp/src/barretenberg/api/file_io.hpp +++ b/barretenberg/cpp/src/barretenberg/api/file_io.hpp @@ -1,5 +1,6 @@ #pragma once #include "barretenberg/common/log.hpp" +#include "barretenberg/common/serialize.hpp" #include "barretenberg/common/try_catch_shim.hpp" #include "barretenberg/ecc/curves/bn254/fr.hpp" #include @@ -9,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -153,6 +155,16 @@ inline std::vector read_vk_file(const std::filesystem::path& vk_path) } } +template +inline std::vector many_from_buffer_exact(const std::vector& buffer, std::string_view object_name) +{ + if (buffer.size() % sizeof(T) != 0) { + THROW std::runtime_error(std::string(object_name) + " size must be a multiple of " + + std::to_string(sizeof(T)) + " bytes, got " + std::to_string(buffer.size())); + } + return ::many_from_buffer(buffer); +} + // On Windows, std::filesystem::path uses wide strings (wchar_t) and doesn't implicitly convert // to std::string. On Linux/macOS (libstdc++), the conversion is implicit so these aren't needed. #ifdef _WIN32 diff --git a/barretenberg/cpp/src/barretenberg/api/file_io.test.cpp b/barretenberg/cpp/src/barretenberg/api/file_io.test.cpp new file mode 100644 index 000000000000..7769de2ea5b2 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/api/file_io.test.cpp @@ -0,0 +1,25 @@ +#include "barretenberg/api/file_io.hpp" +#include "barretenberg/common/assert.hpp" +#include "barretenberg/common/serialize.hpp" +#include "barretenberg/numeric/uint256/uint256.hpp" +#include + +using namespace bb; + +TEST(APIFileIO, ManyFromBufferExactRejectsTrailingBytes) +{ + std::vector bytes(sizeof(uint256_t) + 1, 0); + + EXPECT_THROW_WITH_MESSAGE((many_from_buffer_exact(bytes, "UltraHonk proof file")), + "UltraHonk proof file size must be a multiple of 32 bytes, got 33"); +} + +TEST(APIFileIO, ManyFromBufferExactAcceptsAlignedBuffers) +{ + std::vector expected{ uint256_t(1), uint256_t(2) }; + auto bytes = to_buffer(expected); + + auto parsed = many_from_buffer_exact(bytes, "UltraHonk proof file"); + + EXPECT_EQ(parsed, expected); +} From 90c1d6a145835d218bc966cbf6a5a42fb822b7c8 Mon Sep 17 00:00:00 2001 From: AztecBot Date: Sun, 22 Mar 2026 14:43:18 +0000 Subject: [PATCH 2/2] fix: clang-format file_io.hpp --- barretenberg/cpp/src/barretenberg/api/file_io.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/api/file_io.hpp b/barretenberg/cpp/src/barretenberg/api/file_io.hpp index a61de3098c06..894e7f537ffa 100644 --- a/barretenberg/cpp/src/barretenberg/api/file_io.hpp +++ b/barretenberg/cpp/src/barretenberg/api/file_io.hpp @@ -159,8 +159,8 @@ template inline std::vector many_from_buffer_exact(const std::vector& buffer, std::string_view object_name) { if (buffer.size() % sizeof(T) != 0) { - THROW std::runtime_error(std::string(object_name) + " size must be a multiple of " + - std::to_string(sizeof(T)) + " bytes, got " + std::to_string(buffer.size())); + THROW std::runtime_error(std::string(object_name) + " size must be a multiple of " + std::to_string(sizeof(T)) + + " bytes, got " + std::to_string(buffer.size())); } return ::many_from_buffer(buffer); }