chore: cycle group cleanup #5#17026
Conversation
| // 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)); |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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 }; |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
I suppose in the recursive verifier setting we can have challenges of one scaler field represented in another, e.g. in the eccvm.
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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. |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
I'm not sure why this constant is 252 - would be nice to add some documentation
| 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; |
iakovenkos
left a comment
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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" |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
adding gate pinning logic to all of these tests to avoid unexplained changes
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()`
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()`
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()`
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:
field_t::split_at_unrestricted()(better name TBD!) to implement hi/lo splitting logic previously housed incycle_scalarcycle_scalar(const field_t&)andcycle_scalar(const ScalarField&)skip_primality_testin methodcreate_from_bn254_scalar()