BreakingECDSAwithLLL
Recover ECDSA private keys from biased-nonce signatures via LLL/BKZ lattice reduction.
The core idea: if you have many ECDSA signatures generated with a private key whose nonces have a fixed-bit bias, those signatures converge toward the private key via the Hidden Number Problem (HNP). We solve HNP with the Lenstra–Lenstra–Lovász (LLL) lattice reduction algorithm, optionally followed by a BKZ post-processing pass.
The main countermeasure against this attack is using deterministic signatures
like Z = H(h || d) (RFC 6979), which eliminates nonce bias entirely.
Based on prior work:
- https://blog.trailofbits.com/2020/06/11/ecdsa-handle-with-care/
- https://www.youtube.com/watch?v=6ssTlSSIJQE
Referenced in CVE-2024-31497 on 4/16/2024.
Install
pip install breaking-ecdsa-with-lll
# With weak-signature generator support:
pip install "breaking-ecdsa-with-lll[generator]"
Quick start
# (Victim) generate 6 weak signatures
gen-weak-sigs e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 176 6 > nonces.csv
# (Attacker) recover the private key
break-ecdsa nonces.csv 176 6 | grep e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
Python API
from breaking_ecdsa_with_lll import (
load_csv,
make_matrix,
reduce_matrix,
privkeys_from_reduced_matrix,
display_keys,
)
msgs, sigs, pubs = load_csv("nonces.csv", limit=6)
matrix = make_matrix(msgs, sigs, pubs, B=176)
reduced = reduce_matrix(matrix, do_bkz=False)
keys = privkeys_from_reduced_matrix(msgs, sigs, pubs, reduced)
display_keys(keys)
CLI reference
break-ecdsa
break-ecdsa <filename> <B> <limit> [--matrix_type dense|sparse]
[--order N] [--bkz] [--mmap]
gen-weak-sigs
gen-weak-sigs <secret_hex> <bits> <n> [--mode MSB|LSB]
API
| Symbol | Module | Description |
|---|---|---|
load_csv |
io |
Load signatures from CSV |
make_matrix |
lattice |
Build HNP lattice matrix |
reduce_matrix |
lattice |
LLL (+ optional BKZ) reduction |
privkeys_from_reduced_matrix |
lattice |
Extract private key candidates |
display_keys |
display |
Print keys as 64-char hex strings |
generate_weak_signatures |
generator |
Produce biased-nonce test signatures |
DEFAULT_ORDER |
lattice |
secp256k1 group order |
Development
git clone https://github.com/daedalus/BreakingECDSAwithLLL.git
cd BreakingECDSAwithLLL
pip install -e ".[test]"
# Run tests
pytest
# Format
ruff format src/ tests/
# Lint
ruff check src/ tests/
# Type check
mypy src/
Metadata
Release files for ecdsa-break 0.1.0.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| ecdsa_break-0.1.0.1.tar.gz | 8.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ecdsa_break-0.1.0.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 19.5 kB
Release files / ecdsa_break-0.1.0.1.tar.gz
| Download URL | ecdsa_break-0.1.0.1.tar.gz |
|---|---|
| Size | 8.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
11c7565db339ab672adf8664a0798b699f920dee8f8cce002bbba30400197cb4
|
|
BLAKE2b-256 checksum How to use checksums |
88fd70c424661b5b932bacf300964f57500bc390990b01c9b3a8b1ba93949536
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Mar 25, 2026.
Transparency logRelease files / ecdsa_break-0.1.0.1-py3-none-any.whl
| Download URL | ecdsa_break-0.1.0.1-py3-none-any.whl |
|---|---|
| Size | 11.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
4aedea10bab0a65900949c753541c277204e2109181c1e219a54ba7a2cc258dc
|
|
BLAKE2b-256 checksum How to use checksums |
7624082949d326eaa9989c0105f186f87301584cccb4e142e017b8c18addc8c1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Mar 25, 2026.
Transparency log