bip39
BIP: 39 (助记词)
Layer: Applications
Title: Mnemonic code for generating deterministic keys
Author: Marek Palatinus <slush@satoshilabs.com>
Pavol Rusnak <stick@satoshilabs.com>
Aaron Voisine <voisine@gmail.com>
Sean Bowe <ewillbefull@gmail.com>
Comments-Summary: Unanimously Discourage for implementation
Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0039
Status: Proposed
Type: Standards Track
Created: --
Abstract
This BIP describes the implementation of a mnemonic code or mnemonic sentence -- a group of easy to remember words -- for the generation of deterministic wallets.
下面就是描述助记码或词(即为了生成hd wallet而生成的一组容易记住的词)的生成
It consists of two parts: generating the mnemonic, and converting it into a binary seed. This seed can be later used to generate deterministic wallets using BIP-0032 or similar methods.
包括两部分:一是生成助记词并将其转成二进制的seed,这个能够作为bip32中的seed来生成hd wallet
Motivation
A mnemonic code or sentence is superior for human interaction compared to the handling of raw binary or hexadecimal representations of a wallet seed. The sentence could be written on paper or spoken over the telephone.
与处理钱包seed的原始二进制或十六进制表示形式相比,助记码或句子更适合于人类交互。这个句子可以写在纸上,也可以通过电话告诉对方。
This guide is meant to be a way to transport computer-generated randomness with a human readable transcription. It's not a way to process user-created sentences (also known as brainwallets) into a wallet seed.
本指南旨在通过人类可读的转换来传输计算机生成的随机数。
Generating the mnemonic
The mnemonic must encode entropy in a multiple of 32 bits. With more entropy security is improved but the sentence length increases. We refer to the initial entropy length as ENT. The allowed size of ENT is 128-256 bits.
助记词必须以32位的倍数选择熵值entropy。随着熵值的增加,句子长度增加,安全性提高。我们将初始熵长度称为ENT。ENT的允许大小是128-256位。
ENT /
First, an initial entropy of ENT bits is generated. A checksum is generated by taking the first bits of its SHA256 hash. This checksum is appended to the end of the initial entropy. Next, these concatenated bits are split into groups of 11 bits, each encoding a number from 0-2047, serving as an index into a wordlist. Finally, we convert these numbers into words and use the joined words as a mnemonic sentence.
(1)首先,生成ENT比特的初始熵entropy(如下面的例子00000000000000000000000000000000,16进制,熵长度为32*4=128)。
(2)通过对初始熵entropy取SHA256散列来获得CS位 (CS= 熵长度/32=4,取得到的SHA256散列的前CS位)校验和,然后将校验和附加到初始熵的末尾。
(3)接下来,(熵entropy+校验和)被分成以11位为一组(一共MS组),每个组编码对应一个0-2047的数字,该数字作为一个索引到wordlist,对应获得wordlist上相应索引的值。
(4)最后,我们将这些数字转换成单词,最终合在一起作为助记句。
The following table describes the relation between the initial entropy length (ENT), the checksum length (CS) and the length of the generated mnemonic sentence (MS) in words.
下表描述了单词中初始熵长度(ENT)、校验和长度(CS)和生成的助记句长度(MS)之间的关系。
CS = ENT /
MS = (ENT + CS) /
| ENT | CS | ENT+CS | MS |
+-------+----+--------+------+
| 128 | 4 | 132 | 12 |
| 160 | 5 | 165 | 15 |
| 192 | 6 | 198 | 18 |
| 224 | 7 | 231 | 21 |
| 256 | 8 | 264 | 24 |
Wordlist
An ideal wordlist has the following characteristics:
一个理想的单词表有以下特点:
a) smart selection of words聪明的词汇选择
- the wordlist is created in such way that it's enough to type the first four
letters to unambiguously identify the word
创建单词列表的方式是这样的:只需输入前四个字母就可以清楚地识别单词
b) similar words avoided避免相似的词
- word pairs like "build" and "built", "woman" and "women", or "quick" and "quickly"
not only make remembering the sentence difficult, but are also more error
prone and more difficult to guess
-像“build”和“build”、“woman”和“women”、或“quick”和“quick”这样的词对不仅使记忆句子变得困难,而且更容易出错,更难以猜测
c) sorted wordlists分类词库
- the wordlist is sorted which allows for more efficient lookup of the code words
(i.e. implementations can use binary search instead of linear search)
- this also allows trie (a prefix tree) to be used, e.g. for better compression
- wordlist是有序的,这允许更有效的查找代码字
(例如,实现可以使用二进制搜索代替线性搜索)
-这也允许使用trie(一个前缀树),例如为了更好的压缩
The wordlist can contain native characters, but they must be encoded in UTF-8 using Normalization Form Compatibility Decomposition (NFKD).
wordlist可以包含本机字符,但它们必须使用规范化形式兼容分解(NFKD)以UTF-8编码。
From mnemonic to seed从助记词转成seed
A user may decide to protect their mnemonic with a passphrase. If a passphrase is not present, an empty string "" is used instead.
用户可能决定使用密码来保护他们的助记符。如果没有密码,则使用空字符串“”。
⚠️密码可以作为一个额外的安全因子来保护种子,即使助记词的备份被窃取,也可以保证钱包的安全(也要求密码拥有足够的复杂度和长度),不过另外一方面,如果我们忘记密码,那么将无法恢复我们的数字资产。
To create a binary seed from the mnemonic, we use the PBKDF2 function with a mnemonic sentence (in UTF-8 NFKD) used as the password and the string "mnemonic" + passphrase (again in UTF-8 NFKD) used as the salt. The iteration count is set to 2048 and HMAC-SHA512 is used as the pseudo-random function. The length of the derived key is 512 bits (= 64 bytes).
(1)为了从助记符创建二进制种子,我们使用PBKDF2函数(密钥拉伸(Key stretching)函数),使用助记词(UTF-8 NFKD)作为密码,使用字符串“助记词”+密码(UTF-8 NFKD)作为salt。迭代计数设置为2048(即重复运算2048次),使用hma - sha512作为伪随机函数。派生键的长度是512位(= 64字节,即最后的seed的长度)。
pbkdf2(mnemonicBuffer, saltBuffer, , , 'sha512')
This seed can be later used to generate deterministic wallets using BIP-0032 or similar methods.
这个seed之后将被bip32或相似的方法使用来生成hd wallet
The conversion of the mnemonic sentence to a binary seed is completely independent from generating the sentence. This results in rather simple code; there are no constraints on sentence structure and clients are free to implement their own wordlists or even whole sentence generators, allowing for flexibility in wordlists for typo detection or other purposes.
将助记句转换为二进制种子句与生成句子完全无关。这导致了相当简单的代码;句子结构没有限制,客户机可以自由地实现自己的单词列表,甚至可以实现整个句子生成器,这允许在单词列表中灵活地进行类型检测或其他目的。
Although using a mnemonic not generated by the algorithm described in "Generating the mnemonic" section is possible, this is not advised and software must compute a checksum for the mnemonic sentence using a wordlist and issue a warning if it is invalid.
虽然使用不是由“生成助记符”部分中描述的算法生成的助记符是可能的,但不建议这样做,软件必须使用wordlist计算助记符句子的校验和,并在其无效时发出警告。
The described method also provides plausible deniability, because every passphrase generates a valid seed (and thus a deterministic wallet) but only the correct one will make the desired wallet available.
所描述的方法还提供了可信的可否认性,因为每个密码都生成一个有效的种子(从而产生一个hd wallet),但是只有正确的一个才能使所需的钱包可用。
实现代码:
BIP39标准就是为了解决助记词的需求,通过随机生成12~24个容易记住的单词,单词序列通过PBKDF2与HMAC-SHA512函数创建出随机种子作为BIP32的种子。
bip39/index.js
var Buffer = require('safe-buffer').Buffer
var createHash = require('create-hash')
var pbkdf2 = require('pbkdf2').pbkdf2Sync
var randomBytes = require('randombytes') // use unorm until String.prototype.normalize gets better browser support
var unorm = require('unorm') var CHINESE_SIMPLIFIED_WORDLIST = require('./wordlists/chinese_simplified.json')
var CHINESE_TRADITIONAL_WORDLIST = require('./wordlists/chinese_traditional.json')
var ENGLISH_WORDLIST = require('./wordlists/english.json')
var FRENCH_WORDLIST = require('./wordlists/french.json')
var ITALIAN_WORDLIST = require('./wordlists/italian.json')
var JAPANESE_WORDLIST = require('./wordlists/japanese.json')
var KOREAN_WORDLIST = require('./wordlists/korean.json')
var SPANISH_WORDLIST = require('./wordlists/spanish.json')
var DEFAULT_WORDLIST = ENGLISH_WORDLIST var INVALID_MNEMONIC = 'Invalid mnemonic'
var INVALID_ENTROPY = 'Invalid entropy'
var INVALID_CHECKSUM = 'Invalid mnemonic checksum' function lpad (str, padString, length) {
while (str.length < length) str = padString + str
return str
} function binaryToByte (bin) {
return parseInt(bin, )
} function bytesToBinary (bytes) {
return bytes.map(function (x) {
return lpad(x.toString(), '', )
}).join('')
} function deriveChecksumBits (entropyBuffer) {
var ENT = entropyBuffer.length *
var CS = ENT /
var hash = createHash('sha256').update(entropyBuffer).digest() return bytesToBinary([].slice.call(hash)).slice(, CS)
} function salt (password) {
return 'mnemonic' + (password || '')
} function mnemonicToSeed (mnemonic, password) {
var mnemonicBuffer = Buffer.from(unorm.nfkd(mnemonic), 'utf8')
var saltBuffer = Buffer.from(salt(unorm.nfkd(password)), 'utf8') return pbkdf2(mnemonicBuffer, saltBuffer, , , 'sha512')
} function mnemonicToSeedHex (mnemonic, password) {
return mnemonicToSeed(mnemonic, password).toString('hex')
} function mnemonicToEntropy (mnemonic, wordlist) {
wordlist = wordlist || DEFAULT_WORDLIST var words = unorm.nfkd(mnemonic).split(' ')
if (words.length % !== ) throw new Error(INVALID_MNEMONIC) // convert word indices to 11 bit binary strings
var bits = words.map(function (word) {
var index = wordlist.indexOf(word)
if (index === -) throw new Error(INVALID_MNEMONIC) return lpad(index.toString(), '', )
}).join('') // split the binary string into ENT/CS
var dividerIndex = Math.floor(bits.length / ) *
var entropyBits = bits.slice(, dividerIndex)
var checksumBits = bits.slice(dividerIndex) // calculate the checksum and compare
var entropyBytes = entropyBits.match(/(.{,})/g).map(binaryToByte)
if (entropyBytes.length < ) throw new Error(INVALID_ENTROPY)
if (entropyBytes.length > ) throw new Error(INVALID_ENTROPY)
if (entropyBytes.length % !== ) throw new Error(INVALID_ENTROPY) var entropy = Buffer.from(entropyBytes)
var newChecksum = deriveChecksumBits(entropy)
if (newChecksum !== checksumBits) throw new Error(INVALID_CHECKSUM) return entropy.toString('hex')
} function entropyToMnemonic (entropy, wordlist) {
if (!Buffer.isBuffer(entropy)) entropy = Buffer.from(entropy, 'hex')
wordlist = wordlist || DEFAULT_WORDLIST // 128 <= ENT <= 256
if (entropy.length < ) throw new TypeError(INVALID_ENTROPY)
if (entropy.length > ) throw new TypeError(INVALID_ENTROPY)
if (entropy.length % !== ) throw new TypeError(INVALID_ENTROPY) var entropyBits = bytesToBinary([].slice.call(entropy))
var checksumBits = deriveChecksumBits(entropy) var bits = entropyBits + checksumBits
var chunks = bits.match(/(.{,})/g)
var words = chunks.map(function (binary) {
var index = binaryToByte(binary)
return wordlist[index]
}) return wordlist === JAPANESE_WORDLIST ? words.join('\u3000') : words.join(' ')
} function generateMnemonic (strength, rng, wordlist) {
strength = strength ||
if (strength % !== ) throw new TypeError(INVALID_ENTROPY)
rng = rng || randomBytes return entropyToMnemonic(rng(strength / ), wordlist)
} function validateMnemonic (mnemonic, wordlist) {
try {
mnemonicToEntropy(mnemonic, wordlist)
} catch (e) {
return false
} return true
} module.exports = {
mnemonicToSeed: mnemonicToSeed,
mnemonicToSeedHex: mnemonicToSeedHex,
mnemonicToEntropy: mnemonicToEntropy,
entropyToMnemonic: entropyToMnemonic,
generateMnemonic: generateMnemonic,
validateMnemonic: validateMnemonic,
wordlists: {
EN: ENGLISH_WORDLIST,
JA: JAPANESE_WORDLIST, chinese_simplified: CHINESE_SIMPLIFIED_WORDLIST,
chinese_traditional: CHINESE_TRADITIONAL_WORDLIST,
english: ENGLISH_WORDLIST,
french: FRENCH_WORDLIST,
italian: ITALIAN_WORDLIST,
japanese: JAPANESE_WORDLIST,
korean: KOREAN_WORDLIST,
spanish: SPANISH_WORDLIST
}
}
test vector
"",//entropy
"abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about",//mnemonic
"c55257c360c07c72029aebc1b53c05ed0362ada38ead3e3e9efa3708e53495531f09a6987599d18264c1e1c92f2cf141630c7a3c4ab7c81b2f001698e7463b04",//seed
"xprv9s21ZrQH143K3h3fDYiay8mocZ3afhfULfb5GX8kCBdno77K4HiA15Tg23wpbeF1pLfs1c5SPmYHrEpTuuRhxMwvKDwqdKiGJS9XFKzUsAF"//root key
实例测试:
npm install bip- --save
//+ bip39@2.5.0
var bip39 = require('bip39') // defaults to BIP39 English word list
// uses HEX strings for entropy
var mnemonic = bip39.entropyToMnemonic('')
console.log(mnemonic)
// => abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about // reversible
console.log(bip39.mnemonicToEntropy(mnemonic))
// => '00000000000000000000000000000000' // Generate a random mnemonic (uses crypto.randomBytes under the hood), defaults to 128-bits of entropy
// var mnemonic = bip39.generateMnemonic() console.log(bip39.mnemonicToSeedHex(mnemonic))
// => '5eb00bbddcf069084889a8ab9155568165f5c453ccb85e70811aaed6f6da5fc19a5ac40b389cd370d086206dec8aa6c43daea6690f20ad3d8d48b2d2ce9e38e4' console.log(bip39.mnemonicToSeed(mnemonic))
// => <Buffer 5e b0 0b bd dc f0 69 08 48 89 a8 ab 91 55 56 81 65 f5 c4 53 cc b8 5e 70 81 1a ae d6 f6 da 5f c1 9a 5a c4 0b 38 9c d3 70 d0 86 20 6d ec 8a a6 c4 3d ae ... 14 more bytes> console.log(bip39.validateMnemonic(mnemonic))
// => true console.log(bip39.validateMnemonic('basket actual'))
// => false
bip39的更多相关文章
- 【转】干货 | 【虚拟货币钱包】从 BIP32、BIP39、BIP44 到 Ethereum HD Wallet
虚拟货币钱包 钱包顾名思义是存放$$$.但在虚拟货币世界有点不一样,我的帐户资讯(像是我有多少钱)是储存在区块链上,实际存在钱包中的是我的帐户对应的 key.有了这把 key 我就可以在虚拟货币世界证 ...
- 理解开发HD 钱包涉及的 BIP32、BIP44、BIP39
如果你还在被HD钱包.BIP32.BIP44.BIP39搞的一头雾水,来看看这边文章吧. 数字钱包概念 钱包用来存钱的,在区块链中,我们的数字资产都会对应到一个账户地址上, 只有拥有账户的钥匙(私钥) ...
- Ethereum HD Wallet(虚拟货币钱包)-BIP32、BIP39、BIP44
1.使用HD钱包的好处(链接:https://www.jianshu.com/p/53405db83c16) 备份更容易 传统钱包的问题是一个钱包可能存有一堆密钥地址,每个地址都有一些比特币.这样备份 ...
- 1.16. BIP39协议:使用助记词生成确定性钱包
以太坊系统学习教程: https://www.netkiller.cn/blockchain/bip39.html 1.16. BIP39协议:使用助记词生成确定性钱包 BIP:39 层:应用层 标题 ...
- 【虚拟货币钱包】从 BIP32、BIP39、BIP44 到 Ethereum HD Wallet
干货 | [虚拟货币钱包]从 BIP32.BIP39.BIP44 到 Ethereum HD Wallet {{uploading-image-882090.png(uploading...)}}
- 非对称加密, 助记词, PIN, WIF
一钱包 1.1非对称加密, 助记词, PIN, WIF, 地址 1.1.1 非对称加密算法 非对称加密算法, 加密与解密使用不同的KEY, 我们分别称为私钥与公钥,其中可以通过私钥生成公钥 在比特币中 ...
- [转]HD钱包的助记词与密钥生成原理
本文转自:https://blog.csdn.net/opassf/article/details/79978047 区块链相关的话题持续发酵之时,应该不少人知道加密货币钱包,钱包是普通用户与加密货币 ...
- 以太坊钱包开发系列2 - 账号Keystore文件导入导出
以太坊去中心化网页钱包开发系列,将从零开始开发出一个可以实际使用的钱包,本系列文章是理论与实战相结合,一共有四篇:创建钱包账号.账号Keystore文件导入导出.展示钱包信息及发起签名交易.发送Tok ...
- (转)以太坊 钱包 创建 导入 Keystore
最近闲来无事 研究了下以太坊钱包 下边分享下 准备工作 : 需要用到的加密:BIP32 BIP39 BIP44 SCRYPT 加密算法 githab地址 https://github.com/Nova ...
随机推荐
- 新建hadoop用户以及用户组,给予sudo权限
1.首先新建用户,adduser命令 sudo adduser hadoop passwd hadoop 输入密码之后,一路 y 确定. 2.添加用户组 在创建hadoop用户的同时也创建了hadoo ...
- AngularJS table 按照表头字段排序功能(升序和降序)
一.表格按照表头排序 <!doctype html> <html ng-app="a3_4"> <head> <title>表头排序 ...
- format格式化字符串
假如想要表达这样一条语句:李明今年十二岁 输出这样一条语句 name = 'LiMing' age = 12 print( name + 'is' + age + 'years old') #输出 L ...
- 微信小程序-上传照片-多张显示
图片就是一个简单的效果 实现 先看wxml和wxss代码 <view class='in-demand'> <view class='dema-title'> <text ...
- BZOJ2957: 楼房重建(分块)
题意 题目链接 Sol 自己YY出了一个\(n \sqrt{n} \log n\)的辣鸡做法没想到还能过.. 可以直接对序列分块,我们记第\(i\)个位置的值为\(a[i] = \frac{H_i}{ ...
- 【读书笔记】iOS-自定义视图的创建
静态创建自定义视图就是以拖动的方法来创建. 动态创建自定义视图可以理解为使用代码来创建自定义视图. 参考资料:<iOS7开发快速入门>
- CSS3 鼠标划上图片放大
td img{transition: all 1s}/*鼠标划上,图片1s全部显示完成*/ td img:hover{ transform: scale(5) translateX(50%) tran ...
- Java基础笔记(3) 进制与进制转换
---恢复内容开始--- 进制 在一般生活中,我们一直在应用的十进制,就是逢十进一,而今天我们要接触的是,计算机编程常用的进制!首先我们要知道,计算机内部运算采用的是二进制,也就是逢二进制! 1.什么 ...
- ActiveReports 报表应用教程 (14)---数据可视化
葡萄城ActiveReports报表中提供了丰富的数据可视化解决方案,用户可以将数据以图像化的方式进行显示,让报表数据更加形象且便于理解.在葡萄城ActiveReports报表中提供了大多数常用的二维 ...
- Python 排错UnicodeEncodeError 'ascii' codec can't encode character 错误解决方法
Python UnicodeEncodeError 'ascii' codec can't encode character 错误解决方法 by:授客 QQ:1033553122 错误描述: py ...