Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

19 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

#Module-Lattice-Based Digital Signature Algorithm (CRYSTALS-Dilithium)

A Pure Python, zero-dependency implementation of the NIST-standardized ML-DSA (FIPS 204)

Educational β€’ Research β€’ Post-Quantum Cryptography β€’ Zero External Dependencies

Python 3.10+ MIT License NIST FIPS 204 Standard Post-Quantum Cryptography Build Status


πŸ“– Table of Contents


πŸ” Overview

This repository contains a fully compliant, pure Python 3 implementation of the Module-Lattice-Based Digital Signature Algorithm (ML-DSA), standardized in NIST FIPS 204 (August 2024).

ML-DSA is the standardized successor of CRYSTALS-Dilithium, one of the core algorithms selected in the NIST Post-Quantum Cryptography (PQC) standardization process. Built from the ground up using only the Python standard library, this implementation is designed for researchers, security engineers, students, and educators seeking to explore, benchmark, and understand the mechanics of lattice-based signature schemes.


πŸ›‘οΈ Why Post-Quantum Cryptography?

Traditional digital signature schemes (such as RSA, DSA, and ECDSA) rely on the mathematical difficulty of integer factorization or discrete logarithms. Shor's Algorithm proves that a sufficiently powerful quantum computer can solve these problems in polynomial time, rendering legacy public-key infrastructures obsolete.

ML-DSA addresses this threat by securing communication using lattice-based assumptions:

  • Mathematical Hardness: Relies on the hard lattice problems Module Learning with Errors (M-LWE) and Module Short Integer Solution (M-SIS).
  • Quantum Resistance: There are no known classical or quantum algorithms capable of solving these lattice problems in polynomial time.
  • NIST Standardized: Designated by NIST as the primary standard for general-purpose post-quantum digital signatures.

✨ Features

  • βœ” Complete FIPS 204 Compliance: Full support for all three standardized security parameter sets (ML-DSA-44, ML-DSA-65, and ML-DSA-87).
  • βœ” Pre-hashed Variant (HashML-DSA): High-performance signing for massive payloads using pre-hashing (supporting SHA-256, SHA-512, and SHAKE-128).
  • βœ” Hedged (Default) & Deterministic Signing: Choose between secure hedged random-based signing (resilient against fault injection) or fully deterministic signing (for testing and verification).
  • βœ” Constant-Time Verification Check: Employs hmac.compare_digest for final signature evaluation to avoid timing side-channels.
  • βœ” Strict Parameter Validation: Robust checks for inputs, polynomial coefficients, and strict monotonic order checks on hint bit vectors.
  • βœ” Zero External Runtime Dependencies: Only requires Python 3.10+ standard library.
  • βœ” Comprehensive Test Coverage: Detailed test suite including negative, edge-case, and compliance-level testing.

πŸ“œ Standards Compliance

This implementation accurately implements the FIPS 204 specification:

Standard Component Spec Section / Algorithm Implementation Status
ML-DSA-44 FIPS 204 Table 1 (Cat. 2) βœ… Standard Compliant
ML-DSA-65 FIPS 204 Table 1 (Cat. 3) βœ… Standard Compliant
ML-DSA-87 FIPS 204 Table 1 (Cat. 5) βœ… Standard Compliant
Key Generation Algorithms 1 & 6 βœ… Standard Compliant
Hedged / Random Sign Algorithms 2 & 7 βœ… Standard Compliant
Deterministic Sign Algorithms 2 & 7 (rnd=0) βœ… Standard Compliant
Verification Algorithms 3 & 8 βœ… Standard Compliant
HashML-DSA (Pre-hash) Algorithms 4 & 5 βœ… Standard Compliant
Context Strings Section 5.2 / 5.3 (ctx) βœ… Standard Compliant
Bit Packing / Unpacking Algorithms 15 to 22 βœ… Standard Compliant

βš™οΈ Algorithm Workflow

