本文转自:https://blog.csdn.net/opassf/article/details/79978047

区块链相关的话题持续发酵之时,应该不少人知道加密货币钱包,钱包是普通用户与加密货币系统交互的入口,各种形态的钱百花齐放,手机钱包、桌面钱包、硬件钱包、网页钱包和纸质钱包等。通过钱包可以无国界无限制地转移你的数字资产。从开发者的角度看,钱包的作用是管理用户的私钥、通过私钥签名交易管理用户在区块链上的数字货币。

Bitcoin Address + Private key = Bitcoin Wallet

根据密钥之间是否有关联可把钱包分为两类:nondeterministic wallet 和 deterministic wallet

  • nondeterministic wallet:密钥对之间没有关联
  • deterministic wallet: 密钥对由一个原始的种子主密钥推导而来。最常见的推导方式是树状层级推导 (hierarchical deterministic) 简称 HD

比特币钱包 (Bitcoin Core) 生成密钥对之间没有任何关联,属于 nondeterministic wallet ,这种类型的钱包如果想备份导入是比较麻烦的,用户必须逐个操作钱包中的私钥和对应地址。deterministic wallet 基于 BIP32 (Bitcoin Improvement Proposal 32) 标准实现,通过一个共同的种子维护 n 多私钥,种子推导私钥采用不可逆哈希算法,在需要备份钱包私钥时,只备份这个种子即可(大多数情况下的种子是通过 BIP44 生成了助记词,方便抄写),在支持 BIP32, BIP44 标准的钱包只需导入助记词即可导入全部的私钥。

principle of avoiding address reuse: 提倡避免地址重复使用,当数字货币地址已经发生过一次转账就存在私钥泄漏的可能性。

符合 BIP-32/BIP-44 标准的 HD 钱包

上文提到 Deterministic wallets 能够通过一个种子推导出很多密钥,它基于 BIP32 标准实现,种子能够推导出主密钥 (master key), 主密钥推导出子密钥 (children keys),子密钥推导出孙密钥 (grandchildren keys), 以此递推。

  • 有树状特征的 HD 钱包非常适用于有组织结构的公司使用
  • HD 钱包能够在不需知道私钥的前提下生成大量的公钥,非常适用于只负责收款的服务

BIP32 标准的种子是一个随机 16 字节的 16 进制的字符串。如果能够适用英文单词作为助记词无疑会降低种子备份及恢复钱包难度,BIP39 标准就是为了解决助记词的需求,通过随机生成 12 ~ 24 个容易记住的单词,单词序列通过 PBKDF2 与 HMAC-SHA512 函数创建出随机种子作为 BIP32 的种子。

BIP32/BIP39 标准详解

BIP39 标准定义了钱包助记词和种子生成规则。

通过九个步骤即可生成钱包助记词和种子:

  • 步骤 1~6 生成助记词
  • 步骤 7~9 把前六步生成的助记词转化为 BIP32 种子

生成助记词

  1. 规定熵的位数必须是 32 的整数倍,所以熵的长度取值位 128 到 256 之间取 32 的整数倍的值,分别为 128, 160, 192, 224, 256;
  2. 校验和的长度为熵的长度/32 位, 所以校验和长度可为 4,5,6,7,8 位;
  3. 助记词库有 2048 个词,用 11 位可全部定位词库中所有的词,作为词的索引,故一个词用 11 位表示,助记词的个数可为 (熵+校验和)/11,值为 12,15,18,21,24

熵(bits)校验和(bits)熵 + 校验和 (bits)助记词长度128413212160516515192619818224723121256826424

  1. 生成一个长度为 128~256 位 (bits) 的随机序列(熵)
  2. 取熵哈希后的前 n 位作为校验和 (n= 熵长度/32)
  3. 随机序列 + 校验和
  4. 把步骤三得到的结果每 11 位切割
  5. 步骤四得到的每 11 位字节匹配词库的一个词
  6. 步骤五得到的结果就是助记词串

通过助记词生成种子

助记词由长度为 128 到 256 位的随机序列(熵)匹配词库而来,随后采用 PBKDF2 function 推导出更长的种子(seed)。生成的种子被用来生成构建 deterministic Wallet 和推导钱包密钥。

在密码学中,Key stretching 技术被用来增强弱密钥的安全性,增加了暴力破解 (Brute-force attack) 对每个可能密钥尝试攻破的时间,增强了攻击难度。各种编程语言原生库都提供了 key stretching 的实现。PBKDF2 (Password-Based Key Derivation Function 2) 是常用的 key stretching 算法中的一种。基本原理是通过一个为随机函数(例如 HMAC 函数),把明文和盐值作为输入参数,然后重复进行运算最终产生密钥。

为了从助记词中生成二进制种子,BIP39 采用 PBKDF2 函数推算种子,其参数如下:

  • 助记词句子作为密码
  • "mnemonic" + passphrase 作为盐
  • 2048 作为重复计算的次数
  • HMAC-SHA512 作为随机算法
  • 512 位(64 字节)是期望得到的密钥长度

