Skip to content

Commit 280f9e4

Browse files
committed
docs and stuff for ML-DSA
1 parent 4d996a7 commit 280f9e4

12 files changed

Lines changed: 619 additions & 142 deletions

File tree

cli/src/mldsa_cmd.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
//! by using generics or macros. I just, haven't ... yet.
33
44
use crate::{MLDSAAction, write_bytes_or_hex};
5-
use bouncycastle::core_interface::key_material::{KeyMaterial256, KeyMaterialSized, KeyType};
5+
use bouncycastle::core_interface::key_material::{KeyMaterial256, KeyType};
66
use bouncycastle::core_interface::traits::{
77
KeyMaterial, SecurityStrength, Signature, SignaturePrivateKey, SignaturePublicKey,
88
};
99
use bouncycastle::hex;
10-
use bouncycastle::mldsa::{MLDSA44, MLDSA44_SK_LEN, MLDSA44PrivateKey, MLDSA87_SK_LEN, MLDSAPrivateKeyTrait, MLDSATrait, MLDSAPrivateKey, MLDSA44PublicKey, MLDSA44_PK_LEN, MLDSA65_SK_LEN, MLDSA65PrivateKey, MLDSA65, MLDSA65PublicKey, MLDSA65_PK_LEN, MLDSA87PrivateKey, MLDSA87, MLDSA87PublicKey, MLDSA87_PK_LEN, HashMLDSA44_with_SHA512, HashMLDSA65_with_SHA512, HashMLDSA87_with_SHA512};
10+
use bouncycastle::mldsa::{MLDSA44, MLDSA44_SK_LEN, MLDSA44PrivateKey, MLDSA87_SK_LEN, MLDSAPrivateKeyTrait, MLDSATrait, MLDSA44PublicKey, MLDSA44_PK_LEN, MLDSA65_SK_LEN, MLDSA65PrivateKey, MLDSA65, MLDSA65PublicKey, MLDSA65_PK_LEN, MLDSA87PrivateKey, MLDSA87, MLDSA87PublicKey, MLDSA87_PK_LEN, HashMLDSA44_with_SHA512, HashMLDSA65_with_SHA512, HashMLDSA87_with_SHA512};
1111
use std::{fs, io};
1212
use std::io::{Read};
1313
use std::process::exit;
@@ -85,7 +85,7 @@ pub(crate) fn mldsa44_cmd(
8585
MLDSAAction::Sign => {
8686
// first, read the sk
8787
let mut sk_bytes = [0u8; 2*2560+1];
88-
let mut sk_len: usize;
88+
let sk_len: usize;
8989
if skfile.is_some() {
9090
sk_len = read_from_file(skfile.as_ref().unwrap(), &mut sk_bytes);
9191
} else {
@@ -272,7 +272,7 @@ pub(crate) fn mldsa65_cmd(
272272
MLDSAAction::Sign => {
273273
// first, read the sk
274274
let mut sk_bytes = [0u8; 2*4032+1];
275-
let mut sk_len: usize;
275+
let sk_len: usize;
276276
if skfile.is_some() {
277277
sk_len = read_from_file(skfile.as_ref().unwrap(), &mut sk_bytes);
278278
} else {
@@ -459,7 +459,7 @@ pub(crate) fn mldsa87_cmd(
459459
MLDSAAction::Sign => {
460460
// first, read the sk
461461
let mut sk_bytes = [0u8; 2*4627+1];
462-
let mut sk_len: usize;
462+
let sk_len: usize;
463463
if skfile.is_some() {
464464
sk_len = read_from_file(skfile.as_ref().unwrap(), &mut sk_bytes);
465465
} else {
@@ -646,7 +646,7 @@ pub(crate) fn hash_mldsa44_sha512_cmd(
646646
MLDSAAction::Sign => {
647647
// first, read the sk
648648
let mut sk_bytes = [0u8; 2*2560+1];
649-
let mut sk_len: usize;
649+
let sk_len: usize;
650650
if skfile.is_some() {
651651
sk_len = read_from_file(skfile.as_ref().unwrap(), &mut sk_bytes);
652652
} else {
@@ -833,7 +833,7 @@ pub(crate) fn hash_mldsa65_sha512_cmd(
833833
MLDSAAction::Sign => {
834834
// first, read the sk
835835
let mut sk_bytes = [0u8; 2*4032+1];
836-
let mut sk_len: usize;
836+
let sk_len: usize;
837837
if skfile.is_some() {
838838
sk_len = read_from_file(skfile.as_ref().unwrap(), &mut sk_bytes);
839839
} else {
@@ -1019,7 +1019,7 @@ pub(crate) fn hash_mldsa87_sha512_cmd(
10191019
MLDSAAction::Sign => {
10201020
// first, read the sk
10211021
let mut sk_bytes = [0u8; 2*4627+1];
1022-
let mut sk_len: usize;
1022+
let sk_len: usize;
10231023
if skfile.is_some() {
10241024
sk_len = read_from_file(skfile.as_ref().unwrap(), &mut sk_bytes);
10251025
} else {

crypto/core-test-framework/src/signature.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ impl TestFrameworkSignature {
119119
// fn sign_final_out(&mut self, msg_chunk: &[u8], ctx: &[u8], output: &mut [u8]) -> Result<(), SignatureError>;
120120

121121
// First, test the streaming API with one call to .sign_update
122-
let mut s = SigAlg::sign_init(&sk, Some(b"streaming API")).unwrap();
122+
let mut s = SigAlg::sign_init(&sk, Some(b"streaming API")).unwrap();
123123
s.sign_update(DUMMY_SEED_1024);
124124
let sig_val = s.sign_final().unwrap();
125125
SigAlg::verify(&pk, DUMMY_SEED_1024, Some(b"streaming API"), &sig_val).unwrap();

crypto/mldsa/src/aux_functions.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -458,9 +458,6 @@ pub(crate) fn sig_decode<
458458

459459
let mut pos: usize = 0;
460460

461-
// todo -- compare against nursery impl (mldsa::sign_verify) to see if I can
462-
// todo -- import some optimization
463-
464461
c_tilde.copy_from_slice(&sig[..LAMBDA_over_4]);
465462
pos += LAMBDA_over_4;
466463

@@ -827,7 +824,6 @@ pub(crate) fn decompose<const GAMMA2: i32>(r: i32) -> (i32, i32) {
827824
}
828825
}
829826

830-
let g = GAMMA2;
831827
r1 = r - r0 * 2 * GAMMA2;
832828
r1 -= (((q - 1) / 2 - r1) >> 31) & q;
833829

crypto/mldsa/src/hash_mldsa.rs

Lines changed: 110 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,67 @@
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
566
use std::marker::PhantomData;
667
use 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
};
2586
use 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};
2788
use bouncycastle_core_interface::errors::SignatureError;
2889
use 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};
3091
use bouncycastle_rng::HashDRBG_SHA512;
3192
use 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+
///
38100
pub const Hash_ML_DSA_44_with_SHA256_NAME: &str = "HashML-DSA-44_with_SHA256";
101+
///
39102
pub const Hash_ML_DSA_65_with_SHA256_NAME: &str = "HashML-DSA-65_with_SHA256";
103+
///
40104
pub const Hash_ML_DSA_87_with_SHA256_NAME: &str = "HashML-DSA-87_with_SHA256";
41-
105+
///
42106
pub const Hash_ML_DSA_44_with_SHA512_NAME: &str = "HashML-DSA-44_with_SHA512";
107+
///
43108
pub const Hash_ML_DSA_65_with_SHA512_NAME: &str = "HashML-DSA-65_with_SHA512";
109+
///
44110
pub 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)]
48116
pub 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)]
76150
pub 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)]
104184
pub 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)]
132218
pub 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)]
160252
pub 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)]
188286
pub 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

Comments
 (0)