dilithium-rs 0.2.0

Pure Rust implementation of ML-DSA (FIPS 204) / CRYSTALS-Dilithium post-quantum digital signature scheme
Documentation

dilithium-rs

Pure Rust implementation of ML-DSA (FIPS 204) / CRYSTALS-Dilithium

Post-quantum digital signature scheme — no_std + WASM ready.

License: MIT

Features

Feature Status
ML-DSA-44 / ML-DSA-65 / ML-DSA-87
Pure ML-DSA signing (§6.1)
HashML-DSA pre-hash mode (§6.2)
Key validation (§7.1)
Constant-time verification
Zeroization of secrets
no_std / WASM compatible
Optional serde support
NIST KAT vectors — bit-for-bit match with C reference
SIMD acceleration (AVX2 + NEON)
0 unsafe blocks (core library)

Quick Start

use dilithium::{MlDsaKeyPair, ML_DSA_44};

// Generate a key pair
let kp = MlDsaKeyPair::generate(ML_DSA_44).unwrap();

// Sign a message
let sig = kp.sign(b"Hello, post-quantum world!", b"").unwrap();

// Verify
assert!(MlDsaKeyPair::verify(
    kp.public_key(), &sig,
    b"Hello, post-quantum world!", b"",
    ML_DSA_44
));

Security Levels

FIPS 204 Name NIST Level Public Key Secret Key Signature
ML-DSA-44 2 1,312 B 2,560 B 2,420 B
ML-DSA-65 3 1,952 B 4,032 B 3,309 B
ML-DSA-87 5 2,592 B 4,896 B 4,627 B

API Reference

Key Generation

use dilithium::{DilithiumKeyPair, ML_DSA_65};

// Random key pair (OS entropy)
let kp = DilithiumKeyPair::generate(ML_DSA_65).unwrap();

// Deterministic key pair (from seed)
let seed = [0u8; 32];
let kp = DilithiumKeyPair::generate_deterministic(ML_DSA_65, &seed);

Signing & Verification

// Pure ML-DSA (§6.1)
let sig = kp.sign(b"message", b"context").unwrap();
let ok = DilithiumKeyPair::verify(kp.public_key(), &sig, b"message", b"context", ML_DSA_65);

// HashML-DSA pre-hash (§6.2) — message is SHA-512 hashed internally
let sig = kp.sign_prehash(b"large document", b"").unwrap();
let ok = DilithiumKeyPair::verify_prehash(kp.public_key(), &sig, b"large document", b"", ML_DSA_65);

Serialization

// Key pair round-trip
let bytes = kp.to_bytes();          // [mode_tag | pk | sk]
let kp2 = DilithiumKeyPair::from_bytes(&bytes).unwrap();

// Public key export (for distribution)
let pk_bytes = kp.public_key_bytes(); // [mode_tag | pk]
let (mode, pk) = DilithiumKeyPair::from_public_key(&pk_bytes).unwrap();

// Signature round-trip
let sig_bytes = sig.as_bytes().to_vec();
let sig2 = DilithiumSignature::from_bytes(sig_bytes);

// Import raw keys with validation (FIPS 204 §7.1)
let kp = DilithiumKeyPair::from_keys(sk_bytes, pk_bytes, ML_DSA_65).unwrap();

Serde (optional)

[dependencies]
dilithium-rs = { version = "0.1", features = ["serde"] }
let json = serde_json::to_string(&kp).unwrap();
let kp: DilithiumKeyPair = serde_json::from_str(&json).unwrap();

no_std / WASM

[dependencies]
dilithium-rs = { version = "0.1", default-features = false }

All dependencies support no_std and wasm32-unknown-unknown:

  • sha3, sha2 — SHAKE/SHA hashing
  • subtle — constant-time comparison
  • zeroize — secret material cleanup
  • getrandom — OS entropy (uses crypto.getRandomValues in WASM)

Benchmarks

Measured on Apple Silicon (M-series), --release, 10,000 iterations. Rust uses Criterion; C reference compiled with cc -O3.

Operation Mode Rust (µs) C ref (µs) Ratio
keygen ML-DSA-44 48.9 50.8 0.96×
keygen ML-DSA-65 79.2 94.8 0.84×
keygen ML-DSA-87 130.3 135.9 0.96×
sign ML-DSA-44 126.1 215.7 0.58×
sign ML-DSA-65 529.9 354.3 1.50×
sign ML-DSA-87 284.2 442.6 0.64×
verify ML-DSA-44 53.2 53.8 0.99×
verify ML-DSA-65 85.1 84.6 1.01×
verify ML-DSA-87 135.3 143.5 0.94×

Sign times have high variance due to rejection sampling. Ratios <1.0 mean Rust is faster.

cargo bench                             # run benchmarks

Security

  • 0 unsafe blocks in core library (SIMD modules use unsafe behind simd feature)
  • Constant-time verification via subtle::ConstantTimeEq
  • Zeroize — private keys auto-zeroed on drop, seeds/rnd zeroed after use
  • NIST KAT — bit-for-bit match with C reference (pk, sk, sig hashes)
  • Key validationfrom_keys() validates rho consistency + tr = H(pk)
  • Fuzz tested — 3 targets, 41M+ executions, 0 crashes

See SECURITY.md for responsible disclosure and scope.

Test Suite

cargo test                              # all 73 tests
cargo test --features serde             # with serde
cargo test --features simd              # with SIMD
cargo clippy -- -W clippy::pedantic     # 0 warnings
Suite Tests What
Unit 30 NTT, reduce, rounding, symmetric, poly, SIMD
Round-trip 17 Sign/verify all modes, HashML-DSA, key validation
Coverage 17 Edge cases, error paths, boundaries
KAT 4 Bit-for-bit match with C reference (all 3 modes)
Multi-vector KAT 3 100 vectors × 3 modes accumulated hash
Doc-tests 2 Code examples compile and run

Feature Flags

Feature Default Description
std OS entropy for generate, sign, sign_prehash
serde Serialize/Deserialize for key pairs and signatures
simd AVX2 (x86_64) and NEON (AArch64) NTT acceleration
js getrandom/js for WASM browser targets

License

MIT