【比特币技术系列】 比特币的地址,密钥,钱包之间的关系

引言

目前市面上讲授区块链技术大多比较肤浅,夹杂着很多商业的元素,很难一下子触及技术核心技术,前两天有朋友在群里问,索性决定把 Andreas M. Antonopoulos的经典之作翻译一下,英文名:《Mastering Bitcoin-Unlocking Digital Cryptocurrencies》,中文名《精通比特币》,翻译完第一节的时候才发现网上已经有了翻译版本。

下面的时间里将和大家一起探索比特币技术,以后将尝试推出一系列的文章去探究比特币和区块链的技术本质,今天的主要内容包括:比特币地址,比特币密钥使用,比特币钱包,以及这三者存在怎样的关系。

图片名称

密钥

私钥

A private key in the context of Bitcoin is a secret number that allows bitcoins to be spent. Every Bitcoin wallet contains one or more private keys, which are saved in the wallet file. The private keys are mathematically related to all Bitcoin addresses generated for the wallet. -wiki

私钥就是一个随机选出的数字而已。一个比特币地址中的所有资金的控制取决于相应私钥的所有权和控制权。在比特币交易中,私钥用于生成支付比特币所必需的签名以证明资金的所有权。私钥必须始终保持机密,因为一旦被泄露给第三方,相当于该私钥保护之下的比特币也拱手相让了。私钥还必须进行备份,以防意外丢失,因为私钥一旦丢失就难以复原,其所保护的比特币也将永远丢失。

比特币私钥只是一个数字。你可以用硬币、铅笔和纸来随机生成你的私钥:掷硬币256次,用纸和笔记录正反面并转换为0和1,随机得到的256位二进制数字可作为比特币钱包的私钥。该私钥可进一步生成公钥。

生成密钥的第一步也是最重要的一步,是要找到足够安全的熵源,即随机性来源。生成一个比特币私钥在本质上与“在1到2256之间选一个数字”无异。只要选取的结果是不可预测或不可重复的,那么选取数字的具体方法并不重要。比特币软件使用操作系统底层的随机数生成器来产生256位的熵(随机性)。通常情况下,操作系统随机数生成器由人工的随机源进行初始化,也可能需要通过几秒钟内不停晃动鼠标等方式进行初始化。对于真正的偏执狂,可以使用掷骰子的方法,并用铅笔和纸记录。

  • 比特币私钥空间的大小是$2^{256}$,这是一个非常大的数字。用十进制表示的话,大约是$10^{77}$,而可见宇宙被估计只含有1080个原子。
  • 把私钥以Base58校验和编码格式显示,这种私钥格式被称为钱包导入格式(WIF,Wallet Import Format)。

公钥

非对称密钥往往有一对密码组成,一个是私钥,另一个是公钥,公钥就像银行的帐号,而私钥就像控制账户的PIN码或支票的签名。比特币的用户很少会直接看到数字密钥。一般情况下,它们被存储在钱包文件内,由比特币钱包软件进行管理。

其中公钥是有私钥生成,根据选择的算法(RSA,DSA,EIGamal等)不同,生成的方式也不同。比特币采用是的椭圆曲线算法。通过椭圆曲线算法可以从私钥计算得到公钥,这是不可逆转的过程:K = k * G 。其中k是私钥,G是被称为生成点的常数点,而K是所得公钥。其反向运算,被称为“离散对数分解”——已知公钥K来求出私钥k——是非常困难的,就像去试验所有可能的k值,即暴力破解。为了更好的理解私钥和公钥的对应关系

椭圆曲线加密法是一种基于离散对数问题的非对称(或公钥)加密法,可以用对椭圆曲线上的点进行加法或乘法运算来表达。
下面我们举出一个例子,如下就是我们高中最常见的椭圆曲线
$$y^2 = (x^3 + 7) over (Fp)$$

$$y^2 mod p = (x^3 + 7) mod p$$
假设我们设p=17,就是说在x = 17, y= 17 的范围内找出所有符合上面公式的值。当然了这些值一会落在曲线上面。
图片名称
上面的这些点其实就是构成了一个群GROUP,群一定的特征,这里就不深究了,但是提一点,在群中也具有一定运算,也具有加法乘法等,但是和我们平时认知的加减乘除有所区别。

