发个帖记录收集一些以太坊中签名相关的 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 签名由三个部分组成:
r
、s
和v
。r
和s
是签名的核心部分。v
是恢复标识符,用于确定签名的公钥。
更详细的资料 ECDSA: Elliptic Curve Signatures | Practical Cryptography for Developers
以太坊的签名规则
- 以太坊使用
secp256k1
椭圆曲线。 - 为了防止签名的可塑性(即同一笔交易可能有多个有效签名),以太坊在 Homestead 硬分叉中引入了对
s
值的限制。
签名的可塑性
- 签名的可塑性是指同一笔交易可能有多个有效的签名形式。
- 例如,如果
(r, s)
是一个有效签名,那么(r, N - s)
也是一个有效签名。 - 通过限制
s
的范围(如s <= N/2
),可以消除这种可塑性。
TODO