以太坊的交易数据中之所以没有from
地址,是因为他可以通过签名推导出公钥,而公钥可以推导出地址。推导公钥的过程,实际也是做验签的工作。
前几天有个小伙伴问了一个问题,为什么以太坊的交易数据中没有from
地址,那怎么知道这笔交易是谁发起的?这个问题之前一直没留意,然后回想了一下,之前做验签的时候用到了一个函数 Ecrecover
,它可以从签名中恢复出公钥。随口答曰:可能是签名信息里面携带了公钥吧。
回去研究了一下,前面的回答有些肤浅了。
以太坊的交易数据是这样的,确实没有from
:
// LegacyTx is the transaction data of regular Ethereum transactions.
type LegacyTx struct {
Nonce uint64 // nonce of sender account
GasPrice *big.Int // wei per gas
Gas uint64 // gas limit
To *common.Address `rlp:"nil"` // nil means contract creation
Value *big.Int // wei amount
Data []byte // contract invocation input data
V, R, S *big.Int // signature values
}
然后 Ecrecover
函数是这样的:
// Ecrecover returns the uncompressed public key that created the given signature.
func Ecrecover(hash, sig []byte) ([]byte, error) {
return secp256k1.RecoverPubkey(hash, sig)
}
它的返回值是公钥,传入的两个参数分别是:
而sig是交易数据中的r, s, v三个整数的序列化,代码如下:
func decodeSignature(sig []byte) (r, s, v *big.Int) {
r = new(big.Int).SetBytes(sig[:32])
s = new(big.Int).SetBytes(sig[32:64])
v = new(big.Int).SetBytes([]byte{sig[64] + 27})
return r, s, v
}
怎么跟想像的不一样呢,这里面并没有任何公钥的信息。没办法只能去恶补一下加密理论知识了。
我们知道以太坊账号使用的椭圆曲线方程是secp256k1,它长这样
y² = x³ + 7
Ecc加密理论中私钥其实是一个随机大整数,假设是d,公钥是椭圆曲线上的一个点,假设是Q,椭圆曲线上还有一个点叫生成元G。Q = d*G mod n, n是椭圆曲线群的阶(不理解G和n也没关系,他们都是常量)。所以公钥是私钥推导出来的,公钥不能反推出私钥。以太坊的地址,实际是公钥的哈希,再进行编码(几乎所有区块链都是这么玩的)。
注意G和Q都是坐标点,所以有x和y两个值,本文中用大写字母表示坐标点,小写表示整数
假设待签名的数据T,对T进行hash运算之后得到M,M是一个大整数,所谓签名实际是对M做运算。
现在我们看一下签名过程:
上面公式中 k^−1表示对n取模的逆元
r和s就是签名结果,我们看到在第5步中用到了私钥d。
我们看一下怎么对上面的签名进行验签
上面验签的过程中的第三步用到了公钥, R = u1*G + u2*Q
。结合第二步,可以推导出公钥
Q = (R - u1 G) (u2^-1) = (R - H(s^-1)G) (r^-1)s = (s R - H G) * (r^-1) mod n
在上的式子中,除了R之外都是已知数。其实R(x,y), 通过验签的第4步,可以假设x=r,将x带入椭圆曲线方程中可以技术算出y。根据上面的方程y应该有2个值,
比如下面这个方程 y的值可以是1,4
y² = 1 mod 5
到底用哪个呢。我看回头看一下上面,以太坊交易数据结构体中的签名有3个变量(v,r,s),但是我们前面签名步骤只计算出了(r,s),那v用来干嘛的。对了,它刚好可以在这里指定哪个y才是我们需要的。所以在前面,我们的签名过程还少了一步,即生成v。
我们继续思考,这个方程有没有可能无解呢?当然有这种可能,那就是前面的假设x=r
错了,也就是验签失败。比如下面这个方程就没有解
y² = 2 mod 5
这个v是不是必须的呢,其实也可以不要。因为y只有两个可能的值,将他们依次带入前面的验签过程中去验证,只要通过了,那就是合法的那个。因为v只占一个字节,还能减少计算量,携带一个v是可以接受的。
以太坊的交易数据中之所以没有from
地址,是因为他可以通过签名推导出公钥,而公钥可以推导出地址。推导公钥的过程,实际也是做验签的工作。
公众号:
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!