sign.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. package utils
  2. import (
  3. "crypto/ecdsa"
  4. "fmt"
  5. "github.com/demdxx/gocast"
  6. "github.com/ethereum/go-ethereum/common"
  7. "github.com/ethereum/go-ethereum/common/hexutil"
  8. "github.com/ethereum/go-ethereum/crypto"
  9. "strings"
  10. "time"
  11. )
  12. const (
  13. sysPrefix = "AICGOLD"
  14. pri = "f05ffe77f132b34608e5bbbe5a16527738e3b22dbd50a48c1988529bc7c71b36"
  15. addr = "0x484557aC895B3eEa2cE5B970d4E696DB11D44949"
  16. )
  17. func SystemAddress() string {
  18. return ethPriKey2HexAddress(pri)
  19. }
  20. func BuildSignMessage() (string, error) {
  21. msg := fmt.Sprintf("%s%d", sysPrefix, time.Now().Unix())
  22. sign, err := SignMessage(msg)
  23. if err != nil {
  24. return "", err
  25. }
  26. return fmt.Sprintf("%s%s", msg, sign), nil
  27. }
  28. func priHexKeyToECDSA(hexPriKey string) (*ecdsa.PrivateKey, error) {
  29. return crypto.HexToECDSA(strings.TrimPrefix(hexPriKey, "0x"))
  30. }
  31. func ethPriKey2HexAddress(priKeyHash string) string {
  32. priKey, err := priHexKeyToECDSA(priKeyHash)
  33. if err != nil {
  34. panic(err)
  35. }
  36. pubKey := priKey.Public().(*ecdsa.PublicKey)
  37. addr := crypto.PubkeyToAddress(*pubKey)
  38. return addr.Hex()
  39. }
  40. func EthAddressCheck(addr string) bool {
  41. return common.IsHexAddress(addr)
  42. }
  43. func SignMessage(message string) (string, error) {
  44. priKey, err := priHexKeyToECDSA(pri)
  45. if err != nil {
  46. return "", err
  47. }
  48. return signMessage(message, priKey)
  49. }
  50. // signMessage 使用私钥签名消息
  51. func signMessage(message string, privateKey *ecdsa.PrivateKey) (string, error) {
  52. // 计算消息的Keccak256哈希
  53. hash := crypto.Keccak256Hash([]byte(message))
  54. // 签名
  55. signature, err := crypto.Sign(hash.Bytes(), privateKey)
  56. if err != nil {
  57. return "", err
  58. }
  59. // 添加恢复ID(以太坊要求)
  60. signature[64] += 27
  61. return hexutil.Encode(signature), nil
  62. }
  63. // 消息格式
  64. // 1 去除消息头部信息
  65. // 2 获取前10位数字
  66. // 3 对比时间 不得相差3秒
  67. func checkMessage(message string) (string, string, bool) {
  68. if !strings.HasPrefix(message, sysPrefix) {
  69. return "", "", false
  70. }
  71. removePrefix := strings.TrimPrefix(message, sysPrefix)
  72. timestamp := removePrefix[:10]
  73. notUnixTime := time.Now().Unix()
  74. if notUnixTime > gocast.ToInt64(timestamp)+3 || gocast.ToInt64(timestamp) > notUnixTime {
  75. return "", "", false
  76. }
  77. signature := removePrefix[10:]
  78. return sysPrefix + removePrefix[:10], signature, true
  79. }
  80. func VerifySignature(message string) error {
  81. msg, signature, ok := checkMessage(message)
  82. if !ok {
  83. return fmt.Errorf("非法签名")
  84. }
  85. return verifySignature(msg, signature, common.HexToAddress(addr))
  86. }
  87. // verifySignature 验证签名
  88. func verifySignature(message, signature string, address common.Address) error {
  89. // 解码签名
  90. sig, err := hexutil.Decode(signature)
  91. if err != nil {
  92. return err
  93. }
  94. // 恢复ID必须为27或28
  95. if sig[64] != 27 && sig[64] != 28 {
  96. return fmt.Errorf("无效的恢复ID")
  97. }
  98. // 调整恢复ID为0或1(以太坊库要求)
  99. sig[64] -= 27
  100. // 计算消息哈希
  101. hash := crypto.Keccak256Hash([]byte(message))
  102. // 从签名恢复公钥
  103. publicKey, err := crypto.SigToPub(hash.Bytes(), sig)
  104. if err != nil {
  105. return err
  106. }
  107. // 从公钥生成地址
  108. recoveredAddr := crypto.PubkeyToAddress(*publicKey)
  109. // 验证地址是否匹配
  110. if recoveredAddr != address {
  111. return fmt.Errorf("签名验证失败: 地址不匹配")
  112. }
  113. return nil
  114. }