我正在尝试恢复TypedData消息(eip712)的签名者。
我能够签署和验证与ethersJS以及在合同中的有效性。
使用Go,我也可以签署和验证,但是验证在合同中失败了。
signerData := TypedData{
Types: Types{
"Quote": []Type{
{Name: "cost", Type: "uint256"},
{Name: "deadline", Type: "uint256"},
},
"EIP712Domain": []Type{
{Name: "name", Type: "string"},
{Name: "chainId", Type: "uint256"},
{Name: "version", Type: "string"},
{Name: "verifyingContract", Type: "string"},
{Name: "salt", Type: "string"},
},
},
PrimaryType: "Quote",
Domain: TypedDataDomain{
Name: "MyDomain",
Version: "1",
ChainId: ethMath.NewHexOrDecimal256(ChainId.Int64()),
VerifyingContract: contractAddress.String(),
Salt: "0",
},
Message: TypedDataMessage{
"cost": "0",
"deadline": "1659095005",
},
}func EncodeForSigning(typedData TypedData) (hash common.Hash, err error) {
domainSeparator, err := typedData.HashStruct("EIP712Domain", typedData.Domain.Map())
if err != nil {
return
}
typedDataHash, err := typedData.HashStruct(typedData.PrimaryType, typedData.Message)
if err != nil {
return
}
rawData := []byte(fmt.Sprintf("\x19\x01%s%s", string(domainSeparator), string(typedDataHash)))
hash = common.BytesToHash(crypto.Keccak256(rawData))
return
}func (s Signer) SignTypedData(typedData TypedData) (sig []byte, err error) {
hash, err := EncodeForSigning(typedData)
if err != nil {
return
}
sig, err = crypto.Sign(hash.Bytes(), s.key)
if err != nil {
return
}
sig[64] += 27
return
}我能在Go中验证它;
func Ecrecover(hash, signature []byte) (addr common.Address, err error) {
sig := make([]byte, len(signature))
copy(sig, signature)
if len(sig) != 65 {
err = fmt.Errorf("invalid length of signture: %d", len(sig))
return
}
if sig[64] != 27 && sig[64] != 28 && sig[64] != 1 && sig[64] != 0 {
err = fmt.Errorf("invalid signature type")
return
}
if sig[64] >= 27 {
sig[64] -= 27
}
recoverPub, err := crypto.Ecrecover(hash, sig)
if err != nil {
err = fmt.Errorf("can not ecrecover: %v", err)
return
}
pubKey, err := crypto.UnmarshalPubkey(recoverPub)
if err != nil {
err = fmt.Errorf("can not unmarshal pubkey: %v", err)
return
}
addr = crypto.PubkeyToAddress(*pubKey)
return
}然而,在合同失败的情况下,我尝试了ECDSA和_hashTypedDataV4,他们都返回了相同的地址,但这是错误的。
function validateQuote(uint256 _cost,uint256 _deadline, bytes memory _signature) public view returns (address) {
Quote memory quote = Quote({
cost: _cost,
deadline: _deadline
});
bytes32 msghash = _hashTypedDataV4(hash(quote));
uint8 v;
bytes32 r;
bytes32 s;
(v, r, s) = splitSignature(_signature);
(address signer, ) = ECDSA.tryRecover(msghash,_signature);
console.log("v4 signer", signer);
console.log("v", v);
return (verifyQuote(quote, v,r,s));
}签名的十六进制表示在go和实体中是相同的,但是实体返回的签名人无效。
V= 27
go验证返回正确的地址
//validate signature
hash, err = EncodeForSigning(signerData)
signerAddress, err := Ecrecover(hash.Bytes(), sig)
fmt.Println("Signer Recovery", signerAddress) // good合同一方失败的原因是什么?
我能够用以太验证相同的签名,其中V=28相同的签名与go集的V为27。不确定这是相关的。
发布于 2022-10-25 08:51:32
ethers.utils.splitSignature(signature).compact在用go.I生成签名之后,您可以用ether.js来尝试这一点,我不确定它是否有效,但您可以尝试它。
https://ethereum.stackexchange.com/questions/131756
复制相似问题