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