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}