learn-tech/专栏/左耳听风/054区块链技术-区块链技术细节-加密和挖矿.md
2024-10-16 06:37:41 +08:00

150 lines
10 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

因收到Google相关通知网站将会择期关闭。相关通知内容
054 区块链技术 - 区块链技术细节 - 加密和挖矿
前面一篇文章中讲的技术解决了交易信息不能被篡改的问题。但还有一个比较重要的问题,那就是,我们每个人只能发起和自己有关的交易,也就是能发起自己对别人付钱的交易,我们不能发起别人对我付钱,或是别人向别人付钱的交易。
那么,在比特币中是怎么解决这个问题的?让我们先看一些基础的加密技术。
比特币的加密方法
密钥对 / 签名 / 证书
所谓密钥对,也就是一种非对称加密技术。这种技术,在对信息进行加密和解密时,使用两个不同的密钥。这样一来,我们就可以把其中一个密钥公布出去,称之为公钥,另一个密钥私密地保管好,称之为私钥。
现实社会中有人使用公钥加密私钥解密也有反过来用私钥加密公钥解密这得看具体的场景。比特币使用了非对称加密的技术其使用了ECDSA 密钥对比技术。)
比如,我把我加密的密钥发布给所有人,然后大家都用这个公钥加密信息,但其他人没有私钥,所以他们解不了密文,只有我能解密文,也只有我能看得懂别人用我的公钥加密后发给我的密文。如下图所示。
但是,这会有个问题,那就是每个人都有我的公钥,别人可以截获 Mike 发给我的信息,然后自己用我的公钥加密一个别的信息,伪装成 Mike 发给我, 这样我就被黑了。于是,我们需要对 Mike 的身份进行验证,此时就需要用到 “ 数字签名 ” 的概念了。
Mike 也有一对密钥对,一个公钥给了我,私钥自己保留。
Mike 发自己想要的信息,做个 SHA 或 MD5 的 hash得到一个 hash 串,又叫 Digest。
Mike 用自己的私钥,把 Digest 加密,得到一段 Digest 的密文。我们把这个事叫数字签名Signature。
然后Mike 把他想发给我的信息用我的公钥加密后,连同他的数字签名一同发给我。
我用我的私钥解密 Mike 发给我的密文,然后用 Mike 的公钥解密其数字签名得到 Digest。然后我用 SHA 或 MD5 对解开的密文做 Hash。如果结果和 Digest 一致,就说明,这个信息是 Mike 发给我的,没有人更改过。
这个过程如下图所示。
但是问题还没完。假设有个黑客偷偷地把 Jack 电脑上的 Mike 的公钥给换了,换成自己的,然后截获 Mike 发出来的信息,用自己的密钥加密一段自己的信息,以及自己的数字签名。
于是,对于 Jack 来看,因为他用了黑客的公钥,而不是 Mike 的,那么对他来说,他就以为信息来自 Mike于是黑客可以用自己的私钥伪装成 Mike 给 Jack 通信。反之亦然,于是黑客就可以在中间伪装成 Jack 或 Mike 来通信,这就是中间人攻击。如下图所示。
这个时候就比较麻烦了。Mike 看到有人在伪造他的公钥,想了想,他只能和 Jack 找了个大家都相信的永不作恶的权威的可信机构来认证他的公钥。这个权威机构,用自己的私钥把 Mike 的公钥和其相关信息一起加密,生成一个证书。
此时Jack 就可以放心地使用这个权威机构的证书了。Mike 只需要在发布其信息的时候放上这个权威机构发的数字证书,然后 Jack 用这个权威机构的公钥解密这个证书,得到 Mike 的公钥,再用 Mike 的公钥来验证 Mike 的数字签名。
上面就是整个密钥对、签名和证书的全部基础细节。比特币也用了这样的基础技术来认证用户的身份的。下面,我们来看看比特币的一些细节。
比特币的加密
在比特币的世界里,每一笔交易的 From 和 To 都是每个用户的公钥Public Key。也就是说使用用户的公钥来做交易的账户。于是这个过程很简单。
交易的发起方只能是支付方,支付方需要用自己的私钥来加密交易信息并制作相关的交易签名。
网络上其他人会用你的公钥(也就是交易的支出方)来做解密来验证。
为什么不需要那个证书机构呢?不怕中间人攻击吗?这是因为,如果黑客想要伪造一笔别人的交易,那么他需要换掉半数以上结点上的被攻击者的公钥,这不太现实。与其这样做,还不如去偷被攻击者的私钥,可能还简单一些。
下面是一个交易链的图示。这个交易链的钱从 A -> B -> C -> D一共 3 笔交易。
图片来源Ken Shirriff Blog
发起交易。我们从第一笔交易可以看到A 用自己的私钥为交易信息和自己的地址生成了交易的签名,然后把交易信息、自己的地址、交易签名和自己的公钥放出去,这样方便别人来验证的确是 A 发起的。
验证交易。在验证时,使用 A 的公钥解密交易签名,得到交易的 hash 值。把交易信息和自己的地址做 hash看看是不是和签名解密后的 hash 值一致。
这里需要注意一个细节,比特币的地址是由我们的公钥生成的,生成规则比较复杂,可以参看 Bitcoin 的 Wiki 页 - Technical background of version 1 Bitcoin addresses。
比特币的挖矿
前面说到,在比特币的区块 hash 算法中,要确保下面这个公式成立:
SHA-256(SHA-256 (Block Header)) < Target
而在区块头中可以完全自由修改的只有一个字段就是 Nonce其他的 Timestamp 可以在特定范围内修改Merkle Root 和你需要记录的交易信息有关系所有的矿工可以自由地从待确认交易列表中挑选自己想要的交易打包)。
所以基本上来说你要找到某个数字让整个 hash 值小于 Target这个 Target 是一个数其决定了我们计算出来的 hash 值的字符串最前面有几个零我们知道hash 值本身就是一串相对比较随机的字符串但是要让这个随机的字符串有规律是一件很困难的事除了使用暴力破解没有其他办法在计算机世界里我们把这个事叫 哈希碰撞 “(hash collision)碰撞前几个位都是 0 的哈希值
下面是一个示例我想找到一个数其和 ChenHao 加起来被 hash 后的值前面有 5 个零
测试程序如下
import hashlib
data="ChenHao"
n=1
while n < 2**32:
str = data + `n`
hash = hashlib.sha256(str).hexdigest()
hash = hashlib.sha256(hash).hexdigest()
if hash.startswith('00000'):
print str, hash
break
n = n + 1
这是一个暴力破解的算法这个程序在我的 MacBook Pro 上基本要 10 秒钟才跑得出来结果
找到 1192481 找到了第一个解如下所示
ChenHao1192481
00000669e0eeb33ee5dbb672d3bd2deb0c32ef9879ef260f0debbdcb80121160
那么控制前面有多个 0 的那个 Target 又是怎么来的呢是由 Bits 这个字段控制的也就是难度系数前面需要的 0 越多难度也就越大其中的算法你可以看一下 Bitcoin Wiki 上的Difficulty 词条这里我就不多说了
这个难度系数会在每出 2016 个区块后就调整一次现在这个难度是要在前面找到有 18 个零如下所示 (一个真实的区块链的 Hash )
000000000000000000424118cc80622cb26c07b69fbe2bdafe57fea7d5f59d68
一个 SHA-256 算法算出来的哈希值有 \(2^{256}\) 种可能性而前面有 18 个零意味着前面有 72 bits 是零于是满足条件的哈希值是有 \(2^{184}\) 种可能性概率是 \(\frac{1}{2^{72}}\)
是的很有可能你穷举完 Nonce 后还找不到那就只能调整 Timestamp Merkle Root调整不同的记账交易
所以一般的挖矿流程如下
从网络上取得之前的区块信息
待记账区 中获取一组交易数据有优先级比如成长时间矿工小费等)。
形成区块头计算 Merkle Root 并设计记账时间 Timestamp )。
开始穷举 Nonce来计算区块头的 hash 如果前面有 18 个零小于 Target那么记账成功如果没有则从第一步重新开始
一旦某矿工成功打包一个区块他就会告诉其他矿工收到消息的矿工会停下手上的工作开始验证验证通过后广播给其他矿工
所以满足条件的这个难度系数成为了挖矿的关键设置这个难度系数就是为了让全网产生的区域名平均在 10 分钟一块而根据比特币无中心服务器的架构也就是其挖矿的机器数量是想来就来想走就走的计算力可能会不一样因此为了保证每 10 分钟产生一个区块当算力不足的时候难度下降当算力充足的时候难度提高
今天的这 18 个零基本上来说一般的电脑和服务器就不用想了必须要算力非常非常高的机器才能搞定所以在今天挖矿这个事已经不是一般老百姓能玩的了
下图展示了整个比特币的难度历史
图片来源http://bitcoin.sipa.be
上面这个图只是算力的表现可能并不直观我们还是用其耗电量来说可能会更好一些根据 Bitcoin Energy Consumption Index 统计截至 2017 11 20 比特币过去一年挖矿的电力总消耗已累计达 29.51 TWh1TWh = \(10^{12}\) Wh约占全球总电力消耗的 0.13%。该数字甚至已经超过近 160 个国家或地区一年的电力消耗包含冰岛和尼日利亚若全球的比特币矿工自成一国该国的电力消耗排名可排到全球第 61
看到这里你一定要问为什么要挖矿呢不就是记个账呗为了系统地说明这个问题我们下面来看看去中心化的共识机制