@@ -328,6 +328,46 @@ TYPED_TEST_P(FieldConstantsTest, CosetGeneratorConsistency)
328328 EXPECT_EQ (expected, static_cast <uint512_t >(coset_generator_wasm));
329329}
330330
331+ // Verify coset_generator() returns the correct field element by independently computing
332+ // Montgomery form from the raw integer value using platform-specific field arithmetic.
333+ // Before the fix, the WASM branch of coset_generator() used native Montgomery constants
334+ // (R=2^256) instead of WASM constants (R=2^261). On WASM, Fr(5) computes the WASM-Montgomery
335+ // encoding via self_to_montgomery_form(), while the buggy coset_generator() returned the
336+ // native encoding — a completely different field element.
337+ TYPED_TEST_P (FieldConstantsTest, CosetGeneratorUsesCorrectConstants)
338+ {
339+ using Params = typename TypeParam::Params;
340+ using Field = typename TypeParam::Field;
341+ Field coset_gen = Field::coset_generator ();
342+
343+ // Recover the raw (non-Montgomery) integer value from the known-correct native constants.
344+ // native_encoding = g * R_native mod p, so g = native_encoding * R_native^{-1} mod p.
345+ // We compute this via uint512 arithmetic (independent of platform Montgomery machinery).
346+ uint256_t mod{ Params::modulus_0, Params::modulus_1, Params::modulus_2, Params::modulus_3 };
347+ uint256_t native_encoding{
348+ Params::coset_generator_0, Params::coset_generator_1, Params::coset_generator_2, Params::coset_generator_3
349+ };
350+
351+ // R_native = 2^256. Compute R_native^{-1} mod p via Fermat's little theorem: R^{-1} = R^{p-2} mod p.
352+ // But for a simpler approach: native_encoding IS g*R mod p, and Field(uint256_t) does self_to_montgomery_form()
353+ // which computes input * R mod p. So if we can extract g first, Field(g) gives us the correct platform encoding.
354+ //
355+ // Approach: use the known relationship wasm = native * 32 mod p (since R_wasm/R_native = 2^5).
356+ // On WASM: coset_generator() should return native * 32 mod p as its internal representation.
357+ // On native: coset_generator() should return native directly.
358+ uint512_t expected_wasm_encoding = (uint512_t (native_encoding) * 32 ) % mod;
359+ #if defined(__SIZEOF_INT128__) && !defined(__wasm__)
360+ Field expected (
361+ Params::coset_generator_0, Params::coset_generator_1, Params::coset_generator_2, Params::coset_generator_3);
362+ #else
363+ Field expected (static_cast <uint64_t >(expected_wasm_encoding.lo .data [0 ]),
364+ static_cast <uint64_t >(expected_wasm_encoding.lo .data [1 ]),
365+ static_cast <uint64_t >(expected_wasm_encoding.lo .data [2 ]),
366+ static_cast <uint64_t >(expected_wasm_encoding.lo .data [3 ]));
367+ #endif
368+ EXPECT_EQ (coset_gen, expected);
369+ }
370+
331371REGISTER_TYPED_TEST_SUITE_P (FieldConstantsTest,
332372 Modulus,
333373 RSquared,
@@ -341,7 +381,8 @@ REGISTER_TYPED_TEST_SUITE_P(FieldConstantsTest,
341381 WasmPowMinus29,
342382 WasmCubeRootConsistency,
343383 WasmPrimitiveRootConsistency,
344- CosetGeneratorConsistency);
384+ CosetGeneratorConsistency,
385+ CosetGeneratorUsesCorrectConstants);
345386
346387using FieldTestTypes = ::testing::Types<Bn254FqTestConfig,
347388 Bn254FrTestConfig,
@@ -351,3 +392,16 @@ using FieldTestTypes = ::testing::Types<Bn254FqTestConfig,
351392 Secp256r1FrTestConfig>;
352393
353394INSTANTIATE_TYPED_TEST_SUITE_P (AllFields, FieldConstantsTest, FieldTestTypes);
395+
396+ // BN254 Fr-specific test: the coset generator is the field element 5.
397+ // Fr(5) independently computes 5 → Montgomery form using the platform's arithmetic.
398+ // coset_generator() returns a precomputed Montgomery encoding.
399+ // If the precomputed encoding is for the wrong platform, these will differ.
400+ // Before the fix on WASM: Fr(5) = 5*R_wasm mod p, but coset_generator() = 5*R_native mod p → mismatch.
401+ TEST (CosetGeneratorBn254, CosetGeneratorMatchesFieldElement)
402+ {
403+ bb::fr coset_gen = bb::fr::coset_generator ();
404+ bb::fr expected (5 );
405+ EXPECT_EQ (coset_gen, expected) << " coset_generator() does not equal Fr(5) — "
406+ " likely using wrong Montgomery basis constants" ;
407+ }
0 commit comments