From e594eb3d9617758f99ccfa0ae0f59b6a6ea4981c Mon Sep 17 00:00:00 2001 From: suyash67 Date: Wed, 2 Jul 2025 12:19:12 +0000 Subject: [PATCH] move uint_plookup into uint, remove any `HasPlookup\' relevant to uint_plookup. --- .../uint/{plookup => }/arithmetic.cpp | 55 ++-- .../uint/{plookup => }/comparison.cpp | 38 ++- .../primitives/uint/{plookup => }/logic.cpp | 60 ++-- .../stdlib/primitives/uint/plookup/uint.cpp | 261 ------------------ .../stdlib/primitives/uint/plookup/uint.hpp | 180 ------------ .../stdlib/primitives/uint/uint.cpp | 247 ++++++++++++++++- .../stdlib/primitives/uint/uint.fuzzer.hpp | 12 +- .../stdlib/primitives/uint/uint.hpp | 173 +++++++++++- .../stdlib/primitives/uint/uint.test.cpp | 3 +- 9 files changed, 487 insertions(+), 542 deletions(-) rename barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/{plookup => }/arithmetic.cpp (78%) rename barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/{plookup => }/comparison.cpp (55%) rename barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/{plookup => }/logic.cpp (84%) delete mode 100644 barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/plookup/uint.cpp delete mode 100644 barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/plookup/uint.hpp diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/plookup/arithmetic.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/arithmetic.cpp similarity index 78% rename from barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/plookup/arithmetic.cpp rename to barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/arithmetic.cpp index 177b01ec3ebb..03ea16decf69 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/plookup/arithmetic.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/arithmetic.cpp @@ -4,7 +4,7 @@ // external_2: { status: not started, auditors: [], date: YYYY-MM-DD } // ===================== -#include "../../circuit_builders/circuit_builders.hpp" +#include "../circuit_builders/circuit_builders.hpp" #include "uint.hpp" using namespace bb; @@ -12,7 +12,7 @@ using namespace bb; namespace bb::stdlib { template -uint_plookup uint_plookup::operator+(const uint_plookup& other) const +uint uint::operator+(const uint& other) const { ASSERT(context == other.context || (context != nullptr && other.context == nullptr) || @@ -20,7 +20,7 @@ uint_plookup uint_plookup::operator+(const uin Builder* ctx = (context == nullptr) ? other.context : context; if (is_constant() && other.is_constant()) { - return uint_plookup(context, (additive_constant + other.additive_constant) & MASK); + return uint(context, (additive_constant + other.additive_constant) & MASK); } // N.B. We assume that additive_constant is nonzero ONLY if value is constant @@ -45,7 +45,7 @@ uint_plookup uint_plookup::operator+(const uin ctx->create_balanced_add_gate(gate); - uint_plookup result(ctx); + uint result(ctx); result.witness_index = gate.c; result.witness_status = WitnessStatus::WEAK_NORMALIZED; @@ -53,7 +53,7 @@ uint_plookup uint_plookup::operator+(const uin } template -uint_plookup uint_plookup::operator-(const uint_plookup& other) const +uint uint::operator-(const uint& other) const { ASSERT(context == other.context || (context != nullptr && other.context == nullptr) || @@ -62,7 +62,7 @@ uint_plookup uint_plookup::operator-(const uin Builder* ctx = (context == nullptr) ? other.context : context; if (is_constant() && other.is_constant()) { - return uint_plookup(context, (additive_constant - other.additive_constant) & MASK); + return uint(context, (additive_constant - other.additive_constant) & MASK); } // N.B. We assume that additive_constant is nonzero ONLY if value is constant @@ -91,7 +91,7 @@ uint_plookup uint_plookup::operator-(const uin ctx->create_balanced_add_gate(gate); - uint_plookup result(ctx); + uint result(ctx); result.witness_index = gate.c; result.witness_status = WitnessStatus::WEAK_NORMALIZED; @@ -99,12 +99,12 @@ uint_plookup uint_plookup::operator-(const uin } template -uint_plookup uint_plookup::operator*(const uint_plookup& other) const +uint uint::operator*(const uint& other) const { Builder* ctx = (context == nullptr) ? other.context : context; if (is_constant() && other.is_constant()) { - return uint_plookup(context, (additive_constant * other.additive_constant) & MASK); + return uint(context, (additive_constant * other.additive_constant) & MASK); } if (is_constant() && !other.is_constant()) { return other * (*this); @@ -137,7 +137,7 @@ uint_plookup uint_plookup::operator*(const uin // discard the high bits ctx->decompose_into_default_range(gate.d, width); - uint_plookup result(ctx); + uint result(ctx); result.accumulators = constrain_accumulators(ctx, gate.c); result.witness_index = gate.c; result.witness_status = WitnessStatus::OK; @@ -146,20 +146,19 @@ uint_plookup uint_plookup::operator*(const uin } template -uint_plookup uint_plookup::operator/(const uint_plookup& other) const +uint uint::operator/(const uint& other) const { return divmod(other).first; } template -uint_plookup uint_plookup::operator%(const uint_plookup& other) const +uint uint::operator%(const uint& other) const { return divmod(other).second; } template -std::pair, uint_plookup> uint_plookup::divmod( - const uint_plookup& other) const +std::pair, uint> uint::divmod(const uint& other) const { /** * divmod: returns (a / b) and (a % b) @@ -194,12 +193,12 @@ std::pair, uint_plookup> uint_plo } if (is_constant() && other.is_constant()) { - const uint_plookup remainder(ctx, additive_constant % other.additive_constant); - const uint_plookup quotient(ctx, additive_constant / other.additive_constant); + const uint remainder(ctx, additive_constant % other.additive_constant); + const uint quotient(ctx, additive_constant / other.additive_constant); return std::make_pair(quotient, remainder); } else if (witness_index == other.witness_index) { - const uint_plookup remainder(context, 0); - const uint_plookup quotient(context, 1); + const uint remainder(context, 0); + const uint quotient(context, 1); return std::make_pair(quotient, remainder); } @@ -246,25 +245,25 @@ std::pair, uint_plookup> uint_plo // validate delta is in the correct range ctx->decompose_into_default_range(delta_idx, width); - uint_plookup quotient(ctx); + uint quotient(ctx); quotient.witness_index = quotient_idx; quotient.accumulators = constrain_accumulators(ctx, quotient.witness_index); quotient.witness_status = WitnessStatus::OK; - uint_plookup remainder(ctx); + uint remainder(ctx); remainder.witness_index = remainder_idx; remainder.accumulators = constrain_accumulators(ctx, remainder.witness_index); remainder.witness_status = WitnessStatus::OK; return std::make_pair(quotient, remainder); } -template class uint_plookup; -template class uint_plookup; -template class uint_plookup; -template class uint_plookup; -template class uint_plookup; -template class uint_plookup; -template class uint_plookup; -template class uint_plookup; +template class uint; +template class uint; +template class uint; +template class uint; +template class uint; +template class uint; +template class uint; +template class uint; } // namespace bb::stdlib diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/plookup/comparison.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/comparison.cpp similarity index 55% rename from barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/plookup/comparison.cpp rename to barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/comparison.cpp index 36f65c78942e..294c93cb23a3 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/plookup/comparison.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/comparison.cpp @@ -4,15 +4,14 @@ // external_2: { status: not started, auditors: [], date: YYYY-MM-DD } // ===================== -#include "../../circuit_builders/circuit_builders.hpp" +#include "../circuit_builders/circuit_builders.hpp" #include "uint.hpp" using namespace bb; namespace bb::stdlib { -template -bool_t uint_plookup::operator>(const uint_plookup& other) const +template bool_t uint::operator>(const uint& other) const { Builder* ctx = (context == nullptr) ? other.context : context; @@ -40,26 +39,22 @@ bool_t uint_plookup::operator>(const uint_plookup& oth return result; } -template -bool_t uint_plookup::operator<(const uint_plookup& other) const +template bool_t uint::operator<(const uint& other) const { return other > *this; } -template -bool_t uint_plookup::operator>=(const uint_plookup& other) const +template bool_t uint::operator>=(const uint& other) const { return (!(other > *this)).normalize(); } -template -bool_t uint_plookup::operator<=(const uint_plookup& other) const +template bool_t uint::operator<=(const uint& other) const { return (!(*this > other)).normalize(); } -template -bool_t uint_plookup::operator==(const uint_plookup& other) const +template bool_t uint::operator==(const uint& other) const { // casting to a field type will ensure that lhs / rhs are both normalized const field_t lhs = static_cast>(*this); @@ -68,23 +63,22 @@ bool_t uint_plookup::operator==(const uint_plookup& ot return (lhs == rhs).normalize(); } -template -bool_t uint_plookup::operator!=(const uint_plookup& other) const +template bool_t uint::operator!=(const uint& other) const { return (!(*this == other)).normalize(); } -template bool_t uint_plookup::operator!() const +template bool_t uint::operator!() const { return (field_t(*this).is_zero()).normalize(); } -template class uint_plookup; -template class uint_plookup; -template class uint_plookup; -template class uint_plookup; -template class uint_plookup; -template class uint_plookup; -template class uint_plookup; -template class uint_plookup; +template class uint; +template class uint; +template class uint; +template class uint; +template class uint; +template class uint; +template class uint; +template class uint; } // namespace bb::stdlib diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/plookup/logic.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/logic.cpp similarity index 84% rename from barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/plookup/logic.cpp rename to barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/logic.cpp index f661f5f58064..663a89caee0e 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/plookup/logic.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/logic.cpp @@ -4,7 +4,7 @@ // external_2: { status: not started, auditors: [], date: YYYY-MM-DD } // ===================== -#include "../../circuit_builders/circuit_builders.hpp" +#include "../circuit_builders/circuit_builders.hpp" #include "uint.hpp" using namespace bb; @@ -14,37 +14,36 @@ namespace bb::stdlib { using namespace bb::plookup; template -uint_plookup uint_plookup::operator&(const uint_plookup& other) const +uint uint::operator&(const uint& other) const { return logic_operator(other, LogicOp::AND); } template -uint_plookup uint_plookup::operator^(const uint_plookup& other) const +uint uint::operator^(const uint& other) const { return logic_operator(other, LogicOp::XOR); } template -uint_plookup uint_plookup::operator|(const uint_plookup& other) const +uint uint::operator|(const uint& other) const { return (*this + other) - (*this & other); } -template -uint_plookup uint_plookup::operator~() const +template uint uint::operator~() const { - return uint_plookup(context, MASK) - *this; + return uint(context, MASK) - *this; } template -uint_plookup uint_plookup::operator>>(const size_t shift) const +uint uint::operator>>(const size_t shift) const { if (shift >= width) { - return uint_plookup(context, 0); + return uint(context, 0); } if (is_constant()) { - return uint_plookup(context, (additive_constant >> shift) & MASK); + return uint(context, (additive_constant >> shift) & MASK); } if (witness_status != WitnessStatus::OK) { @@ -93,20 +92,20 @@ uint_plookup uint_plookup::operator>>(const si } uint32_t result_index = field_t::accumulate(sublimbs).get_witness_index(); - uint_plookup result(context); + uint result(context); result.witness_index = result_index; result.witness_status = WitnessStatus::WEAK_NORMALIZED; return result; } template -uint_plookup uint_plookup::operator<<(const size_t shift) const +uint uint::operator<<(const size_t shift) const { if (shift >= width) { - return uint_plookup(context, 0); + return uint(context, 0); } if (is_constant()) { - return uint_plookup(context, (additive_constant << shift) & MASK); + return uint(context, (additive_constant << shift) & MASK); } if (witness_status != WitnessStatus::OK) { @@ -164,14 +163,14 @@ uint_plookup uint_plookup::operator<<(const si } uint32_t result_index = field_t::accumulate(sublimbs).get_witness_index(); - uint_plookup result(context); + uint result(context); result.witness_index = result_index; result.witness_status = WitnessStatus::WEAK_NORMALIZED; return result; } template -uint_plookup uint_plookup::ror(const size_t target_rotation) const +uint uint::ror(const size_t target_rotation) const { const size_t rotation = target_rotation & (width - 1); @@ -182,7 +181,7 @@ uint_plookup uint_plookup::ror(const size_t ta }; if (is_constant()) { - return uint_plookup(context, rotate(additive_constant, rotation)); + return uint(context, rotate(additive_constant, rotation)); } if (witness_status != WitnessStatus::OK) { @@ -240,21 +239,20 @@ uint_plookup uint_plookup::ror(const size_t ta sublimbs.emplace_back(field_t::from_witness_index(context, slice_lo_idx) * field_t(coefficient)); uint32_t result_index = field_t::accumulate(sublimbs).get_witness_index(); - uint_plookup result(context); + uint result(context); result.witness_index = result_index; result.witness_status = WitnessStatus::WEAK_NORMALIZED; return result; } template -uint_plookup uint_plookup::rol(const size_t target_rotation) const +uint uint::rol(const size_t target_rotation) const { return ror(width - (target_rotation & (width - 1))); } template -uint_plookup uint_plookup::logic_operator(const uint_plookup& other, - const LogicOp op_type) const +uint uint::logic_operator(const uint& other, const LogicOp op_type) const { Builder* ctx = (context == nullptr) ? other.context : context; @@ -278,7 +276,7 @@ uint_plookup uint_plookup::logic_operator(cons } if (is_constant() && other.is_constant()) { - return uint_plookup(ctx, out); + return uint(ctx, out); } ReadData> lookup; @@ -289,7 +287,7 @@ uint_plookup uint_plookup::logic_operator(cons lookup = plookup_read::get_lookup_accumulators( MultiTableId::UINT32_AND, field_t(*this), field_t(other), true); } - uint_plookup result(ctx); + uint result(ctx); // result.accumulators.resize(num_accumulators()); field_t scaling_factor(context, bb::fr(1ULL << bits_per_limb)); @@ -331,13 +329,13 @@ uint_plookup uint_plookup::logic_operator(cons return result; } -template class uint_plookup; -template class uint_plookup; -template class uint_plookup; -template class uint_plookup; -template class uint_plookup; -template class uint_plookup; -template class uint_plookup; -template class uint_plookup; +template class uint; +template class uint; +template class uint; +template class uint; +template class uint; +template class uint; +template class uint; +template class uint; } // namespace bb::stdlib diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/plookup/uint.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/plookup/uint.cpp deleted file mode 100644 index 4f029160055b..000000000000 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/plookup/uint.cpp +++ /dev/null @@ -1,261 +0,0 @@ -// === AUDIT STATUS === -// internal: { status: not started, auditors: [], date: YYYY-MM-DD } -// external_1: { status: not started, auditors: [], date: YYYY-MM-DD } -// external_2: { status: not started, auditors: [], date: YYYY-MM-DD } -// ===================== - -#include "uint.hpp" -#include "../../circuit_builders/circuit_builders.hpp" - -using namespace bb; - -namespace bb::stdlib { - -template -std::vector uint_plookup::constrain_accumulators(Builder* context, - const uint32_t witness_index) const -{ - const auto res = context->decompose_into_default_range(witness_index, width, bits_per_limb); - return res; -} - -template -uint_plookup::uint_plookup(const witness_t& witness) - : context(witness.context) - , witness_status(WitnessStatus::OK) -{ - if (witness.witness_index == IS_CONSTANT) { - additive_constant = witness.witness; - witness_index = IS_CONSTANT; - } else { - accumulators = constrain_accumulators(context, witness.witness_index); - witness_index = witness.witness_index; - } -} - -template -uint_plookup::uint_plookup(const field_t& value) - : context(value.context) - , additive_constant(0) - , witness_status(WitnessStatus::OK) -{ - if (value.witness_index == IS_CONSTANT) { - additive_constant = value.additive_constant; - witness_index = IS_CONSTANT; - } else { - field_t norm = value.normalize(); - accumulators = constrain_accumulators(context, norm.get_witness_index()); - witness_index = norm.get_witness_index(); - } -} - -template -uint_plookup::uint_plookup(Builder* builder, const uint256_t& value) - : context(builder) - , additive_constant(value) - , witness_status(WitnessStatus::OK) - , accumulators() - , witness_index(IS_CONSTANT) -{} - -template -uint_plookup::uint_plookup(const uint256_t& value) - : context(nullptr) - , additive_constant(value) - , witness_status(WitnessStatus::OK) - , accumulators() - , witness_index(IS_CONSTANT) -{} - -template -uint_plookup::uint_plookup(const byte_array& other) - : context(other.get_context()) - , additive_constant(0) - , witness_status(WitnessStatus::WEAK_NORMALIZED) - , accumulators() - , witness_index(IS_CONSTANT) -{ - field_t accumulator(context, fr::zero()); - field_t scaling_factor(context, fr::one()); - const auto bytes = other.bytes(); - - // TODO JUMP IN STEPS OF TWO - for (size_t i = 0; i < bytes.size(); ++i) { - accumulator = accumulator + scaling_factor * bytes[bytes.size() - 1 - i]; - scaling_factor = scaling_factor * fr(256); - } - accumulator = accumulator.normalize(); - if (accumulator.witness_index == IS_CONSTANT) { - additive_constant = uint256_t(accumulator.additive_constant); - } else { - witness_index = accumulator.witness_index; - } -} - -template -uint_plookup::uint_plookup(Builder* parent_context, const std::array, width>& wires) - : uint_plookup(parent_context, std::vector>(wires.begin(), wires.end())) -{} - -template -uint_plookup::uint_plookup(Builder* parent_context, const std::vector>& wires) - : context(parent_context) - , additive_constant(0) - , witness_status(WitnessStatus::WEAK_NORMALIZED) - , accumulators() - , witness_index(IS_CONSTANT) -{ - field_t accumulator(context, fr::zero()); - field_t scaling_factor(context, fr::one()); - - // TODO JUMP IN STEPS OF TWO - for (size_t i = 0; i < wires.size(); ++i) { - accumulator = accumulator + scaling_factor * field_t(wires[i]); - scaling_factor = scaling_factor + scaling_factor; - } - accumulator = accumulator.normalize(); - if (accumulator.witness_index == IS_CONSTANT) { - additive_constant = uint256_t(accumulator.additive_constant); - } else { - witness_index = accumulator.witness_index; - } -} - -template -uint_plookup::uint_plookup(const uint_plookup& other) - : context(other.context) - , additive_constant(other.additive_constant) - , witness_status(other.witness_status) - , accumulators(other.accumulators) - , witness_index(other.witness_index) -{} - -template -uint_plookup::uint_plookup(uint_plookup&& other) - : context(other.context) - , additive_constant(other.additive_constant) - , witness_status(other.witness_status) - , accumulators(other.accumulators) - , witness_index(other.witness_index) -{} - -template -uint_plookup& uint_plookup::operator=(const uint_plookup& other) -{ - context = other.context; - additive_constant = other.additive_constant; - witness_status = other.witness_status; - accumulators = other.accumulators; - witness_index = other.witness_index; - return *this; -} - -template -uint_plookup& uint_plookup::operator=(uint_plookup&& other) -{ - context = other.context; - additive_constant = other.additive_constant; - witness_status = other.witness_status; - accumulators = other.accumulators; - witness_index = other.witness_index; - return *this; -} - -template uint_plookup::operator field_t() const -{ - normalize(); - field_t target(context); - target.witness_index = witness_index; - target.additive_constant = is_constant() ? fr(additive_constant) : fr::zero(); - return target; -} - -template uint_plookup::operator byte_array() const -{ - return byte_array(static_cast>(*this), width / 8); -} - -template -uint_plookup uint_plookup::normalize() const -{ - if (!context || is_constant()) { - return *this; - } - - if (witness_status == WitnessStatus::WEAK_NORMALIZED) { - accumulators = constrain_accumulators(context, witness_index); - witness_status = WitnessStatus::OK; - } - return *this; -} - -template uint256_t uint_plookup::get_value() const -{ - if (!context || is_constant()) { - return additive_constant; - } - return (uint256_t(context->get_variable(witness_index))) & MASK; -} - -template uint256_t uint_plookup::get_unbounded_value() const -{ - if (!context || is_constant()) { - return additive_constant; - } - return (uint256_t(context->get_variable(witness_index))); -} - -template -bool_t uint_plookup::at(const size_t bit_index) const -{ - if (is_constant()) { - return bool_t(context, get_value().get_bit(bit_index)); - } - if (witness_status != WitnessStatus::OK) { - normalize(); - } - - const uint64_t slice_bit_position = bit_index % bits_per_limb; - - const uint32_t slice_index = accumulators[bit_index / bits_per_limb]; - const uint64_t slice_value = uint256_t(context->get_variable(slice_index)).data[0]; - - const uint64_t slice_lo = slice_value % (1ULL << slice_bit_position); - const uint64_t bit_value = (slice_value >> slice_bit_position) & 1ULL; - const uint64_t slice_hi = slice_value >> (slice_bit_position + 1); - - const uint32_t slice_lo_idx = slice_bit_position ? context->add_variable(slice_lo) : context->zero_idx; - const uint32_t bit_idx = context->add_variable(bit_value); - const uint32_t slice_hi_idx = - (slice_bit_position + 1 != bits_per_limb) ? context->add_variable(slice_hi) : context->zero_idx; - - context->create_big_add_gate({ slice_index, - slice_lo_idx, - bit_idx, - slice_hi_idx, - -1, - 1, - (1 << slice_bit_position), - (1 << (slice_bit_position + 1)), - 0 }); - - if (slice_bit_position != 0) { - context->create_new_range_constraint(slice_lo_idx, (1ULL << slice_bit_position) - 1); - } - if (slice_bit_position + 1 != bits_per_limb) { - context->create_new_range_constraint(slice_hi_idx, (1ULL << (bits_per_limb - (slice_bit_position + 1))) - 1); - } - bool_t result = witness_t(context, bit_value); - return result; -} - -template class uint_plookup; -template class uint_plookup; -template class uint_plookup; -template class uint_plookup; -template class uint_plookup; -template class uint_plookup; -template class uint_plookup; -template class uint_plookup; - -} // namespace bb::stdlib diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/plookup/uint.hpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/plookup/uint.hpp deleted file mode 100644 index 99d90b27930e..000000000000 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/plookup/uint.hpp +++ /dev/null @@ -1,180 +0,0 @@ -// === AUDIT STATUS === -// internal: { status: not started, auditors: [], date: YYYY-MM-DD } -// external_1: { status: not started, auditors: [], date: YYYY-MM-DD } -// external_2: { status: not started, auditors: [], date: YYYY-MM-DD } -// ===================== - -#pragma once -#include "../../bool/bool.hpp" -#include "../../byte_array/byte_array.hpp" -#include "../../circuit_builders/circuit_builders_fwd.hpp" -#include "../../field/field.hpp" -#include "../../plookup/plookup.hpp" - -namespace bb::stdlib { - -template class uint_plookup { - public: - using FF = typename Builder::FF; - static constexpr size_t width = sizeof(Native) * 8; - - uint_plookup(const witness_t& other); - uint_plookup(const field_t& other); - uint_plookup(const uint256_t& value = 0); - uint_plookup(Builder* builder, const uint256_t& value = 0); - uint_plookup(const byte_array& other); - uint_plookup(Builder* parent_context, const std::vector>& wires); - uint_plookup(Builder* parent_context, const std::array, width>& wires); - - uint_plookup(const Native v) - : uint_plookup(static_cast(v)) - {} - - std::vector constrain_accumulators(Builder* ctx, const uint32_t witness_index) const; - - static constexpr size_t bits_per_limb = 12; - static constexpr size_t num_accumulators() { return (width + bits_per_limb - 1) / bits_per_limb; } - - uint_plookup(const uint_plookup& other); - uint_plookup(uint_plookup&& other); - - uint_plookup& operator=(const uint_plookup& other); - uint_plookup& operator=(uint_plookup&& other); - - explicit operator byte_array() const; - explicit operator field_t() const; - - uint_plookup operator+(const uint_plookup& other) const; - uint_plookup operator-(const uint_plookup& other) const; - uint_plookup operator*(const uint_plookup& other) const; - uint_plookup operator/(const uint_plookup& other) const; - uint_plookup operator%(const uint_plookup& other) const; - - uint_plookup operator&(const uint_plookup& other) const; - uint_plookup operator^(const uint_plookup& other) const; - uint_plookup operator|(const uint_plookup& other) const; - uint_plookup operator~() const; - - uint_plookup operator>>(const size_t shift) const; - uint_plookup operator<<(const size_t shift) const; - - uint_plookup ror(const size_t target_rotation) const; - uint_plookup rol(const size_t target_rotation) const; - uint_plookup ror(const uint256_t target_rotation) const - { - return ror(static_cast(target_rotation.data[0])); - } - uint_plookup rol(const uint256_t target_rotation) const - { - return rol(static_cast(target_rotation.data[0])); - } - - bool_t operator>(const uint_plookup& other) const; - bool_t operator<(const uint_plookup& other) const; - bool_t operator>=(const uint_plookup& other) const; - bool_t operator<=(const uint_plookup& other) const; - bool_t operator==(const uint_plookup& other) const; - bool_t operator!=(const uint_plookup& other) const; - bool_t operator!() const; - - uint_plookup operator+=(const uint_plookup& other) - { - *this = operator+(other); - return *this; - } - uint_plookup operator-=(const uint_plookup& other) - { - *this = operator-(other); - return *this; - } - uint_plookup operator*=(const uint_plookup& other) - { - *this = operator*(other); - return *this; - } - uint_plookup operator/=(const uint_plookup& other) - { - *this = operator/(other); - return *this; - } - uint_plookup operator%=(const uint_plookup& other) - { - *this = operator%(other); - return *this; - } - - uint_plookup operator&=(const uint_plookup& other) - { - *this = operator&(other); - return *this; - } - uint_plookup operator^=(const uint_plookup& other) - { - *this = operator^(other); - return *this; - } - uint_plookup operator|=(const uint_plookup& other) - { - *this = operator|(other); - return *this; - } - - uint_plookup operator>>=(const size_t shift) - { - *this = operator>>(shift); - return *this; - } - uint_plookup operator<<=(const size_t shift) - { - *this = operator<<(shift); - return *this; - } - - uint_plookup normalize() const; - - uint256_t get_value() const; - - bool is_constant() const { return witness_index == IS_CONSTANT; } - Builder* get_context() const { return context; } - - bool_t at(const size_t bit_index) const; - - size_t get_width() const { return width; } - - uint32_t get_witness_index() const { return witness_index; } - - uint256_t get_additive_constant() const { return additive_constant; } - - std::vector get_accumulators() const { return accumulators; } - uint256_t get_unbounded_value() const; - - protected: - Builder* context; - - enum WitnessStatus { OK, NOT_NORMALIZED, WEAK_NORMALIZED }; - - mutable uint256_t additive_constant; - mutable WitnessStatus witness_status; - - // N.B. Not an accumulator! Contains 6-bit slices of input - mutable std::vector accumulators; - mutable uint32_t witness_index; - - static constexpr uint256_t CIRCUIT_UINT_MAX_PLUS_ONE = (uint256_t(1) << width); - static constexpr uint256_t MASK = CIRCUIT_UINT_MAX_PLUS_ONE - 1; - - private: - enum LogicOp { - AND, - XOR, - }; - - std::pair divmod(const uint_plookup& other) const; - uint_plookup logic_operator(const uint_plookup& other, const LogicOp op_type) const; -}; - -template inline std::ostream& operator<<(std::ostream& os, uint_plookup const& v) -{ - return os << v.get_value(); -} -} // namespace bb::stdlib \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.cpp index a50363889fe9..2fbd81f9d756 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.cpp @@ -7,4 +7,249 @@ #include "uint.hpp" #include "../circuit_builders/circuit_builders.hpp" -using namespace bb; +namespace bb::stdlib { + +template +std::vector uint::constrain_accumulators(Builder* context, + const uint32_t witness_index) const +{ + const auto res = context->decompose_into_default_range(witness_index, width, bits_per_limb); + return res; +} + +template +uint::uint(const witness_t& witness) + : context(witness.context) + , witness_status(WitnessStatus::OK) +{ + if (witness.witness_index == IS_CONSTANT) { + additive_constant = witness.witness; + witness_index = IS_CONSTANT; + } else { + accumulators = constrain_accumulators(context, witness.witness_index); + witness_index = witness.witness_index; + } +} + +template +uint::uint(const field_t& value) + : context(value.context) + , additive_constant(0) + , witness_status(WitnessStatus::OK) +{ + if (value.witness_index == IS_CONSTANT) { + additive_constant = value.additive_constant; + witness_index = IS_CONSTANT; + } else { + field_t norm = value.normalize(); + accumulators = constrain_accumulators(context, norm.get_witness_index()); + witness_index = norm.get_witness_index(); + } +} + +template +uint::uint(Builder* builder, const uint256_t& value) + : context(builder) + , additive_constant(value) + , witness_status(WitnessStatus::OK) + , accumulators() + , witness_index(IS_CONSTANT) +{} + +template +uint::uint(const uint256_t& value) + : context(nullptr) + , additive_constant(value) + , witness_status(WitnessStatus::OK) + , accumulators() + , witness_index(IS_CONSTANT) +{} + +template +uint::uint(const byte_array& other) + : context(other.get_context()) + , additive_constant(0) + , witness_status(WitnessStatus::WEAK_NORMALIZED) + , accumulators() + , witness_index(IS_CONSTANT) +{ + field_t accumulator(context, fr::zero()); + field_t scaling_factor(context, fr::one()); + const auto bytes = other.bytes(); + + // TODO JUMP IN STEPS OF TWO + for (size_t i = 0; i < bytes.size(); ++i) { + accumulator = accumulator + scaling_factor * bytes[bytes.size() - 1 - i]; + scaling_factor = scaling_factor * fr(256); + } + accumulator = accumulator.normalize(); + if (accumulator.witness_index == IS_CONSTANT) { + additive_constant = uint256_t(accumulator.additive_constant); + } else { + witness_index = accumulator.witness_index; + } +} + +template +uint::uint(Builder* parent_context, const std::array, width>& wires) + : uint(parent_context, std::vector>(wires.begin(), wires.end())) +{} + +template +uint::uint(Builder* parent_context, const std::vector>& wires) + : context(parent_context) + , additive_constant(0) + , witness_status(WitnessStatus::WEAK_NORMALIZED) + , accumulators() + , witness_index(IS_CONSTANT) +{ + field_t accumulator(context, fr::zero()); + field_t scaling_factor(context, fr::one()); + + // TODO JUMP IN STEPS OF TWO + for (size_t i = 0; i < wires.size(); ++i) { + accumulator = accumulator + scaling_factor * field_t(wires[i]); + scaling_factor = scaling_factor + scaling_factor; + } + accumulator = accumulator.normalize(); + if (accumulator.witness_index == IS_CONSTANT) { + additive_constant = uint256_t(accumulator.additive_constant); + } else { + witness_index = accumulator.witness_index; + } +} + +template +uint::uint(const uint& other) + : context(other.context) + , additive_constant(other.additive_constant) + , witness_status(other.witness_status) + , accumulators(other.accumulators) + , witness_index(other.witness_index) +{} + +template +uint::uint(uint&& other) + : context(other.context) + , additive_constant(other.additive_constant) + , witness_status(other.witness_status) + , accumulators(other.accumulators) + , witness_index(other.witness_index) +{} + +template uint& uint::operator=(const uint& other) +{ + context = other.context; + additive_constant = other.additive_constant; + witness_status = other.witness_status; + accumulators = other.accumulators; + witness_index = other.witness_index; + return *this; +} + +template uint& uint::operator=(uint&& other) +{ + context = other.context; + additive_constant = other.additive_constant; + witness_status = other.witness_status; + accumulators = other.accumulators; + witness_index = other.witness_index; + return *this; +} + +template uint::operator field_t() const +{ + normalize(); + field_t target(context); + target.witness_index = witness_index; + target.additive_constant = is_constant() ? fr(additive_constant) : fr::zero(); + return target; +} + +template uint::operator byte_array() const +{ + return byte_array(static_cast>(*this), width / 8); +} + +template uint uint::normalize() const +{ + if (!context || is_constant()) { + return *this; + } + + if (witness_status == WitnessStatus::WEAK_NORMALIZED) { + accumulators = constrain_accumulators(context, witness_index); + witness_status = WitnessStatus::OK; + } + return *this; +} + +template uint256_t uint::get_value() const +{ + if (!context || is_constant()) { + return additive_constant; + } + return (uint256_t(context->get_variable(witness_index))) & MASK; +} + +template uint256_t uint::get_unbounded_value() const +{ + if (!context || is_constant()) { + return additive_constant; + } + return (uint256_t(context->get_variable(witness_index))); +} + +template bool_t uint::at(const size_t bit_index) const +{ + if (is_constant()) { + return bool_t(context, get_value().get_bit(bit_index)); + } + if (witness_status != WitnessStatus::OK) { + normalize(); + } + + const uint64_t slice_bit_position = bit_index % bits_per_limb; + + const uint32_t slice_index = accumulators[bit_index / bits_per_limb]; + const uint64_t slice_value = uint256_t(context->get_variable(slice_index)).data[0]; + + const uint64_t slice_lo = slice_value % (1ULL << slice_bit_position); + const uint64_t bit_value = (slice_value >> slice_bit_position) & 1ULL; + const uint64_t slice_hi = slice_value >> (slice_bit_position + 1); + + const uint32_t slice_lo_idx = slice_bit_position ? context->add_variable(slice_lo) : context->zero_idx; + const uint32_t bit_idx = context->add_variable(bit_value); + const uint32_t slice_hi_idx = + (slice_bit_position + 1 != bits_per_limb) ? context->add_variable(slice_hi) : context->zero_idx; + + context->create_big_add_gate({ slice_index, + slice_lo_idx, + bit_idx, + slice_hi_idx, + -1, + 1, + (1 << slice_bit_position), + (1 << (slice_bit_position + 1)), + 0 }); + + if (slice_bit_position != 0) { + context->create_new_range_constraint(slice_lo_idx, (1ULL << slice_bit_position) - 1); + } + if (slice_bit_position + 1 != bits_per_limb) { + context->create_new_range_constraint(slice_hi_idx, (1ULL << (bits_per_limb - (slice_bit_position + 1))) - 1); + } + bool_t result = witness_t(context, bit_value); + return result; +} + +template class uint; +template class uint; +template class uint; +template class uint; +template class uint; +template class uint; +template class uint; +template class uint; + +} // namespace bb::stdlib diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.fuzzer.hpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.fuzzer.hpp index 99da93aa693a..22b2a1ef056a 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.fuzzer.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.fuzzer.hpp @@ -40,14 +40,10 @@ template class UintFuzzBase { private: typedef bb::stdlib::bool_t bool_t; - using uint_8_t = - typename std::conditional, bb::stdlib::uint_plookup, void>::type; - using uint_16_t = - typename std::conditional, bb::stdlib::uint_plookup, void>::type; - using uint_32_t = - typename std::conditional, bb::stdlib::uint_plookup, void>::type; - using uint_64_t = - typename std::conditional, bb::stdlib::uint_plookup, void>::type; + using uint_8_t = bb::stdlib::uint8; + using uint_16_t = bb::stdlib::uint16; + using uint_32_t = bb::stdlib::uint32; + using uint_64_t = bb::stdlib::uint64; typedef bb::stdlib::field_t field_t; typedef bb::stdlib::byte_array byte_array_t; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.hpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.hpp index 717e58012688..7c68f3de436a 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.hpp @@ -11,17 +11,170 @@ #include "../field/field.hpp" #include "../plookup/plookup.hpp" -#include "./plookup/uint.hpp" - namespace bb::stdlib { -template -using uint8 = typename std::conditional, uint_plookup, void>::type; -template -using uint16 = typename std::conditional, uint_plookup, void>::type; -template -using uint32 = typename std::conditional, uint_plookup, void>::type; -template -using uint64 = typename std::conditional, uint_plookup, void>::type; +template class uint { + public: + using FF = typename Builder::FF; + static constexpr size_t width = sizeof(Native) * 8; + + uint(const witness_t& other); + uint(const field_t& other); + uint(const uint256_t& value = 0); + uint(Builder* builder, const uint256_t& value = 0); + uint(const byte_array& other); + uint(Builder* parent_context, const std::vector>& wires); + uint(Builder* parent_context, const std::array, width>& wires); + + uint(const Native v) + : uint(static_cast(v)) + {} + + std::vector constrain_accumulators(Builder* ctx, const uint32_t witness_index) const; + + static constexpr size_t bits_per_limb = 12; + static constexpr size_t num_accumulators() { return (width + bits_per_limb - 1) / bits_per_limb; } + + uint(const uint& other); + uint(uint&& other); + + uint& operator=(const uint& other); + uint& operator=(uint&& other); + + explicit operator byte_array() const; + explicit operator field_t() const; + + uint operator+(const uint& other) const; + uint operator-(const uint& other) const; + uint operator*(const uint& other) const; + uint operator/(const uint& other) const; + uint operator%(const uint& other) const; + + uint operator&(const uint& other) const; + uint operator^(const uint& other) const; + uint operator|(const uint& other) const; + uint operator~() const; + + uint operator>>(const size_t shift) const; + uint operator<<(const size_t shift) const; + + uint ror(const size_t target_rotation) const; + uint rol(const size_t target_rotation) const; + uint ror(const uint256_t target_rotation) const { return ror(static_cast(target_rotation.data[0])); } + uint rol(const uint256_t target_rotation) const { return rol(static_cast(target_rotation.data[0])); } + + bool_t operator>(const uint& other) const; + bool_t operator<(const uint& other) const; + bool_t operator>=(const uint& other) const; + bool_t operator<=(const uint& other) const; + bool_t operator==(const uint& other) const; + bool_t operator!=(const uint& other) const; + bool_t operator!() const; + + uint operator+=(const uint& other) + { + *this = operator+(other); + return *this; + } + uint operator-=(const uint& other) + { + *this = operator-(other); + return *this; + } + uint operator*=(const uint& other) + { + *this = operator*(other); + return *this; + } + uint operator/=(const uint& other) + { + *this = operator/(other); + return *this; + } + uint operator%=(const uint& other) + { + *this = operator%(other); + return *this; + } + + uint operator&=(const uint& other) + { + *this = operator&(other); + return *this; + } + uint operator^=(const uint& other) + { + *this = operator^(other); + return *this; + } + uint operator|=(const uint& other) + { + *this = operator|(other); + return *this; + } + + uint operator>>=(const size_t shift) + { + *this = operator>>(shift); + return *this; + } + uint operator<<=(const size_t shift) + { + *this = operator<<(shift); + return *this; + } + + uint normalize() const; + + uint256_t get_value() const; + + bool is_constant() const { return witness_index == IS_CONSTANT; } + Builder* get_context() const { return context; } + + bool_t at(const size_t bit_index) const; + + size_t get_width() const { return width; } + + uint32_t get_witness_index() const { return witness_index; } + + uint256_t get_additive_constant() const { return additive_constant; } + + std::vector get_accumulators() const { return accumulators; } + uint256_t get_unbounded_value() const; + + protected: + Builder* context; + + enum WitnessStatus { OK, NOT_NORMALIZED, WEAK_NORMALIZED }; + + mutable uint256_t additive_constant; + mutable WitnessStatus witness_status; + + // N.B. Not an accumulator! Contains 6-bit slices of input + mutable std::vector accumulators; + mutable uint32_t witness_index; + + static constexpr uint256_t CIRCUIT_UINT_MAX_PLUS_ONE = (uint256_t(1) << width); + static constexpr uint256_t MASK = CIRCUIT_UINT_MAX_PLUS_ONE - 1; + + private: + enum LogicOp { + AND, + XOR, + }; + + std::pair divmod(const uint& other) const; + uint logic_operator(const uint& other, const LogicOp op_type) const; +}; + +template using uint8 = uint; +template using uint16 = uint; +template using uint32 = uint; +template using uint64 = uint; + +template inline std::ostream& operator<<(std::ostream& os, uint const& v) +{ + return os << v.get_value(); +} } // namespace bb::stdlib diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.test.cpp index acfbdb011e71..65e5cce229ba 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.test.cpp @@ -74,7 +74,7 @@ uint_native rotate(uint_native value, size_t rotation) : value; } template class stdlib_uint : public testing::Test { - using uint_ct = stdlib::uint_plookup; + using uint_ct = stdlib::uint; using bool_ct = stdlib::bool_t; using witness_ct = stdlib::witness_t; using byte_array_ct = stdlib::byte_array; @@ -1911,6 +1911,7 @@ TYPED_TEST(stdlib_uint, test_at) } // There was one plookup-specific test in the ./plookup/uint_plookup.test.cpp +// TODO: either remove this test or move it to a more appropriate location TEST(stdlib_uint32, test_accumulators_plookup_uint32) { using uint32_ct = stdlib::uint32;