使用js-ethereum-cryptography 2.0的recoverPublicKey恢复公钥遇undefined错误求助
问题分析与解决
核心错误点
你的代码存在3个关键问题导致recoverPublicKey返回undefined:
- 参数顺序与含义完全错误:
recoverPublicKey第一个参数需要被签名消息的哈希值,第二个参数是签名对象;你错误地将sender地址作为第二个参数传入。 - 签名数据类型不匹配:从
req.body获取的r、s是字符串类型(JSON传输限制),但库要求传入Uint8Array或BigInt类型。 - 缺失原始消息哈希:恢复公钥必须依赖与签名时完全一致的消息哈希,你没有生成这个核心参数。
修正后的代码示例
const { secp256k1, keccak256 } = require("@noble/secp256k1"); const { hexToBytes } = require("@noble/hashes/utils"); app.post("/send", (req, res) => { const { sender, recipient, amount, signature } = req.body; const { r, s, recovery } = signature; try { // 1. 重构与签名时完全一致的原始消息(注意格式、顺序、数据类型必须完全匹配) const rawMessage = `${sender}${recipient}${amount}`; // 2. 对消息做哈希(必须和签名时使用的算法一致,这里以keccak256为例) const messageHash = keccak256(new TextEncoder().encode(rawMessage)); // 3. 将字符串格式的r、s转换为库要求的Uint8Array类型 const rBytes = hexToBytes(r); const sBytes = hexToBytes(s); // 4. 正确调用recoverPublicKey方法 const publicKey = secp256k1.recoverPublicKey(messageHash, { r: rBytes, s: sBytes, recovery: parseInt(recovery, 10) // 确保recovery是数字类型(0或1) }); // 可选:验证恢复的公钥是否对应sender地址 const publicKeyBytes = publicKey.slice(1); // 去掉公钥开头的0x04标识位 const addressHash = keccak256(publicKeyBytes); const derivedAddress = `0x${Buffer.from(addressHash.slice(-20)).toString("hex")}`; if (derivedAddress.toLowerCase() === sender.toLowerCase()) { console.log("签名验证通过,公钥恢复成功:", publicKey.toString()); res.json({ success: true, publicKey: publicKey.toString() }); } else { res.status(400).json({ success: false, message: "签名与地址不匹配" }); } } catch (err) { console.error("公钥恢复失败:", err); res.status(500).json({ success: false, error: err.message }); } });
额外注意事项
- 签名时的原始消息必须和恢复时的
rawMessage完全一致,包括空格、数据类型(比如amount是数字还是字符串)、拼接顺序。 - 最新版
js-ethereum-cryptography基于@noble/secp256k1实现,API与旧版存在差异,需严格遵循当前版本文档。 recovery参数只能是0或1,必须确保前端传入的是有效数字而非字符串。
内容的提问来源于stack exchange,提问作者Siamak Abdi
相关产品推荐
相关产品推荐