The following diagram illustrates how keys are generated, and how messages are signed and verified within the ML-DSA cryptosystem:

                                 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                                 β”‚   Seed (32 B)   β”‚
                                 β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                          β”‚
                                          β–Ό
                               β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                               β”‚  ML_DSA.KeyGen()    β”‚
                               β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜
                                    β”‚           β”‚
                     Public Key (pk)β”‚           β”‚Secret Key (sk)
                                    β–Ό           β–Ό
                               β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                               β”‚  pk.bin β”‚ β”‚  sk.bin β”‚
                               β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜
                                    β”‚           β”‚
                                    β”‚     M     β”‚  rnd (hedged/deterministic)
                                    β”‚   β”Œβ”€β”€β”€β”   β”‚ β”Œβ”€β”€β”€β”
                                    β”‚   β”‚   β”‚   β–Ό β–Ό   β–Ό
                                    β”‚   β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                                    β”‚   β”‚ β”‚ ML_DSA.Sign β”‚
                                    β”‚   β”‚ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜
                                    β”‚   β”‚        β”‚
                                    β”‚   β”‚        β–Ό Signature (sig)
                                    β”‚   β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                                    β”‚   β”‚   β”‚ sig.bin β”‚
                                    β”‚   β”‚   β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜
                                    β–Ό   β–Ό        β–Ό
                                β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                                β”‚   ML_DSA.Verify   β”‚
                                β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                          β”‚
                                   β”Œβ”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”
                                   β–Ό             β–Ό
                               [ Valid ]     [ Invalid ]

πŸ“Š Security Parameters

ML-DSA defines three parameter sets corresponding to different security levels:

Parameter Set Security Level Public Key Size (pk) Secret Key Size (sk) Signature Size (sig) M-LWE Dimension ($k \times l$)
ML-DSA-44 Category 2 (~128-bit PQ) 1,312 Bytes 2,560 Bytes 2,420 Bytes $4 \times 4$
ML-DSA-65 Category 3 (~192-bit PQ) 1,952 Bytes 4,032 Bytes 3,309 Bytes $6 \times 5$
ML-DSA-87 Category 5 (~256-bit PQ) 2,592 Bytes 4,896 Bytes 4,627 Bytes $8 \times 7$

⚑ Project Architecture & Highlights

This pure Python implementation organizes the complex operations of lattice-based schemes into isolated, highly readable modules:

  • Number Theoretic Transform (ntt.py): Implements the fast NTT and inverse NTT in the modular ring $R_q = \mathbb{Z}_q[x]/(x^{256} + 1)$ where $q = 8380417$. This speeds up polynomial matrix-vector multiplications.
  • Polynomial Arithmetic (polynomial.py): Defines clean abstractions for Polynomial, PolynomialVector, and PolynomialMatrix with operator overloading (+, -, *).
  • Lattice Sampling (sampling.py): Implements deterministic rejection sampling algorithms:
    • ExpandA: Expand matrices from a seed.
    • ExpandS: Sample short secret vectors using ternary distributions.
    • ExpandMask: Sample error mask vectors.
    • SampleInBall: Deterministic sampling of challenges on the unit sphere.
  • Strict Rejection Logic: Implements the norm-bound loop in Dilithium signing. It strictly rejects candidates where the coefficients of the polynomial vector check exceed the bound $\gamma_1 - \beta$, preventing leakage of secret key geometry.
  • Bit-Packing & Unpacking (encoding.py): Encodes high-dimensional elements into standard compact byte formats. Enforces exact specification constraints like the monotonicity checks on hint vectors.

πŸ“‚ Repository Layout

Below is the directory structure of the repository:

Module-Lattice-Based-Digital-Signature-Algorithm-CRYSTALS-Dilithium/
β”‚
β”œβ”€β”€ ml_dsa/                   # Source code for the core implementation
β”‚   β”œβ”€β”€ __init__.py           # Package initialization & public exports
β”‚   β”œβ”€β”€ ml_dsa.py             # ML_DSA & HashML_DSA classes (Algorithms 1-8)
β”‚   β”œβ”€β”€ encoding.py           # Bit-packing and serialization algorithms
β”‚   β”œβ”€β”€ ntt.py                # NTT coefficients & fast polynomial math helper
β”‚   β”œβ”€β”€ params.py             # Standard parameters sets (FIPS 204 Table 1)
β”‚   β”œβ”€β”€ polynomial.py         # Polynomial, vector, and matrix abstractions
β”‚   β”œβ”€β”€ sampling.py           # Uniform, ternary, and spherical sampling
β”‚   └── utils.py              # Keccak-based hashes (SHAKE-128/256), conversions
β”‚
β”œβ”€β”€ benchmarks/               # Performance measurement
β”‚   └── bench.py              # Execution speed benchmarking script
β”‚
β”œβ”€β”€ examples/                 # Practical implementation recipes
β”‚   └── usage.py              # Quick-start demonstration scripts
β”‚
β”œβ”€β”€ tests/                    # Robust verification suites
β”‚   └── test_ml_dsa.py        # Automated testing suite (~200 test cases)
β”‚
β”œβ”€β”€ LICENSE                   # MIT License
β”œβ”€β”€ README.md                 # Project README
β”œβ”€β”€ pyproject.toml            # Build config and dependency definitions
└── run_all.sh                # Execution script to run example, tests, and benchmarks

