SphincsStandardVerifier
src/Verifiers/SphincsStandardVerifier.sol is the verifier behind the SPHINCS-only account. Like the other two verifiers it is stateless and pure, deployed once and shared. It exposes the same ISphincsVerifier.verify interface as the backup verifier but implements a different, standard parameter set: plain FORS under plain WOTS+, with no +C tricks on either layer.
Interface
uint256 constant SPHINCS_STANDARD_SIG_LEN = 6176;
function verify(bytes32 pkSeed, bytes32 pkRoot, bytes32 message, bytes calldata sig)
external pure returns (bool valid);Same contract as the backup verifier: reverts Invalid sig length on any length other than 6,176 and Invalid public key on a non-canonical key (low 128 bits nonzero); returns false for any well-formed but invalid signature. SphincsAccount checks the length before calling and rejects non-canonical keys at initialize, so in the account path it always returns a boolean.
Parameters
| Parameter | Value | Notes |
|---|---|---|
n | 16 bytes | 128-bit, Keccak-256 |
h / d | 20 / 5 | five XMSS layers of height 4 |
k / a | 19 / 9 | all 19 trees opened, each with a full 9-node auth path |
w / l | 16 / 35 | 32 message chains + 3 checksum chains (log w = 4) |
| signature | 6,176 bytes | |
| verify gas | not yet measured for this profile | |
| budget | ~10^6 signatures | 2^20 FORS instances |
What differs from the backup verifier
SphincsVerifier (backup) | SphincsStandardVerifier | |
|---|---|---|
| FORS layer | FORS+C: last tree's index forced to zero by grinding R, its auth path omitted | standard: every index used as drawn from the digest, including the last at bits [162, 171) |
| WOTS layer | WOTS+C: 43 chains, per-layer 4-byte counter ground until digits sum to 208 | standard WOTS+: 32 message chains plus a 3-digit base-16 checksum csum = 480 − digitSum |
| Signer work | grinding on both layers | none; a standard SLH-DSA-style signer with Keccak swapped in |
| Signature | 3,688 B | 6,176 B |
| Gas | ~105k | not yet measured |
Forgery resistance in the WOTS layer comes from the checksum: raising any message digit lowers csum, and a lower csum cannot be signed because some checksum chain would have to be walked backwards.
Layout
R (16)
‖ 19 FORS secrets (19 × 16 = 304)
‖ 19 FORS auth paths (19 × 9 × 16 = 2,736)
‖ 5 × [ 35 WOTS chains (35 × 16 = 560) ‖ subtree auth path (4 × 16 = 64) ] (5 × 624 = 3,120)
= 6,176 bytesHmsg is the same 160-byte keccak256(pkSeed ‖ pkRoot ‖ R ‖ message ‖ 0xFF…FF) as the backup verifier. The hypertree index is (digest >> 171) & 0xFFFFF (k · a = 171, 2^h − 1). ADRS is the FIPS 205 §4.2 uncompressed layout shared by all three NiceTry verifiers.
Tests
test/SphincsStandardVerifier.t.sol checks the length arithmetic (including that the blob is exactly one FORS auth path longer than a FORS+C equivalent), that 3 checksum digits suffice, that the 6,176 class is disjoint from every other length in the repo, the two revert guards, and a fuzz test that random input returns false. A positive test will be added once scripts/sphincs_reference.py can drive a signer for this parameter set.