1use crate::mldsa::{H, MLDSA_MU_LEN, MLDSA_RND_LEN, MLDSATrait};
67use crate::mldsa::{
68 MLDSA44_BETA, MLDSA44_C_TILDE, MLDSA44_ETA, MLDSA44_GAMMA1, MLDSA44_GAMMA1_MASK_LEN,
69 MLDSA44_GAMMA1_MINUS_BETA, MLDSA44_GAMMA2, MLDSA44_GAMMA2_MINUS_BETA, MLDSA44_LAMBDA,
70 MLDSA44_LAMBDA_over_4, MLDSA44_OMEGA, MLDSA44_PK_LEN, MLDSA44_POLY_W1_PACKED_LEN,
71 MLDSA44_POLY_Z_PACKED_LEN, MLDSA44_SIG_LEN, MLDSA44_SK_LEN, MLDSA44_TAU, MLDSA44_k, MLDSA44_l,
72};
73use crate::mldsa::{
74 MLDSA65_BETA, MLDSA65_C_TILDE, MLDSA65_ETA, MLDSA65_GAMMA1, MLDSA65_GAMMA1_MASK_LEN,
75 MLDSA65_GAMMA1_MINUS_BETA, MLDSA65_GAMMA2, MLDSA65_GAMMA2_MINUS_BETA, MLDSA65_LAMBDA,
76 MLDSA65_LAMBDA_over_4, MLDSA65_OMEGA, MLDSA65_PK_LEN, MLDSA65_POLY_W1_PACKED_LEN,
77 MLDSA65_POLY_Z_PACKED_LEN, MLDSA65_SIG_LEN, MLDSA65_SK_LEN, MLDSA65_TAU, MLDSA65_k, MLDSA65_l,
78};
79use crate::mldsa::{
80 MLDSA87_BETA, MLDSA87_C_TILDE, MLDSA87_ETA, MLDSA87_GAMMA1, MLDSA87_GAMMA1_MASK_LEN,
81 MLDSA87_GAMMA1_MINUS_BETA, MLDSA87_GAMMA2, MLDSA87_GAMMA2_MINUS_BETA, MLDSA87_LAMBDA,
82 MLDSA87_LAMBDA_over_4, MLDSA87_OMEGA, MLDSA87_PK_LEN, MLDSA87_POLY_W1_PACKED_LEN,
83 MLDSA87_POLY_Z_PACKED_LEN, MLDSA87_SIG_LEN, MLDSA87_SK_LEN, MLDSA87_TAU, MLDSA87_k, MLDSA87_l,
84};
85use crate::mldsa_keys::{MLDSAPrivateKeyInternalTrait, MLDSAPublicKeyInternalTrait};
86use crate::{
87 MLDSA, MLDSA44PrivateKey, MLDSA44PublicKey, MLDSA65PrivateKey, MLDSA65PublicKey,
88 MLDSA87PrivateKey, MLDSA87PublicKey, MLDSAPrivateKeyExpanded, MLDSAPrivateKeyTrait,
89 MLDSAPublicKeyExpanded, MLDSAPublicKeyTrait, Matrix,
90};
91use bouncycastle_core::errors::SignatureError;
92use bouncycastle_core::key_material::KeyMaterial;
93use bouncycastle_core::traits::{
94 Algorithm, Hash, PHSignature, RNG, SecurityStrength, Signature, XOF,
95};
96use bouncycastle_rng::HashDRBG_SHA512;
97use bouncycastle_sha2::{SHA256, SHA512};
98use core::marker::PhantomData;
99
100#[allow(unused_imports)]
102use crate::mldsa::MuBuilder;
103
104const SHA256_OID: &[u8] = &[0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01];
105const SHA512_OID: &[u8] = &[0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03];
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 SHA256_OID,
130 MLDSA44_PK_LEN,
131 MLDSA44_SK_LEN,
132 MLDSA44_SIG_LEN,
133 MLDSA44PublicKey,
134 MLDSA44PrivateKey,
135 MLDSA44_TAU,
136 MLDSA44_LAMBDA,
137 MLDSA44_GAMMA1,
138 MLDSA44_GAMMA2,
139 MLDSA44_k,
140 MLDSA44_l,
141 MLDSA44_ETA,
142 MLDSA44_BETA,
143 MLDSA44_OMEGA,
144 MLDSA44_C_TILDE,
145 MLDSA44_POLY_Z_PACKED_LEN,
146 MLDSA44_POLY_W1_PACKED_LEN,
147 MLDSA44_LAMBDA_over_4,
148 MLDSA44_GAMMA1_MASK_LEN,
149 MLDSA44_GAMMA1_MINUS_BETA,
150 MLDSA44_GAMMA2_MINUS_BETA,
151>;
152
153impl Algorithm for HashMLDSA44_with_SHA256 {
154 const ALG_NAME: &'static str = HASH_ML_DSA_44_with_SHA256_NAME;
155 const MAX_SECURITY_STRENGTH: SecurityStrength = SecurityStrength::_128bit;
156}
157
158#[allow(non_camel_case_types)]
160pub type HashMLDSA65_with_SHA256 = HashMLDSA<
161 SHA256,
162 32,
163 SHA256_OID,
164 MLDSA65_PK_LEN,
165 MLDSA65_SK_LEN,
166 MLDSA65_SIG_LEN,
167 MLDSA65PublicKey,
168 MLDSA65PrivateKey,
169 MLDSA65_TAU,
170 MLDSA65_LAMBDA,
171 MLDSA65_GAMMA1,
172 MLDSA65_GAMMA2,
173 MLDSA65_k,
174 MLDSA65_l,
175 MLDSA65_ETA,
176 MLDSA65_BETA,
177 MLDSA65_OMEGA,
178 MLDSA65_C_TILDE,
179 MLDSA65_POLY_Z_PACKED_LEN,
180 MLDSA65_POLY_W1_PACKED_LEN,
181 MLDSA65_LAMBDA_over_4,
182 MLDSA65_GAMMA1_MASK_LEN,
183 MLDSA65_GAMMA1_MINUS_BETA,
184 MLDSA65_GAMMA2_MINUS_BETA,
185>;
186
187impl Algorithm for HashMLDSA65_with_SHA256 {
188 const ALG_NAME: &'static str = HASH_ML_DSA_65_WITH_SHA256_NAME;
189 const MAX_SECURITY_STRENGTH: SecurityStrength = SecurityStrength::_128bit;
190}
191
192#[allow(non_camel_case_types)]
194pub type HashMLDSA87_with_SHA256 = HashMLDSA<
195 SHA256,
196 32,
197 SHA256_OID,
198 MLDSA87_PK_LEN,
199 MLDSA87_SK_LEN,
200 MLDSA87_SIG_LEN,
201 MLDSA87PublicKey,
202 MLDSA87PrivateKey,
203 MLDSA87_TAU,
204 MLDSA87_LAMBDA,
205 MLDSA87_GAMMA1,
206 MLDSA87_GAMMA2,
207 MLDSA87_k,
208 MLDSA87_l,
209 MLDSA87_ETA,
210 MLDSA87_BETA,
211 MLDSA87_OMEGA,
212 MLDSA87_C_TILDE,
213 MLDSA87_POLY_Z_PACKED_LEN,
214 MLDSA87_POLY_W1_PACKED_LEN,
215 MLDSA87_LAMBDA_over_4,
216 MLDSA87_GAMMA1_MASK_LEN,
217 MLDSA87_GAMMA1_MINUS_BETA,
218 MLDSA87_GAMMA2_MINUS_BETA,
219>;
220
221impl Algorithm for HashMLDSA87_with_SHA256 {
222 const ALG_NAME: &'static str = HASH_ML_DSA_87_with_SHA256_NAME;
223 const MAX_SECURITY_STRENGTH: SecurityStrength = SecurityStrength::_128bit;
224}
225
226#[allow(non_camel_case_types)]
228pub type HashMLDSA44_with_SHA512 = HashMLDSA<
229 SHA512,
230 64,
231 SHA512_OID,
232 MLDSA44_PK_LEN,
233 MLDSA44_SK_LEN,
234 MLDSA44_SIG_LEN,
235 MLDSA44PublicKey,
236 MLDSA44PrivateKey,
237 MLDSA44_TAU,
238 MLDSA44_LAMBDA,
239 MLDSA44_GAMMA1,
240 MLDSA44_GAMMA2,
241 MLDSA44_k,
242 MLDSA44_l,
243 MLDSA44_ETA,
244 MLDSA44_BETA,
245 MLDSA44_OMEGA,
246 MLDSA44_C_TILDE,
247 MLDSA44_POLY_Z_PACKED_LEN,
248 MLDSA44_POLY_W1_PACKED_LEN,
249 MLDSA44_LAMBDA_over_4,
250 MLDSA44_GAMMA1_MASK_LEN,
251 MLDSA44_GAMMA1_MINUS_BETA,
252 MLDSA44_GAMMA2_MINUS_BETA,
253>;
254
255impl Algorithm for HashMLDSA44_with_SHA512 {
256 const ALG_NAME: &'static str = HASH_ML_DSA_44_with_SHA512_NAME;
257 const MAX_SECURITY_STRENGTH: SecurityStrength = SecurityStrength::_128bit;
258}
259
260#[allow(non_camel_case_types)]
262pub type HashMLDSA65_with_SHA512 = HashMLDSA<
263 SHA512,
264 64,
265 SHA512_OID,
266 MLDSA65_PK_LEN,
267 MLDSA65_SK_LEN,
268 MLDSA65_SIG_LEN,
269 MLDSA65PublicKey,
270 MLDSA65PrivateKey,
271 MLDSA65_TAU,
272 MLDSA65_LAMBDA,
273 MLDSA65_GAMMA1,
274 MLDSA65_GAMMA2,
275 MLDSA65_k,
276 MLDSA65_l,
277 MLDSA65_ETA,
278 MLDSA65_BETA,
279 MLDSA65_OMEGA,
280 MLDSA65_C_TILDE,
281 MLDSA65_POLY_Z_PACKED_LEN,
282 MLDSA65_POLY_W1_PACKED_LEN,
283 MLDSA65_LAMBDA_over_4,
284 MLDSA65_GAMMA1_MASK_LEN,
285 MLDSA65_GAMMA1_MINUS_BETA,
286 MLDSA65_GAMMA2_MINUS_BETA,
287>;
288
289impl Algorithm for HashMLDSA65_with_SHA512 {
290 const ALG_NAME: &'static str = HASH_ML_DSA_65_WITH_SHA512_NAME;
291 const MAX_SECURITY_STRENGTH: SecurityStrength = SecurityStrength::_192bit;
292}
293
294#[allow(non_camel_case_types)]
296pub type HashMLDSA87_with_SHA512 = HashMLDSA<
297 SHA512,
298 64,
299 SHA512_OID,
300 MLDSA87_PK_LEN,
301 MLDSA87_SK_LEN,
302 MLDSA87_SIG_LEN,
303 MLDSA87PublicKey,
304 MLDSA87PrivateKey,
305 MLDSA87_TAU,
306 MLDSA87_LAMBDA,
307 MLDSA87_GAMMA1,
308 MLDSA87_GAMMA2,
309 MLDSA87_k,
310 MLDSA87_l,
311 MLDSA87_ETA,
312 MLDSA87_BETA,
313 MLDSA87_OMEGA,
314 MLDSA87_C_TILDE,
315 MLDSA87_POLY_Z_PACKED_LEN,
316 MLDSA87_POLY_W1_PACKED_LEN,
317 MLDSA87_LAMBDA_over_4,
318 MLDSA87_GAMMA1_MASK_LEN,
319 MLDSA87_GAMMA1_MINUS_BETA,
320 MLDSA87_GAMMA2_MINUS_BETA,
321>;
322
323impl Algorithm for HashMLDSA87_with_SHA512 {
324 const ALG_NAME: &'static str = HASH_ML_DSA_87_WITH_SHA512_NAME;
325 const MAX_SECURITY_STRENGTH: SecurityStrength = SecurityStrength::_256bit;
326}
327
328pub struct HashMLDSA<
335 HASH: Hash + Default,
336 const HASH_LEN: usize,
337 const oid: &'static [u8],
338 const PK_LEN: usize,
339 const SK_LEN: usize,
340 const SIG_LEN: usize,
341 PK: MLDSAPublicKeyTrait<k, l, PK_LEN> + MLDSAPublicKeyInternalTrait<k, PK_LEN>,
342 SK: MLDSAPrivateKeyTrait<k, l, ETA, SK_LEN, PK_LEN>
343 + MLDSAPrivateKeyInternalTrait<k, l, ETA, SK_LEN, PK_LEN>,
344 const TAU: i32,
345 const LAMBDA: i32,
346 const GAMMA1: i32,
347 const GAMMA2: i32,
348 const k: usize,
349 const l: usize,
350 const ETA: usize,
351 const BETA: i32,
352 const OMEGA: i32,
353 const C_TILDE: usize,
354 const POLY_Z_PACKED_LEN: usize,
355 const POLY_W1_PACKED_LEN: usize,
356 const LAMBDA_over_4: usize,
357 const GAMMA1_MASK_LEN: usize,
358 const GAMMA1_MINUS_BETA: i32,
359 const GAMMA2_MINUS_BETA: i32,
360> {
361 _phantom: PhantomData<(PK, SK)>,
362
363 signer_rnd: Option<[u8; MLDSA_RND_LEN]>,
364
365 sk: Option<SK>,
367
368 seed: Option<KeyMaterial<32>>,
370
371 pk: Option<PK>,
373
374 hash: HASH,
376
377 ctx: [u8; 255],
380 ctx_len: usize,
381}
382
383impl<
384 HASH: Hash + Default,
385 const PH_LEN: usize,
386 const oid: &'static [u8],
387 const PK_LEN: usize,
388 const SK_LEN: usize,
389 const SIG_LEN: usize,
390 PK: MLDSAPublicKeyTrait<k, l, PK_LEN> + MLDSAPublicKeyInternalTrait<k, PK_LEN>,
391 SK: MLDSAPrivateKeyTrait<k, l, ETA, SK_LEN, PK_LEN>
392 + MLDSAPrivateKeyInternalTrait<k, l, ETA, SK_LEN, PK_LEN>,
393 const TAU: i32,
394 const LAMBDA: i32,
395 const GAMMA1: i32,
396 const GAMMA2: i32,
397 const k: usize,
398 const l: usize,
399 const ETA: usize,
400 const BETA: i32,
401 const OMEGA: i32,
402 const C_TILDE: usize,
403 const POLY_Z_PACKED_LEN: usize,
404 const POLY_W1_PACKED_LEN: usize,
405 const LAMBDA_over_4: usize,
406 const GAMMA1_MASK_LEN: usize,
407 const GAMMA1_MINUS_BETA: i32,
408 const GAMMA2_MINUS_BETA: i32,
409>
410 HashMLDSA<
411 HASH,
412 PH_LEN,
413 oid,
414 PK_LEN,
415 SK_LEN,
416 SIG_LEN,
417 PK,
418 SK,
419 TAU,
420 LAMBDA,
421 GAMMA1,
422 GAMMA2,
423 k,
424 l,
425 ETA,
426 BETA,
427 OMEGA,
428 C_TILDE,
429 POLY_Z_PACKED_LEN,
430 POLY_W1_PACKED_LEN,
431 LAMBDA_over_4,
432 GAMMA1_MASK_LEN,
433 GAMMA1_MINUS_BETA,
434 GAMMA2_MINUS_BETA,
435 >
436{
437 pub fn keygen_from_seed(seed: &KeyMaterial<32>) -> Result<(PK, SK), SignatureError> {
439 MLDSA::<
440 PK_LEN,
441 SK_LEN,
442 SIG_LEN,
443 PK,
444 SK,
445 TAU,
446 LAMBDA,
447 GAMMA1,
448 GAMMA2,
449 k,
450 l,
451 ETA,
452 BETA,
453 OMEGA,
454 C_TILDE,
455 POLY_Z_PACKED_LEN,
456 POLY_W1_PACKED_LEN,
457 LAMBDA_over_4,
458 GAMMA1_MASK_LEN,
459 GAMMA1_MINUS_BETA,
460 GAMMA2_MINUS_BETA,
461 >::keygen_internal(seed)
462 }
463 pub fn sign_with_expanded_key(
465 sk: &MLDSAPrivateKeyExpanded<k, l, ETA, PK, SK, SK_LEN, PK_LEN>,
466 msg: &[u8],
467 ctx: Option<&[u8]>,
468 ) -> Result<[u8; SIG_LEN], SignatureError> {
469 let mut out = [0u8; SIG_LEN];
470 Self::sign_with_expanded_key_out(sk, msg, ctx, &mut out)?;
471
472 Ok(out)
473 }
474 pub fn sign_with_expanded_key_out(
476 sk: &MLDSAPrivateKeyExpanded<k, l, ETA, PK, SK, SK_LEN, PK_LEN>,
477 msg: &[u8],
478 ctx: Option<&[u8]>,
479 output: &mut [u8; SIG_LEN],
480 ) -> Result<usize, SignatureError> {
481 let mut ph_m = [0u8; PH_LEN];
482 _ = HASH::default().hash_out(msg, &mut ph_m);
483 Self::sign_ph_with_expanded_key_out(sk, &ph_m, ctx, output)
484 }
485 pub fn sign_ph_with_expanded_key(
487 sk: &MLDSAPrivateKeyExpanded<k, l, ETA, PK, SK, SK_LEN, PK_LEN>,
488 ph: &[u8; PH_LEN],
489 ctx: Option<&[u8]>,
490 ) -> Result<[u8; SIG_LEN], SignatureError> {
491 let mut out = [0u8; SIG_LEN];
492 _ = Self::sign_ph_with_expanded_key_out(sk, ph, ctx, &mut out);
493
494 Ok(out)
495 }
496 pub fn sign_ph_with_expanded_key_out(
498 sk: &MLDSAPrivateKeyExpanded<k, l, ETA, PK, SK, SK_LEN, PK_LEN>,
499 ph: &[u8; PH_LEN],
500 ctx: Option<&[u8]>,
501 output: &mut [u8; SIG_LEN],
502 ) -> Result<usize, SignatureError> {
503 let mut rnd: [u8; MLDSA_RND_LEN] = [0u8; MLDSA_RND_LEN];
504 HashDRBG_SHA512::new_from_os().next_bytes_out(&mut rnd)?;
505 Self::sign_ph_deterministic_out(&sk.sk, Some(&sk.A_hat), ctx, ph, rnd, output)
506 }
507 pub fn sign_ph_deterministic(
521 sk: &SK,
522 A_hat: Option<&Matrix<k, l>>,
523 ctx: Option<&[u8]>,
524 ph: &[u8; PH_LEN],
525 rnd: [u8; 32],
526 ) -> Result<[u8; SIG_LEN], SignatureError> {
527 let mut out: [u8; SIG_LEN] = [0u8; SIG_LEN];
528 Self::sign_ph_deterministic_out(sk, A_hat, ctx, ph, rnd, &mut out)?;
529 Ok(out)
530 }
531 pub fn sign_ph_deterministic_out(
544 sk: &SK,
545 A_hat: Option<&Matrix<k, l>>,
546 ctx: Option<&[u8]>,
547 ph: &[u8; PH_LEN],
548 rnd: [u8; 32],
549 output: &mut [u8; SIG_LEN],
550 ) -> Result<usize, SignatureError> {
551 let ctx = if ctx.is_some() { ctx.unwrap() } else { &[] };
552
553 if ctx.len() > 255 {
556 return Err(SignatureError::LengthError("ctx value is longer than 255 bytes"));
557 }
558
559 let mu = {
562 let mut h = H::new();
563 h.absorb(sk.tr());
564
565 h.absorb(&[1u8]);
569 h.absorb(&[ctx.len() as u8]);
570 h.absorb(ctx);
571 h.absorb(oid);
572 h.absorb(ph);
573 let mut mu = [0u8; MLDSA_MU_LEN];
574 let bytes_written = h.squeeze_out(&mut mu);
575 debug_assert_eq!(bytes_written, MLDSA_MU_LEN);
576
577 mu
578 };
579
580 let bytes_written = MLDSA::<
582 PK_LEN,
583 SK_LEN,
584 SIG_LEN,
585 PK,
586 SK,
587 TAU,
588 LAMBDA,
589 GAMMA1,
590 GAMMA2,
591 k,
592 l,
593 ETA,
594 BETA,
595 OMEGA,
596 C_TILDE,
597 POLY_Z_PACKED_LEN,
598 POLY_W1_PACKED_LEN,
599 LAMBDA_over_4,
600 GAMMA1_MASK_LEN,
601 GAMMA1_MINUS_BETA,
602 GAMMA2_MINUS_BETA,
603 >::sign_mu_deterministic_out(sk, A_hat, &mu, rnd, output)?;
604
605 Ok(bytes_written)
606 }
607
608 pub fn set_signer_rnd(&mut self, rnd: [u8; 32]) {
612 self.signer_rnd = Some(rnd);
613 }
614
615 fn parse_ctx(ctx: Option<&[u8]>) -> Result<([u8; 255], usize), SignatureError> {
616 if ctx.is_some() {
617 if ctx.unwrap().len() > 255 {
620 return Err(SignatureError::LengthError("ctx value is longer than 255 bytes"));
621 }
622
623 let mut ctx_buf = [0u8; 255];
624 ctx_buf[..ctx.unwrap().len()].copy_from_slice(ctx.unwrap());
625 Ok((ctx_buf, ctx.unwrap().len()))
626 } else {
627 Ok(([0u8; 255], 0))
628 }
629 }
630
631 pub fn sign_init_from_seed(
634 seed: &KeyMaterial<32>,
635 ctx: Option<&[u8]>,
636 ) -> Result<Self, SignatureError> {
637 let (ctx, ctx_len) = Self::parse_ctx(ctx)?;
638 Ok(Self {
639 _phantom: PhantomData,
640 signer_rnd: None,
641 sk: None,
642 seed: Some(seed.clone()),
643 pk: None,
644 hash: HASH::default(),
645 ctx,
646 ctx_len,
647 })
648 }
649 pub fn verify_with_expanded_key(
651 pk: &MLDSAPublicKeyExpanded<k, l, PK, PK_LEN>,
652 msg: &[u8],
653 ctx: Option<&[u8]>,
654 sig: &[u8],
655 ) -> Result<(), SignatureError> {
656 let mut ph_m = [0u8; PH_LEN];
657 _ = HASH::default().hash_out(msg, &mut ph_m);
658
659 Self::verify_ph_internal(&pk.pk, Some(&pk.A_hat()), &ph_m, ctx, sig)
660 }
661
662 fn verify_ph_internal(
663 pk: &PK,
664 A_hat: Option<&Matrix<k, l>>,
665 ph: &[u8; PH_LEN],
666 ctx: Option<&[u8]>,
667 sig: &[u8],
668 ) -> Result<(), SignatureError> {
669 if sig.len() != SIG_LEN {
670 return Err(SignatureError::LengthError("Signature value is not the correct length."));
671 }
672 let sig_sized: &[u8; SIG_LEN] = sig[..SIG_LEN].try_into().unwrap();
673
674 let ctx = if ctx.is_some() { ctx.unwrap() } else { &[] };
675
676 if ctx.len() > 255 {
679 return Err(SignatureError::LengthError("ctx value is longer than 255 bytes"));
680 }
681
682 let mu = {
685 let mut h = H::new();
686 h.absorb(&pk.compute_tr());
687
688 h.absorb(&[1u8]);
692 h.absorb(&[ctx.len() as u8]);
693 h.absorb(ctx);
694 h.absorb(oid);
695 h.absorb(ph);
696 let mut mu = [0u8; MLDSA_MU_LEN];
697 _ = h.squeeze_out(&mut mu);
698
699 mu
700 };
701
702 match A_hat {
703 Some(A_hat) => {
704 if MLDSA::<
705 PK_LEN,
706 SK_LEN,
707 SIG_LEN,
708 PK,
709 SK,
710 TAU,
711 LAMBDA,
712 GAMMA1,
713 GAMMA2,
714 k,
715 l,
716 ETA,
717 BETA,
718 OMEGA,
719 C_TILDE,
720 POLY_Z_PACKED_LEN,
721 POLY_W1_PACKED_LEN,
722 LAMBDA_over_4,
723 GAMMA1_MASK_LEN,
724 GAMMA1_MINUS_BETA,
725 GAMMA2_MINUS_BETA,
726 >::verify_mu_internal(pk, A_hat, &mu, sig_sized)
727 {
728 Ok(())
729 } else {
730 Err(SignatureError::SignatureVerificationFailed)
731 }
732 }
733 None => {
734 if MLDSA::<
735 PK_LEN,
736 SK_LEN,
737 SIG_LEN,
738 PK,
739 SK,
740 TAU,
741 LAMBDA,
742 GAMMA1,
743 GAMMA2,
744 k,
745 l,
746 ETA,
747 BETA,
748 OMEGA,
749 C_TILDE,
750 POLY_Z_PACKED_LEN,
751 POLY_W1_PACKED_LEN,
752 LAMBDA_over_4,
753 GAMMA1_MASK_LEN,
754 GAMMA1_MINUS_BETA,
755 GAMMA2_MINUS_BETA,
756 >::verify_mu_internal(pk, &pk.A_hat(), &mu, sig_sized)
757 {
758 Ok(())
759 } else {
760 Err(SignatureError::SignatureVerificationFailed)
761 }
762 }
763 }
764 }
765}
766
767impl<
768 HASH: Hash + Default,
769 PK: MLDSAPublicKeyTrait<k, l, PK_LEN> + MLDSAPublicKeyInternalTrait<k, PK_LEN>,
770 SK: MLDSAPrivateKeyTrait<k, l, ETA, SK_LEN, PK_LEN>
771 + MLDSAPrivateKeyInternalTrait<k, l, ETA, SK_LEN, PK_LEN>,
772 const PH_LEN: usize,
773 const oid: &'static [u8],
774 const PK_LEN: usize,
775 const SK_LEN: usize,
776 const SIG_LEN: usize,
777 const TAU: i32,
778 const LAMBDA: i32,
779 const GAMMA1: i32,
780 const GAMMA2: i32,
781 const k: usize,
782 const l: usize,
783 const ETA: usize,
784 const BETA: i32,
785 const OMEGA: i32,
786 const C_TILDE: usize,
787 const POLY_Z_PACKED_LEN: usize,
788 const POLY_W1_PACKED_LEN: usize,
789 const LAMBDA_over_4: usize,
790 const GAMMA1_MASK_LEN: usize,
791 const GAMMA1_MINUS_BETA: i32,
792 const GAMMA2_MINUS_BETA: i32,
793> Signature<PK, SK, PK_LEN, SK_LEN, SIG_LEN>
794 for HashMLDSA<
795 HASH,
796 PH_LEN,
797 oid,
798 PK_LEN,
799 SK_LEN,
800 SIG_LEN,
801 PK,
802 SK,
803 TAU,
804 LAMBDA,
805 GAMMA1,
806 GAMMA2,
807 k,
808 l,
809 ETA,
810 BETA,
811 OMEGA,
812 C_TILDE,
813 POLY_Z_PACKED_LEN,
814 POLY_W1_PACKED_LEN,
815 LAMBDA_over_4,
816 GAMMA1_MASK_LEN,
817 GAMMA1_MINUS_BETA,
818 GAMMA2_MINUS_BETA,
819 >
820{
821 fn keygen() -> Result<(PK, SK), SignatureError> {
823 MLDSA::<
824 PK_LEN,
825 SK_LEN,
826 SIG_LEN,
827 PK,
828 SK,
829 TAU,
830 LAMBDA,
831 GAMMA1,
832 GAMMA2,
833 k,
834 l,
835 ETA,
836 BETA,
837 OMEGA,
838 C_TILDE,
839 POLY_Z_PACKED_LEN,
840 POLY_W1_PACKED_LEN,
841 LAMBDA_over_4,
842 GAMMA1_MASK_LEN,
843 GAMMA1_MINUS_BETA,
844 GAMMA2_MINUS_BETA,
845 >::keygen()
846 }
847
848 fn sign(sk: &SK, msg: &[u8], ctx: Option<&[u8]>) -> Result<[u8; SIG_LEN], SignatureError> {
851 let mut out = [0u8; SIG_LEN];
852 Self::sign_out(sk, msg, ctx, &mut out)?;
853
854 Ok(out)
855 }
856
857 fn sign_out(
858 sk: &SK,
859 msg: &[u8],
860 ctx: Option<&[u8]>,
861 output: &mut [u8; SIG_LEN],
862 ) -> Result<usize, SignatureError> {
863 let mut ph_m = [0u8; PH_LEN];
864 _ = HASH::default().hash_out(msg, &mut ph_m);
865 Self::sign_ph_out(sk, &ph_m, ctx, output)
866 }
867
868 fn sign_init(sk: &SK, ctx: Option<&[u8]>) -> Result<Self, SignatureError> {
869 let (ctx, ctx_len) = Self::parse_ctx(ctx)?;
870 Ok(Self {
871 _phantom: PhantomData,
872 signer_rnd: None,
873 sk: Some(sk.clone()),
874 seed: None,
875 pk: None,
876 hash: HASH::default(),
877 ctx,
878 ctx_len,
879 })
880 }
881
882 fn sign_update(&mut self, msg_chunk: &[u8]) {
883 self.hash.do_update(msg_chunk);
884 }
885
886 fn sign_final(self) -> Result<[u8; SIG_LEN], SignatureError> {
887 let mut out = [0u8; SIG_LEN];
888 self.sign_final_out(&mut out)?;
889 Ok(out)
890 }
891
892 fn sign_final_out(self, output: &mut [u8; SIG_LEN]) -> Result<usize, SignatureError> {
893 let ph: [u8; PH_LEN] = self.hash.do_final().try_into().unwrap();
894
895 if self.sk.is_none() && self.seed.is_none() {
896 return Err(SignatureError::GenericError(
897 "Somehow you managed to construct a streaming signer without a private key, impressive!",
898 ));
899 }
900
901 if output.len() < SIG_LEN {
902 return Err(SignatureError::LengthError(
903 "Output buffer insufficient size to hold signature",
904 ));
905 }
906 let output_sized: &mut [u8; SIG_LEN] = output[..SIG_LEN].as_mut().try_into().unwrap();
907
908 if self.sk.is_some() {
909 if self.signer_rnd.is_none() {
910 Self::sign_ph_out(
911 &self.sk.unwrap(),
912 &ph,
913 Some(&self.ctx[..self.ctx_len]),
914 output_sized,
915 )
916 } else {
917 Self::sign_ph_deterministic_out(
918 &self.sk.unwrap(),
919 None,
920 Some(&self.ctx[..self.ctx_len]),
921 &ph,
922 self.signer_rnd.unwrap(),
923 output_sized,
924 )
925 }
926 } else if self.seed.is_some() {
927 let rnd = if self.signer_rnd.is_some() {
928 self.signer_rnd.unwrap()
929 } else {
930 let mut rnd: [u8; MLDSA_RND_LEN] = [0u8; MLDSA_RND_LEN];
931 HashDRBG_SHA512::new_from_os().next_bytes_out(&mut rnd)?;
932 rnd
933 };
934 let (_pk, sk) = Self::keygen_from_seed(&self.seed.unwrap())?;
937 Self::sign_ph_deterministic_out(
938 &sk,
939 None,
940 Some(&self.ctx[..self.ctx_len]),
941 &ph,
942 rnd,
943 output_sized,
944 )
945 } else {
946 unreachable!()
947 }
948 }
949
950 fn verify(pk: &PK, msg: &[u8], ctx: Option<&[u8]>, sig: &[u8]) -> Result<(), SignatureError> {
951 let mut ph_m = [0u8; PH_LEN];
952 _ = HASH::default().hash_out(msg, &mut ph_m);
953
954 Self::verify_ph(pk, &ph_m, ctx, sig)
955 }
956
957 fn verify_init(pk: &PK, ctx: Option<&[u8]>) -> Result<Self, SignatureError> {
958 let (ctx, ctx_len) = Self::parse_ctx(ctx)?;
959 Ok(Self {
960 _phantom: Default::default(),
961 signer_rnd: None,
962 sk: None,
963 seed: None,
964 pk: Some(pk.clone()),
965 hash: HASH::default(),
966 ctx,
967 ctx_len,
968 })
969 }
970
971 fn verify_update(&mut self, msg_chunk: &[u8]) {
972 self.hash.do_update(msg_chunk);
973 }
974
975 fn verify_final(self, sig: &[u8]) -> Result<(), SignatureError> {
976 assert!(
977 self.pk.is_some(),
978 "Somehow you managed to construct a streaming verifier without a public key, impressive!"
979 );
980 let ph: [u8; PH_LEN] = self.hash.do_final().try_into().unwrap();
981 Self::verify_ph(&self.pk.unwrap(), &ph, Some(&self.ctx[..self.ctx_len]), sig)
982 }
983}
984
985impl<
986 HASH: Hash + Default,
987 const PH_LEN: usize,
988 const oid: &'static [u8],
989 const PK_LEN: usize,
990 const SK_LEN: usize,
991 const SIG_LEN: usize,
992 PK: MLDSAPublicKeyTrait<k, l, PK_LEN> + MLDSAPublicKeyInternalTrait<k, PK_LEN>,
993 SK: MLDSAPrivateKeyTrait<k, l, ETA, SK_LEN, PK_LEN>
994 + MLDSAPrivateKeyInternalTrait<k, l, ETA, SK_LEN, PK_LEN>,
995 const TAU: i32,
996 const LAMBDA: i32,
997 const GAMMA1: i32,
998 const GAMMA2: i32,
999 const k: usize,
1000 const l: usize,
1001 const ETA: usize,
1002 const BETA: i32,
1003 const OMEGA: i32,
1004 const C_TILDE: usize,
1005 const POLY_Z_PACKED_LEN: usize,
1006 const POLY_W1_PACKED_LEN: usize,
1007 const LAMBDA_over_4: usize,
1008 const GAMMA1_MASK_LEN: usize,
1009 const GAMMA1_MINUS_BETA: i32,
1010 const GAMMA2_MINUS_BETA: i32,
1011> PHSignature<PK, SK, PK_LEN, SK_LEN, SIG_LEN, PH_LEN>
1012 for HashMLDSA<
1013 HASH,
1014 PH_LEN,
1015 oid,
1016 PK_LEN,
1017 SK_LEN,
1018 SIG_LEN,
1019 PK,
1020 SK,
1021 TAU,
1022 LAMBDA,
1023 GAMMA1,
1024 GAMMA2,
1025 k,
1026 l,
1027 ETA,
1028 BETA,
1029 OMEGA,
1030 C_TILDE,
1031 POLY_Z_PACKED_LEN,
1032 POLY_W1_PACKED_LEN,
1033 LAMBDA_over_4,
1034 GAMMA1_MASK_LEN,
1035 GAMMA1_MINUS_BETA,
1036 GAMMA2_MINUS_BETA,
1037 >
1038{
1039 fn sign_ph(
1040 sk: &SK,
1041 ph: &[u8; PH_LEN],
1042 ctx: Option<&[u8]>,
1043 ) -> Result<[u8; SIG_LEN], SignatureError> {
1044 let mut out = [0u8; SIG_LEN];
1045 Self::sign_out(sk, ph, ctx, &mut out)?;
1046
1047 Ok(out)
1048 }
1049
1050 fn sign_ph_out(
1055 sk: &SK,
1056 ph: &[u8; PH_LEN],
1057 ctx: Option<&[u8]>,
1058 output: &mut [u8; SIG_LEN],
1059 ) -> Result<usize, SignatureError> {
1060 let mut rnd: [u8; MLDSA_RND_LEN] = [0u8; MLDSA_RND_LEN];
1061 HashDRBG_SHA512::new_from_os().next_bytes_out(&mut rnd)?;
1062 Self::sign_ph_deterministic_out(sk, None, ctx, ph, rnd, output)
1063 }
1064
1065 fn verify_ph(
1066 pk: &PK,
1067 ph: &[u8; PH_LEN],
1068 ctx: Option<&[u8]>,
1069 sig: &[u8],
1070 ) -> Result<(), SignatureError> {
1071 Self::verify_ph_internal(pk, None, ph, ctx, sig)
1072 }
1073}