You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ECDSA.recover无法验证钱包签名的认证消息问题求助

验签失败问题排查与解决方案

已发现的核心错误点

  • 合约前缀字符串拼写错误:代码中\x19Ethereum Signed Messsage:\n32的Messsage多写了一个s,正确拼写为Message,字符串不匹配直接导致最终哈希计算错误
  • 客户端签名参数类型错误:keccak256(utils.toUtf8Bytes(message))返回的是0x开头的十六进制字符串,直接传入signMessage会被ethers当成普通字符串处理(长度为66),而合约侧写死了长度为32,两边前缀的长度字段不匹配
  • 哈希处理逻辑不一致:客户端提前对原消息做了一次keccak哈希,再传给签名方法,和合约侧的哈希处理逻辑没有对齐

修复方案

方案一:使用标准EIP-191签名逻辑(推荐,不易出错)

  1. 客户端修改为直接传入原消息签名,不需要提前做哈希:
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);
  1. 合约侧直接使用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;
 }

方案二:保留原逻辑仅修复错误

如果需要保留「先对原消息哈希再签名」的逻辑,只修改错误点即可:

  1. 客户端修改为将哈希转为二进制字节数组再传入签名方法:
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);
  1. 合约侧修正前缀的拼写错误:
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 10:36:04