Skip to content

fix: use WASM Montgomery constants in coset_generator()#22486

Open
ElusAegis wants to merge 1 commit intoAztecProtocol:nextfrom
ElusAegis:fix/coset-generator-wasm-constants
Open

fix: use WASM Montgomery constants in coset_generator()#22486
ElusAegis wants to merge 1 commit intoAztecProtocol:nextfrom
ElusAegis:fix/coset-generator-wasm-constants

Conversation

@ElusAegis
Copy link
Copy Markdown
Contributor

@ElusAegis ElusAegis commented Apr 11, 2026

Summary

coset_generator() in field_declarations.hpp has a preprocessor split for native vs WASM Montgomery form, but both branches use the native constants (Params::coset_generator_0..3). The WASM branch should use Params::coset_generator_wasm_0..3, matching the pattern used by every other constant accessor (cube_root_of_unity, get_root_of_unity, r_squared_uint).

This is a copy-paste oversight — the _wasm constants exist in all field parameter files and were correctly computed for the WASM Montgomery basis (R=2^261 vs native R=2^256).

The bug, numerically

The coset generator is the field element g = 5. Its Montgomery encodings are:

Basis Encoding (g * R mod p)
Native (R=2^256) 0x463456c8...8fffffe7
WASM (R=2^261) 0x1484c05b...dffffcb2

Before this fix, the WASM branch returned the native encoding. Interpreting native constants under the WASM basis gives field element 0x28d4a230...d2800001 (≈1.8×10^76) instead of 5. The error is exactly R_native / R_wasm mod p — a silent, mathematically consistent wrong value that would produce invalid proofs.

Why it hasn't been noticed

  1. constexpr evaluation uses host arithmetic. The primary consumer — tonelli_shanks_sqrt — evaluates coset_generator().pow(Q) at compile time. Clang's constexpr evaluator runs host-native code even when cross-compiling to WASM, so #if defined(__SIZEOF_INT128__) takes the native (correct) path. The buggy WASM branch is never exercised at compile time.

  2. Honk doesn't use EvaluationDomain. The modern proving system doesn't touch coset generators at runtime. The only runtime call site is in evaluation_domain.cpp, which is legacy Plonk polynomial arithmetic.

  3. Tests run natively. Field tests for coset_generator() always take the native branch on the host machine.

Risk and relevance

If EvaluationDomain is ever exercised in a WASM build (e.g., client-side Plonk proving), coset FFTs would produce silently wrong results due to incorrect Montgomery encoding. The bug is also fragile — a compiler change to constexpr evaluation behavior could expose it.

Practically, this is low-risk today since Honk has replaced Plonk. But it's the sole remaining inconsistency in constant dispatch and should be fixed for correctness.

Changes

  • Fix (4 lines): replace Params::coset_generator_0..3 with Params::coset_generator_wasm_0..3 in the #else branch of coset_generator()
  • Test: add CosetGeneratorUsesCorrectConstants to field_params_constants.test.cpp — verifies coset_generator() returns values matching the expected platform constants. Would have caught this on any WASM test run.

The WASM branch of coset_generator() was using native Montgomery form
constants (R=2^256) instead of the WASM-specific constants (R=2^261).
Every other constant accessor (cube_root_of_unity, get_root_of_unity,
r_squared) correctly dispatches to Params::*_wasm_* variants — this
was a copy-paste oversight.

On WASM, coset_generator() returned field element 0x28d4a230...d2800001
instead of the correct value (5 for BN254 Fr). Added
CosetGeneratorUsesCorrectConstants test that independently derives the
expected value and catches this on any WASM test run.
@ElusAegis ElusAegis force-pushed the fix/coset-generator-wasm-constants branch from bb7197a to b3a58e1 Compare April 11, 2026 12:37
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.

1 participant