ethers.js中recoverPublicKey能否用于ECDSA签名验证?
关于ECDSA签名验证与ethers.js
recoverPublicKey的疑问解答 核心结论
直接对比原公钥与ethers.utils.recoverPublicKey(digest, signature)的返回值是可行的,但需要注意公钥格式的一致性。
关键细节解析
所谓“一个私钥对应多个公钥”,实际是公钥的两种编码格式:
- 非压缩公钥:65字节,以
0x04开头,后跟x、y坐标各32字节 - 压缩公钥:33字节,以
0x02或0x03开头,仅包含x坐标,y坐标的奇偶性由前缀标识
这两种格式只是同一公钥的不同表示,本质指向椭圆曲线上的同一个点。
- 非压缩公钥:65字节,以
SEC1规范提到的“多个候选公钥”是签名恢复的中间状态:
理论上,ECDSA签名恢复过程可能生成4个候选公钥点,但签名中的v值(恢复ID)会明确指定正确的那个。ethers.js的recoverPublicKey函数会利用签名中的v值直接返回对应正确的公钥,不会返回多个候选结果。
验证注意事项
- 必须保证原公钥与恢复出的公钥格式一致:
如果你的原公钥是压缩格式,需要先转为非压缩格式再对比;可以用ethers.utils.computePublicKey统一格式:// 将压缩公钥转为非压缩格式 const uncompressedPubKey = ethers.utils.computePublicKey(compressedPubKey, false); // 对比验证 const isValid = uncompressedPubKey === ethers.utils.recoverPublicKey(digest, signature); - 若签名是仅包含r+s的原始格式,需要先补充正确的
v值才能恢复正确公钥,但ethers.js处理的标准签名(65字节)通常已包含v值。
更简便的替代验证方式
如果担心格式问题,可直接使用ethers.utils.verifyDigest函数,它会直接验证签名是否匹配指定公钥,无需手动对比:
const isValid = ethers.utils.verifyDigest(digest, signature, publicKey);
内容的提问来源于stack exchange,提问作者Luis F.
相关产品推荐
相关产品推荐

