ChainMaker v3.0.0 EVM ecrecover returns zero address for valid secp256k1 recoverable signature
【问题分类】
- bug
- P2P网络相关(包含libp2p,liquid)
- 链账户身份与权限相关(证书问题、public、多签投票问题)
- 核心交易引擎相关(交易池、DAG)
- 共识相关
- 智能合约相关
- 存储相关
- SDK相关
- 长安链CMC工具
- 长安链管理台
- 长安链浏览器
- 长安链合约IDE
- 长安链web签名插件
- 跨链相关
- 轻节点相关
- 隐私计算相关
- 密码学相关
- 环境依赖
- 其他补充:
【问题描述】
在 ChainMaker v3.0.0 的 EVM 合约中测试 ecrecover 时,发现对一组 65 字节 secp256k1 recoverable signature,ecrecover 始终返回零地址。
测试方式如下:
- 在 Solidity 合约中将签名拆分为
v/r/s - 分别尝试:
ecrecover(hash, v, r, s)ecrecover(hash, v + 27, r, s)ecrecover(hash, v - 27, r, s)
测试使用合约:
pragma solidity 0.7.6;
contract EcrecoverDebug {
event DebugResult(
uint8 rawV,
address rawAddr,
address plus27Addr,
address minus27Addr
);
function splitSignature(bytes memory sig)
public
pure
returns (uint8 v, bytes32 r, bytes32 s)
{
require(sig.length == 65, "bad sig len");
assembly {
r := mload(add(sig, 32))
s := mload(add(sig, 64))
v := byte(0, mload(add(sig, 96)))
}
}
function debugRecover(bytes32 hash, bytes memory sig)
public
returns (uint8 rawV, address rawAddr, address plus27Addr, address minus27Addr)
{
(rawV, bytes32 r, bytes32 s) = splitSignature(sig);
rawAddr = ecrecover(hash, rawV, r, s);
plus27Addr = ecrecover(hash, rawV + 27, r, s);
minus27Addr = ecrecover(hash, rawV - 27, r, s);
emit DebugResult(rawV, rawAddr, plus27Addr, minus27Addr);
}
function recoverRaw(bytes32 hash, bytes memory sig) public pure returns (address) {
(uint8 v, bytes32 r, bytes32 s) = splitSignature(sig);
return ecrecover(hash, v, r, s);
}
}
测试参数 1:
hash:
0xf86fcb350fe0dd52c5eceef2a8a1bd1390ee06875a831075dff5d34bdaf530d5
sig:
0xd3c2126abbb1efcd64735ecb1d4078e59e5a464979d3bf0f1ac94f5b9c85e77c36a6d614ece8158a1130d7e88400d6e03c9d601f63240200b08d8980a0b0a41a01
返回结果:
[1, 0x0000000000000000000000000000000000000000,
0x0000000000000000000000000000000000000000,
0x0000000000000000000000000000000000000000,
0x0000000000000000000000000000000000000000]
测试参数 2,仅将最后一个字节改为 00:
sig:
0xd3c2126abbb1efcd64735ecb1d4078e59e5a464979d3bf0f1ac94f5b9c85e77c36a6d614ece8158a1130d7e88400d6e03c9d601f63240200b08d8980a0b0a41a00
返回结果:
[0, 0x0000000000000000000000000000000000000000,
0x0000000000000000000000000000000000000000,
0x0000000000000000000000000000000000000000,
0x0000000000000000000000000000000000000000]
实际结果:
- 无论
v=0/1还是兼容尝试27/28,ecrecover都返回零地址
预期结果:
- 对于合法的 65 字节 secp256k1 recoverable signature,
ecrecover应恢复出正确地址,或与 Ethereum/geth 保持一致行为
初步怀疑与 vm-evm 中 ecRecover.go 的实现有关,关键逻辑包括:
v := input[63] - 27recoverPubkey(append(input[64:128], v), input[:32])btcec.RecoverCompact
希望协助确认:
- 当前 ChainMaker EVM
ecrecover是否保证与 Ethereum/geth 完全兼容 - 对于
r || s || v格式的 secp256k1 recoverable signature,官方推荐输入格式是什么 - 该问题是否已知,后续版本是否已有修复
【相关日志文件】
当前无明显 panic.log。
【系统信息】
-
chainmaker-go version * :
v3.0.0 -
OS & version * :
CentOS 7 - docker镜像 version: 暂不涉及
- 管理台 version: 暂不涉及
- 区块浏览器 version: 暂不涉及
- 合约IDE version: 暂不涉及
- web签名插件 version: 暂不涉及
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information