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}