大家好,首先感谢腾讯云提供云社区这样一个让技术人员沟通交流的平台,其次很高兴入驻到云+社区认识到大家,我是腾讯云TVP一员,专注于云计算、区块链、Web架构方向,myPagination作者,Github也开源了很多区块链的项目:https://github.com/linapex,有需要的朋友可以下载学习,本文是区块链技术实战系列的第二篇(不定期更新):
《区块链核心技术-P2P网络构建》
《区块链核心技术-分布式一致性与共识算法》
《区块链核心技术-区块设计与存储》
今天我们聊一聊区块链的核心技术密码学,区块链技术离不开密码学,可以说密码学是区块链系统的基石之一,我们先来了解一下。
这是以太坊黄皮书关于钱包(私钥、公钥、地址)的描述,仅仅 2 行文字。主要讲解私钥通过 ECDSA(椭圆曲线签名算法)推导出公钥,继而经过 Keccak 单向散列函数推导出地址。分解为 3 个步骤:
1. 创建随机私钥 (64 位 16 进制字符 / 256 比特 / 32 字节)
2. 从私钥推导出公钥 (128 位 16 进制字符 / 512 比特 / 64 字节)
3. 从公钥推导出地址 (40 位 16 进制字符 / 160 比特 / 20 字节)
这是从ethereumjs/keythereum中剥离出来的 JavaScript 代码,关于黄皮书上的公式的具体实现,仅仅 6 行代码。
这是一件很奇妙的事情,2 行文字,6 行代码承载着亿万级别的资产,但往往越简单,越奥妙。以上的 6 行代码,就已经囊括密码学中大多数技术,比如随机数生成器、非对称加密,单向散列函数等。
什么是随机数生成器?
随机数用于生成私钥,若随机数可以被预测或重现,则私钥就会立刻形同虚设。所以保证随机数拥有下列三项特征,至关重要:
1.随机性:不存在统计学偏差,完全杂乱的数列
2.不可预测性:不能从过去的数列推测下一个出现的数
3.不可重现性:除非将数列保存下来,否则不能重现相同的数列
软件本身是无法生成具有不可重现性的随机数,因为运行软件的计算机本身仅具备有限的内部状态。所以通过确定性的代码,在周期足够长的情况下,必然会出现相同的随机数。因此要生成具备不可重现性的随机数,需要从不确定的物理现象中获取信息,比如周围温度、环境噪音、鼠标移动,键盘输入间隔等。
在 Linux 内核中维护了一个熵(shāng)池用来收集来自设备驱动程序和其它来源的环境噪音。熵(entropy)是描述系统混乱无序程度的物理量,一个系统的熵越大则说明该系统的有序性越差,即不确定性越大。
所以在选择生成私钥的随机数方法时,需要选择满足密码学强度的随机数方法,比如 Node 中的 crypto.randomBytes。当你调用 crypto.randomBytes(32) 方法时,它会等待熵池搜集足够的信息后,返回 64 位的随机数,即私钥。
const privateKey = crypto.randomBytes(32)
privateKey.toString('hex'):
ea4692a11d962b249f8f0439d642a9013a1a08807649311d3672886d72d1fe51
什么是非对称加密?
在非对称加密中,将密钥分为加密密钥和解密密钥,也就是我们常说的公钥和私钥。公钥和私钥一一对应,由公钥加密的密文,必须使用公钥配对的私钥才可以解密。
当我们调用 secp256k1.publicKeyCreate 获得公钥时,实际使用的是非对称加密中的椭圆曲线算法。通过该算法可以从私钥推导出公钥,这是一个不可逆的过程:K = k * G。给出常数点 G 时,使用已知私钥 k 求公钥 K 的问题并不困难,但反过来,已知公钥 K 求私钥 k,则非常困难。这就是椭圆曲线算法上的离散对数问题,也是为什么你可以分享地址(或公钥)给别人,但不能暴露自己的私钥。
const publicKey = secp256k1.publicKeyCreate(privateKey, false).slice(1)
publicKey.toString('hex'):
1e3f1532e3285b02...45d91a36a8d78cb6bef8
为了形象的表现椭圆曲线算法如何将私钥推导出公钥,我们将使用简单的整数作为私钥 k,找到公钥 K = k * G,也就是 G 相加 k 次(数学原理一致)。在椭圆曲线中, 点的相加等同于从该点画切线找到与曲线相交的另⼀点, 然后映射到 x 轴。下图展示了从曲线上获得 G、2G、4G、8G 的几何操作。
什么是哈希算法?
密码学技术,也称散列函数,原理是把任意长度的输入通过哈希算法,变换成固定长度的由字母和数字组成的输出,如:钱包的地址、交易地址都是通过哈希算法运算出来的。
作为加密算法的一种,散列函数是一种单向密码体制,对于给定的哈希值,无法推倒输入的原始数据,具有不可逆性,这也是哈希算法安全性的重要基础。
目前,哈希算法主要有两类:MD系列和SHA系列。MD(Message Digest,消息摘要)系列包含MD4、MD5、HAVAL等,SHA(Secure Hash Algorithm,安全散列算法)系列包含SHA1、SHA256等。其中MD5是密码学专家R.L.Rivest设计,SHA是美国算法制定机构设计。
当我们调用 createKeccakHash(“keccak256”) 方法时,Keccak 使用海绵函数,对公钥与初始的内部状态做 XOR 运算得到 32 字节散列值,取其后 20 字节,转成 40 位的 16 进制字符,即为地址。
const address =
createKeccakHash("keccak256").update(publicKey).digest().slice(-20)
address.toString("hex"):
7a48ac1bf3943b2ca7a4ca4999cbcbb0e999950c
什么是区块链哈希?
在区块链系统中,构建交易数据对应的Merkle树,计算得到Merkle树根节点的区块链哈希值,区块链的哈希值能够唯一而精准地标识一个区块,区块链中任意节点通过简单的哈希计算都接获得这个区块的哈希值,计算出的哈希值没有变化也就意味着区块链中的信息没有被篡改。
Merkle树在数字货币、零知识证明、文件完整性校验等领域有广泛的应用,如:比特币以太坊系统利用Merkle proofs来存储每个区块的交易,Git也是通过Merkle树来进行完整性校验。比特币简化支付验证SPV(Simplified Payment Verification)也是使用此方式进行验证支付。
Merkle树是Ralph Merkle于1979提出,是一种哈希二叉树,在计算机科学中,二叉树是每个节点最多有两个子树的树结构,每个节点代表一条结构化数据。通常子树被称作“左子树”(left subtree)和“右子树”(right subtree)。二叉树常被用于实现数据快速查询,是散列列表和散列链的泛化。