DK = PBKDF2(PRF, Password, Salt, c, dkLen)

BIP32 标准定义了 HD 钱包的生成规则。HD 钱包中的所有层级密钥都是由根种子推导而来,通常根种子由上述步骤 BIP39 生成。所以只需通过助记词就能备份和恢复钱包,这也是 HD 钱包的缺陷,如果你的根种子泄漏,那么全部密钥随之都泄漏。

主私钥和主链码

首先是从根种子生成主密钥 (master key) 和主链码 (master chain code)

上图中根种子通过不可逆 HMAC-SHA512 算法推算出 512 位的哈希串,左 256 位是 Master Private key(m), 右 256 位是 master chain code, 通过 m 结合推导公钥的椭圆曲线算法能推导出与之对应的 264 位 master public Key (M)。chain code 作为推导下级密钥的熵。

子私钥推导

HD 钱包使用 CKD(child key derivation) 函数从父密钥(parent keys)推导子密钥(child keys),CKD 由下列三个要素做单向散列哈希(one way hash function) 。

  • 父密钥 (没有压缩过的椭圆曲线推导的私钥或公钥 ECDSA uncompressed key)
  • 链码作为熵 (chain code 256 bits)
  • 子代索引序号 (index 32 bits)

索引号个数为 2 的 32 次方,每个父级密钥能推导出该数目一半的子密钥 (索引号从 0x00 到 0x7fffffff (0 to 2 的 21 次方减 1) 会生成正常的密钥;索引号从 0x80000000 到 0xffffffff 会生成增强密钥)。CKD 采用不可逆的 HMAC-SHA512 不可逆加密算法,子密钥不能向上推导出父密钥、同时也不能水平推导出同一级的密钥。

扩展密钥

CKD 推导子密钥的三个元素中,其中父密钥和链码结合统称为扩展密钥 (Extended keys)。256 位的密钥和 256 位的链码串联起来的 512 位就是扩展密钥。

  1. 包含私钥的扩展密钥用以推导子私钥,从子私钥又可推导对应的公钥和比特币地址
  2. 包含公钥的扩展密钥用以推导子公钥

扩展密钥使用 Base58Check 算法加上特定的前缀编码,编码得到的包含私钥的前缀为 xprv, 包含公钥的扩展密钥前缀为 xpub,相比比特币的公私钥,扩展密钥编码之后得到的长度为 512 或 513 位。

子公钥推导

上述方法中通过推导出的私钥可推导出对应公钥,但 HD 钱包非常好用的特征之一就是在隐藏私钥的前提下通过公钥推导出子公钥,极大加强安全性。在只需要生成地址接受比特币而无权消费的场景下非常有用,通过公钥扩展密钥能生成无穷尽的公钥和比特币地址。

HD 钱包通过公钥推导子公钥的使用场景:在接受数字货币支付的电商系统中,Web 服务中集成了比特币扩展公钥服务,系统为客户的每笔订单生成一个接受比特币支付的地址,不涉及到私钥的 web 服务极大地减低了被盗币的可能性。如果不采用 HD 钱包,通常都是在物理隔绝的服务器中批量生成比特币地址,然后再导入到电商系统,这种方式需要定时生成并导入地址维护防止 web 服务系统把预先导入的地址用完。

子私钥推导流程和子公钥流程基本一样,差异之处有两点:

  1. 把子私钥推导过程中私钥替换为公钥。
  2. 子公钥推导出对应出与之的子链码

增强扩展密钥推导

密钥需加强保管以免泄漏,泄漏私钥意味着对应的地址上的币可被转走、泄漏公钥意味着 HD 钱包的隐私被泄漏。增强密钥推导 (Hardened child key derivation) 解决下述两个问题:

  1. 虽然泄漏公钥并不会导致丢币,但含有公钥的扩展密钥泄漏会导致以此为根节点推导出来的扩展公钥全部泄漏,一定程度上破坏了隐私性。
  2. 泄漏扩展公钥加上该公钥推导出的后任一代扩展公钥对应的私钥有被推导出该扩展公钥的所有后代私钥的可能性

于此,BIP32 协议把 CKD 函数改为 HKD (hardened key derivation formula) 生成增强密钥推导函数。

CKD 函数以推导扩展密钥的序列号 ( 0x00 到 0x7fffffff)、父链码和父公钥生或父私钥成子链码和子公钥,子私钥从父私钥推导;而 HKD 通过父私钥、父链码和推导增强扩展密钥的序列号 (0x80000000 到 0xffffffff) 增强子私钥和增强子链码。

HD 钱包密钥路径表示

HD 路径密钥描述m/0从主私钥(m) 推导出的第一代的第一个子私钥m/0/0从第一代子密钥m(0)推导出的第二代第一个孙私钥m/0'/0从第一代增强密钥 (m/0')推导出得第二代第一个孙密钥m/1/0从第一代的第二个子密钥推导出的第二代第一个孙密钥

参考和推荐阅读

