
Studio educativo sull'entropia delle chiavi Bitcoin: enumerazione di wallet con RNG debole (classe Milk Sad / CVE-2023-39910) rispetto all'infattibilità del brute-forcing di una chiave sicura.
Uno studio didattico su da dove proviene realmente la sicurezza delle chiavi Bitcoin — e da dove non proviene. Costruito attorno alla derivazione reale BIP39/BIP32, con due esperimenti che si trovano agli estremi opposti della stessa idea:
| Experiment | Search space | Feasible? | What it teaches |
|---|---|---|---|
weak_entropy — enumerare uno spazio wallet con RNG debole | 2³² (un RNG cattivo) | Sì, in giorni | Un wallet è forte quanto l'entropia che lo genera. |
blind_search — forzare bruta un buon spazio di chiavi | 2¹⁶⁰ (un RNG buono) | No, mai | Con entropia reale, lo spazio delle chiavi è fisicamente non ricercabile. |
Il punto centrale è il contrasto: le chiavi vengono rubate attaccando la scarsa casualità, mai superando in calcolo la buona casualità. Entrambi gli esperimenti derivano lo stesso tipo di indirizzi reali su mainnet, quindi l'unica variabile è l'entropia.
Questo repository è per educazione difensiva e ricerca sulla sicurezza: comprendere perché i bug dei wallet con RNG debole (Milk Sad / CVE-2023-39910, il bug dell'estensione Trust Wallet del 2018 e simili) sono stati catastrofici, e perché non lo è forzare brutalmente una chiave generata correttamente.
weak_entropy enumera uno spazio sintetico autonomo. La sua weak_entropy() è un modello deliberato della classe di vulnerabilità — un PRNG a 32 bit che alimenta BIP39 — non un clone byte-per-byte dell'RNG di un wallet reale. Gli indirizzi che produce non corrispondono al wallet reale di nessuno.blind_search è una ricerca di saldo in sola lettura sul tuo nodo. Non deriva alcuna chiave e non può spendere nulla; la sua modalità principale misura l'inutilità della ricerca cieca.Usalo su wallet che controlli, su testnet o come sandbox. Non puntarlo verso il denaro degli altri.
Solo per istruzione e ricerca sulla sicurezza autorizzata. Usalo esclusivamente su chiavi, wallet e sistemi che possiedi o per i quali hai esplicito permesso scritto di testare. L'accesso non autorizzato a wallet o sistemi altrui e il furto di asset digitali sono illegali ai sensi di leggi come il CFAA statunitense (18 U.S.C. § 1030), il Computer Misuse Act 1990 del Regno Unito e la Direttiva UE 2013/40/UE — indipendentemente dai mezzi tecnici. Fornito "così com'è", senza garanzia; gli autori non si assumono alcuna responsabilità per un uso improprio. Non è consulenza legale. Termini completi e indicazioni sulla divulgazione responsabile: DISCLAIMER.md.
La sicurezza di un wallet è limitata dall'entropia che è confluita nel suo seed, non dalla robustezza di SHA-256 / PBKDF2 / secp256k1 a valle.
BIP39 trasforma l'entropia in un mnemonico, PBKDF2 la espande in un seed e BIP32 deriva un albero di chiavi. Tutto questo è robusto. Ma nessuno di questi passaggi aggiunge entropia — se il seed è stato estratto da un insieme piccolo, ogni indirizzo che il wallet può mai produrre è enumerabile, e nessuna quantità di hashing lo nasconde.
bitcoin-security/
├── bitcoin_security/ # the package
│ ├── derivation.py # shared core: BIP39 + BIP32 + P2PKH/WIF
│ ├── data/english.txt # BIP39 English wordlist (2048 words)
│ ├── weak_entropy/ # Experiment 1 — enumerable weak space
│ │ ├── enumerate.py # recovery demo + full-space dump
│ │ └── README.md
│ └── blind_search/ # Experiment 2 — futile brute-force search
│ ├── scan.py # UTXO-set balance scanner + odds
│ └── README.md
├── tests/ # offline test suites (no node/network)
│ ├── test_blind_search_addresses.py
│ └── test_blind_search_pipeline.py
├── docs/FINDINGS.md # benchmarks + exact full-space size derivation
├── pyproject.toml
├── requirements.txt
└── LICENSE
L'albero riflette l'idea: un unico core derivation condiviso, due esperimenti che lo usano per giungere a conclusioni opposte sullo stesso spazio di indirizzi.
pip install -r requirements.txt # runtime deps
# optional — installs the package + `bsec-enumerate` / `bsec-scan` commands:
pip install -e .
coincurve (libsecp256k1 nativa) rende la derivazione ~5× più veloce ma è opzionale — derivation.py ripiega su ecdsa puro Python con output identico. Niente qui tocca la rete, eccetto il flag opzionale --check-balance e blind_search (che richiede un nodo Bitcoin locale).
Tutto viene eseguito come modulo dalla radice del repository; nessuna installazione richiesta:
python3 -m bitcoin_security.weak_entropy --help
python3 -m bitcoin_security.blind_search --help
weak_entropy: l'entropia debole è enumerabileI 16 byte "casuali" di entropia BIP39 del wallet provengono in realtà da un seed a 32 bit. L'intera derivazione è reale e verificata rispetto ai vettori di specifica.
seed32 ──MT19937──▶ 16-byte entropy ──BIP39──▶ mnemonic ──PBKDF2(2048)──▶ 64-byte seed
│
address ◀──hash160──── pubkey ◀──BIP32 m/44'/0'/0'/0/0
# Recovery: derive a victim wallet from a weak seed, then recover its full
# mnemonic + private key knowing only the public address.
python3 -m bitcoin_security.weak_entropy
# Expand one seed into every form.
python3 -m bitcoin_security.weak_entropy --show 3571
# Materialize the whole 2**32 space to sharded, resumable files.
python3 -m bitcoin_security.weak_entropy --dump-all --out-dir space_dump --max-file-mb 1000
Le righe sono minime (address <TAB> seed32) perché ogni altra forma è una funzione deterministica di seed32, rigenerata on demand con --show. I dump sono riprendibili a granularità di shard (verificati per riprodurre una copertura contigua, senza buchi e senza duplicati). Riferimento completo ai flag in weak_entropy/README.md.
Avvertenza sulla scala. Il dump completo 2³² è di ~196 GB (minimo) o ~1.05 TB (
--full) e richiede giorni anche con il backend nativo — vedidocs/FINDINGS.md. Non ti serve quasi mai l'intero dump; esporta una porzione limitata per ispezione.
blind_search: non puoi forzare brutalmente una buona chiaveUno scanner di saldo reale e funzionante sull'insieme UTXO di un nodo locale (anche in pruning) tramite scantxoutset. Il suo scopo è il risultato nullo: cercare lo spazio degli indirizzi alla cieca, misurare che non trovi nulla e stampare l'aritmetica che dimostra che non troverai mai nulla.
python3 -m bitcoin_security.blind_search --odds-only # just the math, no node
python3 -m bitcoin_security.blind_search --random 200000 --odds # search 200k random addrs, then the math
python3 -m bitcoin_security.blind_search --control # verify the pipeline finds known-funded addrs