Skip to main content

bouncycastle_mldsa/
lib.rs

1//!
2//! This crate implements the Module Lattice Digital Signature Algorithm (ML-DSA) as per FIPS 204.
3//!
4//! # Usage
5//!
6//! This crate has been designed to serve a wide range of use cases, from people dabbling in
7//! cryptography for the first time, to cryptographic protocol designers who need access to the advanced
8//! functionality of the ML-DSA algorithm, to embedded systems developers who want access to memory
9//! and performance optimized functions.
10//!
11//! This page gives examples of simple usage for generating keys and signatures, and verifying signatures.//!
12//!
13//! More examples on advanced usage can be found on the [mldsa] and [hash_mldsa] pages.
14//!
15//! ## Generating Keys
16//!
17//! ```rust
18//! use bouncycastle_mldsa::MLDSA65;
19//! use bouncycastle_core_interface::traits::Signature;
20//!
21//! let (pk, sk) = MLDSA65::keygen().unwrap();
22//! ```
23//! That's it. That will use the library's default OS-backend RNG.
24//!
25//! Commonly with the ML-DSA algorithm, a 32-byte seed is used as the private key, and expanded into
26//! a full private key as needed. This is offered through the library's [KeyMaterial] object:
27//!
28//! ```rust
29//! use bouncycastle_core_interface::traits::KeyMaterial;
30//! use bouncycastle_core_interface::key_material::{KeyMaterial256, KeyType};
31//! use bouncycastle_mldsa::{MLDSA65, MLDSATrait};
32//!
33//! let seed = KeyMaterial256::from_bytes_as_type(
34//!     &hex::decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f").unwrap(),
35//!     KeyType::Seed,
36//! ).unwrap();
37//!
38//! let (pk, sk) = MLDSA65::keygen_from_seed(&seed).unwrap();
39//! ```
40//!
41//! See [MLDSATrait] and [MLDSATrait::sign_mu_deterministic_from_seed] for an API flow that uses a merged
42//! keygen-and-sign function to provide improved speed and memory performance compared with making
43//! separate calls to [MLDSATrait::keygen_from_seed] followed by [Signature::sign].
44//!
45//! ## Generating and Verifying Signatures
46//!
47//! ```rust
48//! use bouncycastle_core_interface::errors::SignatureError;
49//! use bouncycastle_mldsa::{MLDSA65, MLDSATrait};
50//! use bouncycastle_core_interface::traits::Signature;
51//!
52//! let msg = b"The quick brown fox";
53//!
54//! let (pk, sk) = MLDSA65::keygen().unwrap();
55//!
56//! let sig: Vec<u8> = MLDSA65::sign(&sk, msg, None).unwrap();
57//! // This is the signature value that you can save to a file or whatever you need.
58//!
59//! match MLDSA65::verify(&pk, msg, None, &sig) {
60//!     Ok(()) => println!("Signature is valid!"),
61//!     Err(SignatureError::SignatureVerificationFailed) => println!("Signature is invalid!"),
62//!     Err(e) => panic!("Something else went wrong: {:?}", e),
63//! }
64//!
65//! ```
66//! And that's the basic usage! There are lots more bells-and-whistles in the form of exposed algorithm
67//! parameters, streaming APIs and other goodies that you can find by poking around this documentation.
68//!
69//! # Security
70//! All functionality exposed by this crate is considered secure to use.
71//! In other words, this crate does not contain any "hazmat" except for the obvous points about
72//! handling your private keys properly: if you post your private key to github, or you generate
73//! production keys from a weak seed, I can't help you, that's on you.
74//!
75//! While the full formulation of the ML-DSA and HashML-DSA algorithms look complex with parameters
76//! like `seed`, `mu`, `ph`, `ctx`, and `rnd`, rest assured that use (or misuse) of these parameters
77//! do not really affect security of the algorithm; they just mean that you might produce a signature
78//! that nobody else can verify.
79//!
80//! A note about cryptographic side-channel attacks: considerable effort has been expended to attempt
81//! to make this implementation constant-time, which generally means that the core mathematical algorithm
82//! code that handles secret data uses bitshift-and-xor type constructions instead of if-and-loop
83//! constructions. That should give this implementation reasonably good resistance to timing and
84//! power analysis key extraction attacks, however: A) this is a "best-effort" and not formally verified,
85//! and B) the Rust compiler does not guarantee constant-time behaviour no matter how clever your code,
86//! so like all Safe Rust code (ie Rust code that does not include inline assembly), we are at the mercy
87//! of the Rust compiler's optimizer for whether our bitshift-and-xor code actually remains
88//! constant-time after compilation.
89
90
91#![forbid(missing_docs)]
92
93#![forbid(unsafe_code)]
94#![allow(incomplete_features)] // needed because currently generic_const_exprs is experimental
95#![feature(generic_const_exprs)]
96// #![feature(int_roundings)]
97// #![feature(inherent_associated_types)]
98#![feature(adt_const_params)]
99
100// These are because I'm matching variable names exactly against FIPS 204, for example both 'K' and 'k',
101// or 'A' and 'a' are used and have specific meanings.
102// But need to tell the rust linter to not care.
103#![allow(non_snake_case)]
104#![allow(non_upper_case_globals)]
105
106// so I can use private traits to hide internal stuff that needs to be generic within the
107// MLDSA implementation, but I don't want accessed from outside, such as FIPS-internal functions.
108#![allow(private_bounds)]
109
110// Used in HashMLDSA
111#![feature(unsized_const_params)]
112
113// imports needed just for docs
114#[allow(unused_imports)]
115use bouncycastle_core_interface::traits::{KeyMaterial, Signature, PHSignature};
116
117pub mod mldsa; // todo -- pub just to get the docs. Is that right? Or should I suck the docs up here?
118pub mod hash_mldsa; // todo -- pub just to get the docs. Is that right? Or should I suck the docs up here?
119mod mldsa_keys;
120mod polynomial;
121mod aux_functions;
122mod matrix;
123
124
125/*** Exported types ***/
126pub use mldsa::{MLDSATrait, MLDSA, MLDSA44, MLDSA65, MLDSA87};
127pub use hash_mldsa::{HashMLDSA44_with_SHA256, HashMLDSA65_with_SHA256, HashMLDSA87_with_SHA256};
128pub use hash_mldsa::{HashMLDSA44_with_SHA512, HashMLDSA65_with_SHA512, HashMLDSA87_with_SHA512};
129pub use mldsa_keys::{MLDSAPrivateKeyTrait, MLDSAPublicKeyTrait};
130pub use mldsa_keys::{MLDSAPublicKey, MLDSA44PublicKey, MLDSA65PublicKey, MLDSA87PublicKey};
131pub use mldsa_keys::{MLDSAPrivateKey, MLDSA44PrivateKey, MLDSA65PrivateKey, MLDSA87PrivateKey};
132pub use mldsa::{MuBuilder};
133
134/*** Exported constants ***/
135pub use mldsa::ML_DSA_44_NAME;
136pub use mldsa::ML_DSA_65_NAME;
137pub use mldsa::ML_DSA_87_NAME;
138
139pub use hash_mldsa::Hash_ML_DSA_44_with_SHA256_NAME;
140pub use hash_mldsa::Hash_ML_DSA_65_with_SHA256_NAME;
141pub use hash_mldsa::Hash_ML_DSA_87_with_SHA256_NAME;
142
143pub use hash_mldsa::Hash_ML_DSA_44_with_SHA512_NAME;
144pub use hash_mldsa::Hash_ML_DSA_65_with_SHA512_NAME;
145pub use hash_mldsa::Hash_ML_DSA_87_with_SHA512_NAME;
146
147pub use mldsa::{TR_LEN, RND_LEN, MU_LEN};
148pub use mldsa::{MLDSA44_PK_LEN, MLDSA44_SK_LEN, MLDSA44_SIG_LEN};
149pub use mldsa::{MLDSA65_PK_LEN, MLDSA65_SK_LEN, MLDSA65_SIG_LEN};
150pub use mldsa::{MLDSA87_PK_LEN, MLDSA87_SK_LEN, MLDSA87_SIG_LEN};