Skip to content

chore: cycle group cleanup #5#17026

Merged
ledwards2225 merged 23 commits intomerge-train/barretenbergfrom
lde/cycle-group-5
Sep 19, 2025
Merged

chore: cycle group cleanup #5#17026
ledwards2225 merged 23 commits intomerge-train/barretenbergfrom
lde/cycle-group-5

Conversation

@ledwards2225
Copy link
Contributor

@ledwards2225 ledwards2225 commented Sep 12, 2025

Cleaning up and restricting the interface to cycle_scalar. The main purpose of this thread of work is to make it easier to identify when certain constraints need to be applied (e.g. primality) and to make applying them less error prone:

  • Add method field_t::split_at_unrestricted() (better name TBD!) to implement hi/lo splitting logic previously housed in cycle_scalar
  • Remove unused constructors cycle_scalar(const field_t&) and cycle_scalar(const ScalarField&)
  • remove option to skip_primality_test in method create_from_bn254_scalar()

@ledwards2225 ledwards2225 changed the base branch from next to merge-train/barretenberg September 12, 2025 23:37
@ledwards2225 ledwards2225 marked this pull request as ready for review September 13, 2025 21:18
// 1: add entry where point, scalar are witnesses
expected += (element * scalar);
points.emplace_back(cycle_group_ct::from_witness(&builder, element));
scalars.emplace_back(cycle_group_ct::cycle_scalar::from_witness(&builder, scalar));
Copy link
Contributor Author

@ledwards2225 ledwards2225 Sep 14, 2025

Choose a reason for hiding this comment

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

cycle_scalar::from_witness is not used anywhere in production so it seems better to test the main production use case instead which is cycle_scalars constructed from bigfield elements (i.e. in the ECCVM recursive verifier). I've updated all of the tests accordingly. Eventually I may expand them to use cycle_scalars constructed through all of the main production entrypoints

, hi(_hi)
{}

template <typename Builder> cycle_scalar<Builder>::cycle_scalar(const field_t& in)
Copy link
Contributor Author

@ledwards2225 ledwards2225 Sep 14, 2025

Choose a reason for hiding this comment

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

previously only used in the transcript split_challenge which now uses an analogous field_utils method

hi.set_origin_tag(in.get_origin_tag());
}

template <typename Builder> cycle_scalar<Builder>::cycle_scalar(const ScalarField& in)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This was not used anywhere

* @return cycle_scalar<Builder>
*/
template <typename Builder>
cycle_scalar<Builder> cycle_scalar<Builder>::create_from_bn254_scalar(const field_t& in, const bool skip_primality_test)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

this method should never skip the bn254 scalar field primality test (and indeed this path was never used) so I've removed skip_primality_test from the signature.


cycle_scalar result{ lo, hi, NUM_BITS, skip_primality_test, true };
return result;
return cycle_scalar{ lo, hi, NUM_BITS, skip_primality_test, use_bn254_scalar_field_for_primality_test };
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 think eventually I can just get rid of skip_primality_test and use_bn254_scalar_field_for_primality_test altogether and simply perform the right primality test right in the appropriate constructor / factory method. One step at a time.

// WORKTODO: now that we're not using cycle_scalar, should we split differently?
const size_t low_bits = 128;
const size_t high_bits = 126;
const auto [lo, high] = challenge.split_at_unrestricted(low_bits);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This change has the effect of removing a validate_scalar_is_in_field(); call which was present in the constructor cycle_scalar(const field_t&) and therefore previously applied here. I don't see why such a check would be needed - maybe I'm missing something.

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 suppose in the recursive verifier setting we can have challenges of one scaler field represented in another, e.g. in the eccvm.

Copy link
Contributor

@iakovenkos iakovenkos Sep 16, 2025

Choose a reason for hiding this comment

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

The primality check is not needed here, cause the challenge is computed in-circuit, and it's fr by default, which is then converted in-circuit to bigfield in the case of eccvm


// Check that the size of the recursive verifier is consistent with historical expectation
uint32_t NUM_GATES_EXPECTED = 213923;
uint32_t NUM_GATES_EXPECTED = 213307;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Gate count reduction here and in UH rec verifier is due to no longer calling validate_scalar_is_in_field() within transcript method split_challenge(). This used to happen under the hood by virtue of using cycle_scalar(const field_t&) to perform the hi/lo splitting. We now use field_t::split_at() which performs identical splitting but does not perform an "in field" check.

scalar.lo.create_range_constraint(cycle_scalar::LO_BITS);
scalar.hi.create_range_constraint(cycle_scalar::HI_BITS);
return std::array<DataType, 2>{ scalar.lo, scalar.hi };
// Note: Current choice of bit splitting is somewhat arbitrary and based on historic use of cycle_scalar.
Copy link
Contributor Author

