-
Notifications
You must be signed in to change notification settings - Fork 615
chore: cycle group cleanup #5 #17026
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 7 commits
6b23fd2
4832bd6
bf3eacb
c6292e0
14c1400
fb17bdf
ce5e3da
dd1401e
3035add
984cb44
d1d440e
d9eb676
7c563b0
5da71f1
6001747
e690fd2
83be28b
1de5c17
50808c0
12c79de
1b5047e
739ad72
99c1cd1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1260,14 +1260,43 @@ template <typename Builder> field_t<Builder> field_t<Builder>::accumulate(const | |
| return total.normalize(); | ||
| } | ||
|
|
||
| // WORKTODO: better name! | ||
| template <typename Builder> | ||
| std::pair<field_t<Builder>, field_t<Builder>> field_t<Builder>::split_at(const size_t lsb_index) const | ||
| { | ||
| // WORKTODO: is this right? depends on how bb::fr is implemented. ideally this would be some predefined constant.. | ||
| const size_t max_bits = 254; | ||
| ASSERT(lsb_index < max_bits); | ||
|
|
||
| const uint256_t value(this->get_value()); | ||
| const uint256_t lo_val = value.slice(0, lsb_index); | ||
| const uint256_t hi_val = value.slice(lsb_index, max_bits); | ||
|
|
||
| // If `this` is constant, return constants based on the native hi/lo values | ||
| if (this->is_constant()) { | ||
| return { field_t(lo_val), field_t(hi_val) }; | ||
| } | ||
|
|
||
| // Otherwise, create hi/lo witnesses and constrain them to reconstruct `this` as field elements | ||
| field_t lo = from_witness(get_context(), lo_val); | ||
| field_t hi = from_witness(get_context(), hi_val); | ||
| const uint256_t shift = uint256_t(1) << lsb_index; | ||
| (lo + (hi * shift)).assert_equal(*this); | ||
|
|
||
| // Set the origin tag for the limbs to be that of the original field element | ||
| lo.set_origin_tag(get_origin_tag()); | ||
| hi.set_origin_tag(get_origin_tag()); | ||
| return { lo, hi }; | ||
| } | ||
|
|
||
| /** | ||
| * @brief Splits the field element into (lo, hi), where: | ||
| * - lo contains bits [0, lsb_index) | ||
| * - hi contains bits [lsb_index, num_bits) | ||
| */ | ||
| 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); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -388,7 +388,9 @@ 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>> split_at(const size_t lsb_index) const; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. makes sense to me |
||
|
|
||
| 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; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,7 +20,8 @@ | |
| using Group = typename Curve::Group; \ | ||
| using bool_ct = stdlib::bool_t<Builder>; \ | ||
| using witness_ct = stdlib::witness_t<Builder>; \ | ||
| using cycle_scalar_ct = cycle_group_ct::cycle_scalar; | ||
| using cycle_scalar_ct = cycle_group_ct::cycle_scalar; \ | ||
| using BigScalarField = typename cycle_scalar_ct::BigScalarField; | ||
|
|
||
| using namespace bb; | ||
|
|
||
|
|
@@ -771,22 +772,26 @@ TYPED_TEST(CycleGroupTest, TestBatchMulGeneralMSM) | |
| // 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)); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| BigScalarField big_scalar1(&builder, scalar); | ||
| scalars.emplace_back(cycle_scalar_ct(big_scalar1)); | ||
|
|
||
| // 2: add entry where point is constant, scalar is witness | ||
| expected += (element * scalar); | ||
| points.emplace_back(cycle_group_ct(element)); | ||
| scalars.emplace_back(cycle_group_ct::cycle_scalar::from_witness(&builder, scalar)); | ||
| BigScalarField big_scalar2(&builder, scalar); | ||
| scalars.emplace_back(cycle_scalar_ct(big_scalar2)); | ||
|
|
||
| // 3: add entry where point is witness, scalar is constant | ||
| expected += (element * scalar); | ||
| points.emplace_back(cycle_group_ct::from_witness(&builder, element)); | ||
| scalars.emplace_back(typename cycle_group_ct::cycle_scalar(scalar)); | ||
| BigScalarField big_scalar3(&builder, scalar); | ||
| scalars.emplace_back(cycle_scalar_ct(big_scalar3)); | ||
|
|
||
| // 4: add entry where point is constant, scalar is constant | ||
| expected += (element * scalar); | ||
| points.emplace_back(cycle_group_ct(element)); | ||
| scalars.emplace_back(typename cycle_group_ct::cycle_scalar(scalar)); | ||
| BigScalarField big_scalar4(&builder, scalar); | ||
| scalars.emplace_back(cycle_scalar_ct(big_scalar4)); | ||
| } | ||
|
|
||
| // Here and in the following cases assign different tags to points and scalars and get the union of them back | ||
|
|
@@ -813,10 +818,12 @@ TYPED_TEST(CycleGroupTest, TestBatchMulProducesInfinity) | |
| auto element = TestFixture::generators[0]; | ||
| typename Group::Fr scalar = Group::Fr::random_element(&engine); | ||
| points.emplace_back(cycle_group_ct::from_witness(&builder, element)); | ||
| scalars.emplace_back(cycle_group_ct::cycle_scalar::from_witness(&builder, scalar)); | ||
| BigScalarField big_scalar1(&builder, scalar); | ||
| scalars.emplace_back(cycle_scalar_ct(big_scalar1)); | ||
|
|
||
| points.emplace_back(cycle_group_ct::from_witness(&builder, element)); | ||
| scalars.emplace_back(cycle_group_ct::cycle_scalar::from_witness(&builder, -scalar)); | ||
| BigScalarField big_scalar2(&builder, -scalar); | ||
| scalars.emplace_back(cycle_scalar_ct(big_scalar2)); | ||
|
|
||
| const auto expected_tag = assign_and_merge_tags(points, scalars); | ||
|
|
||
|
|
@@ -841,7 +848,8 @@ TYPED_TEST(CycleGroupTest, TestBatchMulMultiplyByZero) | |
| auto element = TestFixture::generators[0]; | ||
| typename Group::Fr scalar = 0; | ||
| points.emplace_back(cycle_group_ct::from_witness(&builder, element)); | ||
| scalars.emplace_back(cycle_group_ct::cycle_scalar::from_witness(&builder, scalar)); | ||
| BigScalarField big_scalar(&builder, scalar); | ||
| scalars.emplace_back(cycle_scalar_ct(big_scalar)); | ||
|
|
||
| const auto expected_tag = assign_and_merge_tags(points, scalars); | ||
| auto result = cycle_group_ct::batch_mul(points, scalars); | ||
|
|
@@ -869,14 +877,16 @@ TYPED_TEST(CycleGroupTest, TestBatchMulInputsAreInfinity) | |
| cycle_group_ct point = cycle_group_ct::from_witness(&builder, element); | ||
| point.set_point_at_infinity(witness_ct(&builder, true)); | ||
| points.emplace_back(point); | ||
| scalars.emplace_back(cycle_group_ct::cycle_scalar::from_witness(&builder, scalar)); | ||
| BigScalarField big_scalar1(&builder, scalar); | ||
| scalars.emplace_back(cycle_scalar_ct(big_scalar1)); | ||
| } | ||
| // is_infinity = constant | ||
| { | ||
| cycle_group_ct point = cycle_group_ct::from_witness(&builder, element); | ||
| point.set_point_at_infinity(true); | ||
| points.emplace_back(point); | ||
| scalars.emplace_back(cycle_group_ct::cycle_scalar::from_witness(&builder, scalar)); | ||
| BigScalarField big_scalar2(&builder, scalar); | ||
| scalars.emplace_back(cycle_scalar_ct(big_scalar2)); | ||
| } | ||
|
|
||
| const auto expected_tag = assign_and_merge_tags(points, scalars); | ||
|
|
@@ -907,14 +917,16 @@ TYPED_TEST(CycleGroupTest, TestBatchMulFixedBaseInLookupTable) | |
| // 1: add entry where point is constant, scalar is witness | ||
| expected += (element * scalar); | ||
| points.emplace_back(element); | ||
| scalars.emplace_back(cycle_group_ct::cycle_scalar::from_witness(&builder, scalar)); | ||
| BigScalarField big_scalar(&builder, scalar); | ||
| scalars.emplace_back(cycle_scalar_ct(big_scalar)); | ||
| scalars_native.emplace_back(uint256_t(scalar)); | ||
|
|
||
| // 2: add entry where point is constant, scalar is constant | ||
| element = plookup::fixed_base::table::rhs_generator_point(); | ||
| expected += (element * scalar); | ||
| points.emplace_back(element); | ||
| scalars.emplace_back(typename cycle_group_ct::cycle_scalar(scalar)); | ||
| BigScalarField big_scalar_const(&builder, scalar); | ||
| scalars.emplace_back(cycle_scalar_ct(big_scalar_const)); | ||
| scalars_native.emplace_back(uint256_t(scalar)); | ||
| } | ||
| const auto expected_tag = assign_and_merge_tags(points, scalars); | ||
|
|
@@ -946,22 +958,25 @@ TYPED_TEST(CycleGroupTest, TestBatchMulFixedBaseSomeInLookupTable) | |
| // 1: add entry where point is constant, scalar is witness | ||
| expected += (element * scalar); | ||
| points.emplace_back(element); | ||
| scalars.emplace_back(cycle_group_ct::cycle_scalar::from_witness(&builder, scalar)); | ||
| BigScalarField big_scalar(&builder, scalar); | ||
| scalars.emplace_back(cycle_scalar_ct(big_scalar)); | ||
| scalars_native.emplace_back(scalar); | ||
|
|
||
| // 2: add entry where point is constant, scalar is constant | ||
| element = plookup::fixed_base::table::rhs_generator_point(); | ||
| expected += (element * scalar); | ||
| points.emplace_back(element); | ||
| scalars.emplace_back(typename cycle_group_ct::cycle_scalar(scalar)); | ||
| BigScalarField big_scalar_const(&builder, scalar); | ||
| scalars.emplace_back(cycle_scalar_ct(big_scalar_const)); | ||
| scalars_native.emplace_back(scalar); | ||
|
|
||
| // 3: add entry where point is constant, scalar is witness | ||
| scalar = Group::Fr::random_element(&engine); | ||
| element = Group::one * Group::Fr::random_element(&engine); | ||
| expected += (element * scalar); | ||
| points.emplace_back(element); | ||
| scalars.emplace_back(cycle_group_ct::cycle_scalar::from_witness(&builder, scalar)); | ||
| BigScalarField big_scalar2(&builder, scalar); | ||
| scalars.emplace_back(cycle_scalar_ct(big_scalar2)); | ||
| scalars_native.emplace_back(scalar); | ||
| } | ||
| const auto expected_tag = assign_and_merge_tags(points, scalars); | ||
|
|
@@ -989,11 +1004,13 @@ TYPED_TEST(CycleGroupTest, TestBatchMulFixedBaseZeroScalars) | |
|
|
||
| // 1: add entry where point is constant, scalar is witness | ||
| points.emplace_back((element)); | ||
| scalars.emplace_back(cycle_group_ct::cycle_scalar::from_witness(&builder, scalar)); | ||
| BigScalarField big_scalar(&builder, scalar); | ||
| scalars.emplace_back(cycle_scalar_ct(big_scalar)); | ||
|
|
||
| // 2: add entry where point is constant, scalar is constant | ||
| points.emplace_back((element)); | ||
| scalars.emplace_back(typename cycle_group_ct::cycle_scalar(scalar)); | ||
| BigScalarField big_scalar_const(&builder, scalar); | ||
| scalars.emplace_back(cycle_scalar_ct(big_scalar_const)); | ||
| } | ||
| const auto expected_tag = assign_and_merge_tags(points, scalars); | ||
| auto result = cycle_group_ct::batch_mul(points, scalars); | ||
|
|
@@ -1014,7 +1031,6 @@ TYPED_TEST(CycleGroupTest, TestMul) | |
| // case 1, general MSM with inputs that are combinations of constant and witnesses | ||
| { | ||
| cycle_group_ct point; | ||
| typename cycle_group_ct::cycle_scalar scalar; | ||
| cycle_group_ct result; | ||
| for (size_t i = 0; i < num_muls; ++i) { | ||
| auto element = TestFixture::generators[i]; | ||
|
|
@@ -1023,7 +1039,8 @@ TYPED_TEST(CycleGroupTest, TestMul) | |
|
|
||
| // 1: add entry where point, scalar are witnesses | ||
| point = (cycle_group_ct::from_witness(&builder, element)); | ||
| scalar = (cycle_group_ct::cycle_scalar::from_witness(&builder, native_scalar)); | ||
| BigScalarField big_scalar1(&builder, native_scalar); | ||
| cycle_scalar_ct scalar = (cycle_scalar_ct(big_scalar1)); | ||
| point.set_origin_tag(submitted_value_origin_tag); | ||
| scalar.set_origin_tag(challenge_origin_tag); | ||
| result = point * scalar; | ||
|
|
@@ -1032,16 +1049,21 @@ TYPED_TEST(CycleGroupTest, TestMul) | |
|
|
||
| // 2: add entry where point is constant, scalar is witness | ||
| point = (cycle_group_ct(element)); | ||
| scalar = (cycle_group_ct::cycle_scalar::from_witness(&builder, native_scalar)); | ||
| BigScalarField big_scalar2(&builder, native_scalar); | ||
| scalar = (cycle_scalar_ct(big_scalar2)); | ||
|
|
||
| EXPECT_EQ((result).get_value(), (expected_result)); | ||
|
|
||
| // 3: add entry where point is witness, scalar is constant | ||
| point = (cycle_group_ct::from_witness(&builder, element)); | ||
| BigScalarField big_scalar3(&builder, native_scalar); | ||
| scalar = (cycle_scalar_ct(big_scalar3)); | ||
| EXPECT_EQ((result).get_value(), (expected_result)); | ||
|
|
||
| // 4: add entry where point is constant, scalar is constant | ||
| point = (cycle_group_ct(element)); | ||
| BigScalarField big_scalar4(&builder, native_scalar); | ||
| scalar = (cycle_scalar_ct(big_scalar4)); | ||
| EXPECT_EQ((result).get_value(), (expected_result)); | ||
| } | ||
| } | ||
|
|
@@ -1156,7 +1178,8 @@ TYPED_TEST(CycleGroupTest, MixedLengthScalarsIsNotSupported) | |
|
|
||
| // First scalar: 256 bits | ||
| uint256_t scalar1_value = uint256_t(123456789); | ||
| scalars.push_back(cycle_group_ct::cycle_scalar::from_witness(&builder, typename Curve::ScalarField(scalar1_value))); | ||
| BigScalarField big_scalar1(&builder, typename Curve::ScalarField(scalar1_value)); | ||
| scalars.push_back(cycle_scalar_ct(big_scalar1)); | ||
|
|
||
| // Second scalar: 128 bits | ||
| uint256_t scalar2_value = uint256_t(987654321); | ||
|
|
@@ -1188,8 +1211,10 @@ TYPED_TEST(CycleGroupTest, TestFixedBaseBatchMul) | |
| auto scalar1_val = Group::Fr::random_element(&engine); | ||
| auto scalar2_val = Group::Fr::random_element(&engine); | ||
|
|
||
| scalars.push_back(cycle_scalar_ct::from_witness(&builder, scalar1_val)); | ||
| scalars.push_back(cycle_scalar_ct::from_witness(&builder, scalar2_val)); | ||
| BigScalarField big_scalar1(&builder, scalar1_val); | ||
| BigScalarField big_scalar2(&builder, scalar2_val); | ||
| scalars.push_back(cycle_scalar_ct(big_scalar1)); | ||
| scalars.push_back(cycle_scalar_ct(big_scalar2)); | ||
| points.push_back(cycle_group_ct(lhs_generator)); // constant point | ||
| points.push_back(cycle_group_ct(rhs_generator)); // constant point | ||
|
|
||
|
|
||
There was a problem hiding this comment.
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 methodsplit_challenge(). This used to happen under the hood by virtue of usingcycle_scalar(const field_t&)to perform the hi/lo splitting. We now usefield_t::split_at()which performs identical splitting but does not perform an "in field" check.