| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136 |
- package utils
- import (
- "crypto/ecdsa"
- "fmt"
- "github.com/demdxx/gocast"
- "github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/common/hexutil"
- "github.com/ethereum/go-ethereum/crypto"
- "strings"
- "time"
- )
- const (
- sysPrefix = "AICGOLD"
- pri = "f05ffe77f132b34608e5bbbe5a16527738e3b22dbd50a48c1988529bc7c71b36"
- addr = "0x484557aC895B3eEa2cE5B970d4E696DB11D44949"
- )
- func SystemAddress() string {
- return ethPriKey2HexAddress(pri)
- }
- func BuildSignMessage() (string, error) {
- msg := fmt.Sprintf("%s%d", sysPrefix, time.Now().Unix())
- sign, err := SignMessage(msg)
- if err != nil {
- return "", err
- }
- return fmt.Sprintf("%s%s", msg, sign), nil
- }
- func priHexKeyToECDSA(hexPriKey string) (*ecdsa.PrivateKey, error) {
- return crypto.HexToECDSA(strings.TrimPrefix(hexPriKey, "0x"))
- }
- func ethPriKey2HexAddress(priKeyHash string) string {
- priKey, err := priHexKeyToECDSA(priKeyHash)
- if err != nil {
- panic(err)
- }
- pubKey := priKey.Public().(*ecdsa.PublicKey)
- addr := crypto.PubkeyToAddress(*pubKey)
- return addr.Hex()
- }
- func EthAddressCheck(addr string) bool {
- return common.IsHexAddress(addr)
- }
- func SignMessage(message string) (string, error) {
- priKey, err := priHexKeyToECDSA(pri)
- if err != nil {
- return "", err
- }
- return signMessage(message, priKey)
- }
- // signMessage 使用私钥签名消息
- func signMessage(message string, privateKey *ecdsa.PrivateKey) (string, error) {
- // 计算消息的Keccak256哈希
- hash := crypto.Keccak256Hash([]byte(message))
- // 签名
- signature, err := crypto.Sign(hash.Bytes(), privateKey)
- if err != nil {
- return "", err
- }
- // 添加恢复ID(以太坊要求)
- signature[64] += 27
- return hexutil.Encode(signature), nil
- }
- // 消息格式
- // 1 去除消息头部信息
- // 2 获取前10位数字
- // 3 对比时间 不得相差3秒
- func checkMessage(message string) (string, string, bool) {
- if !strings.HasPrefix(message, sysPrefix) {
- return "", "", false
- }
- removePrefix := strings.TrimPrefix(message, sysPrefix)
- timestamp := removePrefix[:10]
- notUnixTime := time.Now().Unix()
- if notUnixTime > gocast.ToInt64(timestamp)+3 || gocast.ToInt64(timestamp) > notUnixTime {
- return "", "", false
- }
- signature := removePrefix[10:]
- return sysPrefix + removePrefix[:10], signature, true
- }
- func VerifySignature(message string) error {
- msg, signature, ok := checkMessage(message)
- if !ok {
- return fmt.Errorf("非法签名")
- }
- return verifySignature(msg, signature, common.HexToAddress(addr))
- }
- // verifySignature 验证签名
- func verifySignature(message, signature string, address common.Address) error {
- // 解码签名
- sig, err := hexutil.Decode(signature)
- if err != nil {
- return err
- }
- // 恢复ID必须为27或28
- if sig[64] != 27 && sig[64] != 28 {
- return fmt.Errorf("无效的恢复ID")
- }
- // 调整恢复ID为0或1(以太坊库要求)
- sig[64] -= 27
- // 计算消息哈希
- hash := crypto.Keccak256Hash([]byte(message))
- // 从签名恢复公钥
- publicKey, err := crypto.SigToPub(hash.Bytes(), sig)
- if err != nil {
- return err
- }
- // 从公钥生成地址
- recoveredAddr := crypto.PubkeyToAddress(*publicKey)
- // 验证地址是否匹配
- if recoveredAddr != address {
- return fmt.Errorf("签名验证失败: 地址不匹配")
- }
- return nil
- }
|