ML-DSA (Digital Signatures)

ML-DSA (Module-Lattice-Based Digital Signature Algorithm) is the NIST-standardized post-quantum digital signature scheme, based on the Dilithium algorithm.

Overview

ML-DSA is designed to resist attacks from both classical and quantum computers, providing:

  • Quantum Resistance: Security against Shor’s algorithm
  • Efficiency: Fast signature generation and verification
  • Small Signatures: Compact signature sizes for practical deployment
  • NIST Standardized: FIPS 204 compliant implementation

Security Levels

Cypheron Core implements three ML-DSA variants:

VariantSecurity LevelPublic KeySecret KeySignature
ML-DSA-44Level 2 (~112-bit)1,312 bytes2,560 bytes2,420 bytes
ML-DSA-65Level 3 (~128-bit)1,952 bytes4,032 bytes3,293 bytes
ML-DSA-87Level 5 (~256-bit)2,592 bytes4,896 bytes4,595 bytes

Basic Usage

Key Generation

#![allow(unused)]
fn main() {
use cypheron_core::sig::{MlDsa65, DigitalSignature};

// Generate a new keypair
let (public_key, secret_key) = MlDsa65::keypair()?;
}

Message Signing

#![allow(unused)]
fn main() {
let message = b"Hello, post-quantum world!";

// Sign the message
let signature = MlDsa65::sign(&secret_key, message)?;
}

Signature Verification

#![allow(unused)]
fn main() {
// Verify the signature
let is_valid = MlDsa65::verify(&public_key, message, &signature)?;
assert!(is_valid);
}

Advanced Usage

Deterministic Key Generation

#![allow(unused)]
fn main() {
use cypheron_core::sig::MlDsa65;

// Generate keypair from seed (for testing)
let seed = [42u8; 32];
let (pk, sk) = MlDsa65::keypair_deterministic(&seed)?;
}

Context Separation

#![allow(unused)]
fn main() {
// Sign with context for domain separation
let context = b"email-signature-v1";
let signature = MlDsa65::sign_with_context(&secret_key, message, context)?;
let is_valid = MlDsa65::verify_with_context(&public_key, message, &signature, context)?;
}

Security Considerations

  • Use ML-DSA-65 for most applications (128-bit security level)
  • Use ML-DSA-87 for high-security applications requiring 256-bit security
  • Use ML-DSA-44 only for resource-constrained environments

Key Management

#![allow(unused)]
fn main() {
use secrecy::{ExposeSecret, Zeroize};

// Secret keys are automatically zeroized on drop
impl Drop for MlDsaSecretKey {
    fn drop(&mut self) {
        self.0.zeroize();
    }
}

// Access secret key material safely
secret_key.expose_secret(|key_bytes| {
    // Use key_bytes for signing operation
    MlDsa65::sign_with_raw_key(key_bytes, message)
})
}

Side-Channel Resistance

  • Implementation uses constant-time operations where feasible
  • Secret key operations avoid data-dependent branches
  • Memory access patterns independent of secret values

Performance Characteristics

Typical Performance (x86_64, 3.0 GHz)

OperationML-DSA-44ML-DSA-65ML-DSA-87
Key Generation~95μs~120μs~160μs
Sign~180μs~250μs~380μs
Verify~85μs~110μs~150μs

Memory Usage

  • Stack allocation for all operations
  • No dynamic memory allocation required
  • Secure automatic cleanup on scope exit

Error Handling

Common Errors

#![allow(unused)]
fn main() {
use cypheron_core::error::Error;

match MlDsa65::verify(&public_key, message, &signature) {
    Ok(true) => println!("Valid signature"),
    Ok(false) => println!("Invalid signature"),
    Err(Error::InvalidPublicKey) => println!("Malformed public key"),
    Err(Error::InvalidSignature) => println!("Malformed signature"),
    Err(e) => println!("Other error: {}", e),
}
}

Input Validation

  • All inputs are validated before processing
  • Malformed keys/signatures return appropriate errors
  • No panics on invalid input data

Interoperability

NIST Compliance

  • Implements FIPS 204 specification exactly
  • Compatible with other FIPS 204 implementations
  • Passes all NIST Known Answer Tests (KAT)

Serialization

#![allow(unused)]
fn main() {
// Serialize keys and signatures
let pk_bytes = public_key.as_bytes();
let sk_bytes = secret_key.expose_secret(|bytes| bytes.to_vec());
let sig_bytes = signature.as_bytes();

// Deserialize from bytes
let public_key = MlDsaPublicKey::from_bytes(&pk_bytes)?;
let signature = MlDsaSignature::from_bytes(&sig_bytes)?;
}

Hybrid Signatures

ML-DSA can be combined with classical signatures for transitional security:

#![allow(unused)]
fn main() {
use cypheron_core::hybrid::EccDilithium;

// Hybrid ECDSA + ML-DSA signature
let (hybrid_pk, hybrid_sk) = EccDilithium::keypair()?;
let hybrid_sig = EccDilithium::sign(&hybrid_sk, message)?;
let is_valid = EccDilithium::verify(&hybrid_pk, message, &hybrid_sig)?;
}

See Also