package main
import (
"encoding/hex"
"fmt"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto"
"log"
"strings"
"testing"
)
const (
signFormat = "\x19Ethereum Signed Message:\n%d%s"
)
func TestVerifty(t *testing.T) {
ETHPrv := "87f9bc3c6cd57f18a0143b6863d6b47d6364f1a1ba86eae0ce411097704d5d0d"
ETHAdd := "0x296Fd341F90508B6742701F4341D2027CdF5c86d"
//unsigned data
data := "0x1234"
prvKey, _ := hex.DecodeString(ETHPrv)
sig, _ := SignWithEthWeb3(data, prvKey)
log.Println("sig:", sig)
unsignDataHashByte := crypto.Keccak256Hash(common.FromHex(data)).Bytes()
// verify signature at server backend
log.Println("verify sign:", verifySig(strings.ToLower(ETHAdd), sig, unsignDataHashByte))
}
func SignWithEthWeb3(unsignData string, privateByte []byte) (signature string, err error) {
// need to Hash first
unsignDataHashByte := crypto.Keccak256Hash(common.FromHex(unsignData)).Bytes()
return SignWithEth(unsignDataHashByte, privateByte)
}
func SignWithEth(unsignData, privateKeyByte []byte) (signature string, err error) {
// web3 signature need hash with salt, then sign the hashed data
newUnsignData := fmt.Sprintf(signFormat, len(unsignData), unsignData)
unsignDataHash := crypto.Keccak256([]byte(newUnsignData))
key, err := crypto.ToECDSA(privateKeyByte)
if err != nil {
log.Println("sign ToECDSA err:", err.Error())
return "", err
}
signatureByte, err := crypto.Sign(unsignDataHash, key)
if err != nil {
log.Println("sign Sign err:", err.Error())
return "", err
}
signatureByte[64] += 27
return hexutil.Encode(signatureByte), nil
}
// verify signature
func verifySig(from, sigHex string, msg []byte) bool {
fromAddr := common.HexToAddress(from)
sig := hexutil.MustDecode(sigHex)
if sig[64] != 1 && sig[64] != 0 && sig[64] != 27 && sig[64] != 28 {
log.Println("in hexutil.MustDecode error.")
return false
}
if sig[64] != 1 && sig[64] != 0 {
sig[64] -= 27
}
pubKey, err := crypto.SigToPub(createSignHash(msg), sig)
if err != nil {
log.Println("in crypto.SigToPub error:", err.Error())
return false
}
recoveredAddr := crypto.PubkeyToAddress(*pubKey)
log.Println("recoveredAddr:", recoveredAddr.String())
return fromAddr == recoveredAddr
}
// generate hashed data for signing
func createSignHash(data []byte) []byte {
msg := fmt.Sprintf(signFormat, len(data), data)
return crypto.Keccak256([]byte(msg))
}