Skip to content

refactor(field): Rename representative to canonical#1130

Merged
diegokingston merged 3 commits intomainfrom
refactor/canonical-representative
Feb 4, 2026
Merged

refactor(field): Rename representative to canonical#1130
diegokingston merged 3 commits intomainfrom
refactor/canonical-representative

Conversation

@diegokingston
Copy link
Collaborator

Renames the IsPrimeField trait method and associated type to better reflect their purpose:

  • RepresentativeType -> CanonicalType
  • representative() -> canonical()
  • RepresentativeOutOfRange -> CanonicalValueOutOfRange

This aligns with the Goldilocks field naming convention where canonicalize is used to convert values to their canonical form in range [0, p-1].

Changes across:

  • IsPrimeField trait definition
  • All IsPrimeField implementations (Goldilocks, Mersenne31, P448, etc.)
  • FieldElement::canonical() method
  • All usages in crypto, provers, and examples

Note: winterfell_adapter uses external git dependency that still has the old API, so it retains the representative call.

@diegokingston diegokingston requested a review from a team as a code owner February 3, 2026 18:08
@github-actions
Copy link

github-actions bot commented Feb 3, 2026

Kimi AI Review

The PR diff provided contains a large number of changes, primarily focused on replacing the use of the representative() method with canonical() across various parts of the codebase. This change is consistent with the goal of converting from Montgomery form to standard form for field elements. Here are my specific comments and feedback on the changes:

  1. Renaming Method Calls: The change from representative() to canonical() is consistent across all files, indicating a uniform approach to the refactor. This is good for maintaining code consistency.

  2. kzg.rs:

    • The changes at lines 156 and 168 seem correct, as they replace representative() with canonical() when mapping coefficients for use in MSM (multiscalar multiplication).
    • Lines 209 and 260: The changes are appropriate for ensuring that the elements are in the correct form before performing pairing operations.
  3. parameters.rs:

    • Line 478: The change to use canonical() is correct for ensuring the correct representation is used in the formatted string.
  4. compression.rs and sqrt.rs:

    • Across various files like compression.rs and sqrt.rs for different curves (e.g., bls12_381, bn_254), the changes from representative() to canonical() are appropriate for comparisons and operations involving square roots and compression.
  5. errors.rs:

    • Line 13: Renaming RepresentativeOutOfRange to CanonicalValueOutOfRange is consistent with the changes in method names and their purposes.
  6. element.rs:

    • The changes at lines 622, 644, 689, and 831 are correct for aligning with the new method name canonical(). This ensures that serialization and display of field elements are in the standard form.
  7. Performance Considerations:

    • The changes do not seem to introduce any performance regressions. However, it's important to monitor the performance impact of these changes, especially in performance-critical applications like cryptographic proofs and verification.
  8. Cryptographic Security:

    • The changes are internal and do not affect the cryptographic security assumptions, as long as the conversion between Montgomery form and standard form is correctly implemented.
  9. Code Simplicity and Maintainability:

    • The refactor improves code maintainability by standardizing the method used for converting field elements to their standard form.

Overall, the changes appear to be correctly implemented and consistent with the goal of refactoring the codebase to use canonical() instead of representative(). It's important to thoroughly test these changes, especially in the context of cryptographic operations where subtle changes can have significant impacts.

@greptile-apps
Copy link

greptile-apps bot commented Feb 3, 2026

Greptile Overview

Greptile Summary

This PR performs a comprehensive rename of the IsPrimeField trait's representation-related types and methods to better reflect their purpose. The changes rename RepresentativeType to CanonicalType, representative() to canonical(), and RepresentativeOutOfRange to CanonicalValueOutOfRange across the entire codebase.

What Changed:

  • Updated the IsPrimeField trait definition with improved documentation explaining that canonical() converts from internal representation (e.g., Montgomery form) to standard form in range [0, p-1]
  • Modified all field implementations including Goldilocks, Mersenne31, Montgomery-backed fields, and test fields
  • Updated all usages across crypto primitives (KZG commitments, Poseidon hash), zero-knowledge provers (Groth16, PLONK, STARK), and examples (BLS signatures, ECDSA, Schnorr, etc.)
  • Enhanced documentation in README.md with clearer explanations of the canonical form conversion

Key Observations:

  • The renaming is systematic and comprehensive across 48 files
  • The winterfell.rs adapter correctly updates to the new API with stub implementations
  • Two test function names in montgomery_backed_prime_fields.rs still use the old representative terminology (see inline comments)
  • All functional code has been updated consistently

The refactoring improves code clarity by using terminology that better describes the mathematical concept of canonical representation in finite fields.

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk - it's a pure refactoring with consistent naming changes
  • The renaming is systematic and complete across all 48 files with no logic changes. Only minor style improvements suggested for test function names.
  • No files require special attention - the refactoring is thorough and consistent

Important Files Changed

Filename Overview
crates/math/src/field/traits.rs Renamed RepresentativeType to CanonicalType and representative() to canonical() with improved documentation
crates/math/src/field/element.rs Updated FieldElement::representative() to canonical() with enhanced documentation and error message references
crates/math/src/errors.rs Renamed error variant from RepresentativeOutOfRange to CanonicalValueOutOfRange
crates/math/src/field/fields/montgomery_backed_prime_fields.rs Updated Montgomery field implementations with new naming; test function names still reference old representative naming
crates/crypto/src/commitments/kzg.rs Updated KZG commitment scheme to use CanonicalType and canonical() in trait bounds and method calls
crates/provers/groth16/src/prover.rs Updated Groth16 prover to use canonical() for field element conversions in proof generation

Sequence Diagram

