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
相关产品推荐
相关产品推荐

