以太坊中的签名机制资料和问题

发个帖记录收集一些以太坊中签名相关的 EIP 和机制,以及我遇到的问题,之后会总体的进行研讨然后输出成一篇文章。这里记录的比较散乱,如果你有了解的也可以补充,或者疑问,届时一起探究。


AA 或者 Safe 钱包,由于是智能合约,没有私钥,所以签名的机制跟 EOA 是不一样的,就会导致有一些场景下比如 claim NFT 等,是无法正常签名的。不过这里的签名机制区别需要了解一下,以及如何优化 AA 的签名。


https://gisli.hamstur.is/2020/08/understanding-ethereum-by-studying-the-source-code/

core/types/transaction_signing.go

// EIP155Transaction implements Signer using the EIP155 rules.
type EIP155Signer struct {
	chainId, chainIdMul *big.Int
}

// Hash returns the hash to be signed by the sender.
// It does not uniquely identify the transaction.
func (s EIP155Signer) Hash(tx *Transaction) common.Hash {
	return rlpHash([]interface{}{
		tx.data.AccountNonce,
		tx.data.Price,
		tx.data.GasLimit,
		tx.data.Recipient,
		tx.data.Amount,
		tx.data.Payload,
		s.chainId, uint(0), uint(0),
	})
}

func (s EIP155Signer) Sender(tx *Transaction) (common.Address, error) {
	if !tx.Protected() {
		return HomesteadSigner{}.Sender(tx)
	}
	if tx.ChainId().Cmp(s.chainId) != 0 {
		return common.Address{}, ErrInvalidChainId
	}
	V := new(big.Int).Sub(tx.data.V, s.chainIdMul)
	V.Sub(V, big8)
	return recoverPlain(s.Hash(tx), tx.data.R, tx.data.S, V, true)
}

func recoverPlain(sighash common.Hash, R, S, Vb *big.Int, homestead bool) (common.Address, error) {
	if Vb.BitLen() > 8 {
		return common.Address{}, ErrInvalidSig
	}
	V := byte(Vb.Uint64() - 27)
	if !crypto.ValidateSignatureValues(V, R, S, homestead) {
		return common.Address{}, ErrInvalidSig
	}
	// encode the signature in uncompressed format
	r, s := R.Bytes(), S.Bytes()
	sig := make([]byte, crypto.SignatureLength)
	copy(sig[32-len(r):32], r)
	copy(sig[64-len(s):64], s)
	sig[64] = V
	// recover the public key from the signature
	pub, err := crypto.Ecrecover(sighash[:], sig)
	if err != nil {
		return common.Address{}, err
	}
	if len(pub) == 0 || pub[0] != 4 {
		return common.Address{}, errors.New("invalid public key")
	}
	var addr common.Address
	copy(addr[:], crypto.Keccak256(pub[1:])[12:])
	return addr, nil
}

下面的编解码算法是怎么运作的?大概了解是通过签名等值算出来发送者地址,然后进行比较,如果一致则验证成功。需要了解下 椭圆曲线 的工作原理。

ECDSA 签名

  • ECDSA 签名由三个部分组成:rsv
    • rs 是签名的核心部分。
    • v 是恢复标识符,用于确定签名的公钥。

更详细的资料 ECDSA: Elliptic Curve Signatures | Practical Cryptography for Developers

以太坊的签名规则

  • 以太坊使用 secp256k1 椭圆曲线。
  • 为了防止签名的可塑性(即同一笔交易可能有多个有效签名),以太坊在 Homestead 硬分叉中引入了对 s 值的限制。

签名的可塑性

  • 签名的可塑性是指同一笔交易可能有多个有效的签名形式。
  • 例如,如果 (r, s) 是一个有效签名,那么 (r, N - s) 也是一个有效签名。
  • 通过限制 s 的范围(如 s <= N/2),可以消除这种可塑性。

TODO