BIP39 定义了一套将随机数编码为可记忆单词的标准,大多数钱包(MetaMask、Phantom、imToken)都支持。
BIP39 原理
- 生成 128/160/192/224/256 位随机熵
- 取熵的 SHA-256 哈希前
len/32位作为校验位,拼接到熵末尾 - 每 11 位映射一个 BIP39 词表单词(共 2048 个词)
- 最终得到 12/15/18/21/24 个单词
| 熵长度 | 校验位 | 总位数 | 单词数 |
|---|---|---|---|
| 128 bit | 4 bit | 132 bit | 12 |
| 256 bit | 8 bit | 264 bit | 24 |
Python 实现(bip-utils)
pip install bip-utils
从助记词派生以太坊私钥和地址
from bip_utils import (
Bip39SeedGenerator,
Bip39MnemonicValidator,
Bip44,
Bip44Coins,
Bip44Changes,
)
mnemonic = "word1 word2 word3 word4 word5 word6 word7 word8 word9 word10 word11 word12"
# 可选:验证助记词是否合法
if not Bip39MnemonicValidator().IsValid(mnemonic):
raise ValueError("助记词无效")
# 助记词 → 种子(可选 passphrase)
seed = Bip39SeedGenerator(mnemonic).Generate(passphrase="")
# 种子 → BIP44 派生路径 m/44'/60'/0'/0/0
ctx = Bip44.FromSeed(seed, Bip44Coins.ETHEREUM)
addr_ctx = (
ctx.Purpose()
.Coin()
.Account(0)
.Change(Bip44Changes.CHAIN_EXT)
.AddressIndex(0)
)
private_key_hex = addr_ctx.PrivateKey().Raw().ToHex()
address = addr_ctx.PublicKey().ToAddress()
print(f"私钥: {private_key_hex}")
print(f"地址: {address}")
派生多个地址
for i in range(5):
addr_ctx = (
ctx.Purpose()
.Coin()
.Account(0)
.Change(Bip44Changes.CHAIN_EXT)
.AddressIndex(i)
)
print(f"[{i}] {addr_ctx.PublicKey().ToAddress()}")
Solana(BIP44 Coin 501)
from bip_utils import Bip44Coins
ctx = Bip44.FromSeed(seed, Bip44Coins.SOLANA)
sol_ctx = ctx.Purpose().Coin().Account(0).Change(Bip44Changes.CHAIN_EXT).AddressIndex(0)
print(f"Solana 地址: {sol_ctx.PublicKey().ToAddress()}")
手动验证 BIP39 校验和(纯 Python)
import hashlib
def validate_bip39(mnemonic: str, wordlist_path: str) -> bool:
with open(wordlist_path) as f:
words = f.read().splitlines()
word_index = {w: i for i, w in enumerate(words)}
mnemonic_words = mnemonic.strip().split()
bits = ""
for word in mnemonic_words:
if word not in word_index:
return False
bits += format(word_index[word], "011b")
# 最后 len/33 位是校验位
cs_len = len(bits) // 33
entropy_bits = bits[:-cs_len]
checksum_bits = bits[-cs_len:]
# 还原熵字节
entropy = int(entropy_bits, 2).to_bytes(len(entropy_bits) // 8, "big")
# SHA256 前 cs_len 位
h = hashlib.sha256(entropy).digest()
expected_cs = format(h[0], "08b")[:cs_len]
return checksum_bits == expected_cs
注意事项
- 助记词等同于钱包全部资产的控制权,不能在任何联网代码中明文存储
- 生产环境派生私钥只能在离线机器或 HSM 上操作
- 仅用于工具开发/验证时,建议使用测试网地址,不要导入真实资产
