开始之前
在验证之前,我们需要这些基本的信息: 签名,原文,地址(或者公钥)

Sig: 0x5f3c4ab309427d25cdc34a41cb432610c6c817e76ce9aec0c9336365063687ff29c92963edd6935f365d5f28c146f227881b626c7db18e87b9baf2089729741b1c
Message: 签名这段文字以验证你是这个账户的持有者。
Address: 0x1c52C6F743351fC9b97AE4Fe32194A588398FE69
处理原文
首先我们需要将原为处理为Hash形式
1 | MessageHash = keccak256(prefix + message) |
这个prefix是个什么东西?
我们来看看签名在生成的时候是如何计算的。在Ethereum官方文档中,关于eth_sig的描述是这样的:

可疑的地方是sign(keccak256("\x19Ethereum Signed Message:\n" + len(message) + message))),我们可以看到在message之前添加了一段话:"\x19Ethereum Signed Message:\n" + len(message)。真正被签名的数据不是单纯的message,而是在message之前添加了这句话(prefix)后整体做了hash运算。所以,我们在计算hash的时候,也需要照做。
1 | String message = "签名这段文字以验证你是这个账户的持有者。"; |
现在已经将原始消息和prefix都转换成了字节数组的形式,接下来需要把这两部分拼接起来
1 | byte[] msg = new byte[msgPrefix.length + msgBuffer.length]; |
毫无难度,利用System.arraycopy方法可以轻松得拷贝数组,得到msg后,就可以计算keccak256(msg)了
1 | import org.ethereum.crypto.cryptohash.Keccak256; |
这里使用了ethereumj的加密包,当然你也可以使用其他的包或者自己实现keccak256。
结果:msgHash = 767cab717f7e9a3f56765c89f39887b9934a8e78ad4d0a2fb1fd0d009bb7012b (32字节,HEX)
好了,到目前为止msgHash已经拿到了,接下来就要处理签名了
处理签名
再来看一眼签名: 0x5f3c4ab309427d25cdc34a41cb432610c6c817e76ce9aec0c9336365063687ff29c92963edd6935f365d5f28c146f227881b626c7db18e87b9baf2089729741b1c
长度是65个字节。
然而这段签名是由三部分组成的。它们分别是 r, s, v。r和s长度都是32字节,v是一个字节。下面的代码将会吧签名拆分成上述部分。
1 | import org.bouncycastle.util.encoders.Hex; |
结果:
r = 5f3c4ab309427d25cdc34a41cb432610c6c817e76ce9aec0c9336365063687ff (32字节,HEX)
s = 29c92963edd6935f365d5f28c146f227881b626c7db18e87b9baf2089729741b (32字节,HEX)
v = 28 (10进制)
得到这三个数据以后,就可以进入下一个环节辣
什么是椭圆曲线数字签名算法
若果你不想了解或者已经了解椭圆曲线的细节,可以跳过此小节
ECDSA,EC,和Secp256k1
以太坊使用的是Elliptic Curve Digital Signature Algorithm (ECDSA,椭圆曲线数字签名算法)进行签名。可是Elliptic Curve(EC,椭圆曲线)又是个什么东西?
为了有一个直观感受,这里有一个简单但是通用的方程
其中a都是常数b,不同的取值会形成不同的曲线方程

在这里https://www.desmos.com/calculator/9vv5aklebf,你可以调整
a和b的值来观察不同的取值
这些方程和加密有什么联系么?当然!不过首先要了解什么是群以及加法
群(Groups) 和阿贝尔群
群:若 非空 集合 𝔾, 定义在 𝔾 上的一个二元运算:加法,符号+表示,满足:
-
封闭性:存在,
-
结合律:存在,
-
交换律:存在,
-
单位元:集合 𝔾 中有一个确切的值即单位元,使得
-
逆元:集合 𝔾 中每个成员都有其相反数,即
则称为一个群,或者加法群也叫阿贝尔群。
椭圆曲线上的加法
假设曲线上有两个点,和

过 和 做一条直线,相交于曲线

过 做 轴垂线并相交于曲线

那么
如何计算
访问 https://www.desmos.com/calculator/fttnxuzryp 查看更多关于计算的细节
我们已经知道了 和 ,又
那么过这两点直线的斜率
设
椭圆曲线和阿贝尔群
上述对于椭圆曲线上加法的描述和解析使我们得知都是曲线上的点,且满足阿贝尔群的定义。不难证明椭圆曲线上的加法是一个阿贝尔群。
椭圆曲线上的乘法
现在我们已经知道了如何计算加法,那么如何计算的值呢?
其实就是。还记得过两点做直线么?这里只有一个点P, 相当于P和Q重合,那么这段直线的斜率就是过P点的切线的斜率,直接求导。

这样带入上述公式
就能得出的值了
如何计算的值呢?
现在我们已经知道了的值,那么只需要计算Q = 2PP$ 和 做直线,相交于, 过做轴垂线相交于曲线另外一点
那么就是这里的的值啦
依此类推,我们可以计算的值
离散的特性
有空的同学务必要试一试
掏出纸和笔,设定随机点画出的位置。
你会发现的位置相差很大,没有规律可循。如果给定两点以及的值,你能求出乘数吗?
即便是只有7,这里的计算量也是很大的,如果给定和(是一个的数字),那么逆推出的难度就相当大了,以人类文明现有水平,很难在短时间(几百年)计算出结果。
这就是为什么椭圆曲线数字签名算法安全性这么高了。
签名过程
用户持有公钥和私钥, 以及原文
验证过程
签名验证过程
,更具体的,是secp256k1椭圆曲线。
https://en.bitcoin.it/wiki/Secp256k1
此椭圆曲线的方程是
这个方程的图像看起来是这个样子:

https://www.desmos.com/calculator/ialhd71we3
