Skip to main content

quantica/slh_dsa/
params.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2026 Cédric Mesnil <cslashm@pm.me>
3
4//! SLH-DSA parameter sets (FIPS 205, Section 11).
5//!
6//! This module defines the [`Params`] trait and the twelve FIPS 205
7//! parameter set structs — six SHAKE (§11.1) and six SHA-2 (§11.2). All
8//! parameter sets use Winternitz parameter `w = 16` (`lg_w = 4`).
9//!
10//! Each parameter set is identified by its hash family (SHAKE / SHA2),
11//! security level (128, 192, or 256 bits) and a size/speed trade-off
12//! suffix: "s" (small signatures) or "f" (fast signing/verification).
13
14use super::hash::{ShakeFamily, TweakableHash};
15use super::hash_sha2::Sha2Family;
16
17/// Trait defining all compile-time parameters for an SLH-DSA instance.
18///
19/// Implementors of this trait represent a specific FIPS 205 parameter set (e.g.,
20/// SLH-DSA-SHAKE-128f). The constants fully determine key sizes, signature sizes,
21/// tree structures, and hash output lengths; the `Hash` associated
22/// type selects the tweakable-hash instantiation (SHAKE or SHA-2).
23///
24/// See FIPS 205, Table 2 for the complete list of parameter values.
25pub trait Params: Clone + Default {
26    /// Tweakable-hash family for this parameter set: `ShakeFamily`
27    /// (FIPS 205 §11.1) or `Sha2Family` (§11.2).
28    type Hash: TweakableHash;
29
30    /// Security parameter `n`: hash output length in bytes.
31    ///
32    /// This is the fundamental security parameter. All hash outputs, secret values,
33    /// and tree nodes are `n` bytes long.
34    const N: usize;
35    /// Total hypertree height: `h = d * h'`.
36    ///
37    /// Determines the total number of FORS key pairs the scheme can use: `2^h`.
38    const H: usize;
39    /// Number of layers `d` in the hypertree.
40    ///
41    /// The hypertree consists of `d` stacked XMSS trees, each of height `h'`.
42    const D: usize;
43    /// Height `h'` of each individual XMSS tree within the hypertree.
44    ///
45    /// Each XMSS tree authenticates `2^h'` keys in the layer below it.
46    const H_PRIME: usize;
47    /// Height `a` of each FORS tree (each tree has `2^a` leaves).
48    const A: usize;
49    /// Number `k` of FORS trees used per signature.
50    const K: usize;
51    /// Winternitz parameter `lg(w)`, always 4 for the FIPS 205 parameter sets.
52    const LG_W: usize = 4;
53    /// Winternitz parameter `w = 2^lg_w = 16`.
54    ///
55    /// Controls the time/size trade-off in WOTS+ chains: each chain has `w - 1` steps.
56    const W: usize = 16;
57    /// Message digest length `m` in bytes, output by `H_msg`.
58    ///
59    /// The digest is split into FORS indices, a tree index, and a leaf index.
60    const M: usize;
61
62    // Derived WOTS+ constants
63    /// WOTS+ parameter `len1 = ceil(8*n / lg_w) = 2*n` (since `lg_w = 4`).
64    ///
65    /// Number of base-`w` digits needed to represent an `n`-byte message.
66    const LEN1: usize = 2 * Self::N;
67    /// WOTS+ parameter `len2 = 3` for all FIPS 205 parameter sets.
68    ///
69    /// Number of base-`w` digits in the checksum.
70    const LEN2: usize = 3;
71    /// WOTS+ parameter `len = len1 + len2`: total number of hash chains.
72    const LEN: usize = Self::LEN1 + Self::LEN2;
73
74    // Key and signature sizes
75    /// Public key size in bytes: `2*n` (PK.seed || PK.root).
76    const PK_LEN: usize = 2 * Self::N;
77    /// Secret key size in bytes: `4*n` (SK.seed || SK.prf || PK.seed || PK.root).
78    const SK_LEN: usize = 4 * Self::N;
79
80    /// Human-readable name of this parameter set (e.g., `"SLH-DSA-SHAKE-128f"`).
81    const NAME: &'static str;
82}
83
84/// Compute the total SLH-DSA signature length in bytes for parameter set `P`.
85///
86/// The signature layout is `R || SIG_FORS || SIG_HT`, with total size:
87/// `n + k*(1+a)*n + (h + d*len)*n`.
88///
89/// This is a runtime function rather than a `const` due to Rust const-generics limitations.
90pub fn sig_len<P: Params>() -> usize {
91    // R || SIG_FORS || SIG_HT
92    // n + k*(1+a)*n + (h + d*len)*n
93    P::N + P::K * (1 + P::A) * P::N + (P::H + P::D * P::LEN) * P::N
94}
95
96// ============================================================
97// SHAKE parameter sets (FIPS 205 §11.1)
98// ============================================================
99
100/// SLH-DSA-SHAKE-128s parameter set (NIST security level 1, small signatures).
101///
102/// Provides 128-bit security with relatively compact signatures (~7856 bytes) but
103/// slower signing and verification compared to [`Shake128f`].
104#[derive(Clone, Default)]
105pub struct Shake128s;
106
107impl Params for Shake128s {
108    type Hash = ShakeFamily;
109    const N: usize = 16;
110    const H: usize = 63;
111    const D: usize = 7;
112    const H_PRIME: usize = 9;
113    const A: usize = 12;
114    const K: usize = 14;
115    const M: usize = 30;
116    const NAME: &'static str = "SLH-DSA-SHAKE-128s";
117}
118
119/// SLH-DSA-SHAKE-128f parameter set (NIST security level 1, fast operations).
120///
121/// Provides 128-bit security with faster signing and verification but larger
122/// signatures (~17088 bytes) compared to [`Shake128s`].
123#[derive(Clone, Default)]
124pub struct Shake128f;
125
126impl Params for Shake128f {
127    type Hash = ShakeFamily;
128    const N: usize = 16;
129    const H: usize = 66;
130    const D: usize = 22;
131    const H_PRIME: usize = 3;
132    const A: usize = 6;
133    const K: usize = 33;
134    const M: usize = 34;
135    const NAME: &'static str = "SLH-DSA-SHAKE-128f";
136}
137
138/// SLH-DSA-SHAKE-192s parameter set (NIST security level 3, small signatures).
139#[derive(Clone, Default)]
140pub struct Shake192s;
141
142impl Params for Shake192s {
143    type Hash = ShakeFamily;
144    const N: usize = 24;
145    const H: usize = 63;
146    const D: usize = 7;
147    const H_PRIME: usize = 9;
148    const A: usize = 14;
149    const K: usize = 17;
150    const M: usize = 39;
151    const NAME: &'static str = "SLH-DSA-SHAKE-192s";
152}
153
154/// SLH-DSA-SHAKE-192f parameter set (NIST security level 3, fast operations).
155#[derive(Clone, Default)]
156pub struct Shake192f;
157
158impl Params for Shake192f {
159    type Hash = ShakeFamily;
160    const N: usize = 24;
161    const H: usize = 66;
162    const D: usize = 22;
163    const H_PRIME: usize = 3;
164    const A: usize = 8;
165    const K: usize = 33;
166    const M: usize = 42;
167    const NAME: &'static str = "SLH-DSA-SHAKE-192f";
168}
169
170/// SLH-DSA-SHAKE-256s parameter set (NIST security level 5, small signatures).
171#[derive(Clone, Default)]
172pub struct Shake256s;
173
174impl Params for Shake256s {
175    type Hash = ShakeFamily;
176    const N: usize = 32;
177    const H: usize = 64;
178    const D: usize = 8;
179    const H_PRIME: usize = 8;
180    const A: usize = 14;
181    const K: usize = 22;
182    const M: usize = 47;
183    const NAME: &'static str = "SLH-DSA-SHAKE-256s";
184}
185
186/// SLH-DSA-SHAKE-256f parameter set (NIST security level 5, fast operations).
187#[derive(Clone, Default)]
188pub struct Shake256f;
189
190impl Params for Shake256f {
191    type Hash = ShakeFamily;
192    const N: usize = 32;
193    const H: usize = 68;
194    const D: usize = 17;
195    const H_PRIME: usize = 4;
196    const A: usize = 9;
197    const K: usize = 35;
198    const M: usize = 49;
199    const NAME: &'static str = "SLH-DSA-SHAKE-256f";
200}
201
202// ============================================================
203// SHA-2 parameter sets (FIPS 205 §11.2)
204//
205// Structural constants (n, h, d, h', a, k, m) are identical to the
206// same-category SHAKE sets (FIPS 205 Table 2); only the hash family and
207// the name differ.
208// ============================================================
209
210/// SLH-DSA-SHA2-128s parameter set (NIST security level 1, small signatures).
211#[derive(Clone, Default)]
212pub struct Sha2_128s;
213
214impl Params for Sha2_128s {
215    type Hash = Sha2Family;
216    const N: usize = 16;
217    const H: usize = 63;
218    const D: usize = 7;
219    const H_PRIME: usize = 9;
220    const A: usize = 12;
221    const K: usize = 14;
222    const M: usize = 30;
223    const NAME: &'static str = "SLH-DSA-SHA2-128s";
224}
225
226/// SLH-DSA-SHA2-128f parameter set (NIST security level 1, fast operations).
227#[derive(Clone, Default)]
228pub struct Sha2_128f;
229
230impl Params for Sha2_128f {
231    type Hash = Sha2Family;
232    const N: usize = 16;
233    const H: usize = 66;
234    const D: usize = 22;
235    const H_PRIME: usize = 3;
236    const A: usize = 6;
237    const K: usize = 33;
238    const M: usize = 34;
239    const NAME: &'static str = "SLH-DSA-SHA2-128f";
240}
241
242/// SLH-DSA-SHA2-192s parameter set (NIST security level 3, small signatures).
243#[derive(Clone, Default)]
244pub struct Sha2_192s;
245
246impl Params for Sha2_192s {
247    type Hash = Sha2Family;
248    const N: usize = 24;
249    const H: usize = 63;
250    const D: usize = 7;
251    const H_PRIME: usize = 9;
252    const A: usize = 14;
253    const K: usize = 17;
254    const M: usize = 39;
255    const NAME: &'static str = "SLH-DSA-SHA2-192s";
256}
257
258/// SLH-DSA-SHA2-192f parameter set (NIST security level 3, fast operations).
259#[derive(Clone, Default)]
260pub struct Sha2_192f;
261
262impl Params for Sha2_192f {
263    type Hash = Sha2Family;
264    const N: usize = 24;
265    const H: usize = 66;
266    const D: usize = 22;
267    const H_PRIME: usize = 3;
268    const A: usize = 8;
269    const K: usize = 33;
270    const M: usize = 42;
271    const NAME: &'static str = "SLH-DSA-SHA2-192f";
272}
273
274/// SLH-DSA-SHA2-256s parameter set (NIST security level 5, small signatures).
275#[derive(Clone, Default)]
276pub struct Sha2_256s;
277
278impl Params for Sha2_256s {
279    type Hash = Sha2Family;
280    const N: usize = 32;
281    const H: usize = 64;
282    const D: usize = 8;
283    const H_PRIME: usize = 8;
284    const A: usize = 14;
285    const K: usize = 22;
286    const M: usize = 47;
287    const NAME: &'static str = "SLH-DSA-SHA2-256s";
288}
289
290/// SLH-DSA-SHA2-256f parameter set (NIST security level 5, fast operations).
291#[derive(Clone, Default)]
292pub struct Sha2_256f;
293
294impl Params for Sha2_256f {
295    type Hash = Sha2Family;
296    const N: usize = 32;
297    const H: usize = 68;
298    const D: usize = 17;
299    const H_PRIME: usize = 4;
300    const A: usize = 9;
301    const K: usize = 35;
302    const M: usize = 49;
303    const NAME: &'static str = "SLH-DSA-SHA2-256f";
304}