dcrypt_params/pqc/dilithium.rs
1//! Constants for Module-Lattice-Based Digital Signature Algorithm (ML-DSA)
2//!
3//! This module implements the parameter sets defined in FIPS 204 (August 2024)
4//! "Module-Lattice-Based Digital Signature Standard"
5//! <https://doi.org/10.6028/NIST.FIPS.204>
6//!
7//! All constants in this file are taken directly from the final FIPS 204 standard,
8//! NOT from earlier CRYSTALS-Dilithium submissions or draft specifications.
9
10/// Dilithium polynomial degree (n = 256)
11/// FIPS 204, Table 1: Common to all ML-DSA parameter sets
12pub const DILITHIUM_N: usize = 256;
13
14/// Dilithium modulus (q = 8380417 = 2²³ - 2¹³ + 1)
15/// FIPS 204, Table 1: Common to all ML-DSA parameter sets
16pub const DILITHIUM_Q: u32 = 8380417;
17
18/// FIPS 204 Appendix C, Table 3 minimum allowable loop limit for `ML-DSA.Sign_internal`.
19///
20/// NIST states that implementations which cap the signing rejection loop "shall not use
21/// a limit lower than" this value, and that this limit yields an approximately `2^-256`
22/// or smaller probability of being reached under the standard output-distribution
23/// assumptions for the XOF and hash functions.
24pub const FIPS204_SIGN_INTERNAL_MIN_LOOP_LIMIT: u16 = 814;
25
26/// Common trait for ML-DSA parameter sets as defined in FIPS 204
27pub trait DilithiumSchemeParams: Send + Sync + 'static {
28 /// Algorithm name (ML-DSA-44, ML-DSA-65, ML-DSA-87)
29 const NAME: &'static str;
30
31 // Ring parameters (FIPS 204, Section 3)
32 /// Polynomial degree n = 256 (FIPS 204, Table 1)
33 const N: usize = DILITHIUM_N;
34 /// Prime modulus q = 2²³ - 2¹³ + 1 (FIPS 204, Table 1)
35 const Q: u32 = DILITHIUM_Q;
36 /// Dropped bits parameter d (FIPS 204, Table 1)
37 const D_PARAM: u32;
38
39 // Matrix dimensions (FIPS 204, Table 1)
40 /// Number of polynomials in s₂ and t (rows in matrix A)
41 const K_DIM: usize;
42 /// Number of polynomials in s₁ and y (columns in matrix A)
43 const L_DIM: usize;
44
45 // Security parameters (FIPS 204, Table 1)
46 /// Classical security parameter λ in bits
47 /// ML-DSA-44: λ = 128, ML-DSA-65: λ = 192, ML-DSA-87: λ = 256
48 const LAMBDA: usize;
49
50 /// Challenge hash size in bytes (λ/4)
51 /// ML-DSA-44: 32 bytes, ML-DSA-65: 48 bytes, ML-DSA-87: 64 bytes
52 const CHALLENGE_BYTES: usize;
53
54 // Norm bounds (FIPS 204, Table 1)
55 /// Bound η for secret polynomials s₁, s₂
56 const ETA_S1S2: u32;
57 /// Range parameter γ₁ for masking vector y
58 const GAMMA1_PARAM: u32;
59 /// Number of bits to represent z coefficients
60 /// Computed as ceil(log₂(2·γ₁))
61 /// DEPRECATED: Use Z_BITS for packing z coefficients
62 const GAMMA1_BITS: usize;
63 /// Decomposition parameter γ₂
64 const GAMMA2_PARAM: u32;
65 /// Rejection bound β = τ·η (FIPS 204, Table 1)
66 const BETA_PARAM: u32;
67 /// Maximum number of hint bits ω (FIPS 204, Table 1)
68 const OMEGA_PARAM: u32;
69 /// Number of ±1 coefficients in challenge polynomial c
70 const TAU_PARAM: usize;
71
72 // Byte sizes (FIPS 204, Table 1)
73 /// Public key size in bytes
74 const PUBLIC_KEY_BYTES: usize;
75 /// Secret key size in bytes (includes 32-byte K seed)
76 const SECRET_KEY_BYTES: usize;
77 /// Signature size in bytes
78 const SIGNATURE_SIZE: usize;
79
80 // Seed sizes (FIPS 204, Section 5.1)
81 /// Seed size for matrix A generation (ρ)
82 const SEED_RHO_BYTES: usize = 32;
83 /// Seed size for secret/error sampling (ρ')
84 const SEED_KEY_BYTES: usize = 32;
85 /// Master seed size for key generation (ζ)
86 const SEED_ZETA_BYTES: usize = 32;
87 /// Hash output size for tr = H(pk)
88 const HASH_TR_BYTES: usize = 32;
89
90 // Additional parameters
91 /// Maximum signing attempts before failure
92 const MAX_SIGN_ABORTS: u16 = 1000;
93 /// Fixed public signing window used by the constant-time signer.
94 ///
95 /// For a formally justified rejection cap, implementations must not go below the
96 /// Appendix C, Table 3 bound from FIPS 204.
97 const FIXED_SIGNING_WINDOW: u16 = FIPS204_SIGN_INTERNAL_MIN_LOOP_LIMIT;
98 /// Bits for packing w₁ coefficients
99 /// FIPS 204, Algorithm 28: b = bitlen((q-1)/(2·γ₂) − 1)
100 const W1_BITS: usize;
101
102 /// Number of bits used when packing each z-coefficient in signatures
103 /// This is determined by the range [-γ₁+β, γ₁-β] which requires:
104 /// - ML-DSA-44: 18 bits (since 2·(γ₁-β) < 2¹⁸)
105 /// - ML-DSA-65/87: 20 bits (since 2·(γ₁-β) < 2²⁰)
106 const Z_BITS: usize;
107}
108
109/// Structure containing ML-DSA-44 parameters
110/// FIPS 204, Table 1: ML-DSA-44 (NIST security category 2)
111pub struct Dilithium2Params {
112 /// Polynomial degree n = 256
113 pub n: usize,
114
115 /// Modulus q = 8380417
116 pub q: u32,
117
118 /// Dropped bits d = 13
119 pub d: u32,
120
121 /// Matrix dimension k = 4 (rows)
122 pub k: usize,
123
124 /// Matrix dimension ℓ = 4 (columns)
125 pub l: usize,
126
127 /// Infinity norm bound η = 2
128 pub eta: u32,
129
130 /// Challenge weight τ = 39
131 pub tau: usize,
132
133 /// Public key size = 1312 bytes
134 pub public_key_size: usize,
135
136 /// Secret key size = 2560 bytes (includes 32-byte K seed)
137 pub secret_key_size: usize,
138
139 /// Signature size = 2420 bytes
140 pub signature_size: usize,
141}
142
143/// ML-DSA-44 parameter set (FIPS 204, Table 1)
144/// Targets NIST security category 2 (collision resistance of SHA-256)
145pub const DILITHIUM2: Dilithium2Params = Dilithium2Params {
146 n: DILITHIUM_N,
147 q: DILITHIUM_Q,
148 d: 13,
149 k: 4,
150 l: 4,
151 eta: 2,
152 tau: 39,
153 public_key_size: 1312,
154 secret_key_size: 2560, // FIPS 204 final: includes 32-byte K seed
155 signature_size: 2420, // Updated: 32 + 2304 + 80 + 4 = 2420 bytes
156};
157
158impl DilithiumSchemeParams for Dilithium2Params {
159 const NAME: &'static str = "Dilithium2";
160 const D_PARAM: u32 = 13;
161 const K_DIM: usize = 4;
162 const L_DIM: usize = 4;
163 const LAMBDA: usize = 128; // Classical security parameter
164 const CHALLENGE_BYTES: usize = 32; // λ/4 = 128/4 = 32
165 const ETA_S1S2: u32 = 2;
166 const GAMMA1_PARAM: u32 = 1 << 17; // 2¹⁷ = 131072
167 const GAMMA1_BITS: usize = 18; // ceil(log₂(2·2¹⁷)) = 18
168 // γ₂ = (q − 1)/88 = 95232 (FIPS 204, Table 1, ML-DSA-44)
169 const GAMMA2_PARAM: u32 = (DILITHIUM_Q - 1) / 88; // = 95232
170 const BETA_PARAM: u32 = 78; // β = τ·η = 39·2 = 78
171 // FIXED: OMEGA must be 80 for ML-DSA-44 per FIPS 204 Table 1
172 const OMEGA_PARAM: u32 = 80;
173 const TAU_PARAM: usize = 39;
174 const PUBLIC_KEY_BYTES: usize = 1312;
175 const SECRET_KEY_BYTES: usize = 2560;
176 // SIGNATURE_SIZE updated: 32 (challenge) + 2304 (z) + 80 (hints) + 4 (counters) = 2420
177 const SIGNATURE_SIZE: usize = 2420;
178 // w₁ encoding: (q-1)/(2·γ₂) = 8380416/(2·95232) = 44
179 // Decompose returns r₁ ∈ [0, 43], which still requires 6 bits.
180 const W1_BITS: usize = 6;
181 // Number of bits for packing z coefficients
182 // Range [-γ₁+β, γ₁-β] = [-131072+78, 131072-78] = [-130994, 130994]
183 // Maximum absolute value: 130994 < 2¹⁷, so 2·130994 < 2¹⁸
184 // Therefore 18 bits are sufficient
185 const Z_BITS: usize = 18;
186}
187
188/// Structure containing ML-DSA-65 parameters
189/// FIPS 204, Table 1: ML-DSA-65 (NIST security category 3)
190pub struct Dilithium3Params {
191 /// Polynomial degree n = 256
192 pub n: usize,
193
194 /// Modulus q = 8380417
195 pub q: u32,
196
197 /// Dropped bits d = 13
198 pub d: u32,
199
200 /// Matrix dimension k = 6 (rows)
201 pub k: usize,
202
203 /// Matrix dimension ℓ = 5 (columns)
204 pub l: usize,
205
206 /// Infinity norm bound η = 4
207 pub eta: u32,
208
209 /// Challenge weight τ = 49
210 pub tau: usize,
211
212 /// Public key size = 1952 bytes
213 pub public_key_size: usize,
214
215 /// Secret key size = 4032 bytes (includes 32-byte K seed)
216 pub secret_key_size: usize,
217
218 /// Signature size = 3309 bytes
219 pub signature_size: usize,
220}
221
222/// ML-DSA-65 parameter set (FIPS 204, Table 1)
223/// Targets NIST security category 3 (collision resistance of SHA-384)
224pub const DILITHIUM3: Dilithium3Params = Dilithium3Params {
225 n: DILITHIUM_N,
226 q: DILITHIUM_Q,
227 d: 13,
228 k: 6,
229 l: 5,
230 eta: 4,
231 tau: 49,
232 public_key_size: 1952,
233 secret_key_size: 4032, // FIPS 204 final: includes 32-byte K seed
234 signature_size: 3309, // FIPS 204 final value
235};
236
237impl DilithiumSchemeParams for Dilithium3Params {
238 const NAME: &'static str = "Dilithium3";
239 const D_PARAM: u32 = 13;
240 const K_DIM: usize = 6;
241 const L_DIM: usize = 5;
242 const LAMBDA: usize = 192; // Classical security parameter
243 const CHALLENGE_BYTES: usize = 48; // λ/4 = 192/4 = 48
244 const ETA_S1S2: u32 = 4;
245 const GAMMA1_PARAM: u32 = 1 << 19; // 2¹⁹ = 524288
246 const GAMMA1_BITS: usize = 20; // ceil(log₂(2·2¹⁹)) = 20
247 // CORRECTED: γ₂ = (q − 1)/32 = 261888 (FIPS 204, Table 1, ML-DSA-65)
248 const GAMMA2_PARAM: u32 = (DILITHIUM_Q - 1) / 32; // = 261888
249 const BETA_PARAM: u32 = 196; // β = τ·η = 49·4 = 196
250 // CORRECTED: OMEGA must be 55 for ML-DSA-65 per FIPS 204 Table 1
251 const OMEGA_PARAM: u32 = 55;
252 const TAU_PARAM: usize = 49;
253 const PUBLIC_KEY_BYTES: usize = 1952;
254 const SECRET_KEY_BYTES: usize = 4032;
255 const SIGNATURE_SIZE: usize = 3309;
256 // w₁ encoding for γ₂ = 261888
257 // (q-1)/(2·γ₂) = 8380416/(2·261888) = 16
258 // Decompose returns r₁ ∈ [0, 15], which requires 5 bits.
259 const W1_BITS: usize = 5;
260 // Number of bits for packing z coefficients
261 // Range [-γ₁+β, γ₁-β] = [-524288+196, 524288-196] = [-524092, 524092]
262 // Maximum absolute value: 524092 < 2¹⁹, so 2·524092 < 2²⁰
263 // Therefore 20 bits are sufficient
264 const Z_BITS: usize = 20;
265}
266
267/// Structure containing ML-DSA-87 parameters
268/// FIPS 204, Table 1: ML-DSA-87 (NIST security category 5)
269pub struct Dilithium5Params {
270 /// Polynomial degree n = 256
271 pub n: usize,
272
273 /// Modulus q = 8380417
274 pub q: u32,
275
276 /// Dropped bits d = 13
277 pub d: u32,
278
279 /// Matrix dimension k = 8 (rows)
280 pub k: usize,
281
282 /// Matrix dimension ℓ = 7 (columns)
283 pub l: usize,
284
285 /// Infinity norm bound η = 2
286 pub eta: u32,
287
288 /// Challenge weight τ = 60
289 pub tau: usize,
290
291 /// Public key size = 2592 bytes
292 pub public_key_size: usize,
293
294 /// Secret key size = 4896 bytes (includes 32-byte K seed)
295 pub secret_key_size: usize,
296
297 /// Signature size = 4627 bytes
298 pub signature_size: usize,
299}
300
301/// ML-DSA-87 parameter set (FIPS 204, Table 1)
302/// Targets NIST security category 5 (collision resistance of SHA-512)
303pub const DILITHIUM5: Dilithium5Params = Dilithium5Params {
304 n: DILITHIUM_N,
305 q: DILITHIUM_Q,
306 d: 13,
307 k: 8,
308 l: 7,
309 eta: 2,
310 tau: 60,
311 public_key_size: 2592,
312 secret_key_size: 4896, // FIPS 204 final: includes 32-byte K seed
313 signature_size: 4627, // FIPS 204 final value
314};
315
316impl DilithiumSchemeParams for Dilithium5Params {
317 const NAME: &'static str = "Dilithium5";
318 const D_PARAM: u32 = 13;
319 const K_DIM: usize = 8;
320 const L_DIM: usize = 7;
321 const LAMBDA: usize = 256; // Classical security parameter
322 const CHALLENGE_BYTES: usize = 64; // λ/4 = 256/4 = 64
323 const ETA_S1S2: u32 = 2;
324 const GAMMA1_PARAM: u32 = 1 << 19; // 2¹⁹ = 524288
325 const GAMMA1_BITS: usize = 20; // ceil(log₂(2·2¹⁹)) = 20
326 // γ₂ = (q − 1)/32 = 261888 (FIPS 204, Table 1, ML-DSA-87)
327 const GAMMA2_PARAM: u32 = (DILITHIUM_Q - 1) / 32; // = 261888
328 // β = τ·η = 60·2 = 120 (FIPS 204, Table 1, ML-DSA-87)
329 const BETA_PARAM: u32 = 120; // Corrected from earlier drafts
330 // FIPS 204, Table 1 specifies Ω = 75 for ML-DSA-87.
331 const OMEGA_PARAM: u32 = 75;
332 const TAU_PARAM: usize = 60;
333 const PUBLIC_KEY_BYTES: usize = 2592;
334 const SECRET_KEY_BYTES: usize = 4896;
335 const SIGNATURE_SIZE: usize = 4627;
336 // w₁ encoding: (q-1)/(2·γ₂) = 8380416/(2·261888) = 16
337 // Decompose returns r₁ ∈ [0, 15], which requires 5 bits.
338 const W1_BITS: usize = 5;
339 // Number of bits for packing z coefficients
340 // Range [-γ₁+β, γ₁-β] = [-524288+120, 524288-120] = [-524168, 524168]
341 // Maximum absolute value: 524168 < 2¹⁹, so 2·524168 < 2²⁰
342 // Therefore 20 bits are sufficient
343 const Z_BITS: usize = 20;
344}