2.2.4 数字签名
介绍数字签名之前,我们先看一个例子。如图2-35所示,黑客伪装成公司总经理,企图欺骗公司会计汇款,黑客将消息和通过密码哈希函数生成的哈希值发给会计,会计收到后再通过密码哈希函数检验了消息的准确性,可是他能把100万元汇给黑客吗?
图2-35 使用密码哈希函数验证消息的准确性
在实际应用中,我们不仅需要验证消息的准确性,还需要验证消息发送方的真实身份,所以需要进行认证。用于认证的技术包括消息验证码和数字签名,比特币中用到了数字签名。
那么什么是数字签名?
数字签名本质就是一种加密认证技术,表示某人认可某个文件,将纸上的手写签名电子化。其目的是签名,实质是加密。手写签名可以通过笔迹进行辨认,我国公安机关等执法部门就设有专人从事笔迹鉴定工作,通过鉴定笔迹验证签名真伪,尤其在科技不发达时期,笔迹鉴定对于破案起着至关重要的作用。那么数字签名如何实现签名功能呢?我们想象一下,创建一个类似签名的字符串,然后附加到需要签名的文件中。如图2-36所示,假设小明的名字数字化以后是001100,如果小明要签名,在电子文件中附加上小明的这串数字名字001100是不是就可以了?
图2-36 签名数字化
如果这么简单,区块链可就歇菜了。这个签名任何人都可以伪造,只要在文件后面加上001100,就可以说是小明的签名,如图2-37所示。
图2-37 伪造数字化签名
毕竟数字签名与纸上的签名不同,它只是一个字符串而已,没有笔迹可寻。那么如何使用加密技术,把现实生活中在纸上签名的动作数字化,从而达到签名的目的呢?
我们从签名这件事的要求说起。第一,你的签名只有你自己知道怎么做出来,别人无法仿造,只能验证,也就是别人看到签名可以验证就是你签的,不是别人签的。第二,签名与文件之间不能解耦合,也就是说签名与文件是紧密联系的,仅表示签名者认同这份文件而与其他文件无关。这种思维与我们日常生活中看到的在纸上的签名不同,纸上的签名会出现把名字剪下来再贴到其他文件上的情况,而这在数字签名中是不允许发生的。签名就像用一个保密印章来盖章,其他人用印章扫描器验证这个签名是不是某人签的。每个人有其各自的保密印章,每个保密印章盖的章都隐含了一个字符串,该字符串就是保密印章用户的代号,但是单凭肉眼看不出来,也无法通过观察来制造一个一模一样的保密印章。其他人使用印章扫描器扫描已经盖好的章,显示隐含的字符串信息,与相应的用户代号对应,从而验证签名是否属于该用户。数字签名形象化举例如图2-38所示。
图2-38 数字签名形象化举例
需要注意的是,在实际应用中,区块链具有匿名性,我们并不知道现实生活中到底是张三还是李四拥有这个保密印章,我们只是通过拥有这个保密印章的人在区块链中的身份进行签名验证。关于区块链的匿名性在后面章节中会详细阐述。
下面我们看看数字签名是如何实现的。
数字签名的实现采用了公钥密码的设计理念。公钥密码通过生成的密钥对,实现公钥对消息加密和私钥对消息解密,如图2-39所示。
图2-39 公钥密码机制
在数字签名中同样采用公钥和私钥成对的密钥对,只不过与公钥密码机制相反,数字签名中私钥用来生成签名,公钥用来验证签名,如图2-40所示。
图2-40 数字签名机制
从公钥密码和数字签名的区别能够看出,我们可以发送用公钥加密的文件给特定人;特定人可以用私钥对文件进行数字签名让其他人来验证其真实性。
另外需要强调的是,在公钥密码算法中,密钥对中的公钥和私钥数学关系是一一对应的,就像钥匙和锁的对应关系,用公钥加密的文件只能用与该公钥相对应的私钥来解密;同理,用私钥签名的文件只能用与该私钥对应的公钥来验证。
下面介绍数字签名的具体实现方式。
首先,产生一对公钥和私钥。私钥和公钥必须是成对的。
(sk,pk):=createKeys(keyinfo)
式中,sk是私钥,pk是公钥。createKeys用来根据输入keyinfo生成一对私钥和公钥,密钥对生成以后,就可以使用私钥进行签名。
sig:=sign(sk,msg)
以上表达式是将私钥sk和需要签署的文件信息msg作为输入,生成的一串字符串就是“已签名的文件”。这个字符串仅是针对特定的消息做的签名,消息与私钥已完全混合,不同的消息msg会生成截然不同的签名字符串,你无法把签名(这里对应私钥)从sig中分解或者提取出来,这是和传统的纸上签名的重要区别。
isValid:=verify(pk,msg,sig)
以上这一步就是验证签名,把原始消息msg与签过名的消息sig以及公钥pk三者作为输入,判断返回的结果是否为真,如果是真则表示签名属实,否则签名验证不通过。
数字签名在区块链中扮演着非常重要的角色。没有实体,仅仅通过虚拟的账户进行交易,我们如何相信自己账户里的钱不会被盗用?区块链就是这么厉害,数字签名能保证你账户里的钱只有你自己可以消费(在区块链中,消费的动作实际就是一段可执行代码,将你账户地址里面的数字货币转到另一个账户地址)。那么你可能会问,数字签名难道一点都没有漏洞,不能被伪造吗?如果仔细观察一个用户的签名,研究上千次,是否可以尝试在新的消息上伪造签名呢?我们认为这样成功的概率非常非常小,小到在实践中不会发生。
现在我们回到本节刚开始遇到的问题,黑客伪装成公司总经理,欺骗公司会计给自己汇款。有了数字签名后,我们通过验证签名就可以确保消息的真实性。公司总经理用自己的私钥给消息签名,会计用总经理的公钥验证签名,流程如图2-41所示。只要黑客没有获取到总经理的私钥,就无法成功实施欺骗。
图2-41 数字签名实际应用
图2-41中我们是对消息直接进行签名的,这种方法需要对整个消息进行加密,然而在现实中,能够签署的消息大小是有限制的。实际上我们可以对消息的哈希值进行签名,这样就由原先签署任意长度的信息,变为只要签署特定哈希值长度的信息。因为密码哈希函数具有碰撞阻力,消息的哈希值就如一个人的身份证,具有唯一标识性,所以对消息的哈希值签署和对原消息签署的效果是一样的,如图2-42所示。
图2-42 对消息的哈希值进行数字签名
比特币中使用的数字签名算法是椭圆曲线数字签名算法(ECDSA),针对256位的哈希值进行签名,输出是512位的字符串。椭圆曲线数字签名算法基于椭圆曲线密码算法,通用标准的椭圆曲线方程是y2=x3+ax+b。椭圆曲线并不是椭圆形状,因为椭圆曲线的方程类似于计算椭圆周长的方程,因此得名椭圆曲线。椭圆曲线密码算法的数学原理在前面公钥密码算法已做了简单介绍,这里不再赘述。ECDSA是中本聪选定的,除比特币以外很少被使用,感兴趣的读者可以参考相关文献。