BIP39 助记词会不会重复:数学上不会,现实中被坑的另有其人

有人问过我一个纠结的问题:用钱包 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 是伪随机 + 可预测种子。攻击者知道大概时间戳,就能枚举出你所有可能的助记词。

永远用 secretsos.urandom,不用 random

2. “幸运数字”当种子

有人觉得自己的生日、手机号能当种子更好记:

seed = "5201314"
entropy = sha256(seed)

这种熵严重不足。攻击者跑一遍 09,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 是应该的。 只要用正规钱包生成 + 离线纸质备份,安全性远高于随机重复这种理论问题。