/
cardblock.go
220 lines (184 loc) · 5.11 KB
/
cardblock.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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
package share
import (
"bytes"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"io/ioutil"
"math/rand"
"os"
"strconv"
"time"
)
// 难度系数
const version = "v0.2.0"
// CardBlock 卡区块
type CardBlock struct {
Version string
Hard int32
PubKey string
Timestamp int64
RandNumber int32
PrevCardID string
Height int64
}
// Card is CardBlock helper
type Card struct {
ID int
Attack int
Defense int
CardID string
}
// strconv.Itoa(int(timestamp))
// 时间戳
func timestamp() int64 {
return time.Now().UnixNano()
}
// 随机数
func randNumber() int32 {
return rand.Int31()
}
// 判定是否为卡的函数
func findCard(card string, hard int) string {
// 截取这个卡的最后几位
last := string(card[len(card)-(hard+7):])
// 难度系数就是说,最后几位的开头要有几个0
// 由于这个hash应该是随机分布的,那么0越多自然越难
headZero := ""
for index := 0; index < hard; index++ {
headZero += "0"
}
if last[0:hard] != headZero {
return ""
}
// 满足hard个0后,还要是个数字,否则匹配不到卡的id
i, err := strconv.ParseInt(last, 10, 32)
if err != nil || (i == 0 && last[0:2] != "000") {
return ""
}
return card
}
// HardInt 返回int
func (card *CardBlock) HardInt() int {
return int(card.Hard)
}
// VerifyCardID 验证卡片id,也就是验证区块是不是真的
func (card *CardBlock) VerifyCardID() bool {
if findCard(card.CardID(), card.HardInt()) == "" {
fmt.Fprintf(os.Stderr, "CardID验证失败,你可能是一张假卡")
return false
}
return true
}
// Verify 验证是否为真卡
func (card *CardBlock) Verify() bool {
return card.VerifyCardID()
}
// LoadCard json to CardBlock
func LoadCard(filePath string) CardBlock {
raw, err := ioutil.ReadFile(filePath)
if err != nil {
fmt.Println(err.Error())
os.Exit(1)
}
var card CardBlock
if err := json.Unmarshal(raw, &card); err != nil {
panic(err)
}
return card
}
// CardID 获取区块的ID
func (card *CardBlock) CardID() string {
// 使用用户公钥,时间戳以及随机数作为种子
key := bytes.Join([][]byte{
[]byte(card.Version),
[]byte(card.PubKey),
[]byte(strconv.FormatInt(card.Timestamp, 10)),
[]byte(strconv.FormatInt(int64(card.RandNumber), 10)),
[]byte(strconv.FormatInt(int64(card.Hard), 10)),
[]byte(card.PrevCardID),
[]byte(strconv.FormatInt(card.Height, 10)),
}, []byte{})
// 去生成一个hash值,这里使用sha256这个比较公允的算法
hashCard := sha256.Sum256(key)
return hex.EncodeToString(hashCard[:])
}
// Build 构建一张卡
func (card *CardBlock) Build() string {
card.Version = version
card.Timestamp = timestamp()
card.RandNumber = randNumber()
// 根据规则去判断hash是否是一张卡
return findCard(card.CardID(), card.HardInt())
}
// JSON 区块json
func (card *CardBlock) JSON() string {
json, _ := json.Marshal(card)
return string(json)
}
// Cut 切区块字符串
func (card CardBlock) Cut(from int, to int) string {
CardID := card.CardID()
return string(CardID[len(CardID)+from : len(CardID)+to])
}
// Cid 分析区块的卡片id
func (card CardBlock) Cid() (int, error) {
raw := card.Cut(-7, -4)
p1, error := strconv.Atoi(raw[0:1])
p2, error := strconv.Atoi(raw[1:2])
p3, error := strconv.Atoi(raw[2:3])
return p1 + p2 + p3, error
}
// Card 分析区块包含的卡
func (card CardBlock) Card() (Card, error) {
id, error := card.Cid()
attack, error := strconv.Atoi(card.Cut(-4, -2))
defense, error := strconv.Atoi(card.Cut(-2, 0))
c := Card{
ID: id,
Attack: attack,
Defense: defense,
}
return c, error
}
// 未来的签名验证
// func (card *CardBlock) sign(key *rsa.PrivateKey) string {
// m := card.Version + card.PubKey + card.Timestamp + card.RandNumber +
// card.Hard + card.CardID
// message := []byte(m)
// // Only small messages can be signed directly; thus the hash of a
// // message, rather than the message itself, is signed. This requires
// // that the hash function be collision resistant. SHA-256 is the
// // least-strong hash function that should be used for this at the time
// // of writing (2016).
// hashed := sha256.Sum256(message)
// signature, err := rsa.SignPKCS1v15(crand.Reader, key, crypto.SHA256, hashed[:])
// if err != nil {
// fmt.Fprintf(os.Stderr, "Error from signing: %s\n", err)
// }
// s := hex.EncodeToString(signature)
// // try to VerifyPKCS1v15
// ss, err := hex.DecodeString(s)
// err = rsa.VerifyPKCS1v15(&key.PublicKey, crypto.SHA256, hashed[:], ss)
// if err != nil {
// fmt.Fprintf(os.Stderr, "Error from verification: %s\n", err)
// }
// return s
// }
// 验证签名
// func (card *CardBlock) verifySign() bool {
// m := card.Version + card.PubKey + card.Timestamp + card.RandNumber +
// card.Hard + card.CardID
// message := []byte(m)
// hashed := sha256.Sum256(message)
// // try to VerifyPKCS1v15
// ss, err := hex.DecodeString(card.Signature)
// key, err := loadPublicKeyFromString(card.PubKey)
// err = rsa.VerifyPKCS1v15(key, crypto.SHA256, hashed[:], ss)
// if err != nil {
// fmt.Fprintf(os.Stderr, "Error from verification: %s\n", err)
// return false
// }
// return true
// }