@ledwards2225 ledwards2225 Sep 15, 2025

Choose a reason for hiding this comment

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

I'm leaving this in a bit of an in-progress state as I'm hoping the details will be resolved by Sergei in his transcript / field _conversion investigations. In particular, (1) it would be nice to set lo_bits/hi_bits more systematically (e.g. should both be 127?) and (2) I don't see why we need the range constraints.

Copy link
Contributor

Choose a reason for hiding this comment

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

since you're using split_at the range constraints afterwards should be removed

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

@ledwards2225 ledwards2225 changed the base branch from merge-train/barretenberg to next September 16, 2025 03:29
@ledwards2225 ledwards2225 changed the base branch from next to merge-train/barretenberg September 16, 2025 03:29
@fcarreiro fcarreiro removed their request for review September 16, 2025 09:21
Builder* get_context() const { return context; }

std::pair<field_t<Builder>, field_t<Builder>> split_at(
std::pair<field_t<Builder>, field_t<Builder>> split_at(const size_t lsb_index) const;
Copy link
Contributor

Choose a reason for hiding this comment

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

makes sense to me

@iakovenkos iakovenkos self-requested a review September 16, 2025 13:15
Copy link
Contributor

@iakovenkos iakovenkos left a comment

Choose a reason for hiding this comment

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

pls remove extra constraints after split_at, otherwise looks good!

using cycle_scalar = typename stdlib::cycle_group<Builder>::cycle_scalar;
const cycle_scalar scalar = cycle_scalar(challenge);
scalar.lo.create_range_constraint(cycle_scalar::LO_BITS);
scalar.hi.create_range_constraint(cycle_scalar::HI_BITS);
Copy link
Contributor

Choose a reason for hiding this comment

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

I think the vks have changed bc you removed the range constraints here. The gate count is likely the same because of the range constraint batching

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 didn't remove them though, they just moved to split_unique. but its possible some ordering has changed

# - 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)

(void)a;
EXPECT_FALSE(builder.failed());
EXPECT_TRUE(CircuitChecker::check(builder));
check_circuit_and_gates(builder, 1);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

adding gate pinning logic to all of these tests to avoid unexplained changes

@ledwards2225 ledwards2225 merged commit f9a1909 into merge-train/barretenberg Sep 19, 2025
6 checks passed
@ledwards2225 ledwards2225 deleted the lde/cycle-group-5 branch September 19, 2025 18:14
github-merge-queue bot pushed a commit that referenced this pull request Sep 22, 2025
BEGIN_COMMIT_OVERRIDE
chore: Tube-related clean up (#17064)
chore: cycle group cleanup #5 (#17026)
chore: `field_conversion` clean-up/int audit (#16898)
fix: bigfield veridise audit fixes (#16842)
END_COMMIT_OVERRIDE
fcarreiro pushed a commit that referenced this pull request Sep 22, 2025
Cleaning up and restricting the interface to cycle_scalar. The main
purpose of this thread of work is to make it easier to identify when
certain constraints need to be applied (e.g. primality) and to make
applying them less error prone:
- Add method `field_t::split_at_unrestricted()` (better name TBD!) to
implement hi/lo splitting logic previously housed in `cycle_scalar`
- Remove unused constructors `cycle_scalar(const field_t&)` and
`cycle_scalar(const ScalarField&)`
- remove option to `skip_primality_test` in method
`create_from_bn254_scalar()`
mralj pushed a commit that referenced this pull request Oct 13, 2025
Cleaning up and restricting the interface to cycle_scalar. The main
purpose of this thread of work is to make it easier to identify when
certain constraints need to be applied (e.g. primality) and to make
applying them less error prone:
- Add method `field_t::split_at_unrestricted()` (better name TBD!) to
implement hi/lo splitting logic previously housed in `cycle_scalar`
- Remove unused constructors `cycle_scalar(const field_t&)` and
`cycle_scalar(const ScalarField&)`
- remove option to `skip_primality_test` in method
`create_from_bn254_scalar()`
ludamad pushed a commit that referenced this pull request Dec 16, 2025
Cleaning up and restricting the interface to cycle_scalar. The main
purpose of this thread of work is to make it easier to identify when
certain constraints need to be applied (e.g. primality) and to make
applying them less error prone:
- Add method `field_t::split_at_unrestricted()` (better name TBD!) to
implement hi/lo splitting logic previously housed in `cycle_scalar`
- Remove unused constructors `cycle_scalar(const field_t&)` and
`cycle_scalar(const ScalarField&)`
- remove option to `skip_primality_test` in method
`create_from_bn254_scalar()`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants