为什么以太坊的交易数据中没有from地址

  • stirlingx
  • 更新于 2022-02-11 14:53
  • 阅读 3930

以太坊的交易数据中之所以没有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)
}

它的返回值是公钥,传入的两个参数分别是:

  • hash:原始数据的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做运算。

现在我们看一下签名过程:

  • 1) 随机选择一个整数k, 且 0 < k < n
  • 2) 计算 R = k * G =(x, y)
  • 3) r = x mod n, 如果r = 0,则返回步骤1
  • 4) 计算 H = Hash(M),这步是将M映射到椭圆曲线上
  • 5) s = (k^−1) (H + r d) mod n, 若s = 0, 则返回步骤1

上面公式中 k^−1表示对n取模的逆元

r和s就是签名结果,我们看到在第5步中用到了私钥d。

验签

我们看一下怎么对上面的签名进行验签

  • 1) 计算 H = Hash(M)
  • 2) 计算 u1 = H (s^-1) mod n, u2 = r (s ^ -1) mod n
  • 3) R = u1 G + u2Q = (x, y) mod n
  • 4) 如果x = r则签名成功,证明过程此处省略

公钥恢复

上面验签的过程中的第三步用到了公钥, 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地址,是因为他可以通过签名推导出公钥,而公钥可以推导出地址。推导公钥的过程,实际也是做验签的工作。

公众号:

点赞 1
收藏 1
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

1 条评论

请先 登录 后评论
stirlingx
stirlingx
0x7690...f836
江湖只有他的大名,没有他的介绍。