1- //! Note in docs that this is just a light wrapper around [MLDSA], and, for example, the share key types,
1+ //! This implements the HashML-DSA algorithm specified in FIPS 204 which is useful for cases
2+ //! where you need to process the to-be-signed message in chunks, and you cannot use the external mu
3+ //! mode of [MLDSA]; possibly because you have to digest the message before you know which public key
4+ //! will sign it.
5+ //!
6+ //! HashML-DSA is a full signature algorithm implementing the [Signature] trait:
7+ //!
8+ //! ```rust
9+ //! use bouncycastle_core_interface::errors::SignatureError;
10+ //! use bouncycastle_mldsa::{HashMLDSA65_with_SHA512, MLDSATrait, HashMLDSA44_with_SHA512};
11+ //! use bouncycastle_core_interface::traits::Signature;
12+ //!
13+ //! let msg = b"The quick brown fox jumped over the lazy dog";
14+ //!
15+ //! let (pk, sk) = HashMLDSA65_with_SHA512::keygen().unwrap();
16+ //!
17+ //! let sig: Vec<u8> = HashMLDSA65_with_SHA512::sign(&sk, msg, None).unwrap();
18+ //! // This is the signature value that you can save to a file or whatever you need.
19+ //!
20+ //! match HashMLDSA65_with_SHA512::verify(&pk, msg, None, &sig) {
21+ //! Ok(()) => println!("Signature is valid!"),
22+ //! Err(SignatureError::SignatureVerificationFailed) => println!("Signature is invalid!"),
23+ //! Err(e) => panic!("Something else went wrong: {:?}", e),
24+ //! }
25+ //! ```
26+ //!
27+ //! But you also have access to the pre-hashed function available from [PHSignature]:
28+ //!
29+ //! ```rust
30+ //! use bouncycastle_core_interface::errors::SignatureError;
31+ //! use bouncycastle_mldsa::{HashMLDSA65_with_SHA512, MLDSATrait, HashMLDSA44_with_SHA512};
32+ //! use bouncycastle_core_interface::traits::{Signature, PHSignature, Hash};
33+ //! use bouncycastle_sha2::SHA512;
34+ //!
35+ //! let msg = b"The quick brown fox jumped over the lazy dog";
36+ //!
37+ //! // Here, and in contrast to External Mu mode of ML-DSA, we can pre-hash the message before
38+ //! // even generating the signing key.
39+ //! let ph: [u8; 64] = SHA512::default().hash(msg).as_slice().try_into().unwrap();
40+ //!
41+ //!
42+ //! let (pk, sk) = HashMLDSA65_with_SHA512::keygen().unwrap();
43+ //!
44+ //! let sig: Vec<u8> = HashMLDSA65_with_SHA512::sign_ph(&sk, &ph, None).unwrap();
45+ //! // This is the signature value that you can save to a file or whatever you need.
46+ //!
47+ //! // This verifies either through the usual one-shot API of the [Signature] trait
48+ //! match HashMLDSA65_with_SHA512::verify(&pk, msg, None, &sig) {
49+ //! Ok(()) => println!("Signature is valid!"),
50+ //! Err(SignatureError::SignatureVerificationFailed) => println!("Signature is invalid!"),
51+ //! Err(e) => panic!("Something else went wrong: {:?}", e),
52+ //! }
53+ //!
54+ //! // Or though the verify_ph of the [PHSignature] trait
55+ //! match HashMLDSA65_with_SHA512::verify_ph(&pk, &ph, None, &sig) {
56+ //! Ok(()) => println!("Signature is valid!"),
57+ //! Err(SignatureError::SignatureVerificationFailed) => println!("Signature is invalid!"),
58+ //! Err(e) => panic!("Something else went wrong: {:?}", e),
59+ //! }
60+ //! ```
61+ //!
62+ //! Note that the [HashMLDSA] object is just a light wrapper around [MLDSA], and, for example, they share key types,
263//! so if you need the fancy keygen functions, just use them from [MLDSA].
3- //! But a simple [HashMLDSA::keygen] is provided in order to have conformance to the [PHSignature ] trait.
64+ //! But a simple [HashMLDSA::keygen] is provided in order to have conformance to the [Signature ] trait.
465
566use std:: marker:: PhantomData ;
667use crate :: mldsa:: { H , MLDSATrait , MU_LEN , RND_LEN } ;
@@ -23,10 +84,10 @@ use crate::mldsa::{
2384 MLDSA87_SIG_LEN , MLDSA87_SK_LEN , MLDSA87_TAU , MLDSA87_W1_PACKED_LEN , MLDSA87_k , MLDSA87_l ,
2485} ;
2586use crate :: mldsa_keys:: { MLDSAPrivateKeyInternalTrait , MLDSAPublicKeyInternalTrait } ;
26- use crate :: { MLDSA , MLDSA44PrivateKey , MLDSA44PublicKey , MLDSA65PrivateKey , MLDSA65PublicKey , MLDSA87PrivateKey , MLDSA87PublicKey , MLDSAPrivateKeyTrait , MLDSAPublicKeyTrait , MuBuilder } ;
87+ use crate :: { MLDSA , MLDSA44PrivateKey , MLDSA44PublicKey , MLDSA65PrivateKey , MLDSA65PublicKey , MLDSA87PrivateKey , MLDSA87PublicKey , MLDSAPrivateKeyTrait , MLDSAPublicKeyTrait } ;
2788use bouncycastle_core_interface:: errors:: SignatureError ;
2889use bouncycastle_core_interface:: key_material:: KeyMaterialSized ;
29- use bouncycastle_core_interface:: traits:: { Hash , PHSignature , RNG , Signature , XOF } ;
90+ use bouncycastle_core_interface:: traits:: { Hash , PHSignature , RNG , Signature , XOF , Algorithm , SecurityStrength } ;
3091use bouncycastle_rng:: HashDRBG_SHA512 ;
3192use bouncycastle_sha2:: { SHA256 , SHA512 } ;
3293
@@ -35,15 +96,22 @@ const SHA512_OID: &[u8] = &[0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04
3596
3697/*** Constants ***/
3798
99+ ///
38100pub const Hash_ML_DSA_44_with_SHA256_NAME : & str = "HashML-DSA-44_with_SHA256" ;
101+ ///
39102pub const Hash_ML_DSA_65_with_SHA256_NAME : & str = "HashML-DSA-65_with_SHA256" ;
103+ ///
40104pub const Hash_ML_DSA_87_with_SHA256_NAME : & str = "HashML-DSA-87_with_SHA256" ;
41-
105+ ///
42106pub const Hash_ML_DSA_44_with_SHA512_NAME : & str = "HashML-DSA-44_with_SHA512" ;
107+ ///
43108pub const Hash_ML_DSA_65_with_SHA512_NAME : & str = "HashML-DSA-65_with_SHA512" ;
109+ ///
44110pub const Hash_ML_DSA_87_with_SHA512_NAME : & str = "HashML-DSA-87_with_SHA512" ;
45111
46112/*** Pub Types ***/
113+
114+ /// The HashML-DSA-44_with_SHA512 signature algorithm.
47115#[ allow( non_camel_case_types) ]
48116pub type HashMLDSA44_with_SHA256 = HashMLDSA <
49117 SHA256 ,
@@ -72,6 +140,12 @@ pub type HashMLDSA44_with_SHA256 = HashMLDSA<
72140 MLDSA44_GAMMA1_MASK_LEN ,
73141> ;
74142
143+ impl Algorithm for HashMLDSA44_with_SHA256 {
144+ const ALG_NAME : & ' static str = Hash_ML_DSA_44_with_SHA256_NAME ;
145+ const MAX_SECURITY_STRENGTH : SecurityStrength = SecurityStrength :: _128bit;
146+ }
147+
148+ /// The HashML-DSA-65_with_SHA256 signature algorithm.
75149#[ allow( non_camel_case_types) ]
76150pub type HashMLDSA65_with_SHA256 = HashMLDSA <
77151 SHA256 ,
@@ -100,6 +174,12 @@ pub type HashMLDSA65_with_SHA256 = HashMLDSA<
100174 MLDSA65_GAMMA1_MASK_LEN ,
101175> ;
102176
177+ impl Algorithm for HashMLDSA65_with_SHA256 {
178+ const ALG_NAME : & ' static str = Hash_ML_DSA_65_with_SHA256_NAME ;
179+ const MAX_SECURITY_STRENGTH : SecurityStrength = SecurityStrength :: _128bit;
180+ }
181+
182+ /// The HashML-DSA-87_with_SHA256 signature algorithm.
103183#[ allow( non_camel_case_types) ]
104184pub type HashMLDSA87_with_SHA256 = HashMLDSA <
105185 SHA256 ,
@@ -128,6 +208,12 @@ pub type HashMLDSA87_with_SHA256 = HashMLDSA<
128208 MLDSA87_GAMMA1_MASK_LEN ,
129209> ;
130210
211+ impl Algorithm for HashMLDSA87_with_SHA256 {
212+ const ALG_NAME : & ' static str = Hash_ML_DSA_87_with_SHA256_NAME ;
213+ const MAX_SECURITY_STRENGTH : SecurityStrength = SecurityStrength :: _128bit;
214+ }
215+
216+ /// The HashML-DSA-44_with_SHA512 signature algorithm.
131217#[ allow( non_camel_case_types) ]
132218pub type HashMLDSA44_with_SHA512 = HashMLDSA <
133219 SHA512 ,
@@ -156,6 +242,12 @@ pub type HashMLDSA44_with_SHA512 = HashMLDSA<
156242 MLDSA44_GAMMA1_MASK_LEN ,
157243> ;
158244
245+ impl Algorithm for HashMLDSA44_with_SHA512 {
246+ const ALG_NAME : & ' static str = Hash_ML_DSA_44_with_SHA512_NAME ;
247+ const MAX_SECURITY_STRENGTH : SecurityStrength = SecurityStrength :: _128bit;
248+ }
249+
250+ /// The HashML-DSA-65_with_SHA512 signature algorithm.
159251#[ allow( non_camel_case_types) ]
160252pub type HashMLDSA65_with_SHA512 = HashMLDSA <
161253 SHA512 ,
@@ -184,6 +276,12 @@ pub type HashMLDSA65_with_SHA512 = HashMLDSA<
184276 MLDSA65_GAMMA1_MASK_LEN ,
185277> ;
186278
279+ impl Algorithm for HashMLDSA65_with_SHA512 {
280+ const ALG_NAME : & ' static str = Hash_ML_DSA_65_with_SHA512_NAME ;
281+ const MAX_SECURITY_STRENGTH : SecurityStrength = SecurityStrength :: _192bit;
282+ }
283+
284+ /// The HashML-DSA-87_with_SHA512 signature algorithm.
187285#[ allow( non_camel_case_types) ]
188286pub type HashMLDSA87_with_SHA512 = HashMLDSA <
189287 SHA512 ,
@@ -212,6 +310,11 @@ pub type HashMLDSA87_with_SHA512 = HashMLDSA<
212310 MLDSA87_GAMMA1_MASK_LEN ,
213311> ;
214312
313+ impl Algorithm for HashMLDSA87_with_SHA512 {
314+ const ALG_NAME : & ' static str = Hash_ML_DSA_87_with_SHA512_NAME ;
315+ const MAX_SECURITY_STRENGTH : SecurityStrength = SecurityStrength :: _256bit;
316+ }
317+
215318/// An instance of the HashML-DSA algorithm.
216319///
217320/// We are exposing the HashMLDSA struct this way so that alternative hash functions can be used
@@ -465,7 +568,7 @@ impl<
465568 Ok ( ( [ 0u8 ; 255 ] , 0 ) )
466569 }
467570 }
468-
571+
469572 /// Alternative initialization of the streaming signer where you have your private key
470573 /// as a seed and you want to delay its expansion as late as possible for memory-usage reasons.
471574 pub fn sign_init_from_seed ( seed : & KeyMaterialSized < 32 > , ctx : Option < & [ u8 ] > ) -> Result < Self , SignatureError > {
@@ -624,7 +727,7 @@ impl<
624727
625728 if self . sk . is_some ( ) {
626729 if self . signer_rnd . is_none ( ) {
627- Self :: sign_ph_out ( & self . sk . unwrap ( ) , & ph, Some ( & self . ctx ) , output_sized)
730+ Self :: sign_ph_out ( & self . sk . unwrap ( ) , & ph, Some ( & self . ctx [ .. self . ctx_len ] ) , output_sized)
628731 } else {
629732 Self :: sign_ph_deterministic_out ( & self . sk . unwrap ( ) , Some ( & self . ctx [ ..self . ctx_len ] ) , & ph, self . signer_rnd . unwrap ( ) , output_sized)
630733 }
0 commit comments