github.com/MangoDowner/go-gm@v0.0.0-20180818020936-8baa2bd4408c/src/crypto/sm3/sm3.go (about) 1 /* 2 Copyright Suzhou Tongji Fintech Research Institute 2017 All Rights Reserved. 3 Licensed under the Apache License, Version 2.0 (the "License"); 4 you may not use this file except in compliance with the License. 5 You may obtain a copy of the License at 6 7 http://www.apache.org/licenses/LICENSE-2.0 8 9 Unless required by applicable law or agreed to in writing, software 10 distributed under the License is distributed on an "AS IS" BASIS, 11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 See the License for the specific language governing permissions and 13 limitations under the License. 14 */ 15 16 package sm3 17 18 import ( 19 "encoding/binary" 20 "hash" 21 ) 22 23 type SM3 struct { 24 digest [8]uint32 // digest represents the partial evaluation of V 25 length uint64 // length of the message 26 unhandleMsg []byte // uint8 // 27 } 28 29 func (sm3 *SM3) ff0(x, y, z uint32) uint32 { return x ^ y ^ z } 30 31 func (sm3 *SM3) ff1(x, y, z uint32) uint32 { return (x & y) | (x & z) | (y & z) } 32 33 func (sm3 *SM3) gg0(x, y, z uint32) uint32 { return x ^ y ^ z } 34 35 func (sm3 *SM3) gg1(x, y, z uint32) uint32 { return (x & y) | (^x & z) } 36 37 func (sm3 *SM3) p0(x uint32) uint32 { return x ^ sm3.leftRotate(x, 9) ^ sm3.leftRotate(x, 17) } 38 39 func (sm3 *SM3) p1(x uint32) uint32 { return x ^ sm3.leftRotate(x, 15) ^ sm3.leftRotate(x, 23) } 40 41 func (sm3 *SM3) leftRotate(x uint32, i uint32) uint32 { return (x<<(i%32) | x>>(32-i%32)) } 42 43 func (sm3 *SM3) pad() []byte { 44 msg := sm3.unhandleMsg 45 msg = append(msg, 0x80) // Append '1' 46 blockSize := 64 // Append until the resulting message length (in bits) is congruent to 448 (mod 512) 47 for len(msg)%blockSize != 56 { 48 msg = append(msg, 0x00) 49 } 50 // append message length 51 msg = append(msg, uint8(sm3.length>>56&0xff)) 52 msg = append(msg, uint8(sm3.length>>48&0xff)) 53 msg = append(msg, uint8(sm3.length>>40&0xff)) 54 msg = append(msg, uint8(sm3.length>>32&0xff)) 55 msg = append(msg, uint8(sm3.length>>24&0xff)) 56 msg = append(msg, uint8(sm3.length>>16&0xff)) 57 msg = append(msg, uint8(sm3.length>>8&0xff)) 58 msg = append(msg, uint8(sm3.length>>0&0xff)) 59 60 if len(msg)%64 != 0 { 61 panic("------SM3 Pad: error msgLen =") 62 } 63 return msg 64 } 65 66 func (sm3 *SM3) update(msg []byte, nblocks int) { 67 var w [68]uint32 68 var w1 [64]uint32 69 70 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] 71 for len(msg) >= 64 { 72 for i := 0; i < 16; i++ { 73 w[i] = binary.BigEndian.Uint32(msg[4*i : 4*(i+1)]) 74 } 75 for i := 16; i < 68; i++ { 76 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] 77 } 78 for i := 0; i < 64; i++ { 79 w1[i] = w[i] ^ w[i+4] 80 } 81 A, B, C, D, E, F, G, H := a, b, c, d, e, f, g, h 82 for i := 0; i < 16; i++ { 83 SS1 := sm3.leftRotate(sm3.leftRotate(A, 12)+E+sm3.leftRotate(0x79cc4519, uint32(i)), 7) 84 SS2 := SS1 ^ sm3.leftRotate(A, 12) 85 TT1 := sm3.ff0(A, B, C) + D + SS2 + w1[i] 86 TT2 := sm3.gg0(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 for i := 16; i < 64; i++ { 97 SS1 := sm3.leftRotate(sm3.leftRotate(A, 12)+E+sm3.leftRotate(0x7a879d8a, uint32(i)), 7) 98 SS2 := SS1 ^ sm3.leftRotate(A, 12) 99 TT1 := sm3.ff1(A, B, C) + D + SS2 + w1[i] 100 TT2 := sm3.gg1(E, F, G) + H + SS1 + w[i] 101 D = C 102 C = sm3.leftRotate(B, 9) 103 B = A 104 A = TT1 105 H = G 106 G = sm3.leftRotate(F, 19) 107 F = E 108 E = sm3.p0(TT2) 109 } 110 a ^= A 111 b ^= B 112 c ^= C 113 d ^= D 114 e ^= E 115 f ^= F 116 g ^= G 117 h ^= H 118 msg = msg[64:] 119 } 120 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 121 } 122 123 func New() hash.Hash { 124 var sm3 SM3 125 126 sm3.Reset() 127 return &sm3 128 } 129 130 // BlockSize, required by the hash.Hash interface. 131 // BlockSize returns the hash's underlying block size. 132 // The Write method must be able to accept any amount 133 // of data, but it may operate more efficiently if all writes 134 // are a multiple of the block size. 135 func (sm3 *SM3) BlockSize() int { return 64 } 136 137 // Size, required by the hash.Hash interface. 138 // Size returns the number of bytes Sum will return. 139 func (sm3 *SM3) Size() int { return 32 } 140 141 // Reset clears the internal state by zeroing bytes in the state buffer. 142 // This can be skipped for a newly-created hash state; the default zero-allocated state is correct. 143 func (sm3 *SM3) Reset() { 144 // Reset digest 145 sm3.digest[0] = 0x7380166f 146 sm3.digest[1] = 0x4914b2b9 147 sm3.digest[2] = 0x172442d7 148 sm3.digest[3] = 0xda8a0600 149 sm3.digest[4] = 0xa96f30bc 150 sm3.digest[5] = 0x163138aa 151 sm3.digest[6] = 0xe38dee4d 152 sm3.digest[7] = 0xb0fb0e4e 153 154 sm3.length = 0 // Reset numberic states 155 sm3.unhandleMsg = []byte{} 156 } 157 158 // Write, required by the hash.Hash interface. 159 // Write (via the embedded io.Writer interface) adds more data to the running hash. 160 // It never returns an error. 161 func (sm3 *SM3) Write(p []byte) (int, error) { 162 toWrite := len(p) 163 sm3.length += uint64(len(p) * 8) 164 165 msg := append(sm3.unhandleMsg, p...) 166 nblocks := len(msg) / sm3.BlockSize() 167 sm3.update(msg, nblocks) 168 169 // Update unhandleMsg 170 sm3.unhandleMsg = msg[nblocks*sm3.BlockSize():] 171 172 return toWrite, nil 173 } 174 175 // Sum, required by the hash.Hash interface. 176 // Sum appends the current hash to b and returns the resulting slice. 177 // It does not change the underlying hash state. 178 func (sm3 *SM3) Sum(in []byte) []byte { 179 sm3.Write(in) 180 msg := sm3.pad() 181 182 // Finialize 183 sm3.update(msg, len(msg)/sm3.BlockSize()) 184 185 // save hash to in 186 needed := sm3.Size() 187 if cap(in)-len(in) < needed { 188 newIn := make([]byte, len(in), len(in)+needed) 189 copy(newIn, in) 190 in = newIn 191 } 192 out := in[len(in) : len(in)+needed] 193 194 for i := 0; i < 8; i++ { 195 binary.BigEndian.PutUint32(out[i*4:], sm3.digest[i]) 196 } 197 return out 198 199 } 200 201 func Sm3Sum(data []byte) []byte { 202 var sm3 SM3 203 204 sm3.Reset() 205 sm3.Write(data) 206 return sm3.Sum(nil) 207 }