精力有限,后期修订以github为主,建议大家移步github链接阅读更新版本,感谢理解:
https://github.com/tianmingyun/MasterBitcoin2CN
预警:本文5200字,请保存后再浏览。
欢迎联系沟通提供建议意见你可能听说比特币是基于密码学,这是计算机安全性广泛使用的数学基础。 密码学是指希腊语中的“秘密写作”,但密码学的科学不仅仅是学习秘密,而是被称为加密学。 密码学也可以用来证明秘密的知识,而不会泄露秘密(数字签名),或证明数据的真实性(数字指纹)。 这些类型的加密证明是对比特币和在比特币应用程序中广泛使用的数学工具。 具有讽刺意味的是,加密不是比特币的重要组成部分,因为它的通信和交易数据没有加密,也不需要加密来保护资金。 在本章中,我们将介绍一些在比特币中使用的密码学,以密钥,地址和钱包的形式来控制资金的所有权。
4.1简介
比特币的所有权是通过数字密钥、比特币地址和数字签名来确立的。数字密钥实际上并不是存储在网络中,而是由用户生成并存储在一个文件或简单的数据库中,称为钱包。存储在用户钱包中的数字密钥完全独立于比特币协议,可由用户的钱包软件生成并管理,而无需区块链或网络连接。密钥实现了比特币的许多激动人心特性,包括去中心化信任和控制、所 有权认证和基于密码学证明的安全模型。
每笔比特币交易都需要一个有效的签名才会被存储在区块链。只有有效的数字密钥才能产生有效的数字签名,因此拥有 比特币的密钥副本就拥有了该帐户的比特币控制权。用于支出资金的数字签名也称为见证(witness),密码术中使用的术语。 比特币交易中的见证数据证明了所用资金的真正所有权。
密钥是成对出现的,由一个私钥和一个公钥所组成。公钥就像银行 的帐号,而私钥就像控制账户的PIN码或支票的签名。比特币的用户很少会直接看到数字密钥。一般情况下,它们被存储在钱包文件内,由比特币钱包软件进行管理。
在比特币交易的支付环节,收件人的公钥是通过其数字指纹表示的,称为比特币地址,就像支票上的支付对象的名字 (即“收款方”)。一般情况下,比特币地址由一个公钥生成并对应于这个公钥。然而,并非所有比特币地址都是公钥; 他们也可以代表其他支付对象,譬如脚本,我们将在本章后面提及。这样一来,比特币地址把收款方抽象起来了,使得 交易的目的地更灵活,就像支票一样:这个支付工具可支付到个人账户、公司账户,进行账单支付或现金支付。比特币 地址是用户经常看到的密钥的唯一代表,他们只需要把比特币地址告诉其他人即可。
在本章中,我们将介绍钱包,也就是密钥所在之处。我们将了解密钥如何被产生、存储和管理。我们将回顾私钥和公 钥、地址和脚本地址的各种编码格式。最后,我们将讲解密钥的特殊用途:生成签名、证明所有权以及创造比特币靓号 地址和纸钱包。
4.1.1 公钥加密和加密货币
公钥加密发明于20世纪70年代。它是计算机和信息安全的数学基础。
自从公钥加密被发明之后,一些合适的数学函数被提出,譬如:素数幂和椭圆曲线乘法。这些数学函数都是不可逆的, 就是说很容易向一个方向计算,但不可以向相反方向倒推。基于这些数学函数的密码学,使得生成数字密钥和不可伪造 的数字签名成为可能。比特币正是使用椭圆曲线乘法作为其公钥加密的基础算法。
在比特币系统中,我们用公钥加密创建一个密钥对,用于控制比特币的获取。密钥对包括一个私钥,和由其衍生出的唯 一的公钥。公钥用于接收比特币,而私钥用于比特币支付时的交易签名。
公钥和私钥之间的数学关系,使得私钥可用于生成特定消息的签名。此签名可以在不泄露私钥的同时对公钥进行验证。
支付比特币时,比特币的当前所有者需要在交易中提交其公钥和签名(每次交易的签名都不同,但均从同一个私钥生 成)。比特币网络中的所有人都可以通过所提交的公钥和签名进行验证,并确认该交易是否有效,即确认支付者在该时 刻对所交易的比特币拥有所有权。
提示 大多数比特币钱包工具为了方便会将私钥和公钥以密钥对的形式存储在一起。然而,公钥可以由私钥计算得到, 所以只存储私钥也是可以的。
4.1.2 私钥和公钥
一个比特币钱包中包含一系列的密钥对,每个密钥对包括一个私钥和一个公钥。私钥(k)是一个数字,通常是随机选 出的。有了私钥,我们就可以使用椭圆曲线乘法这个单向加密函数产生一个公钥(K)。有了公钥(K),我们就可以使 用一个单向加密哈希函数生成比特币地址(A)。在本节中,我们将从生成私钥开始,讲述如何使用椭圆曲线运算将私 钥生成公钥,并最终由公钥生成比特币地址。私钥、公钥和比特币地址之间的关系如下图所示。
图4-1私钥、公钥和比特币地址之间的关系为什么使用不对称加密(公钥/私钥)?
为什么在比特币中使用非对称密码术? 它不是用于“加密”(make secret)交易。 相反,非对称密码学的有用属性是生成数字签名的能力。 可以将私钥应用于交易的数字指纹以产生数字签名。 该签名只能由具有私钥知识的人生成。 但是,访问公钥和交易指纹的任何人都可以使用它们来验证签名。 这种非对称密码学的适用性使得任何人都可以验证每个交易的每个签名,同时确保只有私钥的所有者可以产生有效的签名。
4.1.3 私钥
私钥就是一个随机选出的数字而已。一个比特币地址中的所有资金的控制取决于相应私钥的所有权和控制权。在比特币 交易中,私钥用于生成支付比特币所必需的签名以证明资金的所有权。私钥必须始终保持机密,因为一旦被泄露给第三 方,相当于该私钥保护之下的比特币也拱手相让了。私钥还必须进行备份,以防意外丢失,因为私钥一旦丢失就难以复 原,其所保护的比特币也将永远丢失。
提示 比特币私钥只是一个数字。你可以用硬币、铅笔和纸来随机生成你的私钥:掷硬币256次,用纸和笔记录正反面并转换为0和1,随机得到的256位二进制数字可作为比特币钱包的私钥。该私钥可进一步生成公钥。
从一个随机数生成私钥
生成密钥的第一步也是最重要的一步,是要找到足够安全的熵源,即随机性来源。生成一个比特币私钥在本质上与“在1 到2^256之间选一个数字”无异。只要选取的结果是不可预测或不可重复的,那么选取数字的具体方法并不重要。比特币 软件使用操作系统底层的随机数生成器来产生256位的熵(随机性)。通常情况下,操作系统随机数生成器由人工的随 机源进行初始化,也可能需要通过几秒钟内不停晃动鼠标等方式进行初始化。对于真正的偏执狂,可以使用掷骰子的方 法,并用铅笔和纸记录。
更准确地说,私钥可以是1和n-1之间的任何数字,其中n是一个常数(n=1.158 * 1077,略小于2256),并由比特币 所使用的椭圆曲线的阶所定义(见4.1.5 椭圆曲线密码学解释)。要生成这样的一个私钥,我们随机选择一个256位的数 字,并检查它是否小于n-1。从编程的角度来看,一般是通过在一个密码学安全的随机源中取出一长串随机字节,对其 使用SHA256哈希算法进行运算,这样就可以方便地产生一个256位的数字。如果运算结果小于n-1,我们就有了一个合 适的私钥。否则,我们就用另一个随机数再重复一次。
警告 本书强烈建议读者不要使用自己写的代码或使用编程语言内建的简易随机数生成器来获得一个随机数。我们建议读者使用密码学安全的伪随机数生成器(CSPRNG),并且需要有一个来自具有足够熵值的源的种子。使用随机数发生器的程序库时,需仔细研读其文档,以确保它是加密安全的。对CSPRNG的正确实现是密钥安全性的关键 所在。
以下是一个随机生成的私钥(k),以十六进制格式表示(256位的二进制数,以64位十六进制数显示,每个十六进制数占4位):
1E99423A4ED27608A15A2616A2B0E9E52CED330AC530EDCC32C8FFC6A526AEDD
提示比特币私钥空间的大小是2256,这是一个非常大的数字。用十进制表示的话,大约是1077,而可见宇宙被估计 只含有10^80个原子。
要使用比特币核心客户端生成一个新的密钥(参见第3章),可使用 getnewaddress 命令。出于安全考虑,命令运行后只 显示生成的公钥,而不显示私钥。如果要bitcoind显示私钥,可以使用 dumpprivkey 命令。 dumpprivkey 命令会把私钥以 Base58校验和编码格式显示,这种私钥格式被称为钱包导入格式(WIF,Wallet Import Format),在“私钥的格式”一 节有详细讲解。下面给出了使用这两个命令生成和显示私钥的例子:
$ bitcoin-cli getnewaddress
1J7mdg5rbQyUHENYdx39WVWK7fsLpEoXZy
$ bitcoin-cli dumpprivkey 1J7mdg5rbQyUHENYdx39WVWK7fsLpEoXZy
KxFC1jmwwCoACiCAWZ3eXa96mBM6tb3TYzGmf6YwgdGWZgawvrtJ
dumpprivkey 命令只是读取钱包里由 getnewaddress 命令生成的私钥,然后显示出来。bitcoind的并不能从公钥得知私钥。 除非密钥对都存储在钱包里, dumpprivkey 命令才有效。
提示 dumpprivkey命令无法从公钥得到对应的私钥,因为这是不可能的。这个命令只是提取钱包中已有的私钥,也就 是提取由getnewaddress命令生成的私钥。
您还可以使用Bitcoin Explorer命令行工具(请参阅附录中的[appdx_bx])使用命令seed,ec-new和ec-to-wif生成和显示私钥:
$ bx seed | bx ec-new | bx ec-to-wif
5J3mBbAH58CpQ3Y5RNJpUKPE62SQ5tfcvU2JpbnkeyhfsYB1Jcn
4.1.4 公钥
通过椭圆曲线算法可以从私钥计算得到公钥,这是不可逆转的过程:K = k * G 。其中k是私钥,G是被称为生成点的常 数点,而K是所得公钥。其反向运算,被称为“寻找离散对数”——已知公钥K来求出私钥k——是非常困难的,就像去试 验所有可能的k值,即暴力搜索。在演示如何从私钥生成公钥之前,我们先稍微详细学习下椭圆曲线加密学。
提示 椭圆曲线乘法是密码学家称之为“陷阱门”功能的一种功能:在一个方向(乘法)很容易做,而不可能在相反的方向(除法)做。 私钥的所有者可以容易地创建公共密钥,然后与世界共享,知道没有人可以从公钥中反转功能并计算私钥。 这个数学技巧成为证明比特币资金所有权的不可伪造和安全的数字签名的基础。
4.1.5 椭圆曲线密码学(Elliptic Curve Cryptography)解释
椭圆曲线加密法是一种基于离散对数问题的非对称(或公钥)加密法,可以用对椭圆曲线上的点进行加法或乘法运算来表达。
下图是一个椭圆曲线的示例,类似于比特币所用的曲线。
比特币使用了secp256k1标准所定义的一条特殊的椭圆曲线和一系列数学常数。该标准由美国国家标准与技术研究院 (NIST)设立。secp256k1曲线由下述函数定义,该函数可产生一条椭圆曲线:
产生椭圆曲线的函数上述mod p(素数p取模)表明该曲线是在素数阶p的有限域内,也写作Fp,其中p = 2^256 – 2^32 – 2^9 – 2^8 – 2^7 – 2^6 – 2^4 – 1, 这是⼀个非常⼤的素数。
因为这条曲线被定义在一个素数阶的有限域内,而不是定义在实数范围,它的函数图像看起来像分散在两个维度上的散 点图,因此很难画图表示。不过,其中的数学原理与实数范围的椭圆曲线相似。作为一个例子,下图显示了在一个小了 很多的素数阶17的有限域内的椭圆曲线,其形式为网格上的一系列散点。而secp256k1的比特币椭圆曲线可以被想象成 一个极大的网格上一系列更为复杂的散点。
下面举一个例子,这是 secp256k1 曲线上的点P,其坐标为(x,y)。可以使用Python对其检验:
P =(55066263022277343669578718895168534326250603453777594175500187360389116729240,32670510020758816978083085130507043184 471273380659243275938904335757337482424)
Python 3.4.0 (default, Mar 30 2014, 19:23:13) [GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.38)] on darwin Type "help", "copyright", "credits" or "license" for more information.
/>>> p = 115792089237316195423570985008687907853269984665640564039457584007908834671663
/>>> x = 55066263022277343669578718895168534326250603453777594175500187360389116729240
/>>> y = 32670510020758816978083085130507043184471273380659243275938904335757337482424
/>>> (x ** 3 + 7 - y**2) % p
0
在椭圆曲线的数学原理中,有一个点被称为“无穷远点”,这大致对应于0在加法中的作用。计算机中,它有时表示为X = Y = 0(虽然这不满足椭圆曲线方程,但可作为特殊情况进行检验)。
还有一个 + 运算符,被称为“加法”,就像小学数学 中的实数相加。给定椭圆曲线上的两个点P1和P2,则椭圆曲线上必定有第三点 P3 = P1 + P2。
几何图形中,该第三点P3可以在P1和P2之间画⼀条线来确定。这条直线恰好与椭圆曲线上的⼀点相交。此点记为 P3'= (x,y)。然后,在x轴做映射获得 P3=(x,-y)。
下⾯是几个可以解释“⽆穷远点”之存在需要的特殊情况。
若 P1和 P2是同⼀点,P1和P2间的连线则为点P1 的切线。曲线上有且只有⼀个新的点与该切线相交。该切线的斜率可⽤微分求得。即使限制曲线点为两个整数坐标也可求得斜率!
在某些情况下(即,如果P1和P2具有相同的x值,但不同的y值),则切线会完全垂直,在这种情况下,P3 = “⽆穷远点”。
若P1就是“无穷远点”,那么其和 P1 + P2= P2。类似地,当P2是无穷远点,则P1+ P2 = P1。这就是把无穷远点类似于0的作用。 事实证明,在这里 + 运算符遵守结合律,这意味着(A+B)C = A(B+C)。这就是说我们可以直接不加括号书写 A + B + C,而不至于混淆。 ⾄此,我们已经定义了椭圆加法,为扩展加法下⾯我们对乘法进⾏标准定义。给定椭圆曲线上的点P,如果k是整数,则 kP = P + P + P + …+ P(k次)。注意,k被有时被混淆而称为“指数”。
4.1.6 生成公钥
以一个随机生成的私钥k为起点,我们将其与曲线上已定义的 生成点G相乘以获得曲线上的另一点,也就是相应的公钥 K。生成点是secp256k1标准的一部分,比特币密钥的生成点都是相同的:
{K = k * G}
其中k是私钥,G是生成点,在该曲线上所得的点K是公钥。因为所有比特币用户的生成点是相同的,一个私钥k乘以G将 得到相同的公钥K。k和K之间的关系是固定的,但只能单向运算,即从k得到K。这就是可以把比特币地址(K的衍生) 与任何人共享而不会泄露私钥(k)的原因。
提示 因为其中的数学运算是单向的,所以私钥可以转换为公钥,但公钥不能转换回私钥。
为实现椭圆曲线乘法,我们 以之前产生的私钥k和与生成点G相乘得到公钥K:
K = 1E99423A4ED27608A15A2616A2B0E9E52CED330AC530EDCC32C8FFC6A526AEDD * G
公钥K 被定义为一个点 K = (x, y):
K = (x, y)
其中,
x = F028892BAD7ED57D2FB57BF33081D5CFCF6F9ED3D3D7F159C2E2FFF579DC341A
y = 07CF33DA18BD734C600B96A72BBC4749D5141C90EC8AC328AE52DDFE2E505BDB
为了展示整数点的乘法,我们将使用较为简单的实数范围的椭圆曲线。请记住,其中的数学原理是相同的。我们的目标 是找到生成点G的倍数kG。也就是将G相加k次。在椭圆曲线中,点的相加等同于从该点画切线找到与曲线相交的另一 点,然后映射到x轴。
下图显示了在曲线上得到 G、2G、4G 的几何操作。
提示大多数比特币程序使用OpenSSL加密库进行椭圆曲线计算。例如,调用EC_POINT_mul() 函数,可计算得到公 钥。
本章未完,待续。
参考内容:
1、本文部分内容摘自《精通比特币》第一版中译本,特此说明并致谢。
本文翻译过程中得到许多朋友(包括区块链研习社higer社长等)的支持和鼓励,在此表示感谢,另外精力有限难免纰漏,也非常希望大家提出宝贵意见和建议,欢迎大家关注下面的二维码加入小密圈:认知学习区块链(免费),进行交流。
欢迎加入小密圈:认知学习区块链
网友评论