chore: field_conversion clean-up/int audit#16898
chore: field_conversion clean-up/int audit#16898ledwards2225 merged 27 commits intomerge-train/barretenbergfrom
field_conversion clean-up/int audit#16898Conversation
…i/field-conversion-audit
| * @tparam Builder | ||
| */ | ||
| template <typename Builder> void cycle_group<Builder>::validate_is_on_curve() const | ||
| template <typename Builder> void cycle_group<Builder>::validate_on_curve() const |
There was a problem hiding this comment.
to match the naming pattern in other groups
| template <typename Builder> class cycle_group { | ||
| public: | ||
| using field_t = stdlib::field_t<Builder>; | ||
| using BaseField = field_t; |
There was a problem hiding this comment.
biggroup and goblin have this alias, seems useful for uniform group element handling in field_conversion
| T out(x, y, check_point_at_infinity<Builder, T>(fr_vec)); | ||
| // Note that in the case of bn254 with Mega arithmetization, the check is delegated to ECCVM, see | ||
| // `on_curve_check` in `ECCVMTranscriptRelationImpl`. | ||
| out.validate_on_curve(); |
There was a problem hiding this comment.
Added in-circuit on_curve checks
|
|
||
| // Recursively verify CIVC proof | ||
| auto mega_vk = std::make_shared<VerificationKey>(builder, key_fields); | ||
| auto mega_vk = std::make_shared<VerificationKey>(key_fields); |
There was a problem hiding this comment.
Here and in several places below, builder is redundant as field_conversion can extract from the fields being passed while ensuring that those are in-circuit.
| // Check the size of the recursive verifier | ||
| if constexpr (std::same_as<RecursiveFlavor, MegaZKRecursiveFlavor_<UltraCircuitBuilder>>) { | ||
| uint32_t NUM_GATES_EXPECTED = 796978; | ||
| uint32_t NUM_GATES_EXPECTED = 803143; |
There was a problem hiding this comment.
More gates due to enabled on-curve checks
| element(); | ||
| element(const typename NativeGroup::affine_element& input); | ||
| element(const Fq& x, const Fq& y); | ||
| element(const Fq& x, const Fq& y, const bool_ct& is_infinity); |
There was a problem hiding this comment.
feels like a very natural constructor, here and in other groups
| auto sum = low + hi * shift; | ||
| builder.assert_equal(f.witness_index, sum.witness_index, "assert_equal"); | ||
| const fr<Builder> zero = fr<Builder>::from_witness_index(&builder, 0); | ||
| fr<Builder>::evaluate_linear_identity(hi * shift, low, -fr_element, zero); |
There was a problem hiding this comment.
minus 1 gate thanks to combining the addition with constraining to be 0
|
|
||
| std::vector<fr<Builder>> fr_vec{ low, hi }; | ||
| return convert_from_bn254_frs<Builder, fq<Builder>>(builder, fr_vec); | ||
| return fq<Builder>(low, hi); |
There was a problem hiding this comment.
not calling convert_from_bn254_frs cause it's not needed/seems convoluted
| * | ||
| * @return | ||
| */ | ||
| template <typename Builder, typename T> bool_t<Builder> check_point_at_infinity(std::span<const fr<Builder>> fr_vec) |
There was a problem hiding this comment.
Isolated the check to handle grumpkin and bn254 uniformly in deserialization
…i/field-conversion-audit
| } | ||
| } | ||
| } | ||
| tamper_with_libra_eval(tampered_proof.translator_proof); |
There was a problem hiding this comment.
the same here, the tampering before would simply invalidate on_curve check. switched to modifying one of the evals
| // Check the size of the recursive verifier | ||
| if constexpr (std::same_as<RecursiveFlavor, MegaZKRecursiveFlavor_<UltraCircuitBuilder>>) { | ||
| uint32_t NUM_GATES_EXPECTED = 796978; | ||
| uint32_t NUM_GATES_EXPECTED = 801953; |
There was a problem hiding this comment.
as a result of enabled on_curve checks
| // Efficiently compute ((x^2 + 5 y^2) == 0) | ||
| const fr<Builder> x_sqr = fr_vec[0].sqr(); | ||
| const fr<Builder> y = fr_vec[1]; | ||
| return (y.madd(y, x_sqr * bb::fr(5)).is_zero()); |
There was a problem hiding this comment.
Should this be:
const fr<Builder> five_y = fr_vec[1] * bb::fr(5);
return (y.madd(five_y, x_sqr)).is_zero());as the comment says:
| BB_ASSERT_EQ(static_cast<uint256_t>(low_val) + (static_cast<uint256_t>(hi_val) << NUM_BITS_IN_TWO_LIMBS), | ||
| value, | ||
| "field_conversion: limb decomposition"); | ||
| // checks this decomposition low + hi * 2^64 = value with an assert_equal |
There was a problem hiding this comment.
nit: the comment needs to be corrected to: low + hi * 2^68
There was a problem hiding this comment.
oops, stale comment, fixed
| using bigfield_ct = fq<Builder>; | ||
|
|
||
| if constexpr (IsAnyOf<T, field_ct>) { | ||
| ; |
| { | ||
| using Builder = TypeParam; | ||
|
|
||
| { // Serialize and deserialize the Grumpkin generator |
There was a problem hiding this comment.
I think it might be worth adding serialize and deserializing random point(s) on curve for testing along with the edge-cases you've already covered.
There was a problem hiding this comment.
thanks, added loops testing 50 random points for both curves
| { | ||
| constexpr uint64_t NUM_BITS_IN_TWO_LIMBS = 2 * NUM_LIMB_BITS; // 136 | ||
| constexpr uint64_t UPPER_TWO_LIMB_BITS = TOTAL_BITS - NUM_BITS_IN_TWO_LIMBS; // 118 | ||
| ASSERT(!fr_element.is_constant()); |
There was a problem hiding this comment.
@ledwards2225 after our discussions, i think this should use split_unique from your pr
There was a problem hiding this comment.
actually merged your changes from cycle-group-5 to my follow-up and nuked the entire method, see stdlib::field_conversion::convert_challenge in #17034
…i/field-conversion-audit
| if constexpr (IsAnyOf<Builder, UltraCircuitBuilder>) { | ||
| EXPECT_THROW_OR_ABORT(group_element = bn254_element<Builder>::from_witness(&builder, group_element_val), | ||
| ""); | ||
| } else { |
There was a problem hiding this comment.
no failure because this is checked in eccvm right?
| { | ||
| using Builder = TypeParam; | ||
| Builder builder; | ||
| const fr<Builder> zero(fr<Builder>::from_witness_index(&builder, 0)); |
There was a problem hiding this comment.
I think we should try to avoid this pattern of assuming index 0 corresponds to value 0
| auto y = bb::stdlib::field_conversion::convert_from_bn254_frs<Builder, T>(frs); | ||
| bool expected = std::is_same_v<Builder, UltraCircuitBuilder> ? !point_at_infinity : true; | ||
|
|
||
| EXPECT_EQ(x.get_value() == y.get_value(), expected); |
There was a problem hiding this comment.
nano-nit: in/out seems clearer than x/y in a context where x/y can be plausibly confused with point coordinates
ledwards2225
left a comment
There was a problem hiding this comment.
Looks good to me - nice simplifications
suyash67
left a comment
There was a problem hiding this comment.
cool stuff, thanks for the amazing documentation!
### 🧾 Audit Context `stdlib::field_conversion` provides the serialization/deserialization methods for `stdlib::Transcript`. ### 🛠️ Changes Made - Simplified the logic by making it more uniform and getting rid of redundant arguments - Enabled `on_curve` checks for Ultra deserialization of group elements (BN254 and Grumpkin) - Removed redundant range constraints in `fr --> bigfield` conversion and optimized the constraint ensuring that `fr = lo + hi * shift`. Note that limbs were constrained to be (136, 118) bits, although such range constraints are enforced by `bigfield(low, hi)` constructor. - Optimized `point_at_infinity` check for Grumpkin points. - Expanded docs and made them Doxygen-friendly - Added tests and [an issue](AztecProtocol/barretenberg#1541) that will be resolved in a follow-up - The vks and circuit sizes have changed due to enabled checks and the small optimizations described above ### 📌 Notes for Reviewers Agreed with @suyash67 that existing point-at-infinity issue AztecProtocol/barretenberg#1527 should be handled by ensuring the consistent representation of points at infinity in all groups. Added a test that will fail once the issue is resolved. --------- Co-authored-by: ledwards2225 <l.edwards.d@gmail.com>
`stdlib::field_conversion` provides the serialization/deserialization methods for `stdlib::Transcript`. - Simplified the logic by making it more uniform and getting rid of redundant arguments - Enabled `on_curve` checks for Ultra deserialization of group elements (BN254 and Grumpkin) - Removed redundant range constraints in `fr --> bigfield` conversion and optimized the constraint ensuring that `fr = lo + hi * shift`. Note that limbs were constrained to be (136, 118) bits, although such range constraints are enforced by `bigfield(low, hi)` constructor. - Optimized `point_at_infinity` check for Grumpkin points. - Expanded docs and made them Doxygen-friendly - Added tests and [an issue](AztecProtocol/barretenberg#1541) that will be resolved in a follow-up - The vks and circuit sizes have changed due to enabled checks and the small optimizations described above Agreed with @suyash67 that existing point-at-infinity issue AztecProtocol/barretenberg#1527 should be handled by ensuring the consistent representation of points at infinity in all groups. Added a test that will fail once the issue is resolved. --------- Co-authored-by: ledwards2225 <l.edwards.d@gmail.com>
### 🧾 Audit Context `stdlib::field_conversion` provides the serialization/deserialization methods for `stdlib::Transcript`. ### 🛠️ Changes Made - Simplified the logic by making it more uniform and getting rid of redundant arguments - Enabled `on_curve` checks for Ultra deserialization of group elements (BN254 and Grumpkin) - Removed redundant range constraints in `fr --> bigfield` conversion and optimized the constraint ensuring that `fr = lo + hi * shift`. Note that limbs were constrained to be (136, 118) bits, although such range constraints are enforced by `bigfield(low, hi)` constructor. - Optimized `point_at_infinity` check for Grumpkin points. - Expanded docs and made them Doxygen-friendly - Added tests and [an issue](AztecProtocol/barretenberg#1541) that will be resolved in a follow-up - The vks and circuit sizes have changed due to enabled checks and the small optimizations described above ### 📌 Notes for Reviewers Agreed with @suyash67 that existing point-at-infinity issue AztecProtocol/barretenberg#1527 should be handled by ensuring the consistent representation of points at infinity in all groups. Added a test that will fail once the issue is resolved. --------- Co-authored-by: ledwards2225 <l.edwards.d@gmail.com>
🧾 Audit Context
stdlib::field_conversionprovides the serialization/deserialization methods forstdlib::Transcript.🛠️ Changes Made
on_curvechecks for Ultra deserialization of group elements (BN254 and Grumpkin)fr --> bigfieldconversion and optimized the constraint ensuring thatfr = lo + hi * shift. Note that limbs were constrained to be (136, 118) bits, although such range constraints are enforced bybigfield(low, hi)constructor.point_at_infinitycheck for Grumpkin points.📌 Notes for Reviewers
Agreed with @suyash67 that existing point-at-infinity issue AztecProtocol/barretenberg#1527 should be handled by ensuring the consistent representation of points at infinity in all groups. Added a test that will fail once the issue is resolved.