Every algorithm in the standard, and where it lives.
Verify numbers against the final PDF
The final FIPS 205 (August 2024) inserted gen_len2 as Algorithm 1 (§3.2),
which was absent from the initial public draft. Every later algorithm number
shifted up by one, and the WOTS+ subsections were renumbered
(chain → §5, wots_pkGen → §5.1, wots_sign → §5.2,
wots_pkFromSig → §5.3).
Any algorithm number from a draft-era paper, blog post, or pre-2024 codebase is
very likely one too low. This project tracks the full draft→final mapping in
issue #16.
The two deferred entries carry their full signatures because that is the shape a
future implementation has to match: PH selects the pre-hash function, and its
identity is bound into the signature via an OID alongside the 0x01 domain
separator. Note slh_keygen() takes no arguments — it draws its three seeds from
an approved RBG internally, which is why this library's deterministic entry point
is the §9.1 KeyPair.fromSeeds rather than a variant of this one.
Dispatched by Hash(p) in src/hash.zig; implemented in hash_shake.zig (§11.1)
and hash_sha2.zig (§11.2).
Function
Signature
SHAKE (§11.1)
SHA-2 (§11.2)
PRF
(sk_seed, pk_seed, ADRS) → n
SHAKE256 absorb/squeeze
keyed SHA-2 with block padding
PRF_msg
(sk_prf, opt_rand, M') → n
SHAKE256
HMAC-SHA-256/512
H_msg
(R, pk_seed, pk_root, M') → m
SHAKE256, squeeze m
MGF1 over SHA-256/512
F
(pk_seed, ADRS, 1 block) → n
SHAKE256
SHA-256 at every level
H
(pk_seed, ADRS, l, r) → n
SHAKE256
SHA-256/512
T_l
(pk_seed, ADRS, l blocks) → n
SHAKE256
SHA-256/512
Two asymmetries worth re-reading:
SHAKE uses SHAKE-256 at every security level. There is no SHAKE-128 variant;
n changes only the squeeze length.
SHA-2 keeps F on SHA-256 at every level, while the message functions move to
SHA-512 for n = 24, 32. F is the most-invoked function in the scheme, so this
is a deliberate performance choice. Implementing it as SHA-512 fails every
category-⅗ vector.