奇技指南
今天要给大家分享区块链相关的内容~
钱包在整个区块链技术领域是比较独立的,和其他部分交互较少;本文介绍开发一款钱包密钥管理需要满足的功能和事实标准。
本文来自360区块链实验室,转载以获取作者授权。
钱包在整个区块链技术领域是比较独立的,和其他部分交互较少;本文介绍开发一款钱包密钥管理需要满足的功能和事实标准。
1
前置知识
这部分主要介绍开发钱包之前需要知道的几个知识点。
1比特币私钥,公钥和地址之前的关系
比特币中使用椭圆曲线密码学做为公私钥的核心算法(所采用的椭圆曲线是 Secp256k1),私钥本质是一个大的随机数,保密存储,用于签名交易,从而证明 UTXO 的所有权。公钥为椭圆曲线上一点坐标,通过私钥和所在曲线计算得来,这个计算是不可逆的,即不存在一种计算方式从公钥算出所在私钥。通常这里私钥是 32Byte,而公钥是 33Byte(压缩公钥格式),比特币地址本质是公钥的哈希结果;这里使用的哈希是 sha256 + ripemd160,即常说的双哈希,或者又叫哈希160,地址通常表示为哈希结果的 Base58Check 编码方式。
2
钱包概述
和生活实际的认知有所不同,比特币钱包并不存储数字货币,钱包的基础是存储私钥,用私钥对交易进行签名,用于证明可以花费掉一定数额的数字货币。
一个完整的交易(转账)过程包括创建交易、签名交易、广播交易,其中创建交易和广播交易不需要访问私钥,创建交易和签名交易不需要访问网络;所以钱包又有硬件钱包、冷钱包、热钱包之分,硬件钱包是将私钥存储在独立硬件上,存储的私钥无法通过外部访问,只提供对交易进行签名的接口,所以安全性上比较高,同时也需要独立购买硬件;冷钱包相较于硬件钱包来说,私钥存储在无法联网的机器上,离线对交易进行签名;热钱包整个签名过程都是在网络环境下,使用起来比较方便;
钱包从另一层面上来说又有全节点钱包和轻钱包之分,因为交易最终是需要广播出去的,而区块链又是分布式去中心化的,所以钱包广播需要节点进行参与,全节点钱包和轻钱包都是钱包本身作为一个节点,然后向其他节点广播交易,是一个完全去中心化的结构,全节点和轻节点只是节点类型不同;还有一类钱包本身不作为节点,而是多个钱包连接一个中心化的服务器,这个中心化的服务器作为一个节点参与广播,而钱包只包含创建交易和签名交易的功能,签名完的交易通过其他协议(例如 HTTPS)传输给中心化服务器,中心化服务器将交易进行广播;而中心化的服务器也能提供其他类似于实时汇率等功能;Coinbase,Copay,Blockchain.info 等钱包都是这样的一个 CS 架构;
还有一类交易所的钱包,例如火币钱包,钱包本身并不存储私钥,所有的操作和中心化服务器进行交互,至于中心化服务器中是否会为每个用户创建私钥进行管理,是一个黑盒不得而知;
2
实现钱包密钥管理的几个标准
现阶段,对于开发钱包来说,有几个事实标准需要遵守和实现,而且现有市面上钱包都是实现这样的几个标准的
-
BIP-0032: 分层确定性钱包(HD钱包)规范;
-
BIP-0039: 私钥与助记词(mnemonic code)相互转换的规范;
-
BIP-0043: 多用途 HD 钱包规范;
-
BIP-0044: 多账户多币种 HD 钱包规范;
这几个规范基本现有的钱包都会实现,其中 BIP-0032、BIP-0038、BIP-0039 之间相互独立,处于钱包实现的不同流程;BIP-0043 是在 BIP-0032 上制定的规范,BIP-0044 又基于 BIP-0043 而制定了更详细的一个规范;和 BIP-0044 同类型的还有 BIP-0045、BIP-0047、BIP-0049 等几种规范;
3
BIP-0032
比特币建议的同一个地址使用一次,相较于普通的 私钥 -> 公钥 -> 地址 的这一关系,钱包需要维护多个地址,所以钱包有两个方向可以做,一种是存储独立的多个私钥,从而对应多个地址,这也就是非确定性钱包;另一种思路是一个种子(Seed)可以扩展产生多个私钥,每个私钥又有自己的对应公钥、地址,这就是确定性钱包;BIP-0032 制定了一种具有分层的确定性钱包规范。
使用非确定性钱包有两个缺点,每个地址对应一个私钥,需要备份的私钥比较多,丢失其中一个私钥,也会损失那部分比特币;私钥在使用过程中不断生成,也需要不时进行备份。
HD 钱包的种子本质还是随机数,或者从别的规范产生的一个数字,最常见是通过 BIP-0039 的助记词产生的;
首先,种子通过 HMAC-SHA512(Key="Bitcoin seed", Data=Seed) 哈希函数产生一个 64Byte 的主密钥(Key 是一个确定的字符串 "Bitcoin seed"),主密钥分割成 32Byte 的两部分,左侧用作主私钥,右侧用作衍生子密钥,称为链码(chain code), 左侧的主私钥可以计算出公钥,从而计算出地址来正常使用;主密钥和链码,再结合子密钥索引(索引是一个 4Byte 序号),通过 HMAC-SHA512 衍生出子密钥,这里主要分为三种类型:
(1). 父级私钥 --> 子级私钥
这里还是使用 HMAC-SHA512 哈希函数,父级的 ChainCode 作为哈希函数的 Key,父级私钥计算得到的公钥(33Byte)和索引拼起来用作哈希函数的 Data,哈希函数同样产生一个 64Byte 的子密钥,同样分割为 32Byte 的两部分,右侧的 ChainCode 用作于子链衍生自己的子链;左侧通过和父级私钥进行数字相加得到子级私钥;这里子级私钥有个椭圆曲线和是否为零的校验;校验通过则是一个合法的子级私钥,不合法则会跳过当前索引。
(2). 父级公钥 --> 子级公钥
这里 HMAC-SHA512 的计算和 (1) 中一致,只是这里父级公钥直接参与计算,而不是从私钥推算;同样哈希函数分为两部分,右侧为 ChainCode,左侧的 32Byte 通过椭圆曲线计算出公钥,再和父级公钥通过椭圆曲线的点坐标加法从而得到子级的公钥;
所以这里在使用中就可以只通过父级公钥和链码在不安全环境下衍生需要的子级公钥,全程不需要私钥的参与;这里有个需要明白的,得到的子级公钥在使用中需要私钥来解密,通过 (1) 中同样的索引,计算出来的子级私钥和这里计算的子级公钥就是一个公私钥对;因为这里的椭圆曲线是个可交换群,满足交换律和结合律,而椭圆曲线中私钥计算公钥是一个乘法(PubKey = PrevKey * P, P 是特定椭圆曲线上常数),所以这里满足 ParentPrevKey * P + LeftBytes * P = (ParentPrevKey + LeftBytes) * P,其中 LeftBytes * P 即为左侧的 32Byte 通过椭圆曲线计算的公钥;
(3). 父级私钥 --> 子级公钥
父级私钥得到子级公钥有两种途径,一种途径是先经过 (1),衍生出子级私钥从而计算出子级公钥;另一种途径先计算出父级公钥,再通过 (2) 衍生出子级公钥;
强化衍生
前面提到的父级公钥和链码合起来称为扩展公钥,在不安全环境下来衍生子公钥,但一旦子私钥被泄漏,和扩展公钥中的链码就可以衍生它的所有子私钥,另外子私钥和父级链码有推断出父级私钥的风险,所以又引入了强化衍生的概念。
强化衍生只能从父级私钥衍生子级私钥,从而得到子级公钥,而不能做如上 (2) 中的公钥衍生,具体的衍生过程和 (1) 中 HMAC-SHA512 有细微区别,不同于 (1) 中的父级私钥计算得到的公钥(33Byte),强化衍生通过 0x00 这样 1Byte 拼上私钥和索引作为 Data,其他衍生步骤一致。强化衍生不会将父级链码暴露到不安全的环境下,所以相较于正常衍生更安全些。
子密钥的索引号码和路径表示
索引的范围有 2^32 个,其中前 2^31 表示正常衍生,通常表示为索引序号即可;后 2^31 表示强化衍生,强化衍生序号也是从 0 开始,会在序号后添加撇号表示强化衍生,例如 0x80000000 为第一个强化衍生的序号,通常表示为 0' ,钱包中有 i'=2^31+i 这样的关系。
子密钥的路径通过 / 分割的索引表示;前缀有 m 和 M 之分,m 表示衍生的子私钥,M 表示衍生的子公钥。例如 m/5/4'/0 表示子私钥 m/5/4' 的第 0 个正常衍生私钥,m/5/4' 则是子私钥 m/5 的第 4 个强化衍生的子私钥,m/5 则是主私钥第 5 个正常衍生的子私钥。
4
BIP-0039
助记词相较于随机数字的表示更容易地被阅读和正确抄写,可以让使用者复制钱包更容易一些。助记词主要使用在钱包进行备份和转移的时候。
助记词生成的基本流程是:
-
生成 128bits 的随机数,称为熵(以128bits为例);
-
计算熵 checksum: 将熵进行 SHA256 哈希,取出前 4bits 用作校验码;(校验码长度 = 数据总长度 / 32);
-
将原始熵和 checksum 拼接为 132bits 长度;
-
将 132bits 长度按照 11bits 分割为 12 份;
-
每 11bits 对应为 2048 长度的单词表中的一个单词;
这 12 个单词就是熵对应的助记词,单词表可以从 单词列表 这里获取到;
其中熵长度不一样,对应的助记词个数也不一样;熵长度可取值范围如下:
| 熵长度 | checksum 长度 | 助记词长度 |
|
128 |
4 |
12 |
|
160 |
5 |
15 |
|
192 |
6 |
18 |
|
224 |
7 |
21 |
|
256 |
8 |
24 |
从助记词生成种子
这里使用称为 PBKDF2 的算法来从助记词生成种子,PBKDF2 函数接收两个参数:生成的助记词字符序列;第二个参数还有用于密码加密的盐,盐(salt)的参数为字符串 "mnemonic" 和用户可选密码拼起来的字符串,没有可选密码则 salt 参数就是 "mnemonic"。
PBKDF2 使用循环 2048 次的 HMAC-SHA512 函数来实现,最后返回一个 512 bits 长度的种子;这里生成的种子可以用作上面 BIP-0032 的种子。
5
BIP-0043
由于 BIP-0032 层级可以无限扩展,每层又可以有很多子密钥,这样定义过于松散,不同钱包可能会定义自己的生成路径规则,所以 BIP-0043 定义了分层钱包层级如何使用的规范。
BIP-0043 规定了 m/purpose'/ 第一级路径作为目的,即定义路径所遵循的规范,这样防止采用不同规范的路径的冲突;例如 0' 为 BIP-32 的默认钱包,44' 为遵守 BIP-0044 规范所定义的前缀;这里规范使用了强化衍生。
6
BIP-0044
BIP-0044 在 BIP-0043 的基础上更详细的定义了一种路径规范:m/purpose'/coin_type'/account'/change/address_index ,这里 purpose 还是遵循 BIP-0043 的规范,在 BIP-0044 中就是固定值 44' ;coin_type 定义了可以支持的数字货币种类,已经注册的有比特币(0' ),比特币测试网(1' ),这里为实现多币种钱包提供了支持;account 定义了多账户的支持,依次从 0 开始,purpose、coin_type、account 都是强化衍生;change 定义了外部地址(0 )和找零地址(1 ),外部地址一般用于接收转账等,找零地址如字面意思,用于接收转账的找零;address_index 就是从 0 开始的地址序号。
BIP-0045 定义了另外一种形式的路径规范,有兴趣可以了解下;
7
隔离见证(Segwit)
对于现在的钱包来说,部分实现了 BIP-0141 的隔离见证。简单来说,比特币扩容和区块大小 1M 的限制相矛盾,有了修改块大小(BCH方案)和隔离见证两种方式,隔离见证就是将脚本签名(scriptSig)这部分结构从区块中拿出来单独存储,计算块大小就不会计算这部分了,从而一个块中容纳更多的交易;这部分脚本签名仍然在区块链中,跟随着交易一起验证。
现在支持隔离见证的钱包有 copay。
结束语
钱包除了上面介绍的公私钥管理以外,一般还需要有创建交易和对创建的交易进行签名并将交易发送到区块链并由矿工确认,交易创建和签名又是一块独立完整的内容,这里就不再展开了。
比特币钱包中的密钥管理相对来说比较简单一些,相对整体结构来说也比较独立。而钱包客户端又是用户和区块链交互的桥梁,所以实现钱包密钥管理的统一规范还是很重要。
更多区块链知识,都在360区块链技术开放日!
扫码或点击阅读原文,立即报名
界世的你当不
只作你的肩膀
无
360官方技术公众号
技术干货|一手资讯|精彩活动
空·