Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
6b23fd2
remove unused cycle_scalar interfaces and use bigfield in test suite
ledwards2225 Sep 12, 2025
4832bd6
remove option to skip primality in construct from bn254
ledwards2225 Sep 13, 2025
bf3eacb
use from_witness for consistency
ledwards2225 Sep 13, 2025
c6292e0
add split_at_unrestricted (bad name!)
ledwards2225 Sep 14, 2025
14c1400
add split method to field and bring back from witness for fuzzer build
ledwards2225 Sep 14, 2025
fb17bdf
bring back constructor for fuzzer
ledwards2225 Sep 14, 2025
ce5e3da
update plsit at naming and fix tests
ledwards2225 Sep 15, 2025
dd1401e
use split_at in create_from_bn254_scalar
ledwards2225 Sep 15, 2025
3035add
cleanup
ledwards2225 Sep 15, 2025
984cb44
Merge branch 'merge-train/barretenberg' into lde/cycle-group-5
ledwards2225 Sep 15, 2025
d1d440e
Merge branch 'next' into lde/cycle-group-5
ledwards2225 Sep 16, 2025
d9eb676
implement split unique in field utils
ledwards2225 Sep 17, 2025
7c563b0
Merge branch 'merge-train/barretenberg' into lde/cycle-group-5
ledwards2225 Sep 17, 2025
5da71f1
fix wasm build
ledwards2225 Sep 17, 2025
6001747
Merge branch 'merge-train/barretenberg' into lde/cycle-group-5
ledwards2225 Sep 18, 2025
e690fd2
revert test changes for now
ledwards2225 Sep 18, 2025
83be28b
add num gates pinning to cycle group tests
ledwards2225 Sep 18, 2025
1de5c17
use evaluate linear identity; no gate change
ledwards2225 Sep 18, 2025
50808c0
Merge branch 'merge-train/barretenberg' into lde/cycle-group-5
ledwards2225 Sep 18, 2025
12c79de
vk hash
ledwards2225 Sep 19, 2025
1b5047e
Merge branch 'merge-train/barretenberg' into lde/cycle-group-5
ledwards2225 Sep 19, 2025
739ad72
vk hash
ledwards2225 Sep 19, 2025
99c1cd1
try again
ledwards2225 Sep 19, 2025
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
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ cd ..
# - Generate a hash for versioning: sha256sum bb-civc-inputs.tar.gz
# - Upload the compressed results: aws s3 cp bb-civc-inputs.tar.gz s3://aztec-ci-artifacts/protocol/bb-civc-inputs-[hash(0:8)].tar.gz
# Note: In case of the "Test suite failed to run ... Unexpected token 'with' " error, need to run: docker pull aztecprotocol/build:3.0
pinned_short_hash="5aa55c9f"
pinned_short_hash="04f38201"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

No change to number of gates, only the details of constant values due to the use of changing the form of operations like a.assert_equal(b) in a couple places (e.g. using evaluate_linear_identity instead)

pinned_civc_inputs_url="https://aztec-ci-artifacts.s3.us-east-2.amazonaws.com/protocol/bb-civc-inputs-${pinned_short_hash}.tar.gz"

