Summary
FORS_C_MAX_GRIND_COUNTER and WOTS_C_MAX_GRIND_COUNTER are both fixed at 1 << 24, independent of profile. At the 128s profiles the FORS-C tree height is a = 24, so forcing the last FORS tree index to zero succeeds with per-counter probability 2^-24 — equal to the grind budget. The chance that all 2^24 counters miss is (1 − 2^-24)^(2^24) ≈ e^-1 ≈ 37%. About 37% of 128s stateless signing attempts fail outright, and because the FORS-C randomizer is a fixed function of (key, message), a message that fails will fail on every retry.
Detail
FORS_C_MAX_GRIND_COUNTER = 1 << 24 and WOTS_C_MAX_GRIND_COUNTER = 1 << 24, independent of profile — src/shrincs/signers/utils.rs:37-38.
- 128s profiles use FORS
a = 24. The 256s profiles use a = 14, where the expected grind of 2^14 sits far below the 2^24 budget, so 256s is unaffected (P(fail) ≈ e^-1024).
- The randomizer is
hash(prf_seed, message) — src/shrincs/signers/fors_c.rs:56 — so retrying the same (key, message) draws the same value and cannot help.
- The failure surfaces as a generic error (
ERR_SIGNING_FAILED in the wasm layer, wasm/mod.rs:250-256), indistinguishable from other errors.
Impact on the recovery path
The stateless path's only sanctioned use in the hybrid spec is rotation and recovery, and a rotation authorization signs a fixed rotation hash. About 37% of 128s rotations and recoveries are unsignable, with no retry short of regenerating the whole next key bundle to change the hash. The failure falls on the safety-critical escape path, not on convenience signing.
Fix
Raise the FORS-C grind-counter bound above the expected work for the 128s profiles — profile-dependent, comfortably above 2^a — so the miss probability drops to negligible. Separately, surface a grind miss as a distinct, non-retryable typed outcome rather than the generic transient error, so callers do not loop on the messages that deterministically fail.
Found during the SHRINCS-hybrid spec review (companion to hybrid signature spec v2.0, sections 3, 8.1, and 14).
Summary
FORS_C_MAX_GRIND_COUNTERandWOTS_C_MAX_GRIND_COUNTERare both fixed at1 << 24, independent of profile. At the 128s profiles the FORS-C tree height isa = 24, so forcing the last FORS tree index to zero succeeds with per-counter probability2^-24— equal to the grind budget. The chance that all2^24counters miss is(1 − 2^-24)^(2^24) ≈ e^-1 ≈ 37%. About 37% of 128s stateless signing attempts fail outright, and because the FORS-C randomizer is a fixed function of(key, message), a message that fails will fail on every retry.Detail
FORS_C_MAX_GRIND_COUNTER = 1 << 24andWOTS_C_MAX_GRIND_COUNTER = 1 << 24, independent of profile —src/shrincs/signers/utils.rs:37-38.a = 24. The 256s profiles usea = 14, where the expected grind of2^14sits far below the2^24budget, so 256s is unaffected (P(fail) ≈ e^-1024).hash(prf_seed, message)—src/shrincs/signers/fors_c.rs:56— so retrying the same(key, message)draws the same value and cannot help.ERR_SIGNING_FAILEDin the wasm layer,wasm/mod.rs:250-256), indistinguishable from other errors.Impact on the recovery path
The stateless path's only sanctioned use in the hybrid spec is rotation and recovery, and a rotation authorization signs a fixed rotation hash. About 37% of 128s rotations and recoveries are unsignable, with no retry short of regenerating the whole next key bundle to change the hash. The failure falls on the safety-critical escape path, not on convenience signing.
Fix
Raise the FORS-C grind-counter bound above the expected work for the 128s profiles — profile-dependent, comfortably above
2^a— so the miss probability drops to negligible. Separately, surface a grind miss as a distinct, non-retryable typed outcome rather than the generic transient error, so callers do not loop on the messages that deterministically fail.Found during the SHRINCS-hybrid spec review (companion to hybrid signature spec v2.0, sections 3, 8.1, and 14).