http://www.7klian.com

一个数字激发的摸索——ECDSA理会

这真是以太坊设计的一个bug吗?
椭圆曲线暗码(ECC)是基于椭圆曲线数学的公钥加密算法,成立在椭圆曲线离散对数坚苦问题之上,常用的协议有ECDH、ECDSA和ECIES等。
· 选择一条椭圆曲线E_P(a,b),选择基点G,G的阶数为n
签名算法Sign
· 取r=x mod n,若r=0则从头选择随机数k

· 判定r == x,若相等则签名验证乐成
由于r = x mod n,因此r,r+n,r+2n…都大概是正当的原始x值,差异的椭圆曲线存在差异数量这样正当的x值,FISCO BCOS回收的secp256k1曲线存在两个大概r, r+n。
总会有一天,当时——拨开云雾见天日,守得云开见月明。

ECDSA算法主要包罗以下四个要害成果:

FISCO BCOS生意业务签名算法基于ECDSA道理举办设计,ECDSA也是回收的生意业务签名算法。
从一个神奇的数字开始,查阅相关资料,相识设计道理,进而冲入ECDSA的世界,在一堆数学公式中苍茫、游荡,问题一个接着一个。一开始雾里看花,似懂非懂,靠着童贞座的洁癖精力,总算把心中疑问一一化解。
搜索发明此前已有很多关于该问题的接头,个中,Stack Exchange的一篇帖子指出这是一个设计bug。以太坊源码github上,也有一个相关issue,该issue被打上了「type:bug」的标签。

那这个小概率事件的概率详细有多小呢?这要从secp256k1曲线的参数说起,凡是描写一个椭圆曲线的点(x,y)的时候,x和y的值是 mod p 的功效,p是曲线的参数,它是一个大素数,之前提到的n也是曲线的参数,便是这条曲线上点的数量(曲线上点的数量为n*h,h也是曲线参数,该曲线h=1),,在secp256k1中,n和p的值很是靠近,详细可见下图。
假如回收「规复算法Recover」,而且在生成的签名中携带recoveryID,就可以快速规复出签发该生意业务对应的公钥,按照公钥计较出用户地点,然后在用户地点空间执行相应操纵。
每一个X轴坐标对应两个大概的Y坐标,因此FISCO BCOS中具备四种大概的R,(r, y) (r, -y) (r+n, y’) (r+n, -y’)。可是,对付一个r值存在两个X轴坐标的概率极低,低到险些可以忽略,以太坊中就忽略了这两种小概率事件。
这不像是一个Bug
· 验证r,s∈n
为了确定正确的Q,需要遍历x的所有大概取值,跑多轮Recover算法,这个时间开销是较量大的。为了提高Recover的时间效率,回收空间换时间的思路,在签名中增加一个v值,用于快速确定x,制止遍历查找试探,这个v值就是recoveryID。
带着这些疑问,再一次查阅相关设计质料,我们看到,以太坊EIP155中描写了有关ChainID的设计。基于以太坊源码构建的网络,实际运行的链有许多,为了防备一条链的生意业务被提交上链到另一条链,造成重放进攻,引入了ChainID的设计,在块高2,675,000的位置举办分叉实现。

加上了27,尚有一个压缩标志,假如有压缩则再加上4,recid的值范畴在27-34。

ECDSA才是“bug”
这要从NetworkID和ChainID的浸染范畴来表明。NetworkID主要在网络层面举办链的断绝,节点在成立彼此毗连的时候需要互换NetworkID,拥有一致的NetworkID才气完成握手毗连。ChainID是生意业务层面,防备差异网络的生意业务被交错反复进攻。
2. id |= (x != r ? 2 : 0);   // 小概率事件,如前文表明

Stack Exchange帖子中有一个链接给出了修复该Bug的代码,请看下面截图(红框)。在注释说明和代码可见,fromRpcSig函数对27这个魔数举办了非凡处理惩罚。从RPC过来的签名中,v值假如小于27(大概是0-3),则直接加上27作为新v值,fromRpcSig函数通过这个方法兼容ECDSA原始v值(也就是recoveryID)和以太坊v值。

· 计较R=(x, y),个中x=r,r+n,r+2n…,代入椭圆曲线方程计较得到R
故事到这里,我们对以太坊代码中谁人魔数27的前世此生有或许相识,但这仅仅是故事的初步,由此激发我们进一步思考一个问题:recoveryID是什么?
假如回收「验证算法Verify」,那节点必需首先知道签发该生意业务所对应的公钥,因此需要在每笔生意业务中携带公钥,这需要耗损很大带宽和存储。
· 计较s = k^−1(z+rd) mod n,若s=0则从头选择随机数k

