node.js - go-ethereum 签名提供与 nodejs ethers 不同的签名
问题描述
我需要在 nodejs 中可验证的 golang 签名,反之亦然(使用以太坊钱包/私钥)。但是我使用的两个库为消息签名提供了不同的结果。我不知道是因为我在某处犯了错误还是签名算法不同。我尝试了其他选项,但找不到在双方都给出相同结果的东西。
带有“go-ethereum”的 Golang 代码:
package main
import (
"bytes"
"crypto/ecdsa"
"fmt"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto"
)
func main() {
hexPrivateKey := "0xae78c8b502571dba876742437f8bc78b689cf8518356c0921393d89caaf284ce"
dataToSign := "bou"
privateKey, err := crypto.HexToECDSA(hexPrivateKey[2:])
if err != nil {
log.Fatal(err)
}
// keccak256 hash of the data
dataBytes := []byte(dataToSign)
hashData := crypto.Keccak256Hash(dataBytes)
signatureBytes, err := crypto.Sign(hashData.Bytes(), privateKey)
if err != nil {
log.Fatal(err)
}
signature = hexutil.Encode(signatureBytes)
fmt.Println(signature) // 0xc83d417a3b99535e784a72af0d9772c019c776aa0dfe4313c001a5548f6cf254477f5334c30da59531bb521278edc98f1959009253dda4ee9f63fe5562ead5aa00
}
带有“ethers”的nodejs代码:
import { ethers } from 'ethers';
let hexPrivateKey = "0xae78c8b502571dba876742437f8bc78b689cf8518356c0921393d89caaf284ce";
let dataToSign := "bou"
let wallet = new ethers.Wallet(hexPrivateKey);
// keccak256 hash of the data
let hashData = ethers.utils.id(dataToSign);
let signature = await wallet.signMessage(ethers.utils.arrayify(hashData));
console.log(signature); // 0x80512c504128c66590fc359fd1e663ec51144086beef775e4e3be14e949fdead5839d90f4789e80bb264dc90474148143b09c286d3d75ba33e20e4117bf5c2881c
解决方案
ethers.js 的人发现了我的问题。正如他们在那里解释的那样:https ://github.com/ethers-io/ethers.js/issues/823#issuecomment-625953096,ethers.js的signMessage
功能使用EIP-191和personal_sign格式,所以它在消息前加上"\x19Ethereum Signed Message:\n"
.
要在 ethers.js 中获得与 golang 中相同的结果,我们必须使用原始 SigningKey,而不是 Wallet 包装器:
const hexPrivateKey = "0xae78c8b502571dba876742437f8bc78b689cf8518356c0921393d89caaf284ce";
const signingKey = new ethers.utils.SigningKey(hexPrivateKey);
const signature = signingKey.signDigest(ethers.utils.id("bou"));
//{ r: '0xc83d417a3b99535e784a72af0d9772c019c776aa0dfe4313c001a5548f6cf254',
// s: '0x477f5334c30da59531bb521278edc98f1959009253dda4ee9f63fe5562ead5aa',
// _vs: '0x477f5334c30da59531bb521278edc98f1959009253dda4ee9f63fe5562ead5aa',
// recoveryParam: 0,
// v: 27 }
ethers.utils.joinSignature(signature);
// "0xc83d417a3b99535e784a72af0d9772c019c776aa0dfe4313c001a5548f6cf254477f5334c30da59531bb521278edc98f1959009253dda4ee9f63fe5562ead5aa1b"
唯一需要考虑的是,ethers.js 中此签名的最后 2 位数字与 golang 中的不同,因为 ethers.js joinSignature 函数在末尾使用 v,但上面显示的 golang 使用最后的恢复参数。
推荐阅读
- javascript - 如何使用 javascript 开发词法分析器?
- flutter - 我正在制作一个图像编辑应用程序。我想通过将文本小部件拖动到图像上的所需位置来移动它。我怎样才能做到这一点。请帮我
- ios - 深度链接在 SwiftUI iOS 中不起作用(未触发打开 url appdelegate 方法)?
- php - 如何使用 AWS EC2 减少 time_starttransfer (TTFB)
- c# - 在 Azure Functions 中处理通用 404 响应
- git - 带有提交历史的 SVN 到 GIT 迁移(使用 git svn)
- c++ - 为 priority_queue 使用自定义比较器会增加 C++ 时间
- java - 当文件在服务器中不存在时响应文件下载请求
- amazon-web-services - 如何处理事务数据的 Amazon S3 更新
- python - 带有自定义数据的 Huggingface NER