首先我们快速的预览一下Substrate中提供的几种密码学算法:
这些密码学原语的定义在代码中都有定义,可以参考链接:
https://github.com/paritytech/substrate/tree/master/primitives/core/src
https://docs.rs/substrate-primitives/1.0.0/substrate_primitives/
https://github.com/paritytech/substrate/blob/master/primitives/core/src/hashing.rs
哈希函数介绍
哈希函数的定义是: A function that input binary data(message) and output hash value. 输入任意二进制数据(消息),生成哈希值的函数。
哈希函数也称为散列函数或者消息摘要函数(message digest function),消息也称为原像(pre-image),哈希值也称为散列值、消息摘要(message digest)或者指纹(fingerprint)。
Hash的原意是古代法语中的“斧子”,后来被形容为“剁碎的肉末”,估计是要的是用斧子一顿乱剁然后搅在一起的感觉吧。哈希函数实际上就是将消息剁碎,再混合成固定长度的哈希值。
-
-
拿SHA-256来说,无论是16字节的用户密码,5M的图像,512G的U盘中的所有文件,还是1TB的硬盘文件,计算出的哈希值永远是256比特(32字节)
-
-
-
常见的哈希算法有 MD5,SHA-1,SHA-2,SHA-3。
-
-
SHA-1 2005年强抗碰撞性被王小云团队攻破,除了用于对过去生成的哈希值进行校验,不应该用于新的用途。
-
SHA-2(SHA-256,SHA-384,SHA-512)是安全的。
-
SHA-3(也叫Keccak [kɛtʃak])是安全的。
SHA-2(SHA-256,SHA-384,SHA-512)
SHA是Secure Hash Algorithm的缩写,SHA 家族包含了SHA -0到SHA -3。
SHA-2由NIST设计,2001年发布,是SHA-1的继任者,其中包含了6种哈希函数。
实际上6种哈希函数都是由SHA-256和SHA-512衍生出来的,将SHA-256和SHA-512的的结果进行截断就得到了其它4种。
https://github.com/RustCrypto/hashes Substrate中提供了 sha2_256。
SHA-3的全称是Secure Hash Algorithm – 3。
NIST(美国国家标准与技术研究院)通过公开竞争的方式来选拔SHA-3算法,整个选拔经历了5年的时间(11/2/2007 – 10/2/2012),具体过程如下:
-
-
2008年10月,征集到64个算法,其中51个进入到第一轮
-
-
(https://nvlpubs.nist.gov/nistpubs/ir/2012/NIST.IR.7896.pdf )
-
2012年10月,Keccak算法被最终确定为SHA-3标准
https://github.com/debris/tiny-keccak
Substrate中提供了 keccak_256。
Blake2b算法的网站可以参考:https://blake2.net/
介绍Blake2b算法之前,先介绍一下Blake2b的前身Blake。Blake的核心算法继承自ChaCha流加密算法(Daniel J. Bernstein发明),Blake于2010年12月被列入SHA-3的最终候选名单,最终没有被选中是因为和SHA-2算法的实现有点类似,NIST的目标是SHA-3尽量与SHA-2不同。
Blake2算法继承自Blake算法,于2012年12月21日正式对外公开。Blake2速度比 MD5,SHA-1,SHA-2,SHA-3 更快(64位x64和ARM的CPU架构上),安全性优于SHA-2,与SHA-3旗鼓相当。
下面的图表是各个哈希算法的速度测试对比,可以看出Blake2b算法的速度是最快的。
上面的哈希函数速度测试是在Skylake Intel CPU上做的测试,使用的是单核CPU。如果使用多核CPU,BLAKE2的优势会更加明显。
BLAKE2 有两个主要版本,BLAKE2b(BLAKE2)和 BLAKE2s,通常所说的BLAKE2默认指BLAKE2b。BLAKE2b 为 64 位 CPU(包括 ARM Neon)优化,可以生成1-64字节的哈希值;BLAKE2s 为 8-32 位 CPU 优化,可以生成1-32 字节的哈希值。
https://github.com/cesarb/blake2-rfc
- blake2_128
- blake2_256
- blake2_512
xxHash的全称是Extremely fast hash algorithm,特点是速度很快。
下表是xxHash和其它哈希算法的速度测试对比,基于2核 Duo @3GHz CPU,Windows 7的32位机器做的测试,可以看出xxHash确实非常快。
https://libraries.io/cargo/twox-hash
https://github.com/Cyan4973/xxHash
秘钥对和签名算法背后的核心是椭圆曲线密码学,椭圆曲线密码学(Elliptic Curve Cryptography, ECC)包含三个方面的内容:
-
-
基于椭圆曲线的数字签名(ECDSA,Elliptic Curve Digital Signature Algorithm)
-
椭圆曲线基础
上面的方程叫做Weierstrass/Weierstraß方程。
通过变换不同的a,b数值得到不同的曲线形状,所以我们可以说椭圆曲线是一个家族,有一系列不同的椭圆曲线。
椭圆曲线上的一些数学运算和我们常规意义上的数学运算很不一样,比如“椭圆曲线上的加法运算“是这样定义的(参照上图):
从几何图形上来说,其中P,Q是曲线上的两个点,R是经过P,Q的直线与椭圆曲线相交的第三个点,-R就是R经过翻转得到的点。从这个加法的定义中我们发现,曲线上两个点相加后可以得到第三个点,并且仍然在这个曲线上。
当P = Q时,经过P和Q的直线是一条与曲线相切的直线。这个时候我们就可以定义标量乘法了,P + P = 2P,如果要计算nP实际上就相当于将P相加n次:
实际上我们说的椭圆曲线是由这些离散的nP点组成的,从1P到nP,椭圆曲线既不是椭圆,也不是曲线,只是一群离散的点,基于这些点才可以生成椭圆曲线密码学需要的点。
这里我们需要知道的是,已知曲线上的点P,求nP是比较容易的,然而已知P和nP,要是想求n的话,是非常非常困难的,这个性质被成为“椭圆曲线上的离散对数问题”。
这个时候就可以介绍椭圆曲线的公钥密码了,上面公式中的n可以作为私钥,P是椭圆曲线上选定好的一个点,而nP就是公钥。
从上图我们可以直观的看到,如果椭圆曲线的形状变了,那得到的公钥的结果也会不一样。下面我们就介绍一下不同的椭圆曲线。
几种不同的椭圆曲线
先看一个上面提到过的方程,叫做Weierstrass/Weierstraß方程:
这个方程是Weierstrass/Weierstraß方程的简化版,称为”short Weierstraß format”。
实际上,所有的曲线都可以由Weierstrass/Weierstraß方程来表达,不同的曲线只是基于这个方程进行了变量的变换。
基于Koblitz曲线,当b = 0时就有了secp256k1曲线:
secp256k1曲线是2000年由SECG(Standards for Efficient Cryptography Group,高效密码组标准)提出的。secp256k1名字的含义:
1987年,Peter L. Montgomery提出了蒙哥马利曲线(Montgomery curve),曲线的方程为:
之后,Daniel J. Bernstein提出了名为Curve25519的蒙哥马利曲线,方程是这样的:
Curve25519由著名的密码学家 Daniel J. Bernstein 于 2005年公布,但实际上直到2013年才流行起来,在众多椭圆曲线家族中,由NIST公布的Curve P曲线(使用Weierstrass曲线方程)最为常用。
2013年斯诺登曝光“棱镜计划”,指出美国国家安全局(National Security Agency,NSA)在NIST标准中使用的Dual_EC_DRBG算法放置了后门,导致人们对于NIST以及其推出的Curve P(例如secp256r1 被称为 P-256)系列曲线的安全性开始产生了质疑,之后Curve25519开始获得广泛的关注。
Curve25519最开始被设计用来进行ECDH(Elliptic Curve Diffie-Hellman,基于椭圆曲线的DH密钥交换)。是目前最快的椭圆曲线密码之一,并且没有专利限制。
最开始Curve25519是被命名为DH(Diffie-Hellman密钥交换)函数的,后来为了区分DH函数和DH函数所使用的椭圆曲线,将DH函数命名为X25519,将其所用的椭圆曲线命名为Curve25519。
还有一种曲线叫做Edwards曲线(爱德华兹曲线),方程式为:
基于Edwards曲线,发明了Twisted Edwards曲线(扭曲爱德华兹曲线,也称为edwards25519 ),Twisted Edwards曲线是Edwards曲线的一般化形式,方程为:
有意思的是,这几个曲线中是有等价关系的。通过一定的映射,蒙哥马利曲线可以转化为Weierstrass曲线。蒙哥马利曲线和Twisted Edwards曲线具有双有理等价关系,通过双有理映射也可以相互转化。
使用椭圆曲线进行签名
了解了哈希函数和椭圆曲线,我们来说说椭圆曲线的签名算法。
其实所有的签名都是“先哈希再签名(hash-then-sign)”,也就是先对消息进行哈希运算得到一个固定长度的哈希值,然后对这个哈希值利用签名算法进行签名。当使用椭圆曲线的签名算法的时候,利用了椭圆曲线上的离散对数问题,使得签名无法被伪造,并且可以很容易的验证签名的有效性,知道是不是给定的公钥签名的。
进行签名时,首先通过私钥a执行公私钥生成算法,得到两个值:
-
计算随机数 r = H(k, M)。其中H是哈希函数,k是上面得到的随机数,M是消息。
-
计算随机点 R = rG。其中G是椭圆曲线上被选定的一个点,每个椭圆曲线都有这个预设值。通过前面的知识我们可以知道R也在椭圆曲线上。
-
计算签名 s = (r + H(R, A, M) x) mod p。其中p是一个很大的质数,mod p 表示前面得到的值对p进行模的运算。得到x的过程是,先对私钥a进行哈希运算,然后取得到的哈希值的前一半,即为x。
验证签名时,使用公开的三个参数和一个公式就可以验证了。三个参数包括:
然后验证公式是否成立: sG = R + H(R, A, M) A
Ed25519签名算法
Ed25519的目标是在保证安全的前提下,提升性能。
和ECDSA 类似,EdDSA(Edwards-Curve Digital Signature Algorithm,爱德华兹曲线数字签名算法)也属于椭圆曲线密码;和ECDSA不同的是,EdDSA采用了不同的椭圆曲线和签名算法。
EdDSA 采用了Twisted Edwards曲线作为椭圆曲线,签名算法采用了Schnorr算法作为签名的生成和验证。
Ed25519是一种EdDSA的实现 ,由 Daniel J. Bernstein 等人设计,采用的曲线参数完全公开,并说明了参数选取的意义,保证曲线中并未内置后门。
https://github.com/dalek-cryptography/ed25519-dalek
sr25519签名算法
Substrate中还使用了一个Ed25519的衍生版本,叫做sr25519,也称为Schnorrkel/Ristretto x25519,解决了使用Ed25519实现复杂协议的安全问题。
其中的h叫做余因子(cofactor),余因子的值最好为1,要不然会产生安全问题,比如其中之一的可以导致加密货币被无限增发,Monero在2017年就发现并修复了这样一个问题,好在当时没有产生损失。
secp256k1和secp256r1的余因子是1,不存在这些安全问题;而Edwards曲线的余因子都大于4,其中Ed25519使用的曲线的余因子是8,都存在这些安全问题。
这是椭圆曲线本身的问题,如果要避免这个问题,就需要在上层使用这个曲线的地方解决这个问题,Mike Hamburg的 Decaf 论文 提供了解决这个问题的方案,并且只有非常少量的性能损耗。
简单的说,就是通过数学方法,将余因子从4转换成1。然而Decaf方案只解决了余因子为4的曲线问题,并没有解决余因子为8的曲线的问题。
为了解决这个问题, Ristretto Group 将Decaf 论文中的方法进行了改进,增加了对余因子为8的曲线的支持。
Web3基金会在 Schnorrkel 这个库中也实现了这项改进,称其为Schnorrkel/Ristretto x25519,简称sr25519,并将其用于Substrate。
这个库还支持其他的协议,例如分层确定性密钥派生(Hierarchical Deterministic Key Derivation,HDKD), 多签(multi-signatures,MuSig), VRF (verifiable random function,可验证随机函数)。
Substrate的账户对于ed25519和sr25519这两种签名都是支持的。对于简单的签名来讲,两种协议有用相同的安全性。
ed25519可以用来支持硬件安全模块(Hardware security module,HSM)以及需要外部秘钥管理的地方。而sr25519提供了更多的区块链友好的功能,例如分层确定性密钥派生和多签,这些复杂的协议使用sr25519来实现会更加安全。
更多的对于这部分的内容,可以参考波卡中的秘钥信息,链接
https://wiki.polkadot.network/docs/en/learn-keys 。
这里还需要提到的一个实现是bip39,增加了对sr25519的支持:
https://github.com/paritytech/substrate-bip39
secp256k1
因为sr25519比较新,很多硬件钱包不支持,Substrate引入了硬件支持更广泛的secp256k1曲线,并已于2019年10月上线Kusama。
secp256k1是在Bitcoin和Ethereum上使用的椭圆曲线,大家应该相对熟悉,这里不对secp256k1做过多介绍。
https://github.com/paritytech/libsecp256k1 包含的功能:
-
-
-
-
-
秘密的分享(Shared secrets,不确定是啥东西)
Substrate上使用的地址格式叫做SS58,是专门设计给基于Substrate开发的链的。
base58encode ( concat ( <address-type>, <address>, <checksum> ) )
SS58是基于比特币中使用的Base58Check地址格式开发的,设计目标是可以通过账户地址识别出不同的Substrate链。使用的base58encode编码函数和比特币中使用的编码函数是一样的,不同的地方,SS58的前缀是地址类型,校验和使用的是blake2-256哈希函数。
-
00000000b..00110000b (0..48): Account/address identifiers on networks:
-
00000000b (0) Polkadot Live (SS58 checksum preimage)
-
00000001b (1) Polkadot Live (AccountId checksum preimage)
-
00000010b (2) Polkadot Canary (SS58 checksum preimage)
-
00000011b (3) Polkadot Canary (AccountId checksum preimage)
-
00010000b (16) Kulupu (SS58 checksum preimage)
-
00010001b (17) Kulupu (Reserved)
-
00010100b (20) Dothereum (SS58 checksum preimage)
-
00010101b (21) Dothereum (AccountId checksum preimage)
-
00101010b (42) Generic Substrate wildcard (SS58 checksum preimage)
-
00101011b (43) Generic Substrate wildcard (AccountId checksum preimage)
-
00110000b..01000000b (48..64): Bare public keys of primary cryptography
-
00110000b (48) Schnorr_Ristretto 25519 (“S_R 25519”) key
-
00110001b (49) Edwards Ed25519 key
-
00110010b (50) ECDSA SECP256k1 key
-
01000000b..11111111b (64-255) Reserved for future address format extensions.
下面是我画的一个生成SS58的流程图,应该可以比较清楚的看到SS58的生成过程。
本文介绍了Substrate中用到的密码学知识,包括哈希函数,椭圆曲线密码,地址格式这几个方面,试图通过尽量简洁的语言将这些知识讲清楚,如果有问题,欢迎大家和我交流。
参考资料
-
-
https://en.wikipedia.org/wiki/BLAKE_(hash_function)#BLAKE2
-
https://zh.wikipedia.org/wiki/BLAKE
-
https://zhuanlan.zhihu.com/p/28563960
-
https://zh.wikipedia.org/wiki/SHA%E5%AE%B6%E6%97%8F
-
https://en.wikipedia.org/wiki/SHA-2
-
https://zh.wikipedia.org/wiki/SHA-2
-
https://csrc.nist.gov/projects/hash-functions/sha-3-project
-
https://wiki.polkadot.network/docs/en/learn-cryptography
-
https://zhuanlan.zhihu.com/p/84322255
-
https://research.web3.foundation/en/latest/polkadot/keys/
-
https://github.com/paritytech/substrate/wiki/External-Address-Format-(SS58)
-
https://andrea.corbellini.name/2015/05/17/elliptic-curve-cryptography-a-gentle-introduction/
-
http://suntus.github.io/2019/05/31/ECC%E7%AE%97%E6%B3%95/
-
https://hackernoon.com/what-is-the-math-behind-elliptic-curve-cryptography-f61b25253da3
-
https://blog.mozilla.org/warner/2011/11/29/ed25519-keys/
-
https://en.wikipedia.org/wiki/Curve25519
-
https://en.wikipedia.org/wiki/Twisted_Edwards_curve
-
https://webencrypt.org/twistededwardscurve/
-
http://netinfo-security.org/article/2017/1671-1122-0-9-122.html
-
https://en.wikipedia.org/wiki/EdDSA#Ed25519
-
https://zhuanlan.zhihu.com/p/44243140
-
https://zhuanlan.zhihu.com/p/76783431
-
https://tiannian.me/2018/12/28/cryptography/ed25519/
-
https://www.getmonero.org/2017/05/17/disclosure-of-a-major-bug-in-cryptonote-based-currencies.html
-
https://tools.ietf.org/html/rfc7748
-
decaf: https://eprint.iacr.org/2015/673.pdf
-
https://ristretto.group/why_ristretto.html
-
https://doc.dalek.rs/curve25519_dalek/ristretto/index.html
-
https://www.oreilly.com/library/view/mastering-bitcoin-2nd/9781491954379/ch04.html
-
https://medium.com/polkadot-network/kusama-cc-2-prepos-a0ce785bb629
-
https://www.johndcook.com/blog/2018/08/21/a-tale-of-two-elliptic-curves/
-
https://www.johndcook.com/blog/2018/08/14/bitcoin-elliptic-curves/
-
https://zh.wikipedia.org/wiki/%E6%A4%AD%E5%9C%86%E6%9B%B2%E7%BA%BF%E5%AF%86%E7%A0%81%E5%AD%A6
-
https://en.bitcoin.it/wiki/Secp256k1
-
https://www.ietf.org/rfc/rfc5480.txt
-
https://learnblockchain.cn/books/geth/part3/sign-and-valid.html
-
https://crypto.stackexchange.com/questions/58506/what-is-the-curve-type-of-secp256k1
本文首发于一块plus社区 https://mp.weixin.qq.com/s/Mrm9ZAmFXriOpalDqOLelQ