ECDSA.recover无法验证钱包签名的认证消息问题求助
验签失败问题排查与解决方案
已发现的核心错误点
- 合约前缀字符串拼写错误:代码中
\x19Ethereum Signed Messsage:\n32的Messsage多写了一个s,正确拼写为Message,字符串不匹配直接导致最终哈希计算错误 - 客户端签名参数类型错误:
keccak256(utils.toUtf8Bytes(message))返回的是0x开头的十六进制字符串,直接传入signMessage会被ethers当成普通字符串处理(长度为66),而合约侧写死了长度为32,两边前缀的长度字段不匹配 - 哈希处理逻辑不一致:客户端提前对原消息做了一次keccak哈希,再传给签名方法,和合约侧的哈希处理逻辑没有对齐
修复方案
方案一:使用标准EIP-191签名逻辑(推荐,不易出错)
- 客户端修改为直接传入原消息签名,不需要提前做哈希:
let message : string = "check this message signed by account0"; // 直接传原字符串,ethers会自动完成utf8转码、加EIP-191前缀、哈希的全流程 let signature = await address0.signMessage(message); await hm.connect(address0).verifyMessage(message, signature);
- 合约侧直接使用OpenZeppelin ECDSA库的标准方法计算签名哈希,避免手动拼写出错:
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; using ECDSA for bytes32; function verifyMessage(string memory message, bytes memory signature) public view returns(bool) { // 自动计算符合EIP-191标准的签名哈希 bytes32 messageHash = ECDSA.toEthSignedMessageHash(bytes(message)); address signerAddress = messageHash.recover(signature); return msg.sender == signerAddress; }
方案二:保留原逻辑仅修复错误
如果需要保留「先对原消息哈希再签名」的逻辑,只修改错误点即可:
- 客户端修改为将哈希转为二进制字节数组再传入签名方法:
let message : string = "check this message signed by account0"; let messageHash = keccak256(utils.toUtf8Bytes(message)); // 把十六进制哈希转成32字节的二进制数组再签名,避免被当成普通字符串 let signature = await address0.signMessage(utils.arrayify(messageHash)); await hm.connect(address0).verifyMessage(message, signature);
- 合约侧修正前缀的拼写错误:
function verifyMessage(string memory message, bytes memory signature) public view returns(bool) { bytes32 messagehash = keccak256(bytes(message)); // 修正Messsage为Message bytes32 messagehash2 = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", messagehash)); address signeraddress = ECDSA.recover( messagehash2, signature); return msg.sender == signeraddress; }
通用排查思路
- 优先核对前缀字符串的拼写,手误打错字母是最常见的低级错误
- 分别打印客户端签名前的最终哈希值、合约侧recover前的最终哈希值,只要两个哈希不一致,验签必然失败
- 确认
signMessage的输入类型,ethers对字符串和二进制字节数组的签名处理逻辑完全不同,不要混用 - 先用官方标准测试用例跑通基础流程,再替换为自己的业务数据,缩小问题范围
内容的提问来源于stack exchange,提问作者GGizmos
相关产品推荐
相关产品推荐

