diff --git a/barretenberg/cpp/src/barretenberg/ecc/fields/field_declarations.hpp b/barretenberg/cpp/src/barretenberg/ecc/fields/field_declarations.hpp index 22aa6c987f7f..e396578a9053 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/fields/field_declarations.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/fields/field_declarations.hpp @@ -69,7 +69,7 @@ template struct alignas(32) field { } constexpr field(const uint128_t& input) noexcept - : field(uint256_t::from_uint128(input)) + : field(static_cast(input)) {} // NOLINTNEXTLINE (unsigned long is platform dependent, which we want in this case) diff --git a/barretenberg/cpp/src/barretenberg/numeric/uint256/uint256.hpp b/barretenberg/cpp/src/barretenberg/numeric/uint256/uint256.hpp index 1094d2acf348..936637f4a40f 100644 --- a/barretenberg/cpp/src/barretenberg/numeric/uint256/uint256.hpp +++ b/barretenberg/cpp/src/barretenberg/numeric/uint256/uint256.hpp @@ -36,20 +36,34 @@ class alignas(32) uint256_t { #define WASM_NUM_LIMBS 9 #define WASM_LIMB_BITS 29 #endif - constexpr uint256_t(const uint64_t a = 0) noexcept - : data{ a, 0, 0, 0 } + constexpr uint256_t() noexcept + : data{ 0, 0, 0, 0 } + {} + + // Template constructor for integral types to avoid ambiguity + // This provides an exact match for int, unsigned int, etc., avoiding conversion ambiguity + // Only accepts integral types that fit in uint64_t to prevent silent truncation + // Note: Accepts both signed and unsigned to handle integer literals (which are signed in C++) + template + requires(!std::same_as, bool> && sizeof(T) <= sizeof(uint64_t)) + constexpr uint256_t(T value) noexcept + : data{ static_cast(value), 0, 0, 0 } {} constexpr uint256_t(const uint64_t a, const uint64_t b, const uint64_t c, const uint64_t d) noexcept : data{ a, b, c, d } {} + constexpr uint256_t(const uint128_t& a) noexcept + : data{ static_cast(a), static_cast(a >> 64), 0, 0 } + {} + constexpr uint256_t(const uint256_t& other) noexcept : data{ other.data[0], other.data[1], other.data[2], other.data[3] } {} constexpr uint256_t(uint256_t&& other) noexcept = default; - explicit constexpr uint256_t(std::string input) noexcept + explicit constexpr uint256_t(const std::string& input) noexcept { /* Quick and dirty conversion from a single character to its hex equivelent */ constexpr auto HexCharToInt = [](uint8_t Input) { @@ -91,11 +105,6 @@ class alignas(32) uint256_t { data[3] = limbs[0]; } - static constexpr uint256_t from_uint128(const uint128_t a) noexcept - { - return { static_cast(a), static_cast(a >> 64), 0, 0 }; - } - constexpr uint256_t& operator=(const uint256_t& other) noexcept = default; constexpr uint256_t& operator=(uint256_t&& other) noexcept = default; constexpr ~uint256_t() noexcept = default; diff --git a/barretenberg/cpp/src/barretenberg/vm2/constraining/relations/field_gt.test.cpp b/barretenberg/cpp/src/barretenberg/vm2/constraining/relations/field_gt.test.cpp index 852187adef72..cd6eb5d3adf4 100644 --- a/barretenberg/cpp/src/barretenberg/vm2/constraining/relations/field_gt.test.cpp +++ b/barretenberg/cpp/src/barretenberg/vm2/constraining/relations/field_gt.test.cpp @@ -235,8 +235,8 @@ TEST(FieldGreaterThanConstrainingTest, NegativeManipulatedComparisonsWithP) check_relation(trace); auto p_limbs = simulation::decompose_256(FF::modulus); - uint256_t p_lo = uint256_t::from_uint128(p_limbs.lo); - uint256_t p_hi = uint256_t::from_uint128(p_limbs.hi); + uint256_t p_lo = p_limbs.lo; + uint256_t p_hi = p_limbs.hi; // Manipulate the decomposition in a way that passes the decomposition check due to overflow trace.set(Column::ff_gt_a_lo, 1, p_lo); diff --git a/barretenberg/cpp/src/barretenberg/vm2/constraining/relations/range_check.test.cpp b/barretenberg/cpp/src/barretenberg/vm2/constraining/relations/range_check.test.cpp index 3d0a20bf1d74..d13ff51e8b63 100644 --- a/barretenberg/cpp/src/barretenberg/vm2/constraining/relations/range_check.test.cpp +++ b/barretenberg/cpp/src/barretenberg/vm2/constraining/relations/range_check.test.cpp @@ -49,7 +49,7 @@ TEST(RangeCheckConstrainingTest, NegativeIsLteMutuallyExclusive) TEST(RangeCheckConstrainingTest, CheckRecomposition) { uint128_t value = 0x3FFFFFFFD; - uint256_t value_u256 = uint256_t::from_uint128(value); + uint256_t value_u256 = value; uint16_t u16_r0 = 0xFFFD; // value & 0xFFFF; uint16_t u16_r1 = 0xFFFF; // (value >> 16) & 0xFFFF; @@ -71,7 +71,7 @@ TEST(RangeCheckConstrainingTest, NegativeCheckRecomposition) { uint128_t value = 0x3FFFFFFFD; // Add 1 to the value to create a "bad" value that doesn't match recomposition - uint256_t bad_value = uint256_t::from_uint128(value + 1); + uint256_t bad_value = value + 1; uint16_t u16_r0 = value & 0xFFFF; uint16_t u16_r1 = (value >> 16) & 0xFFFF; @@ -98,7 +98,7 @@ TEST(RangeCheckConstrainingTest, Full) // Choose a value that has num_bits uint128_t value = (static_cast(1) << num_bits) - 3; - uint256_t value_u256 = uint256_t::from_uint128(value); + uint256_t value_u256 = value; uint16_t u16_r0 = value & 0xFFFF; uint16_t u16_r1 = (value >> 16) & 0xFFFF; @@ -134,7 +134,7 @@ TEST(RangeCheckConstrainingTest, NegativeMissingLookup) // Choose a value that has num_bits uint128_t value = (static_cast(1) << num_bits) - 3; - uint256_t value_u256 = uint256_t::from_uint128(value); + uint256_t value_u256 = value; uint16_t u16_r0 = value & 0xFFFF; uint16_t u16_r1 = (value >> 16) & 0xFFFF; diff --git a/barretenberg/cpp/src/barretenberg/vm2/simulation/gadgets/alu.cpp b/barretenberg/cpp/src/barretenberg/vm2/simulation/gadgets/alu.cpp index 50c4feefeca2..044be9fd5c28 100644 --- a/barretenberg/cpp/src/barretenberg/vm2/simulation/gadgets/alu.cpp +++ b/barretenberg/cpp/src/barretenberg/vm2/simulation/gadgets/alu.cpp @@ -288,7 +288,7 @@ MemoryValue Alu::shl(const MemoryValue& a, const MemoryValue& b) // We cast to uint256_t to be sure that the shift 1 << a_lo_bits has a defined behaviour. // 1 << 128 is undefined behavior on uint128_t. const uint128_t mask = - static_cast((static_cast(1) << uint256_t::from_uint128(a_lo_bits)) - 1); + static_cast((static_cast(1) << static_cast(a_lo_bits)) - 1); // Make use of x % pow_of_two = x & (pow_of_two - 1) uint128_t a_lo = overflow ? b_num - max_bits : a_num & mask; uint128_t a_hi = a_lo_bits >= 128 ? 0 : a_num >> a_lo_bits; // 128-bit shift undefined behaviour guard. @@ -330,7 +330,7 @@ MemoryValue Alu::shr(const MemoryValue& a, const MemoryValue& b) // We cast to uint256_t to be sure that the shift 1 << a_lo_bits has a defined behaviour. // 1 << 128 is undefined behavior on uint128_t. const uint128_t mask = - static_cast((static_cast(1) << uint256_t::from_uint128(a_lo_bits)) - 1); + static_cast((static_cast(1) << static_cast(a_lo_bits)) - 1); // Make use of x % pow_of_two = x & (pow_of_two - 1) uint128_t a_lo = overflow ? b_num - max_bits : a_num & mask; uint128_t a_hi = a_lo_bits >= 128 ? 0 : a_num >> a_lo_bits; // 128-bit shift undefined behaviour guard. diff --git a/barretenberg/cpp/src/barretenberg/vm2/simulation/gadgets/gt.cpp b/barretenberg/cpp/src/barretenberg/vm2/simulation/gadgets/gt.cpp index 7720c24ece66..be4c39b1bb76 100644 --- a/barretenberg/cpp/src/barretenberg/vm2/simulation/gadgets/gt.cpp +++ b/barretenberg/cpp/src/barretenberg/vm2/simulation/gadgets/gt.cpp @@ -17,7 +17,7 @@ bool GreaterThan::gt(const uint128_t& a, const uint128_t& b) { bool res = a > b; const uint128_t abs_diff = res ? a - b - 1 : b - a; - const uint8_t num_bits_bound = static_cast(uint256_t::from_uint128(abs_diff).get_msb() + 1); + const uint8_t num_bits_bound = static_cast(static_cast(abs_diff).get_msb() + 1); const uint8_t num_bits_bound_16 = ((num_bits_bound - 1) / 16 + 1) * 16; // round up to multiple of 16 range_check.assert_range(abs_diff, num_bits_bound_16); events.emit({ diff --git a/barretenberg/cpp/src/barretenberg/vm2/tracegen/alu_trace.cpp b/barretenberg/cpp/src/barretenberg/vm2/tracegen/alu_trace.cpp index 8a67526e2275..74b4e6024a2a 100644 --- a/barretenberg/cpp/src/barretenberg/vm2/tracegen/alu_trace.cpp +++ b/barretenberg/cpp/src/barretenberg/vm2/tracegen/alu_trace.cpp @@ -247,7 +247,7 @@ std::vector> get_operation_specific_columns(const simulation::A uint128_t a_lo_bits = overflow ? max_bits : max_bits - b_num; // Cast to uint256_t to be sure that the shift 1 << a_lo_bits is cpp defined behaviour. const uint128_t mask = - static_cast((static_cast(1) << uint256_t::from_uint128(a_lo_bits)) - 1); + static_cast((static_cast(1) << static_cast(a_lo_bits)) - 1); // The low limb of decomposed input a (if overflow, assigned as b - max_bits to range check and // prove b > max_bits). uint128_t a_lo = @@ -265,8 +265,8 @@ std::vector> get_operation_specific_columns(const simulation::A { C::alu_a_hi_bits, a_hi_bits }, { C::alu_shift_lo_bits, a_lo_bits }, { C::alu_two_pow_shift_lo_bits, - overflow ? 0 : static_cast(1) << uint256_t::from_uint128(a_lo_bits) }, - { C::alu_helper1, overflow ? 0 : static_cast(1) << uint256_t::from_uint128(b_num) }, + overflow ? 0 : static_cast(1) << static_cast(a_lo_bits) }, + { C::alu_helper1, overflow ? 0 : static_cast(1) << static_cast(b_num) }, }); } return res; @@ -306,7 +306,7 @@ std::vector> get_operation_specific_columns(const simulation::A { C::alu_a_hi_bits, a_hi_bits }, { C::alu_shift_lo_bits, a_lo_bits }, { C::alu_two_pow_shift_lo_bits, - overflow ? 0 : static_cast(1) << uint256_t::from_uint128(a_lo_bits) }, + overflow ? 0 : static_cast(1) << static_cast(a_lo_bits) }, }); } return res; diff --git a/barretenberg/cpp/src/barretenberg/vm2/tracegen/range_check_trace.cpp b/barretenberg/cpp/src/barretenberg/vm2/tracegen/range_check_trace.cpp index d6d3b7a5fbf1..beb587e21827 100644 --- a/barretenberg/cpp/src/barretenberg/vm2/tracegen/range_check_trace.cpp +++ b/barretenberg/cpp/src/barretenberg/vm2/tracegen/range_check_trace.cpp @@ -22,11 +22,11 @@ void RangeCheckTraceBuilder::process( for (const auto& event : events) { // store off event entries to be used directly in row const uint256_t original_num_bits = event.num_bits; - const uint256_t original_value = uint256_t::from_uint128(event.value); + const uint256_t original_value = static_cast(event.value); // these will be mutated below uint8_t num_bits = event.num_bits; - uint256_t value = uint256_t::from_uint128(event.value); + uint256_t value = static_cast(event.value); std::array fixed_slice_registers; // u16_r0...6 size_t index_of_most_sig_16b_chunk = 0; diff --git a/barretenberg/cpp/src/barretenberg/vm2/tracegen/range_check_trace.test.cpp b/barretenberg/cpp/src/barretenberg/vm2/tracegen/range_check_trace.test.cpp index 72f3947c4671..b8e97f132c62 100644 --- a/barretenberg/cpp/src/barretenberg/vm2/tracegen/range_check_trace.test.cpp +++ b/barretenberg/cpp/src/barretenberg/vm2/tracegen/range_check_trace.test.cpp @@ -24,7 +24,7 @@ TEST(RangeCheckTraceGenTest, RangeCheckLte16Bit) // Choose a value that has num_bits uint128_t value = (static_cast(1) << num_bits) - 3; - uint256_t value_u256 = uint256_t::from_uint128(value); + uint256_t value_u256 = value; // <= 16 bits means that the only register used is the dynamic slice uint16_t dynamic_slice_register = value & 0xFFFF; @@ -58,7 +58,7 @@ TEST(RangeCheckTraceGenTest, RangeCheckLte48Bit) // Choose a value that has num_bits uint128_t value = (static_cast(1) << num_bits) - 3; - uint256_t value_u256 = uint256_t::from_uint128(value); + uint256_t value_u256 = value; uint16_t u16_r0 = value & 0xFFFF; uint16_t u16_r1 = (value >> 16) & 0xFFFF; @@ -98,7 +98,7 @@ TEST(RangeCheckTraceGenTest, RangeCheckLte128Bit) // Choose a value that has num_bits uint128_t value = static_cast((static_cast(1) << (num_bits)) - 3); - uint256_t value_u256 = uint256_t::from_uint128(value); + uint256_t value_u256 = value; uint16_t u16_r0 = value & 0xFFFF; uint16_t u16_r1 = (value >> 16) & 0xFFFF;