sequenceDiagram
    participant User
    participant FieldElement
    participant IsPrimeField
    participant ConcreteField
    
    Note over User,ConcreteField: Example: Converting to canonical form
    
    User->>FieldElement: element.canonical()
    FieldElement->>IsPrimeField: F::canonical(&self.value)
    IsPrimeField->>ConcreteField: canonical(value)
    Note over ConcreteField: Convert from internal<br/>representation (e.g., Montgomery)<br/>to standard form [0, p-1]
    ConcreteField-->>IsPrimeField: CanonicalType value
    IsPrimeField-->>FieldElement: CanonicalType value
    FieldElement-->>User: CanonicalType value
    
    Note over User,ConcreteField: Example: Serialization flow
    
    User->>FieldElement: Serialize
    FieldElement->>IsPrimeField: F::canonical(&self.value)
    IsPrimeField->>ConcreteField: canonical(value)
    ConcreteField-->>IsPrimeField: CanonicalType value
    IsPrimeField-->>FieldElement: CanonicalType value
    FieldElement->>FieldElement: value.to_string()
    FieldElement-->>User: Serialized string
Loading

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

6 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

@greptile-apps
Copy link

greptile-apps bot commented Feb 3, 2026

Additional Comments (2)

crates/math/src/field/fields/montgomery_backed_prime_fields.rs
test function name still references old representative terminology

    fn montgomery_backend_primefield_canonical() {
Prompt To Fix With AI
This is a comment left during a code review.
Path: crates/math/src/field/fields/montgomery_backed_prime_fields.rs
Line: 560:560

Comment:
test function name still references old `representative` terminology

```suggestion
    fn montgomery_backend_primefield_canonical() {
```

How can I resolve this? If you propose a fix, please make it concise.

crates/math/src/field/fields/montgomery_backed_prime_fields.rs
test function name still references old representative terminology

    fn montgomery_backend_primefield_canonical() {
Prompt To Fix With AI
This is a comment left during a code review.
Path: crates/math/src/field/fields/montgomery_backed_prime_fields.rs
Line: 970:970

Comment:
test function name still references old `representative` terminology

```suggestion
    fn montgomery_backend_primefield_canonical() {
```

How can I resolve this? If you propose a fix, please make it concise.

Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

Code review by ChatGPT

let powers_secondary_group = [g2.clone(), g2.operate_with_self(toxic_waste.canonical())];
StructuredReferenceString::new(&powers_main_group, &powers_secondary_group)
}

Copy link

Choose a reason for hiding this comment

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

Correctness

  • Canonical vs Representative: The change from representative() to canonical() calls alters the semantics of the field operations. Ensure that canonical() is appropriate for the conversion intended here, and that it preserves the correct field representation for all intended mathematical operations and doesn't introduce errors, especially in the edge cases like zero elements.

  • Edge Cases: There is no explicit handling or tests for edge cases such as the identity elements or when the input polynomial is zero. Consider adding tests to confirm behavior.

Security

  • Timing Side-channels: Ensure that operations involving field elements and curve points are constant time with respect to secret data. The use of .canonical() should be verified to maintain constant-time properties.

  • Zeroization: Review if field elements, scalars, or sensitive data are being zeroed out after use to prevent leakage through memory.

  • Randomness: Verify that cryptographically secure random number generation is being uniformly used, where appropriate.

Performance

  • Repeated Allocations: Collecting into a Vec and making calls like acc.operate_with_self(upsilon.to_owned().canonical()) implies potential performance penalties due to unnecessary allocations or copying. Consider optimizing how copies of elements are managed.

  • FFT Efficiency: Not directly visible in this diff, but ensure that the polynomial evaluations or FFT operations avoid redundancy and are concurrent where possible.

Bugs & Errors

  • Unchecked Operations: unwrap, expect, or unchecked operations aren't visible in this snippet but should be avoided or handled gracefully if present elsewhere in the code.

Code Simplicity

  • Complex Implementations: The use of representative or canonical representations should be abstracted if complex, ensuring that high-level operations look clear and are easy to maintain.

  • Duplicated Logic: Consider factoring out repeated logic, especially the mapping and operations over canonical calls, into shared functions for better readability and maintainability.

Overall, ensure that changes in mathematical semantics due to the shift to canonical representations are correct and verified thoroughly through tests, especially for edge and corner cases. Review associated cryptographic considerations tied to these changes as well.

res = format!("{}, Last constant: \n FE::from_hex_unchecked(\"{}\"), \n FE::from_hex_unchecked(\"{}\"), \n FE::from_hex_unchecked(\"{}\")", res, c_next[0].canonical().to_hex(), c_next[1].canonical().to_hex(),c_next[2].canonical().to_hex());
}
i += 1;
}
Copy link

Choose a reason for hiding this comment

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

Correctness

  • Mathematical Operations: Ensure that the transition from representative to canonical does not affect correctness. The canonical() function usually returns a standard or normalized form which should be correct in cryptographic contexts, but verify its implementation to ensure it adheres to the expected finite field properties.

Security

  • Sensitive Data Handling: The lack of explicit zeroization functions on sensitive data may pose security risks if these functions operate on secret elements. Ensure that temporary variables holding sensitive data are securely zeroized before they go out of scope.
  • Constant-Time Operations: Ensure that the canonical() method is implemented in constant time to prevent timing side-channel attacks when operating on secret data.

Performance

  • Function Call Overhead: The change from representative().to_hex() to canonical().to_hex() may introduce additional computational steps or overhead. Verify if the canonical() function adds unnecessary complexity or latency, especially in performance-critical regions such as fast polynomial arithmetic or large-scale MSM.

Bugs & Errors

  • Potential Panics: No explicit panics or unwraps are noted. Verify that the canonical() method does not panic under any circumstances like invalid or corner-case input.