关于此部分是知识,如果读者有浓厚的兴趣可以私信我,因为太过学术,所以点到为止。

下面举一个乘法的例子,下面整数点的乘法,我们的目标是找到生成点G的倍数kG。也就是将G相加k次。在椭圆曲线中,点的相加等同于从该点画切线找到与曲线相交的另一点,然后映射到x轴。
图片名称
如果我们已经知道G和k,可以很轻易的计算出 kG,但是如果知道了KG却很难反推算出k和G,其实这里的k就是私钥,kG就是公钥,
私钥可以推算出公钥,但是公钥计算理论上不能推算出私钥。

Note: 很多人会疑惑,按照上面的理论我们计算出来的至公钥是一个点啊,但是我们平时看到的公钥都是一串数字,其实公钥就是X紧跟着Y。
举个例子,如下(现实中为了安全往往取值非常大,前缀04表示未压缩格式公钥)
x = F028892BAD7ED57D2FB57BF33081D5CFCF6F9ED3D3D7F159C2E2FFF579DC341A
y = 07CF33DA18BD734C600B96A72BBC4749D5141C90EC8AC328AE52DDFE2E505BDB
则公钥为:K = x + y

地址

在比特币交易的支付环节,收件人的公钥是通过其数字指纹表示的,称为比特币地址,就像支票上的支付对象的名字(即“收款方”)。一般情况下,比特币地址由一个公钥生成并对应于这个公钥。地址与公钥之间的关系,如下图所示:
图片名称
javascript的代码实现如下:上图中我提及了Base58Check算法,而在算法实现中我用的却是base58encode,这两者之间有什么差别? 下文将揭晓答案。

1
2
3
4
5
6
7
pubkey2address = function(h){
var r = ripemd160(Crypto.SHA256(Crypto.util.hexToBytes(h), {asBytes: true}));
r.unshift('0x00'); //在数组的前端添加任意各项并返回新数组的长度。
var hash = Crypto.SHA256(Crypto.SHA256(r, {asBytes: true}), {asBytes: true});
var checksum = hash.slice(0, 4);
return base58encode(r.concat(checksum));
}

从Base64编码到Base58

为了更简洁方便地表示长串的数字,许多计算机系统会使用一种以数字和字母组成的大于十进制的表示法。例如,传统的十进制计数系统使用0-9十个数字,而十六进制系统使用了额外的 A-F 六个字母。一个同样的数字,它的十六进制表示就会比十进制表示更短。更进一步,Base64使用了26个小写字母、26个大写字母、10个数字以及两个符号(例如“+”和“/”),用于在电子邮件这样的基于文本的媒介中传输二进制数据。Base64通常用于编码邮件中的附件。Base58是一种基于文本的二进制编码格式,用在比特币和其它的加密货币中。这种编码格式不仅实现了数据压缩,保持了易读性,还具有错误诊断功能。Base58是Base64编码格式的子集,同样使用大小写字母和10个数字,但舍弃了一些容易错读和在特定字体中容易混淆的字符。具体地,Base58不含Base64中的0(数字0)、O(大写字母o)、l(小写字母L)、I(大写字母i),以及“+”和“/”两个字符。简而言之,Base58就是由不包括(0,O,l,I)的大小写字母和数字组成。

比特币的Base58字母表

123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz

从Base58到Base58Check编码

Base58Check是一种常用在比特币中的Base58编码格式,增加了错误校验码来检查数据在转录中出现的错误。校验码长4个字节,添加到需要编码的数据之后。校验码是从需要编码的数据的哈希值中得到的,所以可以用来检测并避免转录和输入中产生的错误。使用Base58check编码格式时,编码软件会计算原始数据的校验码并和结果数据中自带的校验码进行对比。二者不匹配则表明有错误产生,那么这个Base58Check格式的数据就是无效的。例如,一个错误比特币地址就不会被钱包认为是有效的地址,否则这种错误会造成资金的丢失。

