首页 > 解决方案 > 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

标签: node.jscryptographygo-ethereum

解决方案


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 使用最后的恢复参数。


推荐阅读