有人问过我一个纠结的问题:用钱包 APP 生成助记词,会不会跟别人重复导致钱包被盗? 数学上算一下就知道,重复的概率低到根本不用担心;真正被盗的原因,几乎都是别的坑。
BIP39 生成流程
12 词助记词的生成,标准流程只有三步:
1. 从系统 CSPRNG 取 128 位熵
import secrets
entropy = secrets.token_bytes(16) # 16 字节 = 128 位
secrets 底层用的是操作系统提供的密码学安全随机源:
- Windows:
BCryptGenRandom - Linux:
/dev/urandom - macOS:
SecRandomCopyBytes
2. 拼上 4 位校验和
对 128 位熵做 SHA-256,取前 4 位挂到熵尾部,凑成 132 位:
128 位熵 + 4 位校验和 = 132 位
3. 每 11 位查一次词表
BIP39 词表有 2^11 = 2048 个词。132 位 / 11 = 12 个词。
10010101100 → abandon
11100101010 → ability
...
碰撞概率有多低
12 词的熵是 128 位,等于 3.4 × 10³⁸ 种可能。用生日悖论算一下极端情况:
假设全球 100 亿人,每人生成 100 万个钱包,一共 10¹⁶ 个:
碰撞概率 ≈ N² / (2 × 2¹²⁸)
≈ 10³² / 6.8 × 10³⁸
≈ 1.5 × 10⁻⁷
约 0.000015%,还是极端假设。真实世界远远达不到这个量级。24 词是 256 位熵,那更是天文数字。
只要用正规钱包 + 系统 CSPRNG 生成,重复被盗几乎不可能。
真被盗的常见姿势
1. 随机数不安全
自己造轮子最容易出问题:
import random
random.seed(time.time()) # 危险
Python 的 random 是伪随机 + 可预测种子。攻击者知道大概时间戳,就能枚举出你所有可能的助记词。
永远用 secrets 或 os.urandom,不用 random。
2. “幸运数字”当种子
有人觉得自己的生日、手机号能当种子更好记:
seed = "5201314"
entropy = sha256(seed)
这种熵严重不足。攻击者跑一遍 0 到 9,999,999,999 就把你的钱包翻出来了。任何”人可以记住”的种子都不够安全。
3. 脑钱包
想一句话当助记词:
iloveyou123
彩虹表早就把常见短语算光了,这种钱包上链一分钟就被扫走。
4. 假钱包 APP
流程:
APP 生成助记词 → 悄悄上传服务器 → 等你存币 → 转走
来路不明的浏览器插件、“新币空投工具”是重灾区。装钱包只从官网或 App Store。
5. 助记词泄露
- 截屏保存到手机相册(云同步就完了)
- 记在便笺、微信自己的对话
- 输入到”辅助工具”网页
正确做法:只离线纸质备份,多份异地存放。
安全生成的一行代码
用 bip_utils:
from bip_utils import Bip39MnemonicGenerator, Bip39WordsNum
mnemonic = Bip39MnemonicGenerator().FromWordsNumber(Bip39WordsNum.WORDS_NUM_12)
print(mnemonic)
内部就是 CSPRNG + 128 位熵 + SHA-256 校验,标准 BIP39 流程。
一句话总结
担心助记词重复是想多了;担心自己不用 CSPRNG、拿脑钱包和假钱包 APP 是应该的。 只要用正规钱包生成 + 离线纸质备份,安全性远高于随机重复这种理论问题。
