Recover ECDSA private keys from biased-nonce signatures via LLL/BKZ lattice reduction
Project description
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/
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ecdsa_break-0.1.0.1.tar.gz.
File metadata
- Download URL: ecdsa_break-0.1.0.1.tar.gz
- Upload date:
- Size: 8.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
11c7565db339ab672adf8664a0798b699f920dee8f8cce002bbba30400197cb4
|
|
| MD5 |
8c71d7a0bec82e8607653f92f7b765ee
|
|
| BLAKE2b-256 |
88fd70c424661b5b932bacf300964f57500bc390990b01c9b3a8b1ba93949536
|
Provenance
The following attestation bundles were made for ecdsa_break-0.1.0.1.tar.gz:
Publisher:
pypi-publish.yml on daedalus/BreakingECDSAwithLLL
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ecdsa_break-0.1.0.1.tar.gz -
Subject digest:
11c7565db339ab672adf8664a0798b699f920dee8f8cce002bbba30400197cb4 - Sigstore transparency entry: 1181807579
- Sigstore integration time:
-
Permalink:
daedalus/BreakingECDSAwithLLL@08a22387481a531e278673f7cf464f2c41cfc3ac -
Branch / Tag:
refs/tags/v0.1.0.1 - Owner: https://github.com/daedalus
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi-publish.yml@08a22387481a531e278673f7cf464f2c41cfc3ac -
Trigger Event:
release
-
Statement type:
File details
Details for the file ecdsa_break-0.1.0.1-py3-none-any.whl.
File metadata
- Download URL: ecdsa_break-0.1.0.1-py3-none-any.whl
- Upload date:
- Size: 11.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4aedea10bab0a65900949c753541c277204e2109181c1e219a54ba7a2cc258dc
|
|
| MD5 |
cca2148aafae2dde7c9445a9797ca1fc
|
|
| BLAKE2b-256 |
7624082949d326eaa9989c0105f186f87301584cccb4e142e017b8c18addc8c1
|
Provenance
The following attestation bundles were made for ecdsa_break-0.1.0.1-py3-none-any.whl:
Publisher:
pypi-publish.yml on daedalus/BreakingECDSAwithLLL
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ecdsa_break-0.1.0.1-py3-none-any.whl -
Subject digest:
4aedea10bab0a65900949c753541c277204e2109181c1e219a54ba7a2cc258dc - Sigstore transparency entry: 1181807653
- Sigstore integration time:
-
Permalink:
daedalus/BreakingECDSAwithLLL@08a22387481a531e278673f7cf464f2c41cfc3ac -
Branch / Tag:
refs/tags/v0.1.0.1 - Owner: https://github.com/daedalus
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi-publish.yml@08a22387481a531e278673f7cf464f2c41cfc3ac -
Trigger Event:
release
-
Statement type: