助记词生成原理 - 手动选择助记词 - 在线工具

2022-6-16

助记词生成原理 - 手动选择助记词

先来看看助记词的生成原理

bip39.generateMnemonic()可以默认生成12位的助记词,看源码,共分为这几步。

1. 生成长度为128位的随机数

举例,我这边生成128位:

01000101111111000110111011000111011111101010011101011000100100001010000010011101101000011011111101010000011101101100011000100111

js转成Buffer显示就是<Buffer 45 fc 6e c7 7e a7 58 90 a0 9d a1 bf 50 76 c6 27>

2. 生成校验数

对这128位的数字进行校验,采用sha256进行加密。

// entropyBuffer 就是上面的Buffer
const hash = createHash('sha256').update(entropyBuffer).digest();
// 接下来对hash进行处理
// 对每一个的 hashArray 的值进行二进制转化 并且8位补全加拼接
const result = Array.from(hash).map(item => {
    let binary = item.toString(2)
    while (binary.length < 8) {
        binary = '0' + binary;
    }
    return binary
}).join('')

接下来取前随机数位数 / 32位。
我们这里是随机128位,那就得到前四位1000

3. 根据2048个助记词备选项,获取助记词。

将随机128位数和校验码的4位拼接,我们就得到一个132位的二进制数。将这132位数按每11 bit一组。就有了12组。

2 ^ 11 = 2048

每一组都是一个助记词列表的下标。我们就能获得12个助记词。

const bits = entropyBits + checksumBits;
const chunks = bits.match(/(.{1,11})/g);
const words = chunks.map((binary) => {
    const index = binaryToByte(binary);
    return wordlist[index];
});

手动选择助记词

⚠️ 危险!⚠️ 危险!⚠️ 危险!自己挑选助记词,随机性太差。助记词如果泄漏,本站和本人都不承担任何后果。此文只是研究助记词原理使用。

由上文看到 12个助记词,其中11个是随机生成的,最后一个有4/11是校验码。那完全可以自己指定助记词啊。校验码重新生成,重置第12个助记词。go!!!(骚年,你的想法很危险啊 💥)

1. 获取词语下标并转成132位bit(先以中文为例,中英文助记词转换可查看中英文词组数组,下标一样)
const data = '我想要试一下手动生成词汇'

let wordlistIndex = data.split('').map(word => {
    return bip39.wordlists.chinese_simplified.findIndex(item => item == word)
})

// index 下标 转换成 11位的 二进制并拼接
const wordlistIndex_binary = wordlistIndex.map(item => {
    let binary = parseInt(item).toString(2)
    while (binary.length < 11) {
        binary = '0' + binary;
    }
    return binary
}).join('')
重新生成校验位

有了132位的数,那我们就先去掉后四位的校验数,重新生成新的校验数。

const createHash = require("create-hash");
// 去除后4位校验位,分割成长度为8的数组
let wordlistIndex_array = wordlistIndex_binary.slice(0, wordlistIndex_binary.length - 4).match(/.{1,8}/g)

// 转成Buffer
const randomBuffer = Buffer.from(wordlistIndex_array.map(item => '0x' + parseInt(item, 2).toString(16)))

// 重新生成校验位

// 生成校验位的方法
function deriveChecksumBits(entropyBuffer) {
    const ENT = entropyBuffer.length * 8;
    const CS = ENT / 32;
    const hash = createHash('sha256')
        .update(entropyBuffer)
        .digest();
    const result = Array.from(hash).map(item => {
        let binary = item.toString(2)
        while (binary.length < 8) {
            binary = '0' + binary;
        }
        return binary
    }).join('').slice(0, CS);
    return result
}
// 生成校验位
const checksumBits = deriveChecksumBits(randomBuffer)

132位:000000100000001011001100000010010010010001100000000000100000101100000111010000000010011100000011000000001000011000111110001100001111

重新生成助记词

将之前的二进制数后四位改成新的校验位的4位,重新生成助记词。

// 重新生成助记词
const chunks = (wordlistIndex_binary.slice(0, wordlistIndex_binary.length - 4) + checksumBits).match(/(.{1,11})/g)
console.log({chunks});
const words = chunks.map((binary) => {
    const index = parseInt(binary, 2)
    return bip39.wordlists.chinese_simplified[index];
});
// word: [ "我", "想", "要", "试", "一", "下", "手", "动", "生", "成", "词", "炸"]

助记词在线工具

输入助记词生成有效助记词
遇到问题了? 可以直接联系我

评论区