function compress_and_upload {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ UltraCircuitBuilder_<UltraExecutionTraceBlocks> UltraCircuitChecker::prepare_cir
{
// Create a copy of the input circuit
UltraCircuitBuilder_<UltraExecutionTraceBlocks> builder{ builder_in };

builder.finalize_circuit(/*ensure_nonzero=*/true); // Test the ensure_nonzero gates as well
if (!builder.circuit_finalized) { // avoid warnings about finalizing an already finalized circuit
builder.finalize_circuit(/*ensure_nonzero=*/true); // Test the ensure_nonzero gates as well
}

return builder;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1271,10 +1271,13 @@ template <typename Builder> field_t<Builder> field_t<Builder>::accumulate(const
* @brief Splits the field element into (lo, hi), where:
* - lo contains bits [0, lsb_index)
* - hi contains bits [lsb_index, num_bits)
* @details Max bits is specified as an argument, and must be <= grumpkin::MAX_NO_WRAP_INTEGER_BIT_LENGTH (to ensure no
* modular wrap).
*
*/
template <typename Builder>
std::pair<field_t<Builder>, field_t<Builder>> field_t<Builder>::split_at(const size_t lsb_index,
const size_t num_bits) const
std::pair<field_t<Builder>, field_t<Builder>> field_t<Builder>::no_wrap_split_at(const size_t lsb_index,
const size_t num_bits) const
{
ASSERT(lsb_index < num_bits);
ASSERT(num_bits <= grumpkin::MAX_NO_WRAP_INTEGER_BIT_LENGTH);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not sure why this constant is 252 - would be nice to add some documentation

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ template <typename Builder_> class field_t {

Builder* get_context() const { return context; }

std::pair<field_t<Builder>, field_t<Builder>> split_at(
std::pair<field_t<Builder>, field_t<Builder>> no_wrap_split_at(
const size_t lsb_index, const size_t num_bits = grumpkin::MAX_NO_WRAP_INTEGER_BIT_LENGTH) const;

bool_t<Builder> is_zero() const;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -930,7 +930,7 @@ template <typename Builder> class stdlib_field : public testing::Test {
// Lambda to check split_at functionality
auto check_split_at = [&](const field_ct& a, size_t start, size_t num_bits) {
const uint256_t a_native = a.get_value();
auto split_data = a.split_at(start, num_bits);
auto split_data = a.no_wrap_split_at(start, num_bits);
EXPECT_EQ(split_data.first.get_value(), a_native & ((uint256_t(1) << start) - 1));
EXPECT_EQ(split_data.second.get_value(), (a_native >> start) & ((uint256_t(1) << num_bits) - 1));

Expand Down Expand Up @@ -1424,7 +1424,7 @@ template <typename Builder> class stdlib_field : public testing::Test {

// Split preserves tags
const size_t num_bits = uint256_t(a.get_value()).get_msb() + 1;
auto split_data = a.split_at(num_bits / 2, num_bits);
auto split_data = a.no_wrap_split_at(num_bits / 2, num_bits);
EXPECT_EQ(split_data.first.get_origin_tag(), submitted_value_origin_tag);
EXPECT_EQ(split_data.second.get_origin_tag(), submitted_value_origin_tag);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// === 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 "./field_utils.hpp"
#include "./field.hpp"
#include "barretenberg/stdlib/primitives/circuit_builders/circuit_builders.hpp"

namespace bb::stdlib {

template <typename Builder>
void validate_split_in_field(const field_t<Builder>& lo,
const field_t<Builder>& hi,
const size_t lo_bits,
const uint256_t& field_modulus)
{
const size_t hi_bits = static_cast<size_t>(field_modulus.get_msb()) + 1 - lo_bits;

// Split the field modulus at the same position
const uint256_t r_lo = field_modulus.slice(0, lo_bits);
const uint256_t r_hi = field_modulus.slice(lo_bits, field_modulus.get_msb() + 1);

// Check if we need to borrow
bool need_borrow = uint256_t(lo.get_value()) > r_lo;
field_t<Builder> borrow =
lo.is_constant() ? need_borrow : field_t<Builder>::from_witness(lo.get_context(), need_borrow);

// directly call `create_new_range_constraint` to avoid creating an arithmetic gate
if (!lo.is_constant()) {
// We need to manually propagate the origin tag
borrow.set_origin_tag(lo.get_origin_tag());
lo.get_context()->create_new_range_constraint(borrow.get_witness_index(), 1, "borrow");
}

// Hi range check = r_hi - hi - borrow
// Lo range check = r_lo - lo + borrow * 2^lo_bits
field_t<Builder> hi_diff = (-hi + r_hi) - borrow;
field_t<Builder> lo_diff = (-lo + r_lo) + (borrow * (uint256_t(1) << lo_bits));

hi_diff.create_range_constraint(hi_bits);
lo_diff.create_range_constraint(lo_bits);
}

template <typename Builder>
std::pair<field_t<Builder>, field_t<Builder>> split_unique(const field_t<Builder>& field,
const size_t lo_bits,
const bool skip_range_constraints)
{
using native = typename field_t<Builder>::native;
static constexpr size_t max_bits = native::modulus.get_msb() + 1;
ASSERT(lo_bits < max_bits);

const uint256_t value(field.get_value());
const uint256_t lo_val = value.slice(0, lo_bits);
const uint256_t hi_val = value.slice(lo_bits, max_bits);

Builder* ctx = field.get_context();

// If `field` is constant, return constants based on the native hi/lo values
if (field.is_constant()) {
return { field_t<Builder>(lo_val), field_t<Builder>(hi_val) };
}

// Create hi/lo witnesses
auto lo = field_t<Builder>::from_witness(ctx, lo_val);
auto hi = field_t<Builder>::from_witness(ctx, hi_val);

// Component 1: Reconstruction constraint lo + hi * 2^lo_bits - field == 0
const uint256_t shift = uint256_t(1) << lo_bits;
auto zero = field_t<Builder>::from_witness_index(ctx, ctx->zero_idx);
field_t<Builder>::evaluate_linear_identity(lo, hi * shift, -field, zero);

// Set the origin tag for the limbs
lo.set_origin_tag(field.get_origin_tag());
hi.set_origin_tag(field.get_origin_tag());

// Component 2: Field validation against bn254 scalar field modulus
validate_split_in_field(lo, hi, lo_bits, native::modulus);

// Component 3: Range constraints (unless skipped)
if (!skip_range_constraints) {
lo.create_range_constraint(lo_bits);
// For bn254 scalar field, hi_bits = 254 - lo_bits
const size_t hi_bits = 254 - lo_bits;
hi.create_range_constraint(hi_bits);
}

return { lo, hi };
}

// Explicit instantiations for split_unique
template std::pair<field_t<bb::UltraCircuitBuilder>, field_t<bb::UltraCircuitBuilder>> split_unique(
const field_t<bb::UltraCircuitBuilder>& field, const size_t lo_bits, const bool skip_range_constraints);
template std::pair<field_t<bb::MegaCircuitBuilder>, field_t<bb::MegaCircuitBuilder>> split_unique(
const field_t<bb::MegaCircuitBuilder>& field, const size_t lo_bits, const bool skip_range_constraints);

// Explicit instantiations for validate_split_in_field
template void validate_split_in_field(const field_t<bb::UltraCircuitBuilder>& lo,
const field_t<bb::UltraCircuitBuilder>& hi,
const size_t lo_bits,
const uint256_t& field_modulus);
template void validate_split_in_field(const field_t<bb::MegaCircuitBuilder>& lo,
const field_t<bb::MegaCircuitBuilder>& hi,
const size_t lo_bits,
const uint256_t& field_modulus);

} // namespace bb::stdlib
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// === 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 "./field.hpp"
#include <utility>

namespace bb::stdlib {

template <typename Builder> class field_t;

/**
* @brief Split a bn254 scalar field element into unique lo and hi limbs
*
* @details Splits `field` into a low and high limb at the given bit index with:
* 1. Reconstruction constraint: lo + hi * 2^lo_bits = field
* 2. Modulus check: lo + hi * 2^lo_bits < bn254::ScalarField::modulus
* 3. Range constraints: lo in [0, 2^lo_bits), hi in [0, 2^(254-lo_bits)) (unless skip_range_constraints = true)
*
* @note The combination of (2) and (3) establishes the uniqueness of the decomposition.
*
* @param field The bn254 scalar field element to split
* @param lo_bits Number of bits for the low limb
* @param skip_range_constraints If true, skip range constraints (use when they're implicit, e.g., in lookups)
* @return std::pair<field_t<Builder>, field_t<Builder>> The (lo, hi) pair
*/
template <typename Builder>
std::pair<field_t<Builder>, field_t<Builder>> split_unique(const field_t<Builder>& field,
const size_t lo_bits,
const bool skip_range_constraints = false);

/**
* @brief Validates that lo + hi * 2^lo_bits < field_modulus
* @details Can be used in conjunction with range constraints on lo and hi to establish a unique decomposition of a
* field element.
*
* @param lo The low limb
* @param hi The high limb
* @param lo_bits The bit position at which the split occurred
* @param field_modulus The field modulus to validate against
*/
template <typename Builder>
void validate_split_in_field(const field_t<Builder>& lo,
const field_t<Builder>& hi,
const size_t lo_bits,
const uint256_t& field_modulus);

} // namespace bb::stdlib
Loading
Loading