OSDN Git Service

Add BlockWitness (#54)
[bytom/vapor.git] / crypto / sm3 / sm3.go
1 package sm3
2
3 import (
4         "encoding/binary"
5         "hash"
6 )
7
8 type SM3 struct {
9         digest      [8]uint32 // digest represents the partial evaluation of V
10         length      uint64    // length of the message
11         unhandleMsg []byte    // uint8  //
12 }
13
14 func (sm3 *SM3) ff0(x, y, z uint32) uint32 { return x ^ y ^ z }
15
16 func (sm3 *SM3) ff1(x, y, z uint32) uint32 { return (x & y) | (x & z) | (y & z) }
17
18 func (sm3 *SM3) gg0(x, y, z uint32) uint32 { return x ^ y ^ z }
19
20 func (sm3 *SM3) gg1(x, y, z uint32) uint32 { return (x & y) | (^x & z) }
21
22 func (sm3 *SM3) p0(x uint32) uint32 { return x ^ sm3.leftRotate(x, 9) ^ sm3.leftRotate(x, 17) }
23
24 func (sm3 *SM3) p1(x uint32) uint32 { return x ^ sm3.leftRotate(x, 15) ^ sm3.leftRotate(x, 23) }
25
26 func (sm3 *SM3) leftRotate(x uint32, i uint32) uint32 { return (x<<(i%32) | x>>(32-i%32)) }
27
28 func (sm3 *SM3) pad() []byte {
29         msg := sm3.unhandleMsg
30         msg = append(msg, 0x80) // Append '1'
31         blockSize := 64         // Append until the resulting message length (in bits) is congruent to 448 (mod 512)
32         for len(msg)%blockSize != 56 {
33                 msg = append(msg, 0x00)
34         }
35         // append message length
36         // not using loops so that compiler might benefit from it
37         msg = append(msg, uint8(sm3.length>>56&0xff))
38         msg = append(msg, uint8(sm3.length>>48&0xff))
39         msg = append(msg, uint8(sm3.length>>40&0xff))
40         msg = append(msg, uint8(sm3.length>>32&0xff))
41         msg = append(msg, uint8(sm3.length>>24&0xff))
42         msg = append(msg, uint8(sm3.length>>16&0xff))
43         msg = append(msg, uint8(sm3.length>>8&0xff))
44         msg = append(msg, uint8(sm3.length>>0&0xff))
45
46         if len(msg)%64 != 0 {
47                 panic("------SM3 Pad: error msgLen =")
48         }
49         return msg
50 }
51
52 func (sm3 *SM3) update(msg []byte, nblocks int) {
53         var w [68]uint32
54         var w1 [64]uint32
55
56         a, b, c, d, e, f, g, h := sm3.digest[0], sm3.digest[1], sm3.digest[2], sm3.digest[3], sm3.digest[4], sm3.digest[5], sm3.digest[6], sm3.digest[7]
57         for len(msg) >= 64 {
58                 for i := 0; i < 16; i++ {
59                         w[i] = binary.BigEndian.Uint32(msg[4*i : 4*(i+1)])
60                 }
61                 for i := 16; i < 68; i++ {
62                         w[i] = sm3.p1(w[i-16]^w[i-9]^sm3.leftRotate(w[i-3], 15)) ^ sm3.leftRotate(w[i-13], 7) ^ w[i-6]
63                 }
64                 for i := 0; i < 64; i++ {
65                         w1[i] = w[i] ^ w[i+4]
66                 }
67                 A, B, C, D, E, F, G, H := a, b, c, d, e, f, g, h
68                 for i := 0; i < 16; i++ {
69                         SS1 := sm3.leftRotate(sm3.leftRotate(A, 12)+E+sm3.leftRotate(0x79cc4519, uint32(i)), 7)
70                         SS2 := SS1 ^ sm3.leftRotate(A, 12)
71                         TT1 := sm3.ff0(A, B, C) + D + SS2 + w1[i]
72                         TT2 := sm3.gg0(E, F, G) + H + SS1 + w[i]
73                         D = C
74                         C = sm3.leftRotate(B, 9)
75                         B = A
76                         A = TT1
77                         H = G
78                         G = sm3.leftRotate(F, 19)
79                         F = E
80                         E = sm3.p0(TT2)
81                 }
82                 for i := 16; i < 64; i++ {
83                         SS1 := sm3.leftRotate(sm3.leftRotate(A, 12)+E+sm3.leftRotate(0x7a879d8a, uint32(i)), 7)
84                         SS2 := SS1 ^ sm3.leftRotate(A, 12)
85                         TT1 := sm3.ff1(A, B, C) + D + SS2 + w1[i]
86                         TT2 := sm3.gg1(E, F, G) + H + SS1 + w[i]
87                         D = C
88                         C = sm3.leftRotate(B, 9)
89                         B = A
90                         A = TT1
91                         H = G
92                         G = sm3.leftRotate(F, 19)
93                         F = E
94                         E = sm3.p0(TT2)
95                 }
96                 a ^= A
97                 b ^= B
98                 c ^= C
99                 d ^= D
100                 e ^= E
101                 f ^= F
102                 g ^= G
103                 h ^= H
104                 msg = msg[64:]
105         }
106         sm3.digest[0], sm3.digest[1], sm3.digest[2], sm3.digest[3], sm3.digest[4], sm3.digest[5], sm3.digest[6], sm3.digest[7] = a, b, c, d, e, f, g, h
107 }
108
109 func New() hash.Hash {
110         var sm3 SM3
111
112         sm3.Reset()
113         return &sm3
114 }
115
116 // BlockSize, required by the hash.Hash interface.
117 // BlockSize returns the hash's underlying block size.
118 // The Write method must be able to accept any amount
119 // of data, but it may operate more efficiently if all writes
120 // are a multiple of the block size.
121 func (sm3 *SM3) BlockSize() int { return 64 }
122
123 // Size, required by the hash.Hash interface.
124 // Size returns the number of bytes Sum will return.
125 func (sm3 *SM3) Size() int { return 32 }
126
127 // Reset clears the internal state by zeroing bytes in the state buffer.
128 // This can be skipped for a newly-created hash state; the default zero-allocated state is correct.
129 func (sm3 *SM3) Reset() {
130         // Reset digest
131         sm3.digest[0] = 0x7380166f
132         sm3.digest[1] = 0x4914b2b9
133         sm3.digest[2] = 0x172442d7
134         sm3.digest[3] = 0xda8a0600
135         sm3.digest[4] = 0xa96f30bc
136         sm3.digest[5] = 0x163138aa
137         sm3.digest[6] = 0xe38dee4d
138         sm3.digest[7] = 0xb0fb0e4e
139
140         sm3.length = 0 // Reset numberic states
141         sm3.unhandleMsg = []byte{}
142 }
143
144 // Write, required by the hash.Hash interface.
145 // Write (via the embedded io.Writer interface) adds more data to the running hash.
146 // It never returns an error.
147 func (sm3 *SM3) Write(p []byte) (int, error) {
148         toWrite := len(p)
149         sm3.length += uint64(len(p) * 8)
150
151         msg := append(sm3.unhandleMsg, p...)
152         nblocks := len(msg) / sm3.BlockSize()
153         sm3.update(msg, nblocks)
154
155         // Update unhandleMsg
156         sm3.unhandleMsg = msg[nblocks*sm3.BlockSize():]
157
158         return toWrite, nil
159 }
160
161 // Sum, required by the hash.Hash interface.
162 // Sum appends the current hash to b and returns the resulting slice.
163 // It does not change the underlying hash state.
164 func (sm3 *SM3) Sum(in []byte) []byte {
165         sm3.Write(in)
166         msg := sm3.pad()
167
168         // Finialize
169         sm3.update(msg, len(msg)/sm3.BlockSize())
170
171         // save hash to in
172         needed := sm3.Size()
173         if cap(in)-len(in) < needed {
174                 newIn := make([]byte, len(in), len(in)+needed)
175                 copy(newIn, in)
176                 in = newIn
177         }
178         out := in[len(in) : len(in)+needed]
179
180         for i := 0; i < 8; i++ {
181                 binary.BigEndian.PutUint32(out[i*4:], sm3.digest[i])
182         }
183         return out
184
185 }
186
187 func Sm3Sum(data []byte) []byte {
188         var sm3 SM3
189
190         sm3.Reset()
191         sm3.Write(data)
192         return sm3.Sum(nil)
193 }