Skip to content

FIPS 205 map

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.

Section to file

FIPS 205 §3    — Notation and conventions       src/util.zig
FIPS 205 §4.2  — ADRS type values               src/address.zig
FIPS 205 §4.3  — ADRS structure                 src/address.zig
FIPS 205 §5    — WOTS+                          src/wots.zig
FIPS 205 §6    — XMSS                           src/xmss.zig
FIPS 205 §7    — Hypertree                      src/hypertree.zig
FIPS 205 §8    — FORS                           src/fors.zig
FIPS 205 §9    — SLH-DSA (internal interface)   src/slh_dsa.zig
FIPS 205 §10   — SLH-DSA (external interface)   src/slh_dsa.zig
FIPS 205 §11   — Parameter sets                 src/params.zig
FIPS 205 §11.1 — Hash functions (SHAKE)         src/hash_shake.zig
FIPS 205 §11.2 — Hash functions (SHA-2)         src/hash_sha2.zig

Algorithm to function

Supporting functions — §3

Alg § Name Implementation
1 3.2 gen_len2 Params.len_2()src/params.zig
2 3.1 toInt util.toInt
3 3.1 toByte util.toByte
4 3.1 base_2b util.base_2b

WOTS+ — §5

Alg § Name Implementation
5 5 chain Wots(p).chainnotes
6 5.1 wots_pkGen Wots(p).pkGen
7 5.2 wots_sign Wots(p).sign
8 5.3 wots_pkFromSig Wots(p).pkFromSig

XMSS — §6

Alg § Name Implementation
9 6.1 xmss_node Xmss(p).nodenotes
10 6.2 xmss_sign Xmss(p).sign
11 6.3 xmss_pkFromSig Xmss(p).pkFromSig

Hypertree — §7

Alg § Name Implementation
12 7.1 ht_sign Hypertree(p).sign
13 7.2 ht_verify Hypertree(p).verify

FORS — §8

Alg § Name Implementation
14 8.1 fors_skGen Fors(p).skGen
15 8.2 fors_node Fors(p).node
16 8.3 fors_sign Fors(p).sign
17 8.4 fors_pkFromSig Fors(p).pkFromSig

Internal interface — §9

Alg § Name Implementation
18 9.1 slh_keygen_internal KeyPair.fromSeeds
19 9.2 slh_sign_internal signInternalsignCore
20 9.3 slh_verify_internal verifyInternalverifyCore

External interface — §10

Alg § Name Implementation
21 10.1 slh_keygen() KeyPair.generate
22 10.2.1 slh_sign signWithContext (and sign, ctx = "")
23 10.2.2 hash_slh_sign(M, ctx, PH, SK) signPreHash
24 10.3 slh_verify verifyWithContext (and verify, ctx = "")
25 10.3 hash_slh_verify(M, SIG, ctx, PH, PK) verifyPreHash

PH selects the pre-hash function (slh_dsa.PreHash); 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.

Pre-hash functions — §10.2.2

FIPS 205 writes out the OIDs for four functions and leaves case … ▷ other approved hash functions or XOFs open. The twelve below are those the NIST ACVP vectors exercise; all share the DER prefix 06 09 60 86 48 01 65 03 04 02 (the nistAlgorithms.hashAlgs arc 2.16.840.1.101.3.4.2) and differ in the final byte.

PreHash ACVP hashAlg Arc PH_M bytes In FIPS 205?
.sha2_224 SHA2-224 4 28
.sha2_256 SHA2-256 1 32 ✅ verbatim
.sha2_384 SHA2-384 2 48
.sha2_512 SHA2-512 3 64 ✅ verbatim
.sha2_512_224 SHA2-512/224 5 28
.sha2_512_256 SHA2-512/256 6 32
.sha3_224 SHA3-224 7 28
.sha3_256 SHA3-256 8 32
.sha3_384 SHA3-384 9 48
.sha3_512 SHA3-512 10 64
.shake_128 SHAKE-128 11 32 ✅ verbatim
.shake_256 SHAKE-256 12 64 ✅ verbatim

The two XOF lengths are fixed by FIPS 205 — SHAKE128(M, 256) and SHAKE256(M, 512) — rather than by the primitive, so src/prehash.zig declares them from the standard and asserts at compile time that they still agree with the std defaults.

There is deliberately no fromOid()

PreHash.oid() has no inverse, and the omission is a decision rather than a gap (issue #63).

In this library the OID is only ever an output: the signer builds it into M' and the verifier rebuilds it. Nothing hands one in. And the bare NIST hash OID is not a wire field either — RFC 9909 assigns a combined algorithm identifier per parameter set × pure/pre-hash × hash, so an X.509 or CMS consumer maps a single OID to a (ParamSet, PreHash) pair in one step and never sees 2.16.840.1.101.3.4.2.x on its own.

If you do need a reverse mapping, the table above is the whole of it — twelve rows, keyed off whatever your protocol actually gives you.

The six hash functions — §11

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.

Full detail: the hash interface.

ADRS types — §4.2 Table 1

Value Name Used for
0 WOTS_HASH A step within a WOTS+ chain
1 WOTS_PK Compressing a WOTS+ public key into a leaf
2 TREE An internal XMSS node
3 FORS_TREE A FORS tree node
4 FORS_ROOTS Compressing the k FORS roots
5 WOTS_PRF Deriving a WOTS+ secret
6 FORS_PRF Deriving a FORS secret

src/address.zig as AdrsType. Note the separate _PRF types for deriving a secret versus using it — see ADRS.

Not implemented

Feature Status
Runtime parameter-set dispatch Deliberate non-goal
SIMD / vectorised Keccak Deliberate non-goal; the bench gate is pinned to PQClean clean accordingly