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

Solidity使用ecrecover函数验签返回地址与预期不符问题求助

排查Solidity ecrecover验签地址不一致问题

刚看了你的代码和问题描述,核心问题出在签名前缀的长度匹配错误上,咱们一步步拆解:

问题根源

以太坊EIP-191标准规定,签名消息时必须添加固定前缀:"\x19Ethereum Signed Message:\n",后面紧跟原消息的字节长度的字符串形式,再和原消息拼接后做哈希,最终签名这个哈希值。

你的代码里写死了前缀为"\x19Ethereum Signed Message:\n32",这里的32是指消息的字节长度,但你的原消息是'a'——它的字节长度只有1,不是32!这就导致你计算的prefixedHash和签名时用的哈希完全不一致,自然ecrecover返回的地址不对。

场景适配的修正方案

分两种常见场景给你调整代码:

场景1:前端直接签名原始消息(比如MetaMask/ethers.js的signMessage)

这种情况下,前端已经自动帮你加上了符合EIP-191的前缀,你的Solidity代码需要对原始消息计算正确的带前缀哈希:

function verify(string memory message, uint8 v, bytes32 r, bytes32 s) public pure returns(address) {
    bytes memory messageBytes = bytes(message);
    bytes memory prefix = "\x19Ethereum Signed Message:\n";
    // 拼接前缀、消息长度、原始消息后哈希
    bytes32 prefixedHash = keccak256(abi.encodePacked(prefix, uint256(messageBytes.length), messageBytes));
    return ecrecover(prefixedHash, v, r, s);
}

场景2:前端先哈希消息,再签名这个哈希(需手动加前缀)

如果你是先对'a'做哈希得到messageHash,再给这个哈希加前缀签名,那前缀里的32是对的(因为哈希是32字节),但要确保前端签名的是"\x19Ethereum Signed Message:\n32" + messageHash的哈希值,此时你的Solidity代码可以保留结构,但要确认前端的签名流程匹配:

function verify(bytes32 hash, uint8 v, bytes32 r, bytes32 s) public pure returns(address) {
    bytes memory prefix = "\x19Ethereum Signed Message:\n32";
    bytes32 prefixedHash = keccak256(abi.encodePacked(prefix, hash));
    return ecrecover(prefixedHash, v, r, s);
}

额外检查点

除了前缀问题,还要留意这两个常见坑:

  • v值正确性:以太坊签名的v值应为27或28,如果你的签名工具返回0/1,记得加27转换后再传入函数。
  • r/s格式:确保r和s是标准的32字节值,没有被截断或格式错误。

你可以先确认自己的签名生成流程,再对应调整代码,应该就能得到正确的地址了。

内容的提问来源于stack exchange,提问作者Pittie

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 04:07:05