在之前的一篇文章 https://zhuanlan.zhihu.com/p/54391586 中,我们介绍了如何通过椭圆曲线加密的思路来选择私钥并生成对应的公钥,这节来看一下通过这对密钥如何完成数字签名,本节的主题是椭圆曲线签名算法,简称 ECDSA。比特币就是用 ECDSA 来签署交易的。
在深入到数学推导细节之前,我们先聊清楚椭圆曲线签名的基本原理。
ECDSA 涉及到三个重要的概念:
第一个是私钥,私钥是一个只有我自己知道的数字,我可以用私钥去生成签名,比特币使用的私钥是一个256 bit 的整数。
第二个是公钥,公钥是跟私钥配对的一个数,是根据私钥运算得出的,我会把公钥公布给所有人,目的是让大家去验证我的签名。比特币的公钥有65个字节,包括一个前缀加上两个256 bit 的整数,这两个整数就对应椭圆曲线上的一个点的 x 值和 y 值。
第三个是签名,签名就是一个证明我的确执行了签署操作的数字。签名主要由两项内容运算得出,一项是被签署数据的哈希,另外一项就是私钥。签名要保证两点:一个是证明我是私钥的持有者,第二个是证明被签名数据没有被篡改过。
这就是数字签名的基本原理了。
在前一篇文章中,我们使用的运算公钥的等式是 X=x*P
,其中 x 就是私钥,X 是对应的公钥,那么我如何让大家相信我手里是有 x 的呢?当然这里的前提是大家手里都有 X ,同时我不能把 x 展示给大家。
上一篇中我们知道,椭圆曲线点相加满足属性 n*P+r*P = (n+r)*P
,那么由这个等式出发,可以得出 hash(m, r*P)*n*P+r*P = (hash(m, r*P)*n+r)*P
也是成立的,同时不管 m,r 和 n 取任何值,等式都保持成立。
这时取 n*P=X
就会得到 hash(m, r*P)*X+r*P = (hash(m, r*P)*n+r)*P
,那么既然 n*P=X
,那 n 就等于 x,也就是私钥,所以有 hash(m, r*P)*X+r*P = (hash(m, r*P)*x+r)*P
。接下来,让 R=r*P
,同时 s=hash(m,R)*x+r
,所以就可以得出 hash(m, R)*X+R = s*P
。
至此,我的思路就有了,只要我可以提供 m、R 以及 s 就可以证明我是知道 X 对应的私钥是 x 。当然我的思路要有说服力,必须满足两个前提条件:第一个,如果我知道 x,那么我就能够给出一套可以保证等式成立的 m、R 和 s 值。第二个,如果我不知道 x,那我将没有任何办法得到 m、R 和 s 值。
先来验证第一个条件。如果我知道 x,那么得到 m、R 和 s 值真的是非常容易的,只需要我随机的选择 m 和 r 的值,然后根据 R=r*P
和 s=hash(m,R)*x+r
就可以得到 R 和 s 的值了。
再来验证第二个条件。如果我不知道 x,那我有没有可能得到 m、r 和 s 的值呢?这个问题就等价于,我需要去求解 hash(m,R)*X+R=s*P
。而这其实意味着,我需要找到一个哈希值对应的原始数据,而这显然是做不到的。
所以能够得到 m、R 和 s 值的唯一方式就是通过 x 来计算。而一旦我提供了这三个值,就证明了我是有 x 的。因为我提供的值可以让 hash(m,R)*X+R=s*P
这个等式成立。
当然,作为一套安全的签名算法,我还必须证明自己在整个过程中没有暴露出任何跟 x 相关的信息。这一点,本节就不展开了,可以参考这篇文章 https://hackernoon.com/what-is-the-math-behind-elliptic-curve-cryptography-f61b25253da3 的相关讨论。
由前面的推导,可以看出只要我展示出了 m、R 和 s 的值,就可以证明我是拥有私钥的。实际中我们可以把 m 作为要被签名的信息,而把 R 和 s 作为数字签名。
除了能够证明我拥有私钥,数字签名还要能够保证信息是没有被篡改过的,R 和 s 构成的数字签名是能够胜任这个任务的。因为验证数字签名的等式是 hash(m,R)*X+R=s*P
,如果在验证数字签名的时候信息被篡改过了,也就是说此刻 m 有了一个被篡改后的值,那么这个等式就不可能成立了,因为 s 是基于 m 的原始值运算出来的。
对于比特币来说,信息 m 就是交易,每一个数字签名之中都会包含 R 的 x 坐标值( R 是椭圆曲线上的一个点),还会包含 s (s 是一个256 bit 的整数)。
ECDSA 的工作原理我们就介绍到这里了,生成签名的过程就是基于信息 m 来运算 R 和 s,只要我给出的 R 和 s 能够满足等式 hash(m,R)*X+R=s*P
,就可以证明两点:第一,我是拥有私钥的,第二,m 没有被篡改过。对于比特币,每次我会用自己的私钥 x 来签署交易信息 m ,然后我会把得到的数字签名 R 和 s 附着到 m 之后,再加上我自己的公钥 X 公布到全网,于是网络上的其他人就可以通过等式来验证数字签名了。
参考