1use crate::mldsa::{H, MLDSA_MU_LEN, MLDSA_RND_LEN, MLDSATrait};
69use crate::mldsa::{
70 MLDSA44_BETA, MLDSA44_C_TILDE, MLDSA44_ETA, MLDSA44_GAMMA1, MLDSA44_GAMMA1_MASK_LEN,
71 MLDSA44_GAMMA1_MINUS_BETA, MLDSA44_GAMMA2, MLDSA44_GAMMA2_MINUS_BETA, MLDSA44_LAMBDA,
72 MLDSA44_LAMBDA_over_4, MLDSA44_OMEGA, MLDSA44_PK_LEN, MLDSA44_POLY_W1_PACKED_LEN,
73 MLDSA44_POLY_Z_PACKED_LEN, MLDSA44_SIG_LEN, MLDSA44_SK_LEN, MLDSA44_TAU, MLDSA44_k, MLDSA44_l,
74};
75use crate::mldsa::{
76 MLDSA65_BETA, MLDSA65_C_TILDE, MLDSA65_ETA, MLDSA65_GAMMA1, MLDSA65_GAMMA1_MASK_LEN,
77 MLDSA65_GAMMA1_MINUS_BETA, MLDSA65_GAMMA2, MLDSA65_GAMMA2_MINUS_BETA, MLDSA65_LAMBDA,
78 MLDSA65_LAMBDA_over_4, MLDSA65_OMEGA, MLDSA65_PK_LEN, MLDSA65_POLY_W1_PACKED_LEN,
79 MLDSA65_POLY_Z_PACKED_LEN, MLDSA65_SIG_LEN, MLDSA65_SK_LEN, MLDSA65_TAU, MLDSA65_k, MLDSA65_l,
80};
81use crate::mldsa::{
82 MLDSA87_BETA, MLDSA87_C_TILDE, MLDSA87_ETA, MLDSA87_GAMMA1, MLDSA87_GAMMA1_MASK_LEN,
83 MLDSA87_GAMMA1_MINUS_BETA, MLDSA87_GAMMA2, MLDSA87_GAMMA2_MINUS_BETA, MLDSA87_LAMBDA,
84 MLDSA87_LAMBDA_over_4, MLDSA87_OMEGA, MLDSA87_PK_LEN, MLDSA87_POLY_W1_PACKED_LEN,
85 MLDSA87_POLY_Z_PACKED_LEN, MLDSA87_SIG_LEN, MLDSA87_SK_LEN, MLDSA87_TAU, MLDSA87_k, MLDSA87_l,
86};
87use crate::mldsa_keys::{MLDSAPrivateKeyInternalTrait, MLDSAPublicKeyInternalTrait};
88use crate::{
89 MLDSA, MLDSA44PrivateKey, MLDSA44PublicKey, MLDSA65PrivateKey, MLDSA65PublicKey,
90 MLDSA87PrivateKey, MLDSA87PublicKey, MLDSAPrivateKeyExpanded, MLDSAPrivateKeyTrait,
91 MLDSAPublicKeyExpanded, MLDSAPublicKeyTrait, Matrix,
92};
93use bouncycastle_core::errors::SignatureError;
94use bouncycastle_core::key_material::KeyMaterial;
95use bouncycastle_core::traits::{
96 Algorithm, AlgorithmOID, Hash, PHSignatureVerifier, PHSigner, RNG, SecurityStrength,
97 SignatureVerifier, Signer, XOF,
98};
99use bouncycastle_rng::HashDRBG_SHA512;
100use bouncycastle_sha2::{SHA256, SHA512};
101use core::marker::PhantomData;
102
103#[allow(unused_imports)]
105use crate::mldsa::MuBuilder;
106
107pub const HASH_ML_DSA_44_with_SHA256_NAME: &str = "HashML-DSA-44_with_SHA256";
111pub const HASH_ML_DSA_65_WITH_SHA256_NAME: &str = "HashML-DSA-65_with_SHA256";
113pub const HASH_ML_DSA_87_with_SHA256_NAME: &str = "HashML-DSA-87_with_SHA256";
115pub const HASH_ML_DSA_44_with_SHA512_NAME: &str = "HashML-DSA-44_with_SHA512";
117pub const HASH_ML_DSA_65_WITH_SHA512_NAME: &str = "HashML-DSA-65_with_SHA512";
119pub const HASH_ML_DSA_87_WITH_SHA512_NAME: &str = "HashML-DSA-87_with_SHA512";
121
122#[allow(non_camel_case_types)]
126pub type HashMLDSA44_with_SHA256 = HashMLDSA<
127 SHA256,
128 32,
129 MLDSA44_PK_LEN,
130 MLDSA44_SK_LEN,
131 MLDSA44_SIG_LEN,
132 MLDSA44PublicKey,
133 MLDSA44PrivateKey,
134 MLDSA44_TAU,
135 MLDSA44_LAMBDA,
136 MLDSA44_GAMMA1,
137 MLDSA44_GAMMA2,
138 MLDSA44_k,
139 MLDSA44_l,
140 MLDSA44_ETA,
141 MLDSA44_BETA,
142 MLDSA44_OMEGA,
143 MLDSA44_C_TILDE,
144 MLDSA44_POLY_Z_PACKED_LEN,
145 MLDSA44_POLY_W1_PACKED_LEN,
146 MLDSA44_LAMBDA_over_4,
147 MLDSA44_GAMMA1_MINUS_BETA,
148 MLDSA44_GAMMA2_MINUS_BETA,
149 MLDSA44_GAMMA1_MASK_LEN,
150>;
151
152impl Algorithm for HashMLDSA44_with_SHA256 {
153 const ALG_NAME: &'static str = HASH_ML_DSA_44_with_SHA256_NAME;
154 const MAX_SECURITY_STRENGTH: SecurityStrength = SecurityStrength::_128bit;
155}
156
157#[allow(non_camel_case_types)]
159pub type HashMLDSA65_with_SHA256 = HashMLDSA<
160 SHA256,
161 32,
162 MLDSA65_PK_LEN,
163 MLDSA65_SK_LEN,
164 MLDSA65_SIG_LEN,
165 MLDSA65PublicKey,
166 MLDSA65PrivateKey,
167 MLDSA65_TAU,
168 MLDSA65_LAMBDA,
169 MLDSA65_GAMMA1,
170 MLDSA65_GAMMA2,
171 MLDSA65_k,
172 MLDSA65_l,
173 MLDSA65_ETA,
174 MLDSA65_BETA,
175 MLDSA65_OMEGA,
176 MLDSA65_C_TILDE,
177 MLDSA65_POLY_Z_PACKED_LEN,
178 MLDSA65_POLY_W1_PACKED_LEN,
179 MLDSA65_LAMBDA_over_4,
180 MLDSA65_GAMMA1_MINUS_BETA,
181 MLDSA65_GAMMA2_MINUS_BETA,
182 MLDSA65_GAMMA1_MASK_LEN,
183>;
184
185impl Algorithm for HashMLDSA65_with_SHA256 {
186 const ALG_NAME: &'static str = HASH_ML_DSA_65_WITH_SHA256_NAME;
187 const MAX_SECURITY_STRENGTH: SecurityStrength = SecurityStrength::_128bit;
188}
189
190#[allow(non_camel_case_types)]
192pub type HashMLDSA87_with_SHA256 = HashMLDSA<
193 SHA256,
194 32,
195 MLDSA87_PK_LEN,
196 MLDSA87_SK_LEN,
197 MLDSA87_SIG_LEN,
198 MLDSA87PublicKey,
199 MLDSA87PrivateKey,
200 MLDSA87_TAU,
201 MLDSA87_LAMBDA,
202 MLDSA87_GAMMA1,
203 MLDSA87_GAMMA2,
204 MLDSA87_k,
205 MLDSA87_l,
206 MLDSA87_ETA,
207 MLDSA87_BETA,
208 MLDSA87_OMEGA,
209 MLDSA87_C_TILDE,
210 MLDSA87_POLY_Z_PACKED_LEN,
211 MLDSA87_POLY_W1_PACKED_LEN,
212 MLDSA87_LAMBDA_over_4,
213 MLDSA87_GAMMA1_MINUS_BETA,
214 MLDSA87_GAMMA2_MINUS_BETA,
215 MLDSA87_GAMMA1_MASK_LEN,
216>;
217
218impl Algorithm for HashMLDSA87_with_SHA256 {
219 const ALG_NAME: &'static str = HASH_ML_DSA_87_with_SHA256_NAME;
220 const MAX_SECURITY_STRENGTH: SecurityStrength = SecurityStrength::_128bit;
221}
222
223#[allow(non_camel_case_types)]
225pub type HashMLDSA44_with_SHA512 = HashMLDSA<
226 SHA512,
227 64,
228 MLDSA44_PK_LEN,
229 MLDSA44_SK_LEN,
230 MLDSA44_SIG_LEN,
231 MLDSA44PublicKey,
232 MLDSA44PrivateKey,
233 MLDSA44_TAU,
234 MLDSA44_LAMBDA,
235 MLDSA44_GAMMA1,
236 MLDSA44_GAMMA2,
237 MLDSA44_k,
238 MLDSA44_l,
239 MLDSA44_ETA,
240 MLDSA44_BETA,
241 MLDSA44_OMEGA,
242 MLDSA44_C_TILDE,
243 MLDSA44_POLY_Z_PACKED_LEN,
244 MLDSA44_POLY_W1_PACKED_LEN,
245 MLDSA44_LAMBDA_over_4,
246 MLDSA44_GAMMA1_MINUS_BETA,
247 MLDSA44_GAMMA2_MINUS_BETA,
248 MLDSA44_GAMMA1_MASK_LEN,
249>;
250
251impl Algorithm for HashMLDSA44_with_SHA512 {
252 const ALG_NAME: &'static str = HASH_ML_DSA_44_with_SHA512_NAME;
253 const MAX_SECURITY_STRENGTH: SecurityStrength = SecurityStrength::_128bit;
254}
255impl AlgorithmOID for HashMLDSA44_with_SHA512 {
257 const OID: &'static [u32] = &[2, 16, 840, 1, 101, 3, 4, 3, 32];
258 const OID_DER: &'static [u8] =
259 &[0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x20];
260}
261
262#[allow(non_camel_case_types)]
264pub type HashMLDSA65_with_SHA512 = HashMLDSA<
265 SHA512,
266 64,
267 MLDSA65_PK_LEN,
268 MLDSA65_SK_LEN,
269 MLDSA65_SIG_LEN,
270 MLDSA65PublicKey,
271 MLDSA65PrivateKey,
272 MLDSA65_TAU,
273 MLDSA65_LAMBDA,
274 MLDSA65_GAMMA1,
275 MLDSA65_GAMMA2,
276 MLDSA65_k,
277 MLDSA65_l,
278 MLDSA65_ETA,
279 MLDSA65_BETA,
280 MLDSA65_OMEGA,
281 MLDSA65_C_TILDE,
282 MLDSA65_POLY_Z_PACKED_LEN,
283 MLDSA65_POLY_W1_PACKED_LEN,
284 MLDSA65_LAMBDA_over_4,
285 MLDSA65_GAMMA1_MINUS_BETA,
286 MLDSA65_GAMMA2_MINUS_BETA,
287 MLDSA65_GAMMA1_MASK_LEN,
288>;
289
290impl Algorithm for HashMLDSA65_with_SHA512 {
291 const ALG_NAME: &'static str = HASH_ML_DSA_65_WITH_SHA512_NAME;
292 const MAX_SECURITY_STRENGTH: SecurityStrength = SecurityStrength::_192bit;
293}
294impl AlgorithmOID for HashMLDSA65_with_SHA512 {
296 const OID: &'static [u32] = &[2, 16, 840, 1, 101, 3, 4, 3, 33];
297 const OID_DER: &'static [u8] =
298 &[0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x21];
299}
300
301#[allow(non_camel_case_types)]
303pub type HashMLDSA87_with_SHA512 = HashMLDSA<
304 SHA512,
305 64,
306 MLDSA87_PK_LEN,
307 MLDSA87_SK_LEN,
308 MLDSA87_SIG_LEN,
309 MLDSA87PublicKey,
310 MLDSA87PrivateKey,
311 MLDSA87_TAU,
312 MLDSA87_LAMBDA,
313 MLDSA87_GAMMA1,
314 MLDSA87_GAMMA2,
315 MLDSA87_k,
316 MLDSA87_l,
317 MLDSA87_ETA,
318 MLDSA87_BETA,
319 MLDSA87_OMEGA,
320 MLDSA87_C_TILDE,
321 MLDSA87_POLY_Z_PACKED_LEN,
322 MLDSA87_POLY_W1_PACKED_LEN,
323 MLDSA87_LAMBDA_over_4,
324 MLDSA87_GAMMA1_MINUS_BETA,
325 MLDSA87_GAMMA2_MINUS_BETA,
326 MLDSA87_GAMMA1_MASK_LEN,
327>;
328
329impl Algorithm for HashMLDSA87_with_SHA512 {
330 const ALG_NAME: &'static str = HASH_ML_DSA_87_WITH_SHA512_NAME;
331 const MAX_SECURITY_STRENGTH: SecurityStrength = SecurityStrength::_256bit;
332}
333impl AlgorithmOID for HashMLDSA87_with_SHA512 {
335 const OID: &'static [u32] = &[2, 16, 840, 1, 101, 3, 4, 3, 34];
336 const OID_DER: &'static [u8] =
337 &[0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x22];
338}
339
340pub struct HashMLDSA<
347 HASH: Hash + AlgorithmOID + Default,
348 const HASH_LEN: usize,
349 const PK_LEN: usize,
350 const SK_LEN: usize,
351 const SIG_LEN: usize,
352 PK: MLDSAPublicKeyTrait<k, l, PK_LEN> + MLDSAPublicKeyInternalTrait<k, PK_LEN>,
353 SK: MLDSAPrivateKeyTrait<k, l, ETA, SK_LEN, PK_LEN>
354 + MLDSAPrivateKeyInternalTrait<k, l, ETA, SK_LEN, PK_LEN>,
355 const TAU: i32,
356 const LAMBDA: i32,
357 const GAMMA1: i32,
358 const GAMMA2: i32,
359 const k: usize,
360 const l: usize,
361 const ETA: usize,
362 const BETA: i32,
363 const OMEGA: i32,
364 const C_TILDE: usize,
365 const POLY_Z_PACKED_LEN: usize,
366 const POLY_W1_PACKED_LEN: usize,
367 const LAMBDA_over_4: usize,
368 const GAMMA1_MINUS_BETA: i32,
369 const GAMMA2_MINUS_BETA: i32,
370 const GAMMA1_MASK_LEN: usize,
371> {
372 _phantom: PhantomData<(PK, SK)>,
373
374 signer_rnd: Option<[u8; MLDSA_RND_LEN]>,
375
376 sk: Option<SK>,
378
379 seed: Option<KeyMaterial<32>>,
381
382 pk: Option<PK>,
384
385 hash: HASH,
387
388 ctx: [u8; 255],
391 ctx_len: usize,
392}
393
394impl<
395 HASH: Hash + AlgorithmOID + Default,
396 const PH_LEN: usize,
397 const PK_LEN: usize,
398 const SK_LEN: usize,
399 const SIG_LEN: usize,
400 PK: MLDSAPublicKeyTrait<k, l, PK_LEN> + MLDSAPublicKeyInternalTrait<k, PK_LEN>,
401 SK: MLDSAPrivateKeyTrait<k, l, ETA, SK_LEN, PK_LEN>
402 + MLDSAPrivateKeyInternalTrait<k, l, ETA, SK_LEN, PK_LEN>,
403 const TAU: i32,
404 const LAMBDA: i32,
405 const GAMMA1: i32,
406 const GAMMA2: i32,
407 const k: usize,
408 const l: usize,
409 const ETA: usize,
410 const BETA: i32,
411 const OMEGA: i32,
412 const C_TILDE: usize,
413 const POLY_Z_PACKED_LEN: usize,
414 const POLY_W1_PACKED_LEN: usize,
415 const LAMBDA_over_4: usize,
416 const GAMMA1_MASK_LEN: usize,
417 const GAMMA1_MINUS_BETA: i32,
418 const GAMMA2_MINUS_BETA: i32,
419>
420 HashMLDSA<
421 HASH,
422 PH_LEN,
423 PK_LEN,
424 SK_LEN,
425 SIG_LEN,
426 PK,
427 SK,
428 TAU,
429 LAMBDA,
430 GAMMA1,
431 GAMMA2,
432 k,
433 l,
434 ETA,
435 BETA,
436 OMEGA,
437 C_TILDE,
438 POLY_Z_PACKED_LEN,
439 POLY_W1_PACKED_LEN,
440 LAMBDA_over_4,
441 GAMMA1_MINUS_BETA,
442 GAMMA2_MINUS_BETA,
443 GAMMA1_MASK_LEN,
444 >
445{
446 pub fn keygen() -> Result<(PK, SK), SignatureError> {
453 MLDSA::<
454 PK_LEN,
455 SK_LEN,
456 SIG_LEN,
457 PK,
458 SK,
459 TAU,
460 LAMBDA,
461 GAMMA1,
462 GAMMA2,
463 k,
464 l,
465 ETA,
466 BETA,
467 OMEGA,
468 C_TILDE,
469 POLY_Z_PACKED_LEN,
470 POLY_W1_PACKED_LEN,
471 LAMBDA_over_4,
472 GAMMA1_MINUS_BETA,
473 GAMMA2_MINUS_BETA,
474 GAMMA1_MASK_LEN,
475 >::keygen()
476 }
477
478 pub fn keygen_from_seed(seed: &KeyMaterial<32>) -> Result<(PK, SK), SignatureError> {
480 MLDSA::<
481 PK_LEN,
482 SK_LEN,
483 SIG_LEN,
484 PK,
485 SK,
486 TAU,
487 LAMBDA,
488 GAMMA1,
489 GAMMA2,
490 k,
491 l,
492 ETA,
493 BETA,
494 OMEGA,
495 C_TILDE,
496 POLY_Z_PACKED_LEN,
497 POLY_W1_PACKED_LEN,
498 LAMBDA_over_4,
499 GAMMA1_MINUS_BETA,
500 GAMMA2_MINUS_BETA,
501 GAMMA1_MASK_LEN,
502 >::keygen_internal(seed)
503 }
504 pub fn sign_with_expanded_key(
506 sk: &MLDSAPrivateKeyExpanded<k, l, ETA, PK, SK, SK_LEN, PK_LEN>,
507 msg: &[u8],
508 ctx: Option<&[u8]>,
509 ) -> Result<[u8; SIG_LEN], SignatureError> {
510 let mut out = [0u8; SIG_LEN];
511 Self::sign_with_expanded_key_out(sk, msg, ctx, &mut out)?;
512
513 Ok(out)
514 }
515 pub fn sign_with_expanded_key_out(
517 sk: &MLDSAPrivateKeyExpanded<k, l, ETA, PK, SK, SK_LEN, PK_LEN>,
518 msg: &[u8],
519 ctx: Option<&[u8]>,
520 output: &mut [u8; SIG_LEN],
521 ) -> Result<usize, SignatureError> {
522 output.fill(0);
523
524 let mut ph_m = [0u8; PH_LEN];
525 _ = HASH::default().hash_out(msg, &mut ph_m);
526 Self::sign_ph_with_expanded_key_out(sk, &ph_m, ctx, output)
527 }
528 pub fn sign_ph_with_expanded_key(
530 sk: &MLDSAPrivateKeyExpanded<k, l, ETA, PK, SK, SK_LEN, PK_LEN>,
531 ph: &[u8; PH_LEN],
532 ctx: Option<&[u8]>,
533 ) -> Result<[u8; SIG_LEN], SignatureError> {
534 let mut out = [0u8; SIG_LEN];
535 _ = Self::sign_ph_with_expanded_key_out(sk, ph, ctx, &mut out);
536
537 Ok(out)
538 }
539 pub fn sign_ph_with_expanded_key_out(
541 sk: &MLDSAPrivateKeyExpanded<k, l, ETA, PK, SK, SK_LEN, PK_LEN>,
542 ph: &[u8; PH_LEN],
543 ctx: Option<&[u8]>,
544 output: &mut [u8; SIG_LEN],
545 ) -> Result<usize, SignatureError> {
546 output.fill(0);
547
548 let mut rnd: [u8; MLDSA_RND_LEN] = [0u8; MLDSA_RND_LEN];
549 HashDRBG_SHA512::new_from_os().next_bytes_out(&mut rnd)?;
550 Self::sign_ph_deterministic_out(&sk.sk, Some(&sk.A_hat), ctx, ph, rnd, output)
551 }
552 pub fn sign_ph_deterministic(
566 sk: &SK,
567 A_hat: Option<&Matrix<k, l>>,
568 ctx: Option<&[u8]>,
569 ph: &[u8; PH_LEN],
570 rnd: [u8; 32],
571 ) -> Result<[u8; SIG_LEN], SignatureError> {
572 let mut out: [u8; SIG_LEN] = [0u8; SIG_LEN];
573 Self::sign_ph_deterministic_out(sk, A_hat, ctx, ph, rnd, &mut out)?;
574 Ok(out)
575 }
576 pub fn sign_ph_deterministic_out(
589 sk: &SK,
590 A_hat: Option<&Matrix<k, l>>,
591 ctx: Option<&[u8]>,
592 ph: &[u8; PH_LEN],
593 rnd: [u8; 32],
594 output: &mut [u8; SIG_LEN],
595 ) -> Result<usize, SignatureError> {
596 let ctx = if ctx.is_some() { ctx.unwrap() } else { &[] };
597
598 if ctx.len() > 255 {
601 return Err(SignatureError::LengthError("ctx value is longer than 255 bytes"));
602 }
603
604 output.fill(0);
605
606 let mu = {
609 let mut h = H::new();
610 h.absorb(sk.tr()).expect("absorb before squeeze is infallible");
611
612 h.absorb(&[1u8]).expect("absorb before squeeze is infallible");
616 h.absorb(&[ctx.len() as u8]).expect("absorb before squeeze is infallible");
617 h.absorb(ctx).expect("absorb before squeeze is infallible");
618 h.absorb(HASH::OID_DER).expect("absorb before squeeze is infallible");
619 h.absorb(ph).expect("absorb before squeeze is infallible");
620 let mut mu = [0u8; MLDSA_MU_LEN];
621 let bytes_written = h.squeeze_out(&mut mu);
622 debug_assert_eq!(bytes_written, MLDSA_MU_LEN);
623
624 mu
625 };
626
627 let bytes_written = MLDSA::<
629 PK_LEN,
630 SK_LEN,
631 SIG_LEN,
632 PK,
633 SK,
634 TAU,
635 LAMBDA,
636 GAMMA1,
637 GAMMA2,
638 k,
639 l,
640 ETA,
641 BETA,
642 OMEGA,
643 C_TILDE,
644 POLY_Z_PACKED_LEN,
645 POLY_W1_PACKED_LEN,
646 LAMBDA_over_4,
647 GAMMA1_MINUS_BETA,
648 GAMMA2_MINUS_BETA,
649 GAMMA1_MASK_LEN,
650 >::sign_mu_deterministic_out(sk, A_hat, &mu, rnd, output)?;
651
652 Ok(bytes_written)
653 }
654
655 pub fn set_signer_rnd(&mut self, rnd: [u8; 32]) {
659 self.signer_rnd = Some(rnd);
660 }
661
662 fn parse_ctx(ctx: Option<&[u8]>) -> Result<([u8; 255], usize), SignatureError> {
663 if ctx.is_some() {
664 if ctx.unwrap().len() > 255 {
667 return Err(SignatureError::LengthError("ctx value is longer than 255 bytes"));
668 }
669
670 let mut ctx_buf = [0u8; 255];
671 ctx_buf[..ctx.unwrap().len()].copy_from_slice(ctx.unwrap());
672 Ok((ctx_buf, ctx.unwrap().len()))
673 } else {
674 Ok(([0u8; 255], 0))
675 }
676 }
677
678 pub fn sign_init_from_seed(
681 seed: &KeyMaterial<32>,
682 ctx: Option<&[u8]>,
683 ) -> Result<Self, SignatureError> {
684 let (ctx, ctx_len) = Self::parse_ctx(ctx)?;
685 Ok(Self {
686 _phantom: PhantomData,
687 signer_rnd: None,
688 sk: None,
689 seed: Some(seed.clone()),
690 pk: None,
691 hash: HASH::default(),
692 ctx,
693 ctx_len,
694 })
695 }
696 pub fn verify_with_expanded_key(
698 pk: &MLDSAPublicKeyExpanded<k, l, PK, PK_LEN>,
699 msg: &[u8],
700 ctx: Option<&[u8]>,
701 sig: &[u8],
702 ) -> Result<(), SignatureError> {
703 let mut ph_m = [0u8; PH_LEN];
704 _ = HASH::default().hash_out(msg, &mut ph_m);
705
706 Self::verify_ph_internal(&pk.pk, Some(&pk.A_hat()), &ph_m, ctx, sig)
707 }
708
709 fn verify_ph_internal(
710 pk: &PK,
711 A_hat: Option<&Matrix<k, l>>,
712 ph: &[u8; PH_LEN],
713 ctx: Option<&[u8]>,
714 sig: &[u8],
715 ) -> Result<(), SignatureError> {
716 if sig.len() != SIG_LEN {
717 return Err(SignatureError::LengthError("Signature value is not the correct length."));
718 }
719 let sig_sized: &[u8; SIG_LEN] = sig[..SIG_LEN].try_into().unwrap();
720
721 let ctx = if ctx.is_some() { ctx.unwrap() } else { &[] };
722
723 if ctx.len() > 255 {
726 return Err(SignatureError::LengthError("ctx value is longer than 255 bytes"));
727 }
728
729 let mu = {
732 let mut h = H::new();
733 h.absorb(&pk.compute_tr()).expect("absorb before squeeze is infallible");
734
735 h.absorb(&[1u8]).expect("absorb before squeeze is infallible");
739 h.absorb(&[ctx.len() as u8]).expect("absorb before squeeze is infallible");
740 h.absorb(ctx).expect("absorb before squeeze is infallible");
741 h.absorb(HASH::OID_DER).expect("absorb before squeeze is infallible");
742 h.absorb(ph).expect("absorb before squeeze is infallible");
743 let mut mu = [0u8; MLDSA_MU_LEN];
744 _ = h.squeeze_out(&mut mu);
745
746 mu
747 };
748
749 match A_hat {
750 Some(A_hat) => MLDSA::<
751 PK_LEN,
752 SK_LEN,
753 SIG_LEN,
754 PK,
755 SK,
756 TAU,
757 LAMBDA,
758 GAMMA1,
759 GAMMA2,
760 k,
761 l,
762 ETA,
763 BETA,
764 OMEGA,
765 C_TILDE,
766 POLY_Z_PACKED_LEN,
767 POLY_W1_PACKED_LEN,
768 LAMBDA_over_4,
769 GAMMA1_MINUS_BETA,
770 GAMMA2_MINUS_BETA,
771 GAMMA1_MASK_LEN,
772 >::verify_mu(pk, Some(A_hat), &mu, sig_sized),
773 None => MLDSA::<
774 PK_LEN,
775 SK_LEN,
776 SIG_LEN,
777 PK,
778 SK,
779 TAU,
780 LAMBDA,
781 GAMMA1,
782 GAMMA2,
783 k,
784 l,
785 ETA,
786 BETA,
787 OMEGA,
788 C_TILDE,
789 POLY_Z_PACKED_LEN,
790 POLY_W1_PACKED_LEN,
791 LAMBDA_over_4,
792 GAMMA1_MINUS_BETA,
793 GAMMA2_MINUS_BETA,
794 GAMMA1_MASK_LEN,
795 >::verify_mu(pk, Some(&pk.A_hat()), &mu, sig_sized),
796 }
797 }
798}
799
800impl<
801 HASH: Hash + AlgorithmOID + Default,
802 PK: MLDSAPublicKeyTrait<k, l, PK_LEN> + MLDSAPublicKeyInternalTrait<k, PK_LEN>,
803 SK: MLDSAPrivateKeyTrait<k, l, ETA, SK_LEN, PK_LEN>
804 + MLDSAPrivateKeyInternalTrait<k, l, ETA, SK_LEN, PK_LEN>,
805 const PH_LEN: usize,
806 const PK_LEN: usize,
807 const SK_LEN: usize,
808 const SIG_LEN: usize,
809 const TAU: i32,
810 const LAMBDA: i32,
811 const GAMMA1: i32,
812 const GAMMA2: i32,
813 const k: usize,
814 const l: usize,
815 const ETA: usize,
816 const BETA: i32,
817 const OMEGA: i32,
818 const C_TILDE: usize,
819 const POLY_Z_PACKED_LEN: usize,
820 const POLY_W1_PACKED_LEN: usize,
821 const LAMBDA_over_4: usize,
822 const GAMMA1_MINUS_BETA: i32,
823 const GAMMA2_MINUS_BETA: i32,
824 const GAMMA1_MASK_LEN: usize,
825> Signer<SK, SK_LEN, SIG_LEN>
826 for HashMLDSA<
827 HASH,
828 PH_LEN,
829 PK_LEN,
830 SK_LEN,
831 SIG_LEN,
832 PK,
833 SK,
834 TAU,
835 LAMBDA,
836 GAMMA1,
837 GAMMA2,
838 k,
839 l,
840 ETA,
841 BETA,
842 OMEGA,
843 C_TILDE,
844 POLY_Z_PACKED_LEN,
845 POLY_W1_PACKED_LEN,
846 LAMBDA_over_4,
847 GAMMA1_MINUS_BETA,
848 GAMMA2_MINUS_BETA,
849 GAMMA1_MASK_LEN,
850 >
851{
852 fn sign(sk: &SK, msg: &[u8], ctx: Option<&[u8]>) -> Result<[u8; SIG_LEN], SignatureError> {
855 let mut out = [0u8; SIG_LEN];
856 Self::sign_out(sk, msg, ctx, &mut out)?;
857
858 Ok(out)
859 }
860
861 fn sign_out(
862 sk: &SK,
863 msg: &[u8],
864 ctx: Option<&[u8]>,
865 output: &mut [u8; SIG_LEN],
866 ) -> Result<usize, SignatureError> {
867 output.fill(0);
868
869 let mut ph_m = [0u8; PH_LEN];
870 _ = HASH::default().hash_out(msg, &mut ph_m);
871 Self::sign_ph_out(sk, &ph_m, ctx, output)
872 }
873
874 fn sign_init(sk: &SK, ctx: Option<&[u8]>) -> Result<Self, SignatureError> {
875 let (ctx, ctx_len) = Self::parse_ctx(ctx)?;
876 Ok(Self {
877 _phantom: PhantomData,
878 signer_rnd: None,
879 sk: Some(sk.clone()),
880 seed: None,
881 pk: None,
882 hash: HASH::default(),
883 ctx,
884 ctx_len,
885 })
886 }
887
888 fn sign_update(&mut self, msg_chunk: &[u8]) {
889 self.hash.do_update(msg_chunk);
890 }
891
892 fn sign_final(self) -> Result<[u8; SIG_LEN], SignatureError> {
893 let mut out = [0u8; SIG_LEN];
894 self.sign_final_out(&mut out)?;
895 Ok(out)
896 }
897
898 fn sign_final_out(self, output: &mut [u8; SIG_LEN]) -> Result<usize, SignatureError> {
899 let ph: [u8; PH_LEN] = self.hash.do_final().try_into().unwrap();
900
901 if self.sk.is_none() && self.seed.is_none() {
902 return Err(SignatureError::GenericError(
903 "sign_final_out called on a streaming context with no private key or seed; \
904 this is a verify-initialized context. Call verify_final instead",
905 ));
906 }
907
908 output.fill(0);
909
910 if self.sk.is_some() {
911 if self.signer_rnd.is_none() {
912 Self::sign_ph_out(&self.sk.unwrap(), &ph, Some(&self.ctx[..self.ctx_len]), output)
913 } else {
914 Self::sign_ph_deterministic_out(
915 &self.sk.unwrap(),
916 None,
917 Some(&self.ctx[..self.ctx_len]),
918 &ph,
919 self.signer_rnd.unwrap(),
920 output,
921 )
922 }
923 } else if self.seed.is_some() {
924 let rnd = if self.signer_rnd.is_some() {
925 self.signer_rnd.unwrap()
926 } else {
927 let mut rnd: [u8; MLDSA_RND_LEN] = [0u8; MLDSA_RND_LEN];
928 HashDRBG_SHA512::new_from_os().next_bytes_out(&mut rnd)?;
929 rnd
930 };
931 let (_pk, sk) = Self::keygen_from_seed(&self.seed.unwrap())?;
934 Self::sign_ph_deterministic_out(
935 &sk,
936 None,
937 Some(&self.ctx[..self.ctx_len]),
938 &ph,
939 rnd,
940 output,
941 )
942 } else {
943 unreachable!()
944 }
945 }
946}
947
948impl<
949 HASH: Hash + AlgorithmOID + Default,
950 PK: MLDSAPublicKeyTrait<k, l, PK_LEN> + MLDSAPublicKeyInternalTrait<k, PK_LEN>,
951 SK: MLDSAPrivateKeyTrait<k, l, ETA, SK_LEN, PK_LEN>
952 + MLDSAPrivateKeyInternalTrait<k, l, ETA, SK_LEN, PK_LEN>,
953 const PH_LEN: usize,
954 const PK_LEN: usize,
955 const SK_LEN: usize,
956 const SIG_LEN: usize,
957 const TAU: i32,
958 const LAMBDA: i32,
959 const GAMMA1: i32,
960 const GAMMA2: i32,
961 const k: usize,
962 const l: usize,
963 const ETA: usize,
964 const BETA: i32,
965 const OMEGA: i32,
966 const C_TILDE: usize,
967 const POLY_Z_PACKED_LEN: usize,
968 const POLY_W1_PACKED_LEN: usize,
969 const LAMBDA_over_4: usize,
970 const GAMMA1_MINUS_BETA: i32,
971 const GAMMA2_MINUS_BETA: i32,
972 const GAMMA1_MASK_LEN: usize,
973> SignatureVerifier<PK, PK_LEN, SIG_LEN>
974 for HashMLDSA<
975 HASH,
976 PH_LEN,
977 PK_LEN,
978 SK_LEN,
979 SIG_LEN,
980 PK,
981 SK,
982 TAU,
983 LAMBDA,
984 GAMMA1,
985 GAMMA2,
986 k,
987 l,
988 ETA,
989 BETA,
990 OMEGA,
991 C_TILDE,
992 POLY_Z_PACKED_LEN,
993 POLY_W1_PACKED_LEN,
994 LAMBDA_over_4,
995 GAMMA1_MINUS_BETA,
996 GAMMA2_MINUS_BETA,
997 GAMMA1_MASK_LEN,
998 >
999{
1000 fn verify(pk: &PK, msg: &[u8], ctx: Option<&[u8]>, sig: &[u8]) -> Result<(), SignatureError> {
1001 let mut ph_m = [0u8; PH_LEN];
1002 _ = HASH::default().hash_out(msg, &mut ph_m);
1003
1004 Self::verify_ph(pk, &ph_m, ctx, sig)
1005 }
1006
1007 fn verify_init(pk: &PK, ctx: Option<&[u8]>) -> Result<Self, SignatureError> {
1008 let (ctx, ctx_len) = Self::parse_ctx(ctx)?;
1009 Ok(Self {
1010 _phantom: Default::default(),
1011 signer_rnd: None,
1012 sk: None,
1013 seed: None,
1014 pk: Some(pk.clone()),
1015 hash: HASH::default(),
1016 ctx,
1017 ctx_len,
1018 })
1019 }
1020
1021 fn verify_update(&mut self, msg_chunk: &[u8]) {
1022 self.hash.do_update(msg_chunk);
1023 }
1024
1025 fn verify_final(self, sig: &[u8]) -> Result<(), SignatureError> {
1026 assert!(
1027 self.pk.is_some(),
1028 "Somehow you managed to construct a streaming verifier without a public key, impressive!"
1029 );
1030 let ph: [u8; PH_LEN] = self.hash.do_final().try_into().unwrap();
1031 Self::verify_ph(&self.pk.unwrap(), &ph, Some(&self.ctx[..self.ctx_len]), sig)
1032 }
1033}
1034
1035impl<
1036 HASH: Hash + AlgorithmOID + Default,
1037 const PH_LEN: usize,
1038 const PK_LEN: usize,
1039 const SK_LEN: usize,
1040 const SIG_LEN: usize,
1041 PK: MLDSAPublicKeyTrait<k, l, PK_LEN> + MLDSAPublicKeyInternalTrait<k, PK_LEN>,
1042 SK: MLDSAPrivateKeyTrait<k, l, ETA, SK_LEN, PK_LEN>
1043 + MLDSAPrivateKeyInternalTrait<k, l, ETA, SK_LEN, PK_LEN>,
1044 const TAU: i32,
1045 const LAMBDA: i32,
1046 const GAMMA1: i32,
1047 const GAMMA2: i32,
1048 const k: usize,
1049 const l: usize,
1050 const ETA: usize,
1051 const BETA: i32,
1052 const OMEGA: i32,
1053 const C_TILDE: usize,
1054 const POLY_Z_PACKED_LEN: usize,
1055 const POLY_W1_PACKED_LEN: usize,
1056 const LAMBDA_over_4: usize,
1057 const GAMMA1_MASK_LEN: usize,
1058 const GAMMA1_MINUS_BETA: i32,
1059 const GAMMA2_MINUS_BETA: i32,
1060> PHSigner<PK, SK, PK_LEN, SK_LEN, SIG_LEN, PH_LEN>
1061 for HashMLDSA<
1062 HASH,
1063 PH_LEN,
1064 PK_LEN,
1065 SK_LEN,
1066 SIG_LEN,
1067 PK,
1068 SK,
1069 TAU,
1070 LAMBDA,
1071 GAMMA1,
1072 GAMMA2,
1073 k,
1074 l,
1075 ETA,
1076 BETA,
1077 OMEGA,
1078 C_TILDE,
1079 POLY_Z_PACKED_LEN,
1080 POLY_W1_PACKED_LEN,
1081 LAMBDA_over_4,
1082 GAMMA1_MINUS_BETA,
1083 GAMMA2_MINUS_BETA,
1084 GAMMA1_MASK_LEN,
1085 >
1086{
1087 fn sign_ph(
1088 sk: &SK,
1089 ph: &[u8; PH_LEN],
1090 ctx: Option<&[u8]>,
1091 ) -> Result<[u8; SIG_LEN], SignatureError> {
1092 let mut out = [0u8; SIG_LEN];
1093 Self::sign_ph_out(sk, ph, ctx, &mut out)?;
1094
1095 Ok(out)
1096 }
1097
1098 fn sign_ph_out(
1103 sk: &SK,
1104 ph: &[u8; PH_LEN],
1105 ctx: Option<&[u8]>,
1106 output: &mut [u8; SIG_LEN],
1107 ) -> Result<usize, SignatureError> {
1108 output.fill(0);
1109
1110 let mut rnd: [u8; MLDSA_RND_LEN] = [0u8; MLDSA_RND_LEN];
1111 HashDRBG_SHA512::new_from_os().next_bytes_out(&mut rnd)?;
1112 Self::sign_ph_deterministic_out(sk, None, ctx, ph, rnd, output)
1113 }
1114}
1115
1116impl<
1117 HASH: Hash + AlgorithmOID + Default,
1118 const PH_LEN: usize,
1119 const PK_LEN: usize,
1120 const SK_LEN: usize,
1121 const SIG_LEN: usize,
1122 PK: MLDSAPublicKeyTrait<k, l, PK_LEN> + MLDSAPublicKeyInternalTrait<k, PK_LEN>,
1123 SK: MLDSAPrivateKeyTrait<k, l, ETA, SK_LEN, PK_LEN>
1124 + MLDSAPrivateKeyInternalTrait<k, l, ETA, SK_LEN, PK_LEN>,
1125 const TAU: i32,
1126 const LAMBDA: i32,
1127 const GAMMA1: i32,
1128 const GAMMA2: i32,
1129 const k: usize,
1130 const l: usize,
1131 const ETA: usize,
1132 const BETA: i32,
1133 const OMEGA: i32,
1134 const C_TILDE: usize,
1135 const POLY_Z_PACKED_LEN: usize,
1136 const POLY_W1_PACKED_LEN: usize,
1137 const LAMBDA_over_4: usize,
1138 const GAMMA1_MASK_LEN: usize,
1139 const GAMMA1_MINUS_BETA: i32,
1140 const GAMMA2_MINUS_BETA: i32,
1141> PHSignatureVerifier<PK, PK_LEN, SIG_LEN, PH_LEN>
1142 for HashMLDSA<
1143 HASH,
1144 PH_LEN,
1145 PK_LEN,
1146 SK_LEN,
1147 SIG_LEN,
1148 PK,
1149 SK,
1150 TAU,
1151 LAMBDA,
1152 GAMMA1,
1153 GAMMA2,
1154 k,
1155 l,
1156 ETA,
1157 BETA,
1158 OMEGA,
1159 C_TILDE,
1160 POLY_Z_PACKED_LEN,
1161 POLY_W1_PACKED_LEN,
1162 LAMBDA_over_4,
1163 GAMMA1_MINUS_BETA,
1164 GAMMA2_MINUS_BETA,
1165 GAMMA1_MASK_LEN,
1166 >
1167{
1168 fn verify_ph(
1169 pk: &PK,
1170 ph: &[u8; PH_LEN],
1171 ctx: Option<&[u8]>,
1172 sig: &[u8],
1173 ) -> Result<(), SignatureError> {
1174 Self::verify_ph_internal(pk, None, ph, ctx, sig)
1175 }
1176}