[转]HD钱包的助记词与密钥生成原理的更多相关文章

  1. Bytomd 助记词恢复密钥体验指南

    比原项目仓库: Github地址:https://github.com/Bytom/bytom Gitee地址:https://gitee.com/BytomBlockchain/bytom 背景知识 ...

  2. 1.16. BIP39协议:使用助记词生成确定性钱包

    以太坊系统学习教程: https://www.netkiller.cn/blockchain/bip39.html 1.16. BIP39协议:使用助记词生成确定性钱包 BIP:39 层:应用层 标题 ...

  3. [币严BIZZAN区块链]Java生成ETH钱包助记词、私钥、地址

    本文主要介绍在Java工程中如何生成ETH钱包的助记词.私钥.地址. 一.在之前创建的spring boot 项目中的 pom.xml文件中加入需要的依赖 <dependency> < ...

  4. 非对称加密, 助记词, PIN, WIF

    一钱包 1.1非对称加密, 助记词, PIN, WIF, 地址 1.1.1 非对称加密算法 非对称加密算法, 加密与解密使用不同的KEY, 我们分别称为私钥与公钥,其中可以通过私钥生成公钥 在比特币中 ...

  5. [转]简单科普私钥、地址、助记词、Keystore的区别

    本文转自:https://www.jianshu.com/p/d0a4a44685d3 很多人保管不好自己的虚拟财产,发生丢币的情况,很多都是因为不清楚私钥的概念. 私钥(Private Key) 比 ...

  6. 以太坊 生成助记词和infuru插件

    https://iancoleman.io/bip39/ https://infura.io google faucet : https://faucet.rinkeby.io/ 登录google账号 ...

  7. 理解开发HD 钱包涉及的 BIP32、BIP44、BIP39

    如果你还在被HD钱包.BIP32.BIP44.BIP39搞的一头雾水,来看看这边文章吧. 数字钱包概念 钱包用来存钱的,在区块链中,我们的数字资产都会对应到一个账户地址上, 只有拥有账户的钥匙(私钥) ...

  8. 分层确定性钱包开发的代码实现(HD钱包服务)

    HD Wallets的全称是Hierachical Deterministic Wallets, 对应中文是 分层确定性钱包. 这种钱包能够使用一组助记词来管理所有的账户的所有币种,在比特币的BIP3 ...

  9. 分分钟搞懂 HD 钱包

    转自:http://blog.sina.com.cn/s/blog_12ce70a430102v8c7.html 第一次看到 HD 这个词被用在比特币钱包中时,很容易就把它理解成硬件(Hardware ...

随机推荐

  1. 在已有数据的表中添加id字段并且自增

    各位大牛,小弟在开发过程中,遇到了这样一个问题,由于新功能的增加需要使原有的一张表的结构作出调整,需要添加一个id主键字段,但是因为表里有很多数据了,所以,怎样才能添加这个字段,并且使原有的数据也能够 ...

  2. Reids学习2 -- 使用Jedis操作Redis

    1. 如何获取Jedis 获取Jar包可以通过Maven库获取:http://mvnrepository.com/artifact/redis.clients/jedis 或者可以通过Maven配置: ...

  3. Codeforces Round #554 (Div. 2) 1152B. Neko Performs Cat Furrier Transform

    学了这么久,来打一次CF看看自己学的怎么样吧 too young too simple 1152B. Neko Performs Cat Furrier Transform 题目链接:"ht ...

  4. PostgreSQL查看表、表索引、视图、表结构

    -- 表索引select * from pg_indexes where tablename='person_wechat_label';select * from pg_statio_all_ind ...

  5. Python math库常用函数

    math库常用函数及举例: 注意:使用math库前,用import导入该库>>> import math 取大于等于x的最小的整数值,如果x是一个整数,则返回x>>> ...

  6. Java 多线程之自旋锁

    一.什么是自旋锁? 自旋锁(spinlock):是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环. 获取锁的线 ...

  7. 开源网盘云存储 Seafile

    摘要: Seafile 是一款安全.高性能的开源网盘(云存储)软件.Seafile 提供了主流网盘(云盘)产品所具有的功能,包括文件同步.文件共享等.在此基础上,Seafile 还提供了高级的安全保护 ...

  8. 吴恩达机器学习笔记41-支持向量机的优化目标(Optimization Objective of Support Vector Machines)

  9. Metasploit Framework(5)弱点扫描

    文章的格式也许不是很好看,也没有什么合理的顺序 完全是想到什么写一些什么,但各个方面都涵盖到了 能耐下心看的朋友欢迎一起学习,大牛和杠精们请绕道 当我们发现了目标机器开放的端口,开启的服务等等之后 就 ...

  10. RocketMQ入门手册

    前言 继我上一篇博客后 分布式消息队列RocketMQ学习教程① 上一篇博客最主要介绍了几种常用的MQ,所以本博客再简单介绍一下RocketMQ的原理和简单的例子,基于Java实现,希望可以帮助学习者 ...