一项教育性研究,探讨比特币密钥安全性究竟来自哪里——以及它不来自哪里。它围绕真实的 BIP39/BIP32 派生构建,包含两个位于同一理念两端的实验:
| 实验 | 搜索空间 | 可行? | 它教会我们什么 |
|---|---|---|---|
weak_entropy — 枚举弱 RNG 钱包空间 | 2³²(糟糕的 RNG) | 是的,数天内 | 钱包的强弱仅取决于其背后的熵。 |
blind_search — 暴力破解一个良好的密钥空间 | 2¹⁶⁰(良好的 RNG) | 不,永远不可能 | 拥有真实熵时,密钥空间在物理上不可搜索。 |
整个项目的关键恰恰在于这种对比:密钥之所以被盗,是因为糟糕的随机性遭到攻击,而绝不是因为在算力上胜过良好的随机性。 两个实验都派生同一种真实的主网地址,因此唯一的变量就是熵。
本仓库用于防御性教育与安全研究:理解为什么弱 RNG 钱包漏洞(Milk Sad / CVE-2023-39910、2018 年 Trust Wallet 扩展漏洞及其同类问题)是灾难性的,以及为什么暴力破解一个正确生成的密钥则不然。
weak_entropy 枚举一个自包含的合成空间。其 weak_entropy() 是针对该漏洞类别刻意构造的模型——一个为 BIP39 提供输入的 32 位 PRNG——并非任何真实钱包 RNG 的逐字节精确克隆。它生成的地址不对应任何人的真实钱包。blind_search 是对你自己的节点的只读余额查询。它不派生任何密钥,也无法花费任何资金;其招牌模式衡量的是盲目搜索的徒劳。请在你控制的钱包、测试网或沙箱中使用它。不要把它指向别人的资金。
仅限教育和经授权的安全研究。 只在你拥有或已获得明确书面许可测试的密钥、钱包和系统上使用。未经授权访问他人的钱包或系统,以及窃取数字资产,均属违法——无论采用何种技术手段,都将触犯美国 CFAA(18 U.S.C. § 1030)、英国 1990 年《计算机滥用法》以及欧盟指令 2013/40/EU 等法律。按**"原样"提供,不附带任何担保**;作者对滥用行为不承担任何责任。本文档不构成法律建议。完整条款与负责任披露指南:DISCLAIMER.md。
钱包的安全性受限于进入其种子的熵,而非下游 SHA-256 / PBKDF2 / secp256k1 的强度。
BIP39 将熵转换为助记词,PBKDF2 将其拉伸为种子,BIP32 派生出密钥树。所有这些环节都很强。但其中没有任何一步增加熵——如果种子取自一个很小的集合,那么钱包可能生成的每一个地址都是可枚举的,再多哈希也无法掩盖这一点。
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
这个目录树体现了这一理念:一个共享的 derivation 核心,两个实验使用它针对同一个地址空间得出相反的结论。
pip install -r requirements.txt # runtime deps
# optional — installs the package + `bsec-enumerate` / `bsec-scan` commands:
pip install -e .
coincurve(原生 libsecp256k1)可使派生速度提升约 5 倍,但它是可选的——derivation.py 会在缺少时回退到纯 Python 的 ecdsa,输出完全相同。除可选的 --check-balance 标志和 blind_search(需要本地比特币节点)外,这里没有任何内容会接触网络。
所有内容都可以作为模块从仓库根目录运行,无需安装:
python3 -m bitcoin_security.weak_entropy --help
python3 -m bitcoin_security.blind_search --help
weak_entropy:弱熵是可枚举的钱包"随机"的 16 字节 BIP39 熵实际上来自一个 32 位种子。完整的派生是真实的,并已根据规范向量验证通过。
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
每一行都是极简格式(address <TAB> seed32),因为所有其他形式都是 seed32 的确定性函数,可通过 --show 按需重新生成。转储可按分片粒度续传(已验证可重现连续、无间隙、无重复的覆盖)。完整标志参考见 weak_entropy/README.md。
规模警告。 完整的 2³² 转储约 196 GB(极简格式)或约 1.05 TB(
--full),即使使用原生后端也需要数天——参见docs/FINDINGS.md。你几乎永远不需要全部数据;转储一个有界的切片用于检查即可。
blind_search:你无法暴力破解一个好密钥一个真实可用的余额扫描器,通过 scantxoutset 扫描本地(允许剪枝)节点的 UTXO 集。其目的在于空结果:盲搜地址空间,实测你什么都找不到,并打印出表明你永远都会一无所获的算式。
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
结果: 该空间为 2¹⁶⁰ ≈ 1.46×10⁴⁸;约 5500 万个地址持有余额;因此一个随机地址有资金的概率约为 3.8×10⁻⁴¹。即使每秒十亿个地址,你也要等待约 8×10²³ 年——约为宇宙年龄的 61 万亿倍。这不是硬件问题:根据兰道尔极限,仅仅数到 2¹⁶⁰ 就超过了太阳剩余的能量输出。节点设置见 blind_search/README.md。
两个实验都派生同一种地址。唯一的区别在于种子所取自的集合大小:
这 128 位的差距——就是全部关键所在。此类中每一桩真实的盗窃案都发生在这个差距之内。
python3 tests/test_blind_search_addresses.py # BIP-173/350/380 address vectors
python3 tests/test_blind_search_pipeline.py # scan pipeline, RPC stubbed
python3 -m bitcoin_security.derivation # derivation self-test (spec vectors)
完整细节、方法和机器规格见 docs/FINDINGS.md。
coincurve(libsecp256k1)替换纯 Python 的 ecdsa 后,每次钱包派生从 3.02 ms 降至 0.591 ms(约 5.1 倍);剩余的性能下限是 PBKDF2-HMAC-SHA512 ×2048,为 0.463 ms/钱包。--full 约 1.05 TB,由 seed32 各位数字的精确闭式解加上实测的平均地址长度得出。bx seed(由时间播种的 32 位 MT19937)。真实资金被盗。https://milksad.info/MIT——参见 LICENSE。使用条款与负责任披露指南:DISCLAIMER.md。报告漏洞:SECURITY.md。