为了使用Base58Check编码格式对数据(数字)进行编码,首先我们要对数据添加一个称作“版本字节”的前缀,这个前缀用来明确需要编码的数据的类型。例如,比特币地址的前缀是0(十六进制是0x00),而对私钥编码时前缀是128(十六进制是0x80)。 常见版本的前缀。

种类 版本前缀 (hex) Base58 格式
Bitcoin Address 0x00 1
Pay-to-Script-Hash Address 0x05 3
Bitcoin Testnet Address 0x6F m or n
Private Key WIF 0x80 5,K or L
BIP38 Encrypted Private Key 0x0142 6P
BIP32 Extended Public Key 0x0488B21E xpub

钱包

比特币的所有权是通过数字密钥、比特币地址和数字签名来确立的。数字密钥实际上并不是存储在网络中,而是由用户生成并存储在一个文件或简单的数据库中,称为钱包。存储在用户钱包中的数字密钥完全独立于比特币协议,可由用户的钱包软件生成并管理,而无需区块链或网络连接。

钱包是私钥的容器,通常通过有序文件或者简单的数据库实现。另外一种制作私钥的途径是 确定性密钥生成。在这里你可以用原先的私钥,通过单向哈希函数来生成每一个新的私钥,并将新生成的密钥按顺序连接。只要你可以重新创建这个序列,你只需要第一个私钥(称作种子、主私钥)来生成它们

比特币钱包只包含私钥而不是比特币。每一个用户有一个包含多个私钥的钱包。钱包中包含成对的私钥和公钥。用户用这些私钥来签名交易,从而证明它们拥有交易的输出(也就是其中的比特币)。比特币是以交易输出的形式来储存在区块链中(通常记为vout或txout)。

非确定性的钱包

钱包只是随机生成的私钥集合。这种类型的钱包被称作零型非确定钱包。举个例子,比特币核心客户端预先生成100个随机私钥,从最开始就生成足够多的私钥并且每把钥匙只使用一次。这种类型的钱包有一个昵称“Just a Bunch Of Keys(一堆私钥)”简称JBOK。这种钱包现在正在被确定性钱包替换,因为它们难以管理、备份以及导入。随机钥匙的缺点就是如果你生成很多,你必须保存它们所有的副本。这就意味着这个钱包必须被经常性地备份。每一把钥匙都必须备份,否则一旦钱包不可访问时,钱包所控制的资金就付之东流。这种情况直接与避免地址重复使用的原则相冲突——每个比特币地址只能用一次交易。地址通过关联多重交易和对方的地址重复使用会减少隐私。0型非确定性钱包并不是钱包的好选择,尤其是当你不想重复使用地址而创造过多的私钥并且要保存它们。虽然比特币核心客户包含0型钱包,但比特币的核心开发者并不想鼓励大家使用。下图表示包含有松散结构的随机钥匙的集合的非确定性钱包。
图片名称

确定性的钱包

下面列举一种确定性钱包的例子:助记码词汇钱包
助记码词汇是英文单词序列代表(编码)用作种子对应所确定性钱包的随机数。单词的序列足以重新创建种子,并且从种子那里重新创造钱包以及所有私钥。在首次创建钱包时,带有助记码的,运行确定性钱包的钱包的应用程序将会向使用者展示一个12至24个词的顺序。单词的顺序就是钱包的备份。它也可以被用来恢复以及重新创造应用程序相同或者兼容的钱包的钥匙。助记码代码可以让使用者复制钱包更容易一些,因为它们相比较随机数字顺序来说,可以很容易地被读出来并且正确抄写。

总结

本文介绍了比特币地址,比特币密钥原理,比特币钱包,以及这三者存在怎样的关系。

声明

本文70%为翻译组合,30%为原创, 文中大量引用了经典之作《Mastering Bitcoin-Unlocking Digital Cryptocurrencies》
d3d3LmVoY29vLmNvbSwg5L2c6ICFOmVoY29v(BASE64编码)

引用

http://chimera.labs.oreilly.com/books/1234000001802/ch01.html
http://chimera.labs.oreilly.com/books/1234000001802/ch04.html#public_key_derivation

your support will encourage me to continue to create!
版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)