From 1fc43e0f23161129b70f565ae0c0caea81ef24e3 Mon Sep 17 00:00:00 2001 From: AztecBot Date: Wed, 15 Jul 2026 06:16:42 +0000 Subject: [PATCH] Reject oversized VK metadata integers --- .../ecc/fields/field_conversion.hpp | 23 ++++++++++- .../ecc/fields/field_conversion.test.cpp | 38 +++++++++++++++++++ .../flavor/native_verification_key.test.cpp | 19 ++++++++++ 3 files changed, 78 insertions(+), 2 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/ecc/fields/field_conversion.hpp b/barretenberg/cpp/src/barretenberg/ecc/fields/field_conversion.hpp index e23de01cc2de..7462ce1fafd9 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/fields/field_conversion.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/fields/field_conversion.hpp @@ -13,9 +13,24 @@ #include "barretenberg/ecc/curves/grumpkin/grumpkin.hpp" #include "barretenberg/polynomials/univariate.hpp" #include "barretenberg/stdlib/primitives/bigfield/constants.hpp" // NUM_LIMB_BITS_IN_FIELD_SIMULATION +#include namespace bb { +template T deserialize_bounded_integer(const Value& value) +{ + if constexpr (std::is_same_v) { + BB_ASSERT_LTE(uint256_t(value), + uint256_t(std::numeric_limits::max()), + "Non-canonical uint32_t encoding: value exceeds uint32_t range"); + } else if constexpr (std::is_same_v) { + BB_ASSERT_LTE(uint256_t(value), + uint256_t(std::numeric_limits::max()), + "Non-canonical uint64_t encoding: value exceeds uint64_t range"); + } + return static_cast(value); +} + class FrCodec { public: using DataType = bb::fr; @@ -114,7 +129,9 @@ class FrCodec { BB_ASSERT_EQ(fr_vec.size(), calc_num_fields()); if constexpr (IsAnyOf) { return static_cast(fr_vec[0]); - } else if constexpr (IsAnyOf) { + } else if constexpr (IsAnyOf) { + return deserialize_bounded_integer(fr_vec[0]); + } else if constexpr (IsAnyOf) { return static_cast(fr_vec[0]); } else if constexpr (IsAnyOf) { return convert_grumpkin_fr_from_bn254_frs(fr_vec); @@ -277,7 +294,9 @@ class U256Codec { } else if constexpr (IsAnyOf) { BB_ASSERT_LT(vec[0], uint256_t(fq::modulus), "Non-canonical base field element: value >= fq::modulus"); return static_cast(vec[0]); - } else if constexpr (IsAnyOf) { + } else if constexpr (IsAnyOf) { + return deserialize_bounded_integer(vec[0]); + } else if constexpr (IsAnyOf) { return static_cast(vec[0]); } else if constexpr (IsAnyOf) { using BaseField = typename T::Fq; diff --git a/barretenberg/cpp/src/barretenberg/ecc/fields/field_conversion.test.cpp b/barretenberg/cpp/src/barretenberg/ecc/fields/field_conversion.test.cpp index 541ac377837e..8ec3cb5cbc16 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/fields/field_conversion.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ecc/fields/field_conversion.test.cpp @@ -2,6 +2,7 @@ #include "barretenberg/common/assert.hpp" #include "barretenberg/ecc/curves/grumpkin/grumpkin.hpp" #include +#include namespace bb::field_conversion_tests { @@ -26,6 +27,43 @@ TEST_F(FieldConversionTest, FieldConversionUint32) check_conversion(x); } +TEST_F(FieldConversionTest, FrCodecRejectsOversizedUint32Metadata) +{ + const std::vector fields = { bb::fr((uint256_t(1) << 32) + 7) }; + EXPECT_THROW_WITH_MESSAGE(FrCodec::deserialize_from_fields(fields), "uint32_t"); +} + +TEST_F(FieldConversionTest, FrCodecRejectsOversizedUint64Metadata) +{ + const std::vector fields = { bb::fr((uint256_t(1) << 64) + 7) }; + EXPECT_THROW_WITH_MESSAGE(FrCodec::deserialize_from_fields(fields), "uint64_t"); +} + +TEST_F(FieldConversionTest, U256CodecRejectsOversizedUint32Metadata) +{ + const std::vector fields = { (uint256_t(1) << 32) + 7 }; + EXPECT_THROW_WITH_MESSAGE(U256Codec::deserialize_from_fields(fields), "uint32_t"); +} + +TEST_F(FieldConversionTest, U256CodecRejectsOversizedUint64Metadata) +{ + const std::vector fields = { (uint256_t(1) << 64) + 7 }; + EXPECT_THROW_WITH_MESSAGE(U256Codec::deserialize_from_fields(fields), "uint64_t"); +} + +TEST_F(FieldConversionTest, IntegerMetadataMaxValuesAccepted) +{ + const auto max_u32 = std::numeric_limits::max(); + const auto max_u64 = std::numeric_limits::max(); + + EXPECT_EQ(FrCodec::deserialize_from_fields(std::vector{ bb::fr(max_u32) }), max_u32); + EXPECT_EQ(FrCodec::deserialize_from_fields( + std::vector{ bb::fr(uint256_t(std::numeric_limits::max())) }), + max_u64); + EXPECT_EQ(U256Codec::deserialize_from_fields(std::vector{ uint256_t(max_u32) }), max_u32); + EXPECT_EQ(U256Codec::deserialize_from_fields(std::vector{ uint256_t(max_u64) }), max_u64); +} + /** * @brief Field conversion test for bb::fr */ diff --git a/barretenberg/cpp/src/barretenberg/flavor/native_verification_key.test.cpp b/barretenberg/cpp/src/barretenberg/flavor/native_verification_key.test.cpp index 3fafacf5e863..94d241f6fcc8 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/native_verification_key.test.cpp +++ b/barretenberg/cpp/src/barretenberg/flavor/native_verification_key.test.cpp @@ -1,3 +1,4 @@ +#include "barretenberg/common/assert.hpp" #include "barretenberg/flavor/mega_flavor.hpp" #include "barretenberg/flavor/ultra_keccak_flavor.hpp" #include "barretenberg/srs/global_crs.hpp" @@ -7,6 +8,7 @@ #include "barretenberg/ultra_honk/prover_instance.hpp" #include +#include using namespace bb; @@ -106,3 +108,20 @@ TYPED_TEST(NativeVerificationKeyTests, FromFieldElementsRejectsWrongSize) VerificationKey bad; EXPECT_ANY_THROW(bad.from_field_elements(oversize)); } + +TYPED_TEST(NativeVerificationKeyTests, FromFieldElementsRejectsOversizedMetadata) +{ + using Flavor = typename TypeParam::Flavor; + using VerificationKey = typename Flavor::VerificationKey; + using DataType = typename VerificationKey::DataType; + + std::vector fields(VerificationKey::calc_num_data_types()); + if constexpr (std::is_same_v) { + fields[0] = bb::fr((uint256_t(1) << 64) + 1); + } else { + fields[0] = (uint256_t(1) << 64) + 1; + } + + VerificationKey bad; + EXPECT_THROW_WITH_MESSAGE(bad.from_field_elements(fields), "uint64_t"); +}