quantica/slh_dsa/params.rs
1//! SLH-DSA parameter sets (FIPS 205, Section 11).
2//!
3//! This module defines the [`Params`] trait and the six SHAKE-based parameter set structs.
4//! All SHAKE-based parameter sets use Winternitz parameter `w = 16` (`lg_w = 4`).
5//!
6//! Each parameter set is identified by its security level (128, 192, or 256 bits) and
7//! a size/speed trade-off suffix: "s" (small signatures) or "f" (fast signing/verification).
8
9/// Trait defining all compile-time parameters for an SLH-DSA instance.
10///
11/// Implementors of this trait represent a specific FIPS 205 parameter set (e.g.,
12/// SLH-DSA-SHAKE-128f). The constants fully determine key sizes, signature sizes,
13/// tree structures, and hash output lengths.
14///
15/// See FIPS 205, Table 2 for the complete list of parameter values.
16pub trait Params: Clone + Default {
17 /// Security parameter `n`: hash output length in bytes.
18 ///
19 /// This is the fundamental security parameter. All hash outputs, secret values,
20 /// and tree nodes are `n` bytes long.
21 const N: usize;
22 /// Total hypertree height: `h = d * h'`.
23 ///
24 /// Determines the total number of FORS key pairs the scheme can use: `2^h`.
25 const H: usize;
26 /// Number of layers `d` in the hypertree.
27 ///
28 /// The hypertree consists of `d` stacked XMSS trees, each of height `h'`.
29 const D: usize;
30 /// Height `h'` of each individual XMSS tree within the hypertree.
31 ///
32 /// Each XMSS tree authenticates `2^h'` keys in the layer below it.
33 const H_PRIME: usize;
34 /// Height `a` of each FORS tree (each tree has `2^a` leaves).
35 const A: usize;
36 /// Number `k` of FORS trees used per signature.
37 const K: usize;
38 /// Winternitz parameter `lg(w)`, always 4 for SHAKE-based parameter sets.
39 const LG_W: usize = 4;
40 /// Winternitz parameter `w = 2^lg_w = 16`.
41 ///
42 /// Controls the time/size trade-off in WOTS+ chains: each chain has `w - 1` steps.
43 const W: usize = 16;
44 /// Message digest length `m` in bytes, output by `H_msg`.
45 ///
46 /// The digest is split into FORS indices, a tree index, and a leaf index.
47 const M: usize;
48
49 // Derived WOTS+ constants
50 /// WOTS+ parameter `len1 = ceil(8*n / lg_w) = 2*n` (since `lg_w = 4`).
51 ///
52 /// Number of base-`w` digits needed to represent an `n`-byte message.
53 const LEN1: usize = 2 * Self::N;
54 /// WOTS+ parameter `len2 = 3` for all SHAKE-based parameter sets.
55 ///
56 /// Number of base-`w` digits in the checksum.
57 const LEN2: usize = 3;
58 /// WOTS+ parameter `len = len1 + len2`: total number of hash chains.
59 const LEN: usize = Self::LEN1 + Self::LEN2;
60
61 // Key and signature sizes
62 /// Public key size in bytes: `2*n` (PK.seed || PK.root).
63 const PK_LEN: usize = 2 * Self::N;
64 /// Secret key size in bytes: `4*n` (SK.seed || SK.prf || PK.seed || PK.root).
65 const SK_LEN: usize = 4 * Self::N;
66
67 /// Human-readable name of this parameter set (e.g., `"SLH-DSA-SHAKE-128f"`).
68 const NAME: &'static str;
69}
70
71/// Compute the total SLH-DSA signature length in bytes for parameter set `P`.
72///
73/// The signature layout is `R || SIG_FORS || SIG_HT`, with total size:
74/// `n + k*(1+a)*n + (h + d*len)*n`.
75///
76/// This is a runtime function rather than a `const` due to Rust const-generics limitations.
77pub fn sig_len<P: Params>() -> usize {
78 // R || SIG_FORS || SIG_HT
79 // n + k*(1+a)*n + (h + d*len)*n
80 P::N + P::K * (1 + P::A) * P::N + (P::H + P::D * P::LEN) * P::N
81}
82
83// ====== SHAKE-128s ======
84/// SLH-DSA-SHAKE-128s parameter set (NIST security level 1, small signatures).
85///
86/// Provides 128-bit security with relatively compact signatures (~7856 bytes) but
87/// slower signing and verification compared to [`Shake128f`].
88#[derive(Clone, Default)]
89pub struct Shake128s;
90
91impl Params for Shake128s {
92 const N: usize = 16;
93 const H: usize = 63;
94 const D: usize = 7;
95 const H_PRIME: usize = 9;
96 const A: usize = 12;
97 const K: usize = 14;
98 const M: usize = 30;
99 const NAME: &'static str = "SLH-DSA-SHAKE-128s";
100}
101
102// ====== SHAKE-128f ======
103/// SLH-DSA-SHAKE-128f parameter set (NIST security level 1, fast operations).
104///
105/// Provides 128-bit security with faster signing and verification but larger
106/// signatures (~17088 bytes) compared to [`Shake128s`].
107#[derive(Clone, Default)]
108pub struct Shake128f;
109
110impl Params for Shake128f {
111 const N: usize = 16;
112 const H: usize = 66;
113 const D: usize = 22;
114 const H_PRIME: usize = 3;
115 const A: usize = 6;
116 const K: usize = 33;
117 const M: usize = 34;
118 const NAME: &'static str = "SLH-DSA-SHAKE-128f";
119}
120
121// ====== SHAKE-192s ======
122/// SLH-DSA-SHAKE-192s parameter set (NIST security level 3, small signatures).
123///
124/// Provides 192-bit security with compact signatures but slower operations
125/// compared to [`Shake192f`].
126#[derive(Clone, Default)]
127pub struct Shake192s;
128
129impl Params for Shake192s {
130 const N: usize = 24;
131 const H: usize = 63;
132 const D: usize = 7;
133 const H_PRIME: usize = 9;
134 const A: usize = 14;
135 const K: usize = 17;
136 const M: usize = 39;
137 const NAME: &'static str = "SLH-DSA-SHAKE-192s";
138}
139
140// ====== SHAKE-192f ======
141/// SLH-DSA-SHAKE-192f parameter set (NIST security level 3, fast operations).
142///
143/// Provides 192-bit security with faster signing and verification but larger
144/// signatures compared to [`Shake192s`].
145#[derive(Clone, Default)]
146pub struct Shake192f;
147
148impl Params for Shake192f {
149 const N: usize = 24;
150 const H: usize = 66;
151 const D: usize = 22;
152 const H_PRIME: usize = 3;
153 const A: usize = 8;
154 const K: usize = 33;
155 const M: usize = 42;
156 const NAME: &'static str = "SLH-DSA-SHAKE-192f";
157}
158
159// ====== SHAKE-256s ======
160/// SLH-DSA-SHAKE-256s parameter set (NIST security level 5, small signatures).
161///
162/// Provides 256-bit security with compact signatures but slower operations
163/// compared to [`Shake256f`].
164#[derive(Clone, Default)]
165pub struct Shake256s;
166
167impl Params for Shake256s {
168 const N: usize = 32;
169 const H: usize = 64;
170 const D: usize = 8;
171 const H_PRIME: usize = 8;
172 const A: usize = 14;
173 const K: usize = 22;
174 const M: usize = 47;
175 const NAME: &'static str = "SLH-DSA-SHAKE-256s";
176}
177
178// ====== SHAKE-256f ======
179/// SLH-DSA-SHAKE-256f parameter set (NIST security level 5, fast operations).
180///
181/// Provides 256-bit security with faster signing and verification but larger
182/// signatures compared to [`Shake256s`].
183#[derive(Clone, Default)]
184pub struct Shake256f;
185
186impl Params for Shake256f {
187 const N: usize = 32;
188 const H: usize = 68;
189 const D: usize = 17;
190 const H_PRIME: usize = 4;
191 const A: usize = 9;
192 const K: usize = 35;
193 const M: usize = 49;
194 const NAME: &'static str = "SLH-DSA-SHAKE-256f";
195}