我試圖personal_sign在 Golang 中生成一個像它在 ethers.js 中實作的一樣。類似的問題,但最終使用常規sign而不是個人sign_implementation.
醚類
// keccak256 hash of the data
let dataHash = ethers.utils.keccak256(
ethers.utils.toUtf8Bytes(JSON.stringify(dataToSign))
);
//0x8d218fc37d2fd952b2d115046b786b787e44d105cccf156882a2e74ad993ee13
let signature = await wallet.signMessage(dataHash); // 0x469b07327fc41a2d85b7e69bcf4a9184098835c47cc7575375e3a306c3718ae35702af84f3a62aafeb8aab6a455d761274263d79e7fc99fbedfeaf759d8dc9361c
高朗:
func signHash(data []byte) common.Hash {
msg := fmt.Sprintf("\x19Ethereum Signed Message:\n%d%s", len(data), data)
return crypto.Keccak256Hash([]byte(msg))
}
privateKey, err := crypto.HexToECDSA(hexPrivateKey)
if err != nil {
log.Fatal(err)
}
dataHash := crypto.Keccak256Hash(dataToSign) //0x8d218fc37d2fd952b2d115046b786b787e44d105cccf156882a2e74ad993ee13
signHash := signHash(dataHash.Bytes())
signatureBytes, err := crypto.Sign(signHash.Bytes(), privateKey)
if err != nil {
log.Fatal(err)
}
// signatureBytes 0xec56178d3dca77c3cee7aed83cdca2ffa2bec8ef1685ce5103cfa72c27beb61313d91b9ad9b9a644b0edf6352cb69f2f8acd25297e3c64cd060646242e0455ea00
如您所見,哈希值相同,但簽名不同:
0x469b07327fc41a2d85b7e69bcf4a9184098835c47cc7575375e3a306c3718ae35702af84f3a62aafeb8aab6a455d761274263d79e7fc99fbedfeaf759d8dc9361c 醚類
0xec56178d3dca77c3cee7aed83cdca2ffa2bec8ef1685ce5103cfa72c27beb61313d91b9ad9b9a644b0edf6352cb69f2f8acd25297e3c64cd060646242e0455ea00 高朗
查看 Ethers.js 的源代碼,除了填充的管理方式之外,我找不到任何不同的東西。
編輯 檢查批準的答案
signHash(data []byte) common.Hash {
hexData := hexutil.Encode(data)
msg := fmt.Sprintf("\x19Ethereum Signed Message:\n%d%s", len(hexData), hexData)
return crypto.Keccak256Hash([]byte(msg))
}
uj5u.com熱心網友回復:
JavaScript 代碼中存在錯誤。
從signer.signMessage()(請參閱注釋部分)的檔案中,似乎字串是 UTF8 編碼的,并且二進制資料必須作為TypedArrayor傳遞Array。
Keccak 哈希回傳十六進制編碼,即作為字串,因此是 UTF8 編碼,這是不正確的。相反,它必須轉換為TypedArray. 為此,庫提供了功能ethers.utils.arrayify()。
以下 JavaScript 基于發布的代碼,但執行所需的十六進制解碼:
(async () => {
let privateKey = "0x8da4ef21b864d2cc526dbdb2a120bd2874c36c9d0a1fb7f8c63d7f7a8b41de8f";
let dataToSign = {"data1":"value1","data2":"value2"};
let dataHash = ethers.utils.keccak256(
ethers.utils.toUtf8Bytes(JSON.stringify(dataToSign))
);
dataHashBin = ethers.utils.arrayify(dataHash)
let wallet = new ethers.Wallet(privateKey);
let signature = await wallet.signMessage(dataHashBin);
document.getElementById("signature").innerHTML = signature; // 0xfcc3e9431c139b5f943591af78c280b939595ce9df66210b7b8bb69565bdd2af7081a8acc0cbb5ea55bd0d673b176797966a5180c11ac297b7e6344c5822e66d1c
})();
<script src="https://cdn.ethers.io/lib/ethers-5.0.umd.min.js" type="text/javascript"></script>
<p style="font-family:'Courier New', monospace;" id="signature"></p>
產生以下簽名:
0xfcc3e9431c139b5f943591af78c280b939595ce9df66210b7b8bb69565bdd2af7081a8acc0cbb5ea55bd0d673b176797966a5180c11ac297b7e6344c5822e66d1c
下面的 Go 代碼基于未修改發布的 Go 代碼,但使用來自 JavaScript 代碼的鍵和資料進行比較:
package main
import (
"fmt"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"encoding/hex"
"encoding/json"
"log"
)
func signHash(data []byte) common.Hash {
msg := fmt.Sprintf("\x19Ethereum Signed Message:\n%d%s", len(data), data)
return crypto.Keccak256Hash([]byte(msg))
}
func main() {
hexPrivateKey := "8da4ef21b864d2cc526dbdb2a120bd2874c36c9d0a1fb7f8c63d7f7a8b41de8f"
dataMap := map[string]string{"data1":"value1","data2":"value2"}
dataToSign, _ := json.Marshal(dataMap)
privateKey, err := crypto.HexToECDSA(hexPrivateKey)
if err != nil {
log.Fatal(err)
}
dataHash := crypto.Keccak256Hash(dataToSign) //0x8d218fc37d2fd952b2d115046b786b787e44d105cccf156882a2e74ad993ee13
signHash := signHash(dataHash.Bytes())
signatureBytes, err := crypto.Sign(signHash.Bytes(), privateKey)
if err != nil {
log.Fatal(err)
}
fmt.Println("0x" hex.EncodeToString(signatureBytes))
}
Go 代碼給出了以下簽名:
0xfcc3e9431c139b5f943591af78c280b939595ce9df66210b7b8bb69565bdd2af7081a8acc0cbb5ea55bd0d673b176797966a5180c11ac297b7e6344c5822e66d01
除了最后一個位元組外,兩個簽名都匹配。
JavaScript 代碼以格式回傳簽名r|s|v(請參閱此處)。v大小為 1 個位元組,只是兩個簽名不同的值。
這是恢復 IDv = 27 rid所在的位置rid。恢復 ID 的值介于 0 和 3 之間,因此v值介于 27 和 30 或 0x1b 和 0x1e 之間(請參閱此處)。
另一方面,Go 代碼在最后一個位元組而不是v. 為了使 Go 代碼的簽名也與最后一個位元組中的 JavaScript 代碼的簽名相匹配,恢復 ID 必須替換為v:
signatureBytes[64] = 27
fmt.Println("0x" hex.EncodeToString(signatureBytes))
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/343552.html
上一篇:Go中的介面實作實施
下一篇:為什么我在Go中遇到分段違規錯誤
