官方文档

http://www.sca.gov.cn/sca/xwdt/2010-12/17/1002389/files/302a3ada057c4a73830536d03e683110.pdf

杂凑算法实现流程

SM3杂凑算法大致分为: 消息填充、分组、迭代压缩这几个部分

消息填充

对消息m进行填充,m长l, 假设消息为"abc"(该示例为官方文档中例子), 将m转为二进制后,填充bit"1"到末尾,之后再添加k个0,其中l+k+1≡448mod512, 这里l+k+1与448对512同模, 是为了填充后边的64bit, 以构造512bit的一组数据,填充好的数据m'的长度是512的整数倍.

文档中的例子

消息分组B(i)

上一步我们填充好m'之后,将其按照512bit进行分组,即m’ = [B(0), B(1), B(2) …B(n-1)]

消息扩展

这里拿到B(i), 将其进行扩展为W0,W1,…,W67,W’0,W’1,…W’63.

扩展步骤

这里P1如下

1
P1(X) = X ⊕ (X ≪ 15) ⊕ (X ≪ 23)

<<< x 表示左移了x个单位

←是赋值符号

压缩函数

压缩过程图

参数

IV中表示ABCDEFGH

!!这里V(i) 是每一大轮也就是每一组才会异或一次上一轮的v, 第一轮直接异或v(0), 按字来异或

取最后的V的值就是生成的杂凑函数

Golang实现代码

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
221
222
223
224
225
package main

import (
"fmt"
"math"
"strconv"
)

func MsgFilling(plainText string) []string { // 消息填充
final_data := make([]string, 0)
plainData := []byte(plainText)
data := make([]string, 0)
for _, v := range plainData {
tempData := strconv.FormatInt(int64(v), 2)
for len(tempData) < 8 {
tempData = "0" + tempData
}
for _, v := range tempData {
data = append(data, string(v))
}
}
lenth := len(data)
lenth2bin := strconv.FormatInt(int64(lenth), 2)
// +1
data = append(data, "1")
k := 0
for ; (lenth+1+k)%512 != 448; k++ {
data = append(data, "0")
}
for len(lenth2bin) < 64 {
lenth2bin = "0" + lenth2bin
}
// 循环插入
for _, v := range lenth2bin {
data = append(data, string(v))
}
// 对data进行4位处理
for i := 0; i*8 < len(data); i++ {
res := ""
for _, v := range data[i*8 : i*8+8] {
res += v
}
num, _ := strconv.ParseInt(res, 2, 64)
final_num := strconv.FormatInt(int64(num), 16)
// 填充16进制
for len(final_num) < 2 {
final_num = "0" + final_num
}
final_data = append(final_data, final_num)
}
return final_data
}

// 消息分组
func OrgMsg(originData []string) [][132]string {
var b = [...][16]string{{}}
var data = [...][132]string{{}}
for i := 0; i*64 < len(originData); i++ {
for j := 0; j*4 < 64; j++ {
b[i][j] = (originData[j*4] + originData[j*4+1] + originData[j*4+2] + originData[j*4+3])
}
}
for l := 0; l < (len(b)); l++ {
data[l] = msgExpand(b[l])
}
return data[:]
}

// 将int的数据恢复到str16位
func reStr(x int64) string {
data := strconv.FormatInt(x, 2)
res := ""
for len(data) < 32 {
data = "0" + data
}
for i := 0; i*4 < len(data); i++ {
tempData := data[i*4:i*4+1] + data[i*4+1:i*4+2] + data[i*4+2:i*4+3] + data[i*4+3:i*4+4]
tem, _ := strconv.ParseInt(tempData, 2, 64)
res += strconv.FormatInt(tem, 16)
}
return res
}

// P0函数
func P0(X int64) (data string) {
data = reStr(X ^ dataShift(reStr(X), 9) ^ dataShift(reStr(X), 17))
return
}

// P1函数
func P1(x int64) int64 {
strX := reStr(x)
return x ^ dataShift(strX, 15) ^ dataShift(strX, 23)
}

