在 Ethereum 專案使用 Go 對簽章進行驗證

前端

使用 Ethers.js 套件

新增 main.js 檔。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { ethers } from 'ethers';

const message = 'hello';
const hexMessage = ethers.utils.hexlify(ethers.utils.toUtf8Bytes(message));
const web3Provider = new ethers.providers.Web3Provider(window.ethereum, 'any');
const [account] = await web3Provider.send('eth_requestAccounts');
const sig = await web3Provider.getSigner().signMessage(message);
const recovered = ethers.utils.verifyMessage(message, sig);

console.log('message', message);
console.log('hexMessage', hexMessage);
console.log('account', account);
console.log('sig', sig);
console.log('recovered', recovered);

使用 Web3.js 套件

新增 main.js 檔。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import Web3 from 'web3';

const web3 = new Web3(window.ethereum);
const [account] = await web3.eth.getAccounts();
const message = 'hello';
const hexMessage = web3.utils.utf8ToHex(message);
const sig = await web3.eth.personal.sign(hexMessage, account, '');
const recovered = await web3.eth.personal.ecRecover('hello', sig);

console.log('message', message);
console.log('hexMessage', hexMessage);
console.log('account', account);
console.log('sig', sig);
console.log('recovered', recovered);

後端

新增 main.go 檔。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package main

import (
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto"
"log"
"strings"
)

func main() {
hexStr := "0x68656c6c6f" // hello
sig := "0x7c4f5f867466a9244d9c5e59d7b0f0a57b56209789f13997cff86485875eb6bc2e7e802ed7c05c6dc6f5bf27735e43a0240d3404571fbbb222c769f56488e77f1c"
data, err := hexutil.Decode(hexStr)
if err != nil {
log.Fatal(err)
}
recovered := recoverPubKey(data, sig)
log.Println(recovered) // 0x521ec61eb00a45fa2a17e92762dd1d43de9ffe26
}

func recoverPubKey(data []byte, sig string) string {
hash := accounts.TextHash(data)
s, err := hexutil.Decode(sig)
if err != nil {
return ""
}
if s[crypto.RecoveryIDOffset] == 27 || s[crypto.RecoveryIDOffset] == 28 {
s[crypto.RecoveryIDOffset] -= 27
}
recovered, err := crypto.SigToPub(hash, s)
if err != nil {
return ""
}
addr := crypto.PubkeyToAddress(*recovered)
return strings.ToLower(addr.Hex())
}

執行程式。

1
go run main.go

參考資料