故事要从以太坊中一个神奇的魔数开始说起。

大白了ChainID的浸染,另一个疑问又发生了——以太坊中,有NetworkID来区分差异网络,为什么还需要ChainID?
在区块链系统中,客户端对每笔生意业务举办签名,节点对生意业务签名举办验证。

· 上述(r,s)即为ECDSA签名

顺藤摸瓜,打开electrum的github,我们在electrum/electrum/ecc.py中找到如下代码

JavaSDK机能优化的文章就是基于这个计较公式,将遍历探寻recoveryID改为计较得到,大幅晋升了机能。
· 计较u_1 = −zr^−1 mod n和u_2 = sr^−1 mod n
这像是一个bug
为了表明清楚这个问题,我们需要从ECDSA算法着手,从数学角度领略其背后的道理。ECDSA是FISCO BCOS回收的生意业务签名算法,由此我们会发明,ECDSA算法有一种Recover机制,它才是真正“bug”级此外成果。
说到这里其实照旧没有搞清楚为什么是27,为什么是35?我们在EIP github的Issue#155中看到Jan和Buterin的交换记录,看来27是来自比特币的产品。

已知动静m和签名(r,s),规复计较出公钥Q。
故事开始

于是,疑问更多了,魔数35是什么?ChainID又是什么?
至此可知,27和35或许来历于此,以太坊担任比特币的设计,在比特币源码bitcoin/src/key.cpp的CKey::SignCompact函数中也确定了该实现方法,可是比特币为什么如此设计,仍未可知。

· 计较公钥Q= (x’, y’)=u_1⋅G+u_2⋅R
验证算法Verify
后话
本文先容ECDSA及椭圆曲线加密(ECC)相关常识、ECDSA的Recover机制和实现方法、FISCO BCOS生意业务签名和验签的底层道理。内容偏硬(shu)核(xue),接待对暗码学道理、底层道理感乐趣的开拓者一起交换。

recoveryID的计较
FISCO BCOS基于这个道理设计实现了生意业务签名和验签。
为了答复recoveryID的问题,我们重点存眷「规复算法Recover」。
这里躲藏了一个区块链设计哲学,区块链上的资源(资产、合约)都是归属某个用户的,假如可以或许结构出切合该用户地点的签名,等同于把握了该用户的私钥,因此节点无需事先确定用户公钥,仅从签名规复出公钥,进而计较出用户地点,就可以执行这个用户地点空间的相应操纵。
· 计较(x, y) = u1⋅G+u2⋅Q mod n
这个非凡的数字27代表了什么寄义呢?
在计较R的步调可以看到,存在多个x的取值大概性,导致存在多个R的大概性,因此计较获得的Q也存在多个大概的功效,需要通过和已知的公钥比拟,确定哪一个Q是正确的。假如遍历x的所有大概都未找到正确的Q,说明该动静和签名是差池应的,可能是一个未知的公钥。
ECDSA签名(r,s),个中r是椭圆曲线上一个点kG (x, y)对应的x mod n,相当于签名信息中只留下了X轴坐标相关的值,扬弃了Y轴相关的值。在「规复算法Recover」中实验找回Y轴对应的值结构R,进而规复出公钥。

以太坊黄皮书中,关于生意业务签名的叙述讲到两个非凡的数「27,28」,实际上是从「0,1」通过加了一个27演变获得「27,28」,所以本质上是一个非凡的数27。
发生密钥GenKey
基于签名功效(r, s)和签名进程中生成的随机点(x, y)的y值,recoveryID的计较方法如下:
· 对动静m利用动静摘要算法,获得z=hash(m)
· 计较z = hash(m)
· 选择随机数d ∈n为私钥,计较公钥Q = d⋅G
3. if (s > n / 2) id = id ^ 1;  // 签名计较得出的s假如大于n/2就会取n-s作为s值,因此这里做相应转换,这两个转换是同时产生的
ECDSA(Elliptic Curve Digital Signature Algorithm)是基于椭圆曲线的数字签名算法。数字签名算法是回收公私钥体系实现雷同写在纸上的普通签名,用于辨别数字信息的要领,常见的数字签名算法包罗DSA、RSA和ECDSA等。
以太坊(ETH)和经典以太坊(ETC)的主网NetworkID都是1,需要通过 ChainID机制才气防备生意业务在ETH和ETC网络之间交错重放,ETH主网的ChainID是1,ETC主网的ChainID是61。
关于JavaSDK机能优化的文章(记一次JavaSDK机能从8000晋升至30000的进程)中提到一个要害优化点——recoveryID的计较,这里仔细展开接头。

从代码中可见,electrum在签名时,为原本只有0-3之间的recid(recoveryID)

郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。

相关文章阅读