Code Simplicity

  • Complex Functions: The use of manual string formatting might be simplified with conversion traits implementing From or Into for these cryptographic elements. Clarifying function use may aid future maintenance or extension. Consider abstracting the repeated formatting logic.

Overall

Before merging, ensure the canonical() function aligns with cryptographic expectations, particularly concerning security and correctness in finite field operations.

y.value()[1].canonical().cmp(&y_neg.value()[1].canonical()),
) {
(Ordering::Greater, _) | (Ordering::Equal, Ordering::Greater) => {
x_bytes[0] |= 1 << 5;
Copy link

Choose a reason for hiding this comment

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

Correctness

  • The switch from representative() to canonical() requires careful review to ensure both functions preserve the correctness of compression. There is no evidence in the diff to ascertain that these functions behave identically with respect to how comparisons between roots are made.

Security

  • Ensure that all operations involving secret data, like comparisons, are constant-time to mitigate timing side-channels. There should be a verification process for both representative() and canonical() methods.
  • There is no explicit zeroization of y_sqrt_1 and y_sqrt_2, which are part of potentially sensitive data in cryptographic computations.

Performance

  • The comparisons seem efficient, assuming canonical() is not unnecessarily complex or introducing extra overhead.

Bugs & Errors

  • Ensure that canonical() does not panic or cause unintended side effects, especially if the underlying implementation changes from representative().

Code Simplicity

  • The usage of canonical() is consistently replacing representative(), which is good for maintaining consistency; however, the reasoning for this change should be clear and documented to avoid confusion.

Additional Notes

To proceed with confidence, further validation is needed to ensure that canonical() is a proper drop-in replacement for representative(). Documentation or comments explaining the intent and correctness of this change would be beneficial to the maintainers.

match (sqrt_1.canonical().cmp(&sqrt_2.canonical()), third_bit) {
(Ordering::Greater, 0) => sqrt_2,
(Ordering::Greater, _) | (Ordering::Less, 0) | (Ordering::Equal, _) => sqrt_1,
(Ordering::Less, _) => sqrt_2,
Copy link

Choose a reason for hiding this comment

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

Correctness:

  • Ensure that the change from representative() to canonical() for field element comparison maintains mathematical correctness, especially in the context of selecting square roots based on a bit indication. Verify that canonical() consistently provides a distinct comparison within the field characteristics of BLS12-381.

Security:

  • There's no immediate security concern visible from this snippet, but if canonical() involves branching on secret-dependent data, watch for timing side-channel risks. Verify that this operation is constant-time.

Performance:

  • There is no direct concern from this snippet regarding performance improvements, but verify that canonical() does not introduce any unnecessary complexity compared to representative().

Bugs & Errors:

  • Confirm that the change does not inadvertently cause a panic. Ensure that cmp and the subsequent match operation are safe and don't lead to unforeseen unwraps or panics.

Code Simplicity:

  • The change seems to simplify the code by removing redundancy, which is beneficial for clarity. Ensure that canonical() is well-documented for future maintainers to understand its purpose versus representative().

Overall, please verify the canonical() method implementation to ensure it aligns with security and mathematical integrity needs. Once confirmed, it should be fit for merging.

y.value()[1].canonical().cmp(&y_neg.value()[1].canonical()),
) {
(Ordering::Greater, _) | (Ordering::Equal, Ordering::Greater) => {
x_bytes[0] |= 1 << 6; // Prefix: 11
Copy link

Choose a reason for hiding this comment

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

Correctness

  • Ensure that the canonical representation respects the field or curve's expected ordering traits and that it is correctly implemented and tested.
  • Check that the use of canonical in place of representative does not affect any other part of the code relying on specific numerical values.

Security

  • Confirm that any changes do not introduce timing side-channels, especially when handling field elements and comparing them.
  • Use constant-time operations for comparison if canonical involves secret data.
  • Validate that data zeroization is properly handled after it is no longer needed.

Performance

  • Verify whether the switch from representative to canonical adds any unnecessary computational overhead or complexity, potentially affecting performance.

Bugs & Errors

  • Running comprehensive tests is critical to ensuring that the change to canonical does not introduce any off-by-one errors, especially since comparisons are involved.
  • Confirm the absence of memory safety issues related to handling objects using canonical.

Code Simplicity

  • Ensure that switching from representative to canonical improves or maintains code clarity, with well-defined abstractions.
  • Review whether existing documentation needs updates to reflect changes in terminology or implementation due to the introduction of canonical.

Summary

This change requires thorough validation to ensure correctness, as it impacts comparison logic in cryptographic operations. It is crucial to pass all tests before merging this code, especially ones designed to catch edge cases or vulnerabilities related to changes in the comparison logic.

let c_io = c_io.iter().map(|elem| elem.canonical()).collect::<Vec<_>>();

let v_io =
verification_key.g1_vk[0].operate_with(&msm(&c_io, &verification_key.g1_vk[1..]).unwrap());
Copy link

Choose a reason for hiding this comment

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

Correctness

  • Mathematical Operations: Ensure that elem.canonical() correctly transforms elements for the intended operation. If it incorrectly interprets field elements, it could lead to wrong results.
  • Edge Cases: There should be checks or documentation that specifies how edge cases like zero elements (or identity elements) are handled by the canonical() method since it differs from representative().

Security

  • Timing Side-Channels: Ensure canonical() operation is constant-time, especially if used on secret values. The shift from representative() to canonical() may impact side-channel security if not constant-time.

Performance

  • Unnecessary Allocations: Collecting into a Vec might be unnecessary if msm() can process an iterator directly, reducing allocations.
  • FFT and MSM Efficiency: Ensure msm() itself is efficiently implemented (e.g., using Pippenger’s algorithm for MSM if applicable).

Bugs & Errors

  • Potential Panics: The use of unwrap() on the msm() result is risky without ensuring it cannot return an error. Consider handling the error case explicitly.

Code Simplicity

  • No significant issues noted here as long as the change from representative() to canonical() is justified and does not introduce unnecessary complexity. Ensure a consistent abstraction by documenting the difference between the two methods and their usage contexts.

Before merging, ensure these points, especially around correctness and security, are addressed to prevent vulnerabilities or functional issues.

let coeffs: Vec<u32> = c.coefficients().iter().map(|x| x.canonical()).collect();
let is_orig = c == &original_poly;
let is_sage = c == &candidate_poly;
let marker = if is_orig {
Copy link

Choose a reason for hiding this comment

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

Concerns Identified:

Correctness:

  • The changes primarily involve replacing representative() with canonical(). Without further context, it's not clear whether the mathematical correctness of these conversions is maintained. Please ensure that canonical() performs the equivalent operation required for correctness in your particular code context.

Security:

  • Any function that processes data in ways that depend on its value, such as canonical(), must be checked to ensure it does not introduce timing side-channel vulnerabilities.

Performance:

  • map(|x| x.canonical()).collect::<Vec<_>>() is repeated multiple times in the changes. Consider extracting this into a reusable function to reduce redundancy and improve code readability.

Bugs & Errors:

  • Ensure that all uses of canonical() do not result in any unintended consequences, such as panics, due to unexpected input values.

Code Simplicity:

  • The repetition of similar patterns could be improved by more concise abstraction if applicable.

Recommendations:

  • Review and verify the correctness of replacing representative() with canonical() to ensure that it meets the operational requirements of your system.
  • Ensure that all operations involving secrets remain resistant to timing attacks. This might involve ensuring that canonical() operates in constant time.
  • Consider refactoring the repeated pattern to improve maintainability and readability.

Due to these concerns, especially around correctness and potential performance improvements, the current code is not ready for merging.

let coeffs_repr: Vec<_> = coeffs.iter().map(|x| x.canonical()).collect();

let is_original = candidate == &original_poly3;
let marker = if is_original { " <-- ORIGINAL" } else { "" };
Copy link

Choose a reason for hiding this comment

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

Correctness

  • Ensure that changing from representative() to canonical() does not alter the expected output of the modular arithmetic or field operations. Verify that canonical() behaves correctly for edge cases such as zero or identity elements.

Security

  • The code operates on polynomial coefficients but does not clearly indicate if any of these operations might handle secret data. Confirm that the operations involving secrets are constant-time and free of side-channel risks.
  • Ensure any sensitive data, especially if related to cryptographic secrets, is zeroized after use.

Performance

  • The change from representative() to canonical() may impact performance, especially within critical loops. Check if canonical() is optimized for performance and avoids unnecessary allocations.
  • Verify that there are no unnecessary allocations within the .map() and .collect() patterns.

Bugs & Errors

  • There are no obvious panics or unwraps in this snippet, but confirm that any underlying methods like canonical() handle all edge cases without panicking.
  • Be cautious of potential integer overflow/underflow issues in underlying arithmetic operations.

Code Simplicity

  • Transitioning from representative() to canonical() improves code simplicity if canonical() is more intuitive or necessary for the operation context.
  • Consideration of how these changes affect the broader context of the library could identify redundant code or unnecessary complexity elsewhere.

Additional Notes

  • Ensure domain separation in hash functions if any hash function is applied within the library. Although not directly referenced here, it is crucial for security across the library.

coeffs.iter().map(|c| c.canonical()).collect::<Vec<_>>()
);
assert_eq!(coeffs.len(), 4);
assert_eq!(coeffs[0], FE::from(1001u64));
Copy link

Choose a reason for hiding this comment

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

Correctness:

  • The change from c.representative() to c.canonical() in the polynomial coefficients conversion must be verified: ensure canonical() correctly represents the intended form of the coefficients within the field.

Security:

  • No information was provided regarding potential side-channel vulnerabilities or zeroization in the provided snippet; ensure the rest of the module addresses these concerns.

Performance:

  • The change in mapping seems to maintain previous performance; however, verify if canonical() incurs more computational overhead than representative().

Bugs & Errors:

  • Ensure there are no panics or unwraps elsewhere in the code since this snippet does not address these directly.

Code Simplicity:

  • The revised code simplifies the transformation by directly using a map operation, which improves readability and reduces unnecessary intermediate allocations.

Overall, verify the correctness of the canonical() method for the coefficients in the context of the broader code to ensure precision and maintainenance of mathematical properties. Pay particular attention to the broader context for complete assurance against errors and security vulnerabilities.

.operate_with(&public_key.operate_with_self(e.canonical()));

// We want to compute ev = H(rv || M).
let mut hasher = Keccak256::new();
Copy link

Choose a reason for hiding this comment

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

Correctness:

  • Curve Operations: The change from representative() to canonical() is vital to ensure that operations are using canonical representations of field elements. This helps in reducing bugs due to non-canonical forms but ensure that canonical() is implemented correctly to always produce the intended form.

Security:

  • Hash Function Domain Separation: There is no explicit domain separation seen in the hash computations (e.g., the H(r || message)), ensure domain separation constants are used if different contexts use the same hash function.
  • Timing Side-channels: The change to using canonical() could potentially address timing issues if non-canonical forms caused variable execution paths. Confirm that all operations on secrets (such as signing which involves private_key and rand) are constant-time.
  • Secure Randomness: Usage of rand_chacha::ChaCha20Rng::from_entropy() for randomness generation should be reviewed to ensure the entropy source is secure.

Performance:

  • FFT/Polynomial Implementation: Not applicable in the provided diff, ensure such operations avoid unnecessary allocations or operations elsewhere.

Bugs & Errors:

  • Potential Panics: Ensure that functionalities related to field operations and curve points handle edge cases like zero, infinity points, and do not panic.
  • Off-by-One Errors: No clear indication of these in the given snippet but thoroughly verify loops and indices elsewhere in the code for potential issues.

Code Simplicity:

  • Complexity and Abstractions: No major issues observed in the snippet. The canonical() abstraction improves the clarity regarding which form of element is being worked with.

The modifications appear to enhance correctness, but additional scrutiny should be given to the implementation of the canonical() function, ensuring the cryptographic operations remain secure and are executed correctly. Further review of code not in this snippet is recommended, especially regarding domain isolation in hash functions.

@codecov-commenter
Copy link

codecov-commenter commented Feb 3, 2026

Codecov Report

❌ Patch coverage is 85.27132% with 19 lines in your changes missing coverage. Please review.
✅ Project coverage is 71.31%. Comparing base (06425ef) to head (37df92c).

Files with missing lines Patch % Lines
...elds/fft_friendly/u64_mersenne_montgomery_field.rs 0.00% 4 Missing ⚠️
crates/math/src/field/fields/mersenne31/field.rs 72.72% 3 Missing ⚠️
...field/fields/fft_friendly/stark_101_prime_field.rs 50.00% 2 Missing ⚠️
...field/fields/fft_friendly/stark_252_prime_field.rs 60.00% 2 Missing ⚠️
...th/src/field/fields/fft_friendly/u64_goldilocks.rs 50.00% 2 Missing ⚠️
...ates/math/src/field/fields/u64_goldilocks_field.rs 50.00% 2 Missing ⚠️
...th/src/field/fields/u64_goldilocks_hybrid_field.rs 94.73% 1 Missing ⚠️
...rates/math/src/field/test_fields/u32_test_field.rs 0.00% 1 Missing ⚠️
...rates/math/src/field/test_fields/u64_test_field.rs 0.00% 1 Missing ⚠️
...rs/winterfell_adapter/src/field_element/element.rs 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1130      +/-   ##
==========================================
- Coverage   71.33%   71.31%   -0.03%     
==========================================
  Files         166      166              
  Lines       36072    36042      -30     
==========================================
- Hits        25732    25702      -30     
  Misses      10340    10340              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

diegokingston and others added 2 commits February 3, 2026 17:39
Renames the IsPrimeField trait method and associated type to better
reflect their purpose:

- `RepresentativeType` -> `CanonicalType`
- `representative()` -> `canonical()`
- `RepresentativeOutOfRange` -> `CanonicalValueOutOfRange`

This aligns with the Goldilocks field naming convention where
`canonicalize` is used to convert values to their canonical form
in range [0, p-1].

Changes across:
- IsPrimeField trait definition
- All IsPrimeField implementations (Goldilocks, Mersenne31, P448, etc.)
- FieldElement::canonical() method
- All usages in crypto, provers, and examples

Note: winterfell_adapter uses external git dependency that still has
the old API, so it retains the `representative` call.
@jotabulacios jotabulacios force-pushed the refactor/canonical-representative branch from 0356f18 to d86fc67 Compare February 3, 2026 20:40
Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

Code review by ChatGPT

assert_eq!(a.canonical().limbs, limbs);

lambdaworks_vec.push(a);
}
Copy link

Choose a reason for hiding this comment

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

Correctness:

  • Functionality: The change from a.representative().limbs to a.canonical().limbs needs careful consideration. Ensure canonical() performs the expected operation, especially in terms of mathematical correctness. It should truly represent the canonical form of the field element in the given implementation.

Security:

  • Zeroization: Ensure that limbs is properly zeroized if it contains sensitive information once no longer needed. Consider using types that afford automatic zeroization at scope end.

Performance:

  • Efficient Operations: Assess the push operation to ensure it avoids unnecessary allocations. Cache capacity for the vector if possible to reduce reallocations.

Bugs & Errors:

  • Panics: The line assert_eq!() could introduce panics if the condition fails. A thorough examination is necessary to ensure that such asserts do not raise exceptions in a production environment. Opt for error handling where possible.

Code Simplicity:

  • Function Calls: Avoid complex abstractions around canonical() or representative(), and ensure that there is clear documentation on their differences and usage.

This line and its context need further examination and thorough testing for correctness before merging.

@github-actions
Copy link

github-actions bot commented Feb 3, 2026

Kimi AI Review

The PR diff you've provided involves a significant number of changes across various files, primarily replacing the use of representative() with canonical() in the lambdaworks cryptographic library. Here are my specific feedback and concerns:

General Observations

  1. Consistency: The changes are consistent across the board, replacing representative() with canonical(). This suggests a refactoring effort to standardize the API or internal logic of the library.

  2. Documentation: Ensure that the documentation is updated to reflect these changes, especially in places where the behavior or the meaning of certain functions or methods has changed.

Specific Concerns

  1. benches/benches/utils.rs:30:

    • The change from representative() to canonical() might affect performance due to different underlying algorithms or logic. Benchmarks should be updated to reflect any performance changes.
  2. crypto/src/commitments/kzg.rs:156:

    • The change in the IsCommitmentScheme implementation could affect how commitments are computed and verified. Ensure that the security assumptions and properties still hold after this change.
  3. math/src/field/element.rs:632:

    • The new canonical() method should be thoroughly tested to ensure it correctly converts from Montgomery form to the standard form, especially considering edge cases and large numbers.
  4. math/src/field/fields/fft_friendly/stark_252_prime_field.rs:33:

    • The change to canonical() for byte conversion could affect serialization and deserialization processes. Test vectors should be updated to cover these changes.
  5. provers/groth16/src/prover.rs:41:

    • The use of canonical() in the prover's algorithm might affect the generation of proofs. It's crucial to verify that the new method does not introduce any vulnerabilities or inconsistencies in the proof generation process.
  6. provers/plonk/src/constraint_system/types.rs:59:

    • The change in how boolean values are derived could affect the construction of constraint systems. Ensure that the logic remains sound and that no constraints are inadvertently weakened or strengthened.

Recommendations

  • Testing: Extensive testing should be conducted to ensure that the replacement of representative() with canonical() does not introduce any regressions or security vulnerabilities. This includes unit tests, integration tests, and possibly formal verification if applicable.

  • Security Review: Given the nature of cryptographic libraries, a detailed security review should be conducted to ensure that the changes do not compromise the security guarantees of the library.

  • Performance Analysis: Since the replacement might affect performance, a performance analysis should be conducted to understand the implications of these changes, especially in critical sections of the code.

  • Code Simplicity and Maintainability: While the changes seem to be consistent, ensure that the introduction of canonical() does not overly complicate the codebase. Simplicity and maintainability are crucial for long-term sustainability.

Overall, the changes appear to be a significant refactoring effort. It's important to ensure that this refactoring does not introduce any unintended consequences, especially in a cryptographic library where subtle changes can have significant security implications.

@github-actions
Copy link

github-actions bot commented Feb 4, 2026

Kimi AI Review

The diff provided shows a comprehensive renaming of the representative method to canonical across various files in the codebase. This change is consistent and affects multiple modules, including field operations, elliptic curve implementations, and proof systems. Here are some specific comments on the changes:

  1. Renaming Consistency: The renaming from representative to canonical is consistent across all files. This is important for maintaining clarity and consistency in the API.

    • Good: All occurrences of representative have been changed to canonical, which is a more descriptive term for the standard form of a field element.
  2. Documentation Updates: The README files and comments have been updated to reflect the change from representative to canonical. This is crucial for maintaining accurate documentation.

    • Good: Documentation and comments have been updated accordingly, which helps in understanding the purpose of the canonical method.
  3. Error Handling: The error variant RepresentativeOutOfRange has been renamed to CanonicalValueOutOfRange. This change needs to be carefully tested to ensure that all error paths are correctly handled.

    • Good: The error handling has been updated to reflect the new naming convention.
  4. Performance Considerations: The change from representative to canonical should not introduce any performance regressions. The implementation of these methods should remain efficient.

    • Good: No performance regressions are expected from the renaming, as it is a semantic change rather than an algorithmic one.
  5. Cryptographic Security: The use of canonical values is important for ensuring that field elements are correctly reduced and do not leak information through representations. This change does not introduce any new security concerns but reinforces the use of canonical forms.

    • Good: The use of canonical forms is a good practice in cryptographic implementations to avoid representation-based vulnerabilities.
  6. Code Simplicity and Maintainability: The renaming makes the code more readable and maintainable by using a more descriptive term.

    • Good: The code is more readable with the canonical method, which clearly indicates the purpose of converting to a standard form.

Overall, the changes are well-implemented and maintain the integrity and security of the cryptographic library. The renaming is consistent and does not introduce any new issues. The documentation and error handling have been appropriately updated to reflect the changes.

Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

Code review by ChatGPT

.map(|coefficient| coefficient.canonical())
.collect();
msm(
&coefficients,
Copy link

Choose a reason for hiding this comment

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

Correctness:

  • Ensure that replacing coefficient.representative() with coefficient.canonical() provides the correct mathematical behavior expected in this context. Verify that canonical() returns the appropriate reduced form of the field element, especially for edge cases like zero or prime boundaries.

Security:

  • Confirm whether the canonical() method and the MSM operation are implemented in a constant-time manner to prevent timing side-channel attacks, especially since these are basic operations in cryptographic protocols.

Performance:

  • Check if the use of Vec for coefficients introduces any unnecessary allocations, especially if this is used in a performance-critical path. Consider optimizing with iterators or pre-allocating space if possible.

Bugs & Errors:

  • Ensure there are no assumptions that could lead to panics, such as unwrapping optionals or indexing out of bounds in the coefficients vector.

Code Simplicity:

  • Review the abstractions used for the commit function and MSM operation to avoid complexity and duplication, ensuring they're as simple and reusable as possible.

Overall, without further context on other parts of the codebase or tests demonstrating the functionality of the changes, additional verification is required before merging.

Self::as_canonical(a) == Self::as_canonical(b)
}

/// Returns the additive neutral element.
Copy link

Choose a reason for hiding this comment

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

Concerns:

Correctness:

  • The test seems to assume the creation of field elements correctly handles out-of-range values (MERSENNE_31_PRIME_FIELD_ORDER + 1 and MERSENNE_31_PRIME_FIELD_ORDER + 8), but it lacks context on how FE::from(&change) manages wrapping or reduction. Ensure the implementation properly reduces modulo MERSENNE_31_PRIME_FIELD_ORDER.

Security:

  • Timing attacks and side-channel resistance are not directly observable from the test snippet. Ensure that methods like FE::canonical are constant-time for sensitive operations. Verify everywhere constant-time arithmetic is used.

Bugs & Errors:

  • No direct panics or unwraps are noticed here, but the test relies on correct abstract behavior of FE::from and FE::canonical, which is not visible.

Code Simplicity:

  • The simplicity in test names improvement is observed but still ensure meaningful naming represents both the action and expectation clearly.

Recommendations:

To proceed with merging:

  • Verify and demonstrate that field elements are correctly reduced by MERSENNE_31_PRIME_FIELD_ORDER during creation or arithmetic operations.
  • Include tests covering more variations in edge cases such as zero, identity, and MERSENNE_31_PRIME_FIELD_ORDER explicitly to strengthen confidence.
  • Ensure any sensitive calculations remove potential timing discrepancies to maintain security.

@@ -1033,12 +1033,12 @@ mod tests_u256_prime_fields {
Copy link

Choose a reason for hiding this comment

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

Correctness

  • Mathematical Operations: The changes seem focused on renaming functions to use the term canonical instead of representative, which should not affect the underlying mathematical operations if the definitions align.
  • Edge Cases: The tests do not illustrate handling of zero or identity elements explicitly. It is important to consider edge cases like zero elements for modular arithmetic and identity elements for elliptic curve operations.

Security

  • Timing Side-Channels: Ensure that operations involving secrets are constant-time. From the context, there is no specific indication in this diff that the operations are constant-time.
  • Zeroization: There is no visible code handling the zeroization of sensitive data. If not already present elsewhere in the library, this needs to be addressed.
  • Secure Randomness: There is no randomness involved in this particular diff. However, ensure that the rest of the library uses cryptographically secure sources where necessary.

Performance

  • Unnecessary Allocations and Efficiency: There is no indication in this snippet of unnecessary allocations or inefficiencies like redundant field inversions from function renaming itself.

Bugs & Errors

  • Potential Panics: The assert statements used do not cause panics through unwrapping or unsafe operations, but they assume correct environment setup.
  • Integer Overflow/Underflow: Clear checks for overflow/underflow are not visible, but if using safe Rust types, this may inherently be avoided.

Code Simplicity

  • Complex Implementations and Duplicated Code: The renaming does not inherently reduce complexity or duplication but provides more explicit naming which can aid clarity.

Given these observations, I recommend a more extensive functional review to ensure mathematical correctness and security across edge cases not shown here. Additionally, confirm that operations are constant-time, and that any sensitive data is zeroized properly.

type CanonicalType = U448;

fn representative(a: &U56x8) -> U448 {
fn canonical(a: &U56x8) -> U448 {
Copy link

Choose a reason for hiding this comment

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

The code presents a potential issue with handling large integers, especially considering the conversion from U56x8 to a canonical form within P448GoldilocksPrimeField. Ensure that from_hex and the subsequent operations are handling all potential overflows correctly. Verify that U56x8 and U448 conversions do not silently fail or introduce errors in edge cases such as maximum value operations.

  1. Correctness: Verify that the canonical function correctly reduces a large number modulo the prime field order with no overflow errors or incorrect reductions.

  2. Security: The conversion and canonicalization should avoid timing side-channels by ensuring operations like modular reduction are constant-time.

  3. Bugs & Errors: Use proper error handling for the unwrap on line 4 to ensure it does not panic on invalid input. Consider using expect with an informative message or propagate the error upward.

  4. Code Simplicity: Renaming the test function implies a change in semantics. Ensure this new name reflects its purpose accurately and correct behavior is verified for canonicalization use cases.


#[test]
fn creating_a_field_element_from_its_representative_returns_the_same_element_1() {
fn creating_a_field_element_from_its_canonical_returns_the_same_element_1() {
Copy link

Choose a reason for hiding this comment

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

Correctness

  • Field Operations: The test indicates creating a field element from its canonical representative. Ensure that the FE::new implementation correctly reduces elements modulo the field characteristic (i.e., MODULUS), considering edge cases.
  • Edge Cases: It's critical to ensure that the creation of elements handles edge cases like negative inputs.

Security

  • Sensitivity Handling: The code snippet does not demonstrate zeroization or any indication of handling sensitive data. Ensure that FieldElement instances are properly zeroized when no longer needed.

Performance

  • Efficiency: No explicit performance concerns in this test snippet, though it would be beneficial to ensure that FE::new avoids unnecessary computational overhead.

Bugs & Errors

  • Potential Panics: Ensure the canonical method does not result in panics due to invalid inputs or operations like division by zero.
  • Integer Overflows: In the FE::new(MODULUS + change), verify that there is proper handling of integer overflow or consider using Rust's checked arithmetic operations.

Code Simplicity

  • Consistency: The renaming of the test functions (creating_a_field_element_from_its_representative_* to creating_a_field_element_from_its_canonical_*) should be consistently refactored throughout the codebase.
  • Improve Abstraction: If canonical() calls are frequent, consider abstracting such operations to simplify the codebase.

Overall, the current test snippet needs verification for security integrity and proper handling of edge cases to prevent unexpected behavior. Addressing these aspects will improve reliability and safety.

assert_eq!(div.canonical(), expected_div.as_canonical_u32());
}

for n in [&a, &b] {
Copy link

Choose a reason for hiding this comment

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

Correctness:

  • Ensure correct implementation of mathematical operations, particularly for edge cases such as zero, identity elements, and inversion by zero. Verify the changes from 'representative()' to 'canonical()' maintain correctness and do not inadvertently affect behavior.
  • The division assertion assert_eq!(&div * &b, a.clone()) should check for consistency with modular arithmetic constraints (e.g., ensuring division is only performed when the divisor is non-zero and invertible).

Security:

  • Check that use of canonical representations does not lead to timing side-channels, particularly where conversions or representations are involved in operations.
  • Ensure that b.inv().is_ok() accurately detects non-zero elements to prevent division by zero vulnerabilities.

Performance:

  • Verify any performance impact due to changes in representation functions from representative() to canonical(), especially if they cause additional conversions or checks that could be avoided.

Bugs & Errors:

  • Ensure proper handling of possible errors or panics in handling non-invertible element inversions and other operations that may cause panics upon failure of assumption checks (e.g., divisibility checks).
  • Review implications of changed methods for potential off-by-one errors or incorrect assumptions about element structure.

Code Simplicity:

  • Changes from 'representative()' to 'canonical()' might be doing more than just renaming; confirm this change reduces complexity or aligns with naming conventions without introducing added complexity or potential misunderstanding.
  • Inspect if such changes introduce unnecessary complexity or are part of a broader refactor/layer of abstraction that improves the codebase.

assert_eq!(div.canonical(), expected_div.as_canonical_u64());
}

for n in [&a, &b] {
Copy link

Choose a reason for hiding this comment

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

Correctness

  • The changes to .canonical() require verification that this function is correctly implemented for expected field element representation.
  • Ensure proper boundary handling, especially in the division by zero check using value_u64_b != 0. Consider dealing with extremal values explicitly.

Security

  • Examine the pow() function for potential timing side-channels due to input-dependent branching or loop execution differences. Ensure all operations on secret data are constant-time.
  • Ensure that new state canonicalization does not inadvertently expose sensitive data or create side-channels.

Performance

  • Consider optimizing the division operation within a modulo context since the inv().is_ok() check and division operation with &a / &b might involve multiple inversions, which are costly. Investigate if these can be avoided or fused.

Bugs & Errors

  • Guard against panic on integer overflows, especially if as_canonical_u64() conversions involve any unchecked operations. Ensure as_canonical_u64() manages inputs securely under all testable conditions.
  • try_inverse() must be verified to safely handle and not accidentally panic on edge cases where an inverse doesn't exist.

Code Simplicity

  • Review the modified assertions to ensure these operations are atomic and cover the expected set of cases without requiring separate proof verification.

Given these observations, additional scrutiny on the correctness and performance optimization would be prudent before merging these changes.

let pow = &a.pow(b.canonical());
let expected_pow = a_ring.pow(&b_ring.residue());
assert_eq!(&(pow.to_string())[2..], expected_pow.residue().in_radix(16).to_string());

Copy link

Choose a reason for hiding this comment

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

Correctness

  • The change from b.representative() to b.canonical() in the power function call needs verification. Ensure that b.canonical() creates the correct expected value in the finite field operations.

Security

  • Ensure that operations using pow are constant-time if the exponent b.canonical() contains any secret values. The presence of secret-dependent operations could lead to timing side-channel leaks.

Performance

  • There is no evidence of performance degradation in the provided diff. However, ensure that canonical() does not add unnecessary computational overhead compared to representative().

Bugs & Errors

  • Further code review is required to ensure that there are no potential panics or integer overflow/underflow issues that might arise from the change.

Code Simplicity

  • The change appears straightforward and doesn't introduce unnecessary complexity on its own. However, ensure that canonical() and representative() provide clear abstractions and are not redundant.

let pow = &a.pow(b.canonical());
let expected_pow = a_ring.pow(&b_ring.residue());
assert_eq!(&(pow.to_string())[2..], expected_pow.residue().in_radix(16).to_string());

Copy link

Choose a reason for hiding this comment

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

Correctness

  • Mathematical Operations:
    • Changing b.representative() to b.canonical() in the power operation could affect the results if canonical() doesn't correctly align with how other parts of the system interpret field elements. Verify that canonical() ensures it is used consistently wherever pow operations are performed to avoid unexpected results.

Security

  • Timing side-channels:
    • Ensure that operations involving b.canonical() are performed in constant time to prevent timing attacks, particularly if b were secret.

Performance

  • Unnecessary Allocations:
    • Verify if changing to canonical() results in any additional computations or allocations, impacting performance. Ensure that the performance overhead is minimal if canonical() is more computationally intensive.

Bugs & Errors

  • Ensure that canonical() method doesn't introduce new edge cases, such as divisions by zero or invalid state.

Code Simplicity

  • Complex Implementations:
    • Ensure usage of canonical() maintains overall code base simplicity. If canonical() abstracts complex behavior, ensure adequate documentation and comments are present for developers to trace logic easily.

The code change introduces some potential concerns regarding correctness and performance that need further investigation to avoid unexpected behaviors, particularly in cryptographic contexts. Further validation and testing are advised before merging.

let c_hex = c.canonical().to_string()[2..].to_string();

let prime =
UBig::from_str_radix("800000000000011000000000000000000000000000000000000000000000001", 16).unwrap();
Copy link

Choose a reason for hiding this comment

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

Correctness

  • The canonical() method should be reviewed to ensure it provides the correct canonical representation in compliance with the intended cryptographic protocol, replacing representative().

Security

  • Ensure that both from_bytes_be and the to_string method implementations used here are constant-time to mitigate timing-related side-channel attacks, especially since unwrap() indicates a potential error in handling secret data.

Performance

  • The repeated to_string() and slicing operations ([2..]) in the a_hex, b_hex, and c_hex assignments may be optimized. Consider whether the redundant conversion and substring extraction can be minimized.

Bugs & Errors

  • The use of unwrap() on from_bytes_be can lead to panics if the input does not form a valid field element. Consider handling potential errors more gracefully, especially since invalid field elements can emerge from random input.

Code Simplicity

  • The slicing operation [2..] appears several times, which should be abstracted into a function or explained, as the magic number 2 can be unclear to the reader. Also, ensure proper bounds checking on this operation to prevent potential slice panics.

Additional validation on the canonical() method and ensuring error handling for critical operations is suggested before proceeding with the merge.

@diegokingston diegokingston merged commit b8e1aa3 into main Feb 4, 2026
11 of 13 checks passed
@diegokingston diegokingston deleted the refactor/canonical-representative branch February 4, 2026 14:33
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.

3 participants