助记词生成原理 - 手动选择助记词 - 在线工具
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: [ "我", "想", "要", "试", "一", "下", "手", "动", "生", "成", "词", "炸"]
评论区