// 消息扩展
func msgExpand(b [16]string) [132]string {
w := [132]string{}
for i := 0; i < 16; i++ {
w[i] = b[i]
}
for j := 16; j < 68; j++ {
tempW := ""
tempW = reStr(P1(dataShift(w[j-16], 0)^dataShift(w[j-9], 0)^dataShift(w[j-3], 15)) ^ dataShift(w[j-13], 7) ^ dataShift(w[j-6], 0))
w[j] = tempW
}
for k := 68; k < 132; k++ {
w[k] = reStr(dataShift(w[k-68], 0) ^ dataShift(w[k-64], 0))
}
return w
}

// mod2^32加法运算
func mod32(x int64, y int64) int64 {
return (x + y) % int64(math.Pow(2, 32))
}

// T函数
func T(j int) (data int64) {
if j < 16 {
data = dataShift("79cc4519", j)
} else {
j = j % 32
data = dataShift("7a879d8a", j)
}
return
}

// FF函数
func FF(A string, B string, C string, j int) (data int64) {
X := dataShift(A, 0)
Y := dataShift(B, 0)
Z := dataShift(C, 0)
if j < 16 {
data = X ^ Y ^ Z
} else {
data = (X & Y) | (X & Z) | (Y & Z)
}
return
}

func GG(A string, B string, C string, j int) (data int64) {
X := dataShift(A, 0)
Y := dataShift(B, 0)
Z := dataShift(C, 0)
if j < 16 {
data = X ^ Y ^ Z
} else {
data = (X & Y) | (^X & Z)
}
return
}

// msgZip 数据压缩 64轮
func msgZip(w [132]string, v []string) []string {
data := make([]string, 0)
var A, B, C, D, E, F, G, H = v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]
for i := 0; i < 64; i++ {
SS1 := dataShift(reStr(mod32(mod32(dataShift(A, 12), dataShift(E, 0)), T(i))), 7)
SS2 := SS1 ^ dataShift(A, 12)
TT1 := mod32(mod32(mod32(FF(A, B, C, i), dataShift(D, 0)), SS2), dataShift(w[i+68], 0))
TT2 := mod32(GG(E, F, G, i), mod32(mod32(SS1, dataShift(w[i], 0)), dataShift(H, 0)))
D = C
C = reStr(dataShift(B, 9))
B = A
A = reStr(TT1)
H = G
G = reStr(dataShift(F, 19))
F = E
E = P0(TT2)
}
var dataList = []string{A, B, C, D, E, F, G, H}
// fmt.Println(dataList)
for i := 0; i < len(v); i++ {
data = append(data, reStr(dataShift(v[i], 0)^dataShift(dataList[i], 0)))
}
return data
}

// dataShift 数据移位
func dataShift(data string, l int) int64 {
tempData := ""
for _, v := range data {
num, _ := strconv.ParseInt(string(v), 16, 64)
num4 := strconv.FormatInt(num, 2)
for len(num4) < 4 {
num4 = "0" + num4
}
tempData += num4
}
for len(tempData) < 32 {
tempData = "0" + tempData
}
if l != 0 {
tempData = tempData[l:] + tempData[:l]
}
tempRes := ""
for i := 0; i*4 < len(tempData); i++ {
tData := tempData[i*4:i*4+1] + tempData[i*4+1:i*4+2] + tempData[i*4+2:i*4+3] + tempData[i*4+3:i*4+4]
tem, _ := strconv.ParseInt(tData, 2, 64)
tempRes += strconv.FormatInt(tem, 16)
}
res, _ := strconv.ParseInt(tempRes, 16, 64)
return res
}

func main() {
originData := MsgFilling("abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd")
var originV = []string{"7380166f", "4914b2b9", "172442d7", "da8a0600", "a96f30bc", "163138aa", "e38dee4d", "b0fb0e4e"}
V := make([][]string, 0, 0)
V = append(V, originV)

for l := 0; l*64 < len(originData); l++ {
data := originData[l*64 : (l+1)*64]
w := OrgMsg(data)[0]
V = append(V, msgZip(w, V[l]))
}
res := V[len(V)-1:]
final_data := ""
for _, v := range res[0] {
final_data += v
}
fmt.Println(final_data)
}