Solidity中字符串转Keccak256及ECC公钥转地址问题求助
Solidity ECC公钥转地址:差异原因与批量修复方案
结果差异的核心原因
问题出在字符串转字节数组的逻辑错误:
PubtoAddr接收的是已正确解析的ECC公钥原始字节数组(比如去掉0x前缀后,十六进制字符串对应的真实字节数据),后续通过keccak256哈希取后20字节生成地址,逻辑完全符合以太坊地址生成规范,结果正确。PubtoAddr2直接用bytes(string)转换字符串公钥,会把整个字符串(包括常见的0x前缀)当成ASCII字符序列转成字节。例如字符串"0x04abc..."转成bytes后,前两个字节是0x30(对应字符'0')和0x78(对应字符'x'),这完全不是真实的公钥字节数据,后续哈希计算自然得到错误地址。
批量处理的代码修复
要实现字符串公钥批量转地址,必须先将十六进制字符串解析为正确的字节数组,再执行地址转换逻辑。以下是具体实现:
1. 实现十六进制字符串转字节数组的工具函数
这个函数自动兼容带/不带0x前缀的字符串:
function hexStringToBytes(string memory hexStr) internal pure returns (bytes memory) { bytes memory hexBytes = bytes(hexStr); require(hexBytes.length % 2 == 0 || (hexBytes.length >= 2 && hexBytes[0] == '0' && hexBytes[1] == 'x'), "Invalid hex string"); uint256 startIndex = 0; if (hexBytes.length >= 2 && hexBytes[0] == '0' && hexBytes[1] == 'x') { startIndex = 2; require((hexBytes.length - startIndex) % 2 == 0, "Invalid hex length after 0x"); } bytes memory result = new bytes((hexBytes.length - startIndex) / 2); for (uint256 i = 0; i < result.length; i++) { uint256 pos = startIndex + i * 2; uint8 high = hexCharToByte(hexBytes[pos]); uint8 low = hexCharToByte(hexBytes[pos + 1]); result[i] = bytes1((high << 4) | low); } return result; } function hexCharToByte(bytes1 c) internal pure returns (uint8) { if (c >= '0' && c <= '9') return uint8(c) - uint8('0'); if (c >= 'a' && c <= 'f') return uint8(c) - uint8('a') + 10; if (c >= 'A' && c <= 'F') return uint8(c) - uint8('A') + 10; revert("Invalid hex character"); }
2. 修复字符串转地址函数及批量处理函数
基于上述工具函数,修改后的转换逻辑和批量处理函数如下:
function pubToAddrFromStr(string memory pubKeyStr) public pure returns (address) { bytes memory pubKeyBytes = hexStringToBytes(pubKeyStr); // 验证ECC公钥长度(标准非压缩公钥为65字节:0x04开头+32字节X坐标+32字节Y坐标) require(pubKeyBytes.length == 65, "Invalid ECC public key length"); bytes32 hash = keccak256(abi.encodePacked(pubKeyBytes)); return address(uint160(uint256(hash))); } function batchPubToAddr(string[] memory pubKeyStrs) public pure returns (address[] memory) { address[] memory results = new address[](pubKeyStrs.length); for (uint256 i = 0; i < pubKeyStrs.length; i++) { results[i] = pubToAddrFromStr(pubKeyStrs[i]); } return results; }
关键说明
- 工具函数
hexStringToBytes会先判断字符串是否带0x前缀,再将每两个十六进制字符解析为一个字节,还原出真实的公钥字节数组。 - 地址生成逻辑严格遵循以太坊规范:对完整公钥字节数组做
keccak256哈希,再通过uint160截断哈希值的后20字节,转换为最终地址。
内容的提问来源于stack exchange,提问作者SpaceNinja
相关产品推荐
相关产品推荐

