Web3钱包的助记词作用与底层实现机制
助记词(Mnemonic Phrase)在加密货币领域,尤其是在钱包管理和私钥生成中发挥着重要作用。助记词的生成遵循广泛使用的 BIP-39 标准,通过一系列人类易于记忆和书写的英文单词,提供了更加安全且方便的私钥管理方式。
具体而言,助记词的作用包括:
根据 BIP-39 标准,助记词的单词数量可以为 12 个、15 个、18 个、21 个或 24 个,其中最常见的是使用 12 个或 24 个单词。
实际使用中,大多数钱包应用推荐用户使用12或24个单词作为助记词,以提供足够高的安全性,同时兼顾了用户记忆和存储的便捷性。用户在备份助记词时,建议使用离线方式记录,例如纸质存储或硬件钱包,避免助记词被恶意软件或黑客窃取。
需要特别注意的是,助记词的单词顺序至关重要,不同的顺序会生成完全不同的钱包地址和私钥。因此,用户在记录和恢复钱包时,一定要严格按照原始顺序进行,以确保资产安全。
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line
const bip39 = require('bip39');
const crypto_ts = require('crypto');
// 1. 生成 128 位随机熵
const entropy = crypto_ts.randomBytes(16); // 128 位是 16 字节
// 2. 计算校验和 (SHA-256)
const hash = crypto_ts.createHash('sha256').update(entropy).digest();
const checksum = hash[0] >> 4; // 取前 4 位
// 3. 组合熵和校验和
let bits = '';
for (let i = 0; i < entropy.length; i++) {
bits += entropy[i].toString(2).padStart(8, '0');
}
bits += checksum.toString(2).padStart(4, '0');
// 4. 分割为助记词索引
const indices = [];
for (let i = 0; i < bits.length; i += 11) {
const index = parseInt(bits.slice(i, i + 11), 2);
indices.push(index);
}
// 5. 映射为助记词
const wordlist = bip39.wordlists.english;
const mnemonic = indices.map(index => wordlist[index]).join(' ');
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line
def generate_mnemonic():
# 1. 生成 128 位随机熵 (16 字节)
entropy = os.urandom(16)
# 2. 计算校验和 (SHA-256)
hash_bytes = hashlib.sha256(entropy).digest()
checksum_bits = bin(hash_bytes[0])[2:].zfill(8)[:4] # 取前 4 位
# 3. 组合熵和校验和
entropy_bits = ''.join([bin(byte)[2:].zfill(8) for byte in entropy])
combined_bits = entropy_bits + checksum_bits
# 4. 分割为助记词索引
indices = [int(combined_bits[i:i + 11], 2) for i in range(0, len(combined_bits), 11)]
# 5. 映射为助记词
wordlist = bip39.INDEX_TO_WORD_TABLE
mnemonic = ' '.join([wordlist[index] for index in indices])
return mnemonic
# 生成并打印助记词mnemonic_phrase = generate_mnemonic()
print(f"Generated mnemonic phrase: {mnemonic_phrase}")
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line
def validate_mnemonic(mnemonic, wordlist):
words = mnemonic.split()
# 检查单词数量
if len(words) not in [12, 15, 18, 21, 24]:
return False
# 检查单词是否在词汇表中
for word in words:
if word not in wordlist:
return False
# 将助记词转化成位串
binary_string = ''
for word in words:
index = wordlist.index(word)
binary_string += format(index, '011b')
# 提取种子和校验和
seed_bits_length = (len(words) * 11) - (len(words) // 3)
seed_bits = binary_string[:seed_bits_length]
checksum_bits = binary_string[seed_bits_length:]
# 计算校验和
import hashlib
seed_bytes = int(seed_bits, 2).to_bytes(len(seed_bits) // 8, byteorder='big')
hash_value = hashlib.sha256(seed_bytes).hexdigest()
hash_bits = bin(int(hash_value, 16))[2:].zfill(256)
calculated_checksum = hash_bits[:len(words) // 3]
# 验证校验和
return checksum_bits == calculated_checksum
# Example usage:
mnemonic = "legal winner thank year wave sausage worth useful legal winner thank yellow"
wordlist = [...] # BIP-39 wordlist
is_valid = validate_mnemonic(mnemonic, wordlist)
print("Is valid mnemonic:", is_valid)
编码流程如下,解码是下面的逆过程
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line
助记词(Mnemonic words)
↓ (单词表查询索引)
单词索引(Index)
↓ (索引转11位二进制)
二进制(Binary string)
↓ (截取熵Entropy)
二进制熵(Binary Entropy)
↓ (转16进制)
熵(Entropy, Hexadecimal)
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line
const bip39 = require('bip39');
const bip32 = require('bip32');
export function createHelpWord(number: number, language: string) {
switch (language) {
case 'chinese_simplified':
if(number === 12) {
return bip39.generateMnemonic(128, null, bip39.wordlists.chinese_simplified);
} else if(number === 15) {
return bip39.generateMnemonic(160, null, bip39.wordlists.chinese_simplified);
} else if(number === 18) {
return bip39.generateMnemonic(192, null, bip39.wordlists.chinese_simplified);
} else if(number === 21) {
return bip39.generateMnemonic(224, null, bip39.wordlists.chinese_simplified);
} else if(number === 24) {
return bip39.generateMnemonic(256, null, bip39.wordlists.chinese_simplified);
} else {
return "unsupported"
}
case 'chinese_traditional':
if(number === 12) {
return bip39.generateMnemonic(128, null, bip39.wordlists.chinese_traditional);
} else if(number === 15) {
return bip39.generateMnemonic(160, null, bip39.wordlists.chinese_traditional);
} else if(number === 18) {
return bip39.generateMnemonic(192, null, bip39.wordlists.chinese_traditional);
} else if(number === 21) {
return bip39.generateMnemonic(224, null, bip39.wordlists.chinese_traditional);
} else if(number === 24) {
return bip39.generateMnemonic(256, null, bip39.wordlists.chinese_traditional);
} else {
return "unsupported"
}
case 'english':
if(number === 12) {
return bip39.generateMnemonic(128, null, bip39.wordlists.english);
} else if(number === 15) {
return bip39.generateMnemonic(160, null, bip39.wordlists.english);
} else if(number === 18) {
return bip39.generateMnemonic(192, null, bip39.wordlists.english);
} else if(number === 21) {
return bip39.generateMnemonic(224, null, bip39.wordlists.english);
} else if(number === 24) {
return bip39.generateMnemonic(256, null, bip39.wordlists.english);
} else {
return "unsupported"
}
case 'french':
if(number === 12) {
return bip39.generateMnemonic(128, null, bip39.wordlists.french);
} else if(number === 15) {
return bip39.generateMnemonic(160, null, bip39.wordlists.french);
} else if(number === 18) {
return bip39.generateMnemonic(192, null, bip39.wordlists.french);
} else if(number === 21) {
return bip39.generateMnemonic(224, null, bip39.wordlists.french);
} else if(number === 24) {
return bip39.generateMnemonic(256, null, bip39.wordlists.french);
} else {
return "unsupported"
}
case 'italian':
if(number === 12) {
return bip39.generateMnemonic(128, null, bip39.wordlists.italian);
} else if(number === 15) {
return bip39.generateMnemonic(160, null, bip39.wordlists.italian);
} else if(number === 18) {
return bip39.generateMnemonic(192, null, bip39.wordlists.italian);
} else if(number === 21) {
return bip39.generateMnemonic(224, null, bip39.wordlists.italian);
} else if(number === 24) {
return bip39.generateMnemonic(256, null, bip39.wordlists.italian);
} else {
return "unsupported"
}
case 'japanese':
if(number === 12) {
return bip39.generateMnemonic(128, null, bip39.wordlists.japanese);
} else if(number === 15) {
return bip39.generateMnemonic(160, null, bip39.wordlists.japanese);
} else if(number === 18) {
return bip39.generateMnemonic(192, null, bip39.wordlists.japanese);
} else if(number === 21) {
return bip39.generateMnemonic(224, null, bip39.wordlists.japanese);
} else if(number === 24) {
return bip39.generateMnemonic(256, null, bip39.wordlists.japanese);
} else {
return "unsupported"
}
case 'korean':
if(number === 12) {
return bip39.generateMnemonic(128, null, bip39.wordlists.korean);
} else if(number === 15) {
return bip39.generateMnemonic(160, null, bip39.wordlists.korean);
} else if(number === 18) {
return bip39.generateMnemonic(192, null, bip39.wordlists.korean);
} else if(number === 21) {
return bip39.generateMnemonic(224, null, bip39.wordlists.korean);
} else if(number === 24) {
return bip39.generateMnemonic(256, null, bip39.wordlists.korean);
} else {
return "unsupported"
}
case 'spanish':
if(number === 12) {
return bip39.generateMnemonic(128, null, bip39.wordlists.spanish);
} else if(number === 15) {
return bip39.generateMnemonic(160, null, bip39.wordlists.spanish);
} else if(number === 18) {
return bip39.generateMnemonic(192, null, bip39.wordlists.spanish);
} else if(number === 21) {
return bip39.generateMnemonic(224, null, bip39.wordlists.spanish);
} else if(number === 24) {
return bip39.generateMnemonic(256, null, bip39.wordlists.spanish);
} else {
return "unsupported"
}
default:
return "unsupported"
}
}
export function wordsToEntropy(mnemonic: string, language: string) {
switch (language) {
case 'chinese_simplified':
return bip39.mnemonicToEntropy(mnemonic, bip39.wordlists.chinese_simplified);
case 'chinese_traditional':
return bip39.mnemonicToEntropy(mnemonic, bip39.wordlists.chinese_traditional);
case 'english':
return bip39.mnemonicToEntropy(mnemonic, bip39.wordlists.english);
case 'french':
return bip39.mnemonicToEntropy(mnemonic, bip39.wordlists.french);
case 'italian':
return bip39.mnemonicToEntropy(mnemonic, bip39.wordlists.italian);
case 'japanese':
return bip39.mnemonicToEntropy(mnemonic, bip39.wordlists.japanese);
case 'korean':
return bip39.mnemonicToEntropy(mnemonic, bip39.wordlists.korean);
case 'spanish':
return bip39.mnemonicToEntropy(mnemonic, bip39.wordlists.spanish);
default:
return "unsupported"
}
}
export function entropyToWords(encrytMnemonic:string, language:string) {
switch (language) {
case 'chinese_simplified':
return bip39.entropyToMnemonic(encrytMnemonic, bip39.wordlists.chinese_simplified);
case 'chinese_traditional':
return bip39.entropyToMnemonic(encrytMnemonic, bip39.wordlists.chinese_traditional);
case 'english':
return bip39.entropyToMnemonic(encrytMnemonic, bip39.wordlists.english);
case 'french':
return bip39.entropyToMnemonic(encrytMnemonic, bip39.wordlists.french);
case 'italian':
return bip39.entropyToMnemonic(encrytMnemonic, bip39.wordlists.italian);
case 'japanese':
return bip39.entropyToMnemonic(encrytMnemonic, bip39.wordlists.japanese);
case 'korean':
return bip39.entropyToMnemonic(encrytMnemonic, bip39.wordlists.korean);
case 'spanish':
return bip39.entropyToMnemonic(encrytMnemonic, bip39.wordlists.spanish);
default:
return "unsupported"
}
}
export function mnemonicToSeed(mnemonic, password){
return bip39.mnemonicToSeed(mnemonic, password)
}
export function mnemonicToSeedHex(mnemonic, password){
return bip39.mnemonicToSeedHex(mnemonic, password);
}
export function validateMnemonic(mnemonic, language) {
switch (language) {
case 'chinese_simplified':
return bip39.validateMnemonic(mnemonic, bip39.wordlists.chinese_simplified);
case 'chinese_traditional':
return bip39.validateMnemonic(mnemonic, bip39.wordlists.chinese_traditional);
case 'english':
return bip39.validateMnemonic(mnemonic, bip39.wordlists.english);
case 'french':
return bip39.validateMnemonic(mnemonic, bip39.wordlists.french);
case 'italian':
return bip39.validateMnemonic(mnemonic, bip39.wordlists.italian);
case 'japanese':
return bip39.validateMnemonic(mnemonic, bip39.wordlists.japanese);
case 'korean':
return bip39.validateMnemonic(mnemonic, bip39.wordlists.korean);
case 'spanish':
return bip39.validateMnemonic(mnemonic, bip39.wordlists.spanish);
default:
return "unsupported"
}
}
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line
test('test create mnemonic', async () => {
const mnemonic_12_english = createMnemonic(12, "english")
const mnemonic_12_chinese = createMnemonic(12, "chinese_simplified")
console.log(mnemonic_12_chinese) console.log(mnemonic_12_chinese)
const mnemonic_to_entropy = mnemonicToEntropy(mnemonic_12_chinese, "chinese_simplified")
console.log(mnemonic_to_entropy)
const entropy_to_mnemonic = entropyToMnemonic(mnemonic_to_entropy, "chinese_simplified")
console.log(entropy_to_mnemonic)
const mnemonic_to_seed = mnemonicToSeed(mnemonic_to_entropy, "")
console.log(mnemonic_to_seed)
const mnemonic_to_seed_sync = mnemonicToSeedSync(mnemonic_to_entropy, "")
console.log(mnemonic_to_seed_sync)
const vm = validateMnemonic(mnemonic_to_entropy, "")
console.log(vm)});
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line
class Bip39Mnemonic:
def __init__(self):
pass
def createMnemonic(self, number):
mnemonic = bip39.get_entropy_bits(number)
return mnemonic
def mnemonicToEntropy(self, mnemonic):
decode_words = bip39.decode_phrase( mnemonic)
return decode_words
def entropyToMnemonic(self, entropy):
nemonic_entropy = bip39.encode_bytes(entropy)
return nemonic_entropy
def mnemonicToSeed(self, mnemonic):
nemonic_to_seed = bip39.phrase_to_seed(mnemonic)
return nemonic_to_seed
def validateMnemonic(self, mnemonic):
return bip39.check_phrase(mnemonic)
def generateMnemonic(self):
# 1. 生成 128 位随机熵 (16 字节)
entropy = os.urandom(16)
# 2. 计算校验和 (SHA-256)
hash_bytes = hashlib.sha256(entropy).digest()
checksum_bits = bin(hash_bytes[0])[2:].zfill(8)[:4] # 取前 4 位
# 3. 组合熵和校验和
entropy_bits = ''.join([bin(byte)[2:].zfill(8) for byte in entropy])
combined_bits = entropy_bits + checksum_bits
# 4. 分割为助记词索引
indices = [int(combined_bits[i:i + 11], 2) for i in range(0, len(combined_bits), 11)]
# 5. 映射为助记词
wordlist = bip39.INDEX_TO_WORD_TABLE
mnemonic = ' '.join([wordlist[index] for index in indices])
return mnemonic
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line
import bip
bip39_mnemonic = bip.Bip39Mnemonic()
mnemonic_phrase = bip39_mnemonic.generateMnemonic()
print(f"Generated mnemonic phrase: {mnemonic_phrase}")
mnemonic_12_phrase = bip39_mnemonic.createMnemonic(12)
print(f"create mnemonic phrase: {mnemonic_phrase}")
助记词(Mnemonic Phrase)是一种在区块链和加密货币领域广泛使用的安全私钥管理方式,基于 BIP-39 标准。助记词使用一系列易于记忆的单词,能够有效备份和恢复钱包,并派生出多个私钥和地址,极大提升用户使用便捷性与安全性。
助记词的生成主要经历以下步骤:
在实际使用中,常见的是12或24个单词的助记词,推荐用户离线存储,确保安全性。验证助记词时,需要检查单词数量、词汇表有效性、以及校验位的正确性,以保证助记词的合法性。
代码实战部分,文章分别展示了Node.js和Python的助记词生成与验证代码示例,帮助开发者更好地理解并实现相关功能。此外,文章还提供了对助记词编解码过程的详细描述,强调助记词和熵之间相互转换的机制。
最后,为了简化开发,文章中封装了Node.js和Python的助记词工具函数,涵盖多语言助记词生成、助记词与熵互转、以及助记词的种子(Seed)派生和有效性验证。这种封装大幅提高了Web3开发中的安全性与开发效率。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!