πŸš€ Installation

Ensure you have Python 3.10 or higher installed.

Clone the repository and install it in editable mode:

git clone https://github.com/Dheeraj-1103/Module-Lattice-Based-Digital-Signature-Algorithm.git
cd Module-Lattice-Based-Digital-Signature-Algorithm
pip install -e .

No external runtime dependencies are required. If you wish to install test dependencies:

pip install -e ".[dev]"

πŸ’» Quick Start

Basic Signing & Verification

Here is how you generate keypairs, sign messages, and verify signatures using the standard interface:

from ml_dsa import ML_DSA

# Initialize ML-DSA at security category 2 (ML-DSA-44)
# Supported modes: "ML-DSA-44", "ML-DSA-65", "ML-DSA-87"
dsa = ML_DSA("ML-DSA-44")

# Generate cryptographic keypair (pk = Public Key, sk = Secret Key)
pk, sk = dsa.KeyGen()
print(f"Public Key length:  {len(pk)} bytes")
print(f"Secret Key length:  {len(sk)} bytes")

# Sign a message (using the default hedged variant)
message = b"This is a sensitive transaction payload."
sig = dsa.Sign(sk, message)
print(f"Signature length:   {len(sig)} bytes")

# Verify the validity of the signature
is_valid = dsa.Verify(pk, message, sig)
print(f"Signature verification status: {is_valid}")  # True

# Verification fails if message is tampered with
is_tampered_valid = dsa.Verify(pk, b"Tampered transaction payload.", sig)
print(f"Tampered signature status:     {is_tampered_valid}")  # False

Context Strings (Domain Separation)

FIPS 204 allows passing a context string ctx (up to 255 bytes) to separate signatures across different domain scopes:

dsa = ML_DSA("ML-DSA-65")
pk, sk = dsa.KeyGen()

# Sign message under specific domain string
ctx_domain = b"checkout-service-v1"
message = b"Order #2049"
sig = dsa.Sign(sk, message, ctx=ctx_domain)

# Verification must use the identical context string to succeed
assert dsa.Verify(pk, message, sig, ctx=ctx_domain) is True
assert dsa.Verify(pk, message, sig, ctx=b"admin-service") is False

HashML-DSA (Pre-hash Variant)

For signing very large files, transmitting massive payloads directly to the signing function can be memory-intensive. HashML-DSA pre-hashes the message using standard algorithms prior to signing:

from ml_dsa import HashML_DSA

# Initialize HashML-DSA at security category 5 (ML-DSA-87)
hdsa = HashML_DSA("ML-DSA-87")
pk, sk = hdsa.KeyGen()

# Sign with SHA-512 pre-hashing
# Supported hash_name options: "SHA256", "SHA512", "SHAKE128"
large_data = b"Memory-mapped filesystem buffer..." * 10000
sig = hdsa.Sign(sk, large_data, hash_name="SHA512")

# Verify using the identical hashing algorithm
assert hdsa.Verify(pk, large_data, sig, hash_name="SHA512") is True

πŸ› οΈ API Reference

ML_DSA Class

ML_DSA(mode="ML-DSA-44") Creates an instance representing one of the ML-DSA signature suites.

Method Signature Description
KeyGen KeyGen() -> (pk: bytes, sk: bytes) Generates a randomized key pair using system entropy.
KeyGen_internal KeyGen_internal(xi: bytes) -> (pk: bytes, sk: bytes) Generates a deterministic key pair from a 32-byte seed xi.
Sign Sign(sk: bytes, M: bytes, ctx: bytes = b"", deterministic: bool = False) -> bytes Signs message M with context ctx. Employs hedged random signing by default.
Sign_internal Sign_internal(sk: bytes, M_prime: bytes, rnd: bytes) -> bytes FIPS 204 Algorithm 7 implementation using pre-formatted message input and noise vector.
Verify Verify(pk: bytes, M: bytes, sig: bytes, ctx: bytes = b"") -> bool Verifies the signature sig of message M with context ctx. Returns True if valid.
Verify_internal Verify_internal(pk: bytes, M_prime: bytes, sig: bytes) -> bool FIPS 204 Algorithm 8 verification using pre-formatted message byte string.

