The ADRS parameter in SLH-DSA and hash functions
Most of the hash functions in SLH-DSA take a 32-byte address (ADRS) value as input. A different ADRS value is used for each call to each function.
For the SHA2 family, the address is compressed to a 22-byte value,
denoted ADRS_c.
Structure
The structure of an ADRS is
+-----------------+
| layer address | 4 bytes
+-----------------+
| |
| tree address | 12 bytes
| |
+-----------------+
| type | 4 bytes
+-----------------+
| word1 | 4 bytes
+-----------------+
| word2 | 4 bytes
+-----------------+
| word2 | 4 bytes
+-----------------+
The values are encoded as unsigned integers in big-endian byte order.
The layer address is the height within the hypertree. Trees at the bottom have a height of zero and the tree at the top has a height of $d-1$. The tree address is the position of the tree within a layer of the hypertree, starting at zero on the left, and extending up to a large value[1] in the order of $2^{63}$ on the right for the bottom tree.
[1] The maximum value of tree address at height zero is $2^{h - h/d} - 1$.
There are 7 ADRS types:
WOTS_HASH = 0 WOTS_PK = 1 TREE = 2 FORS_TREE = 3 FORS_ROOTS = 4 WOTS_PRF = 5 FORS_PRF = 6
The values of the last 3 words word1,
word2, word3 in ADRS depend on the
type, as follows:
--------------------------------------------------------------------------
Type word1 word2 word3 Type constant
-------------------------------------------------------------------------
0 WOTS+ hash addr keypairaddr chainaddr hashaddr WOTS_HASH
1 WOTS+ pub key compr keypairaddr 0 0 WOTS_PK
2 Hash tree addr 0 tree_ht tree_index TREE
3 FORS tree addr keypairaddr tree_ht tree_index FORS_TREE
4 FORS tree roots compr keypairaddr 0 0 FORS_ROOTS
5 WOTS+ key generation keypairaddr chainaddr 0 WOTS_PRF
6 FORS key generation keypairaddr 0 tree_index FORS_PRF
Compression of ADRS for SHA-2
A compressed address (ADRS_c) is a 22-byte string that is the same as an ADRS with the exceptions that the encodings of the layer address and type are reduced to one byte each and the encoding of the tree address is reduced to eight bytes.
+----+
| | layer address 1 byte
+----+------------+
| tree address | 8 bytes
| |
+----+------------+
| | type 1 byte
+----+------------+
+ word1 + 4 bytes
+-----------------+
+ word2 + 4 bytes
+-----------------+
+ word2 + 4 bytes
+-----------------+
Example
32-byte ADRS
layer treeaddr type word1 word2 word3
[4] [12] [4] [4] [4] [4]
00000000 00000000006894ec35fadda8 00000003 0000000d 00000000 00000ca2
This is a type 3 address (FORS_TREE), where word1 (0xd) represents the keypair address, word2 (0x0) is the tree height, and word3 (0xca2) is the tree index.
Compressed to 22-byte ADRS_c
layer treeaddr type word1 word2 word3
[1] [8] [1] [4] [4] [4]
00 006894ec35fadda8 03 0000000d 00000000 00000ca2
Hash functions
There are 6 hash functions used in SHL-DSA.
| Function | Parameters | Used to compute |
|---|---|---|
| PRF_msg | (SK.prf, opt_rand, M) | The randomizer, $R$ |
| H_msg | (R, PK.seed, PK.root, M) | Digest of message to be signed |
| PRF | (PK.seed, SK.seed, ADRS) | Secret values for WOTS+ and FORS private keys |
| T_len | (PK.seed, ADRS, M) | Compression of $l\cdot n$ bytes message to $n$-byte public key |
| H | (PK.seed, ADRS, M) | Node value $H(\mathtt{left} || \mathtt{right})$ in Merkle tree |
| F | (PK.seed, ADRS, M) | (1) $pk=F(sk)$ for WOTS+ and FORS leaf nodes; (2) WOTS+ chain value $F^i(sk)$ |
Note that the functions PRF, T_len, H and F, which use an ADRS parameter, always have a different ADRS parameter each time they are called.
These functions are instantiated differently depending on the hash family. For the SHAKE family, they use SHAKE256. For the SHA2 family, the functions use either SHA-256 or SHA-512 and their corresponding MGF1 and HMAC functions depending on the security level.
For more details, see sections 11.1 and 11.2 of FIPS.205
Quirks when using SHA-256
- The
ADRSparameter is compressed from 32 bytes to 22 to reduce the number of calls to the SHA256 block algorithm. -
Extra zero-byte padding is added to
PK.seedwhen it is the first parameter. This padding makes the first input to the SHA-256 algorithm an exact block length of 64 bytes, so it can be pre-computed and then called repeatedly.-
BlockPad(PK.seed) = PK.seed || toByte(0, 64 − n) = 'FA495FB834DEFEA7CC96A81309479135' + '000000000000000000000000000000000000000000000000' + '000000000000000000000000000000000000000000000000'
-
- If an output length $n \lt 32$ bytes is required, just truncate to the first $n$ bytes.
| << previous: SLH-DSA Introduction | Contents | next: Computing the FORS signature >> |
Rate this page
Contact us
To comment on this page or to contact us, please send us a message.
This page first published 16 February 2026. Last updated 16 February 2026.

