-
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 10 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,50 @@ template <typename Builder> field_t<Builder> field_t<Builder>::accumulate(const | |
| return total.normalize(); | ||
| } | ||
|
|
||
| /** | ||
| * @brief Splits the field element into (lo, hi), where: | ||
| * - lo contains bits [0, lsb_index) | ||
| * - hi contains bits [lsb_index, max_bits) | ||
| * | ||
| */ | ||
| template <typename Builder> | ||
| std::pair<field_t<Builder>, field_t<Builder>> field_t<Builder>::split_at(const size_t lsb_index) const | ||
| { | ||
| static constexpr size_t max_bits = native::modulus.get_msb() + 1; | ||
| 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` in the field | ||
| 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) | ||
| * @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); | ||
|
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)); | ||
| } | ||
| } | ||
|
|
@@ -1158,9 +1180,9 @@ TYPED_TEST(CycleGroupTest, MixedLengthScalarsIsNotSupported) | |
| std::vector<typename cycle_group_ct::cycle_scalar> scalars; | ||
|
|
||
| // First scalar: 254 bits (default cycle_scalar::NUM_BITS) | ||
| auto scalar1_value = FF::random_element(&engine); | ||
| auto scalar1 = FF_ct::from_witness(&builder, scalar1_value); | ||
| scalars.emplace_back(scalar1); | ||
| uint256_t scalar1_value = uint256_t(123456789); | ||
| BigScalarField big_scalar1(&builder, typename Curve::ScalarField(scalar1_value)); | ||
| scalars.push_back(cycle_scalar_ct(big_scalar1)); | ||
| EXPECT_EQ(scalars[0].num_bits(), cycle_scalar_ct::NUM_BITS); | ||
|
|
||
| // Second scalar: 256 bits | ||
|
|
@@ -1194,8 +1216,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.