Caloogy 文章
English

随机数出问题的钱包

日期
2026 年 5 月 31 日
系列
钱包
阅读
4 分钟
主题
WalletRandomnessEntropyCsprng

一句话版本

私钥就是一个随机数。只要这个随机数不够随机(可选范围太小、可预测、或者被重复使用),攻击者就不用破解任何密码学,直接把所有可能的私钥枚举一遍即可。 从"脑钱包"到 Profanity 靓号工具,再到 Milk Sad 事件,一次次盗币背后都是同一个原因:用了 32 位种子、时间戳或人想出来的句子,而不是真正的密码学安全随机数。

全文分三层:

  1. 通俗理解:256 位的锁,只用了 32 位的钥匙
  2. 实际用处:脑钱包、Android 随机数漏洞、Profanity、Milk Sad、Trust Wallet
  3. 原理与工程要点:熵、CSPRNG、怎么测试随机数,以及签名随机数

第一层:通俗理解

1.1 256 位的锁,32 位的钥匙

以太坊私钥是一个 256 位的数,可能的取值约 107710^{77} 个,比可观测宇宙里的原子还多,猜中是不可能的。

但如果生成私钥的程序是这样的:

  1. 取当前时间(或一个 32 位的数)作为"种子";
  2. 用一个普通的伪随机数生成器从种子算出 256 位私钥。

那么私钥看起来有 256 位,实际上只有 232≈432^{32} \approx 43 亿种可能。一台显卡几个小时就能全部试一遍。

私钥的安全性取决于它的熵(真正不可预测的位数),而不是它的长度。

1.2 三种常见错误

错误 例子
种子太短 用 32 位整数或时间戳给随机数生成器做种子
用错生成器 用游戏、模拟用的伪随机数(如梅森旋转),它的输出可以被推算
人来"想"随机数 用一句诗、一个口号的哈希当私钥(脑钱包)

第二层:实际用处

事件 原因 后果
脑钱包(2010 年代) 用一句话的 SHA-256 当私钥 研究者发现大量常用句子、名言、歌词对应的地址都被机器人监控,一有入账就被秒转走
Android SecureRandom(2013) 系统随机数生成器有缺陷,部分签名重复使用了随机数 kk 多个比特币钱包 App 的私钥可以被算出,资金被盗(kk 重复为何致命,见《椭圆曲线》)
Profanity(2022) 一个流行的以太坊"靓号地址"生成工具,只用 32 位种子初始化 安全研究者披露后数月内,做市商 Wintermute 的一个靓号地址被盗约 1.6 亿美元
Milk Sad(2023) 命令行工具 Libbitcoin Explorer 的 bx seed 用梅森旋转 + 32 位时间种子生成助记词 研究团队发现大量钱包可被枚举,已有资金被盗
Trust Wallet 浏览器扩展(2022–2023) WebAssembly 版本的随机数生成器熵不足 一批在特定时期生成的钱包可被枚举,造成损失

Profanity 事件特别值得一提:"靓号"本身就是一个危险信号。为了得到开头是 0x0000 的地址,工具需要飞快地生成海量私钥,开发者为了速度牺牲了随机性。


第三层:原理与工程要点

3.1 熵和 CSPRNG

正确的来源 错误的来源
操作系统:/dev/urandom、getrandom()、BCryptGenRandom rand()、Math.random()、random.random()
浏览器:crypto.getRandomValues() 梅森旋转(MT19937)
Python:secrets 模块 用时间戳、进程号做种子
硬件钱包的真随机数发生器 自己想的句子、自己掷的少量骰子

3.2 为什么梅森旋转不行

梅森旋转(MT19937)是很好的统计随机数生成器,用于模拟和游戏。但它是线性的(基于 F2\mathbb{F}_2 上的线性递推,和LFSR与流密码是同一类):看到 624 个连续的 32 位输出,就能还原它的全部内部状态,预测之后的所有输出。即使种子足够长,也不能用于密码学。

3.3 怎么测试

随机数的问题几乎不可能靠看输出发现:一个只有 32 位熵的生成器,输出看起来照样很随机,统计检验也都能通过。所以测试的重点在代码审查:

  1. 找出所有生成私钥、助记词、nonce、会话 token 的地方;
  2. 确认每处都直接调用操作系统或语言标准库的 CSPRNG;
  3. 确认没有用时间、PID、计数器做种子,没有"为了可复现"而固定种子;
  4. 对 WebAssembly、嵌入式设备、虚拟机刚启动时等"熵可能不足"的环境格外小心。

3.4 签名时的随机数

不仅生成私钥需要随机数,ECDSA 每次签名也需要一个随机数 kk,它重复或可预测就会泄露私钥。现代做法是 RFC 6979:用私钥和消息哈希确定性地生成 kk,彻底不依赖随机数生成器的质量。Ed25519 和 BLS 签名天生是确定性的(见《Schnorr签名》、双线性配对与BLS签名)。

3.5 给用户的建议


总结

层次 要点
直觉 私钥安全看熵不看长度;32 位种子 = 43 亿种可能
案例 脑钱包、Android、Profanity、Milk Sad、Trust Wallet
原理 只能用 CSPRNG;梅森旋转是线性的,可被预测
测试 靠代码审查而不是统计检验;签名用确定性 kk