HashML_DSA Class

HashML_DSA(mode="ML-DSA-44") (Inherits all methods from ML_DSA) Enables the pre-hashed variants standardizing digital signatures for large files (Algorithms 4 & 5).

Method Signature Description
Sign Sign(sk: bytes, M: bytes, ctx: bytes = b"", hash_name: str = "SHA512") -> bytes Pre-hashes M with hash_name and returns the signature.
Verify Verify(pk: bytes, M: bytes, sig: bytes, ctx: bytes = b"", hash_name: str = "SHA512") -> bool Pre-hashes M and verifies the signature using public key pk.

πŸ“ˆ Performance & Benchmarks

To evaluate the execution speed of this pure Python implementation, run the benchmark suite:

python benchmarks/bench.py

Typical Benchmark Output

Tested on a modern desktop CPU (pure Python interpreter, single-threaded execution, no PyPy/JIT or C optimizations applied):

Operation ML-DSA-44 ML-DSA-65 ML-DSA-87
Key Generation ~120 ms ~200 ms ~290 ms
Signing ~300 ms ~500 ms ~700 ms
Verification ~130 ms ~220 ms ~320 ms

Tip

This is a reference implementation optimized for clarity and standard alignment. For production systems requiring high performance, consider JIT compilation via PyPy or optimized C implementations such as pyca/cryptography.


πŸ§ͺ Testing

The repository features an automated test suite containing over 200 unit and functional tests to ensure the implementation stays compliant with FIPS 204.

Run the complete test suite:

pytest

Generate a detailed code coverage report:

pytest --cov=ml_dsa --cov-report=term-missing

Run a fast smoke test targeting only the lightweight security suite:

pytest -k "ML-DSA-44" -v

Run specific verification tests:

pytest tests/test_ml_dsa.py::TestSignVerify -v

πŸ—ΊοΈ Roadmap

  • FIPS 204 compliance verification across all parameter levels.
  • HashML-DSA (Pre-hash interface) standard implementation.
  • Strict validations (domain separators, key lengths, hint monotonicity).
  • Known Answer Tests (KAT): Integrate official NIST cryptogen test vector parses.
  • Performance Upgrades: Integrate an optional NumPy matrix-vector math backend.
  • CI Pipeline: Setup GitHub Actions to run linters (ruff), typers (mypy), and test sets automatically.
  • PyPI Publishing: Package wheels and submit to PyPI.

🀝 Contributing

Contributions are welcome! If you want to improve this implementation, please follow these steps:

  1. Fork the repository on GitHub.
  2. Create a branch for your feature or bug fix: git checkout -b feature/awesome-feature.
  3. Commit your changes with clear commit messages.
  4. Write tests confirming your changes don't break compatibility.
  5. Open a Pull Request explaining your implementation details.

For major architecture or API changes, please open an issue first to discuss your design thoughts.


⚠️ Security Notice

Caution

This implementation is intended for research, education, and validation purposes only. It has not been independently audited for production use. Pure Python implementations are inherently vulnerable to side-channel analysis (such as timing attacks during polynomial multiplication or cache leakage).

The deterministic signing mode (deterministic=True) is provided strictly for test compatibility and must not be used in active deployments, as it is highly vulnerable to differential fault attacks. For security-critical systems, always deploy audited, hardware-protected, or language-optimized libraries.


πŸ“ Citation

If you use this implementation in an academic project, publication, or security report, please cite it using the following BibTeX entry:

@software{ml_dsa_python,
  author       = {Your Name},
  title        = {Pure Python Implementation of Module-Lattice-Based Digital Signature Algorithm (ML-DSA)},
  year         = {2026},
  publisher    = {GitHub},
  journal      = {GitHub Repository},
  howpublished = {\url{https://github.com/your-username/Module-Lattice-Based-Digital-Signature-Algorithm}}
}

πŸ“š References


πŸ“„ License

This project is licensed under the MIT License. You are free to use, modify, and distribute this software in accordance with the terms of the license.


Developed for research and education in Post-Quantum Cryptography. ⭐ Star this repo if you find it helpful!

About

# ML-DSA: Post-Quantum Digital Signature Scheme Complete Python implementation of NIST FIPS 204 (ML-DSA-44/65/87)

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages