sha3_s390x.go (6988B)
1 // Copyright 2017 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 //go:build gc && !purego 6 // +build gc,!purego 7 8 package sha3 9 10 // This file contains code for using the 'compute intermediate 11 // message digest' (KIMD) and 'compute last message digest' (KLMD) 12 // instructions to compute SHA-3 and SHAKE hashes on IBM Z. 13 14 import ( 15 "hash" 16 17 "golang.org/x/sys/cpu" 18 ) 19 20 // codes represent 7-bit KIMD/KLMD function codes as defined in 21 // the Principles of Operation. 22 type code uint64 23 24 const ( 25 // function codes for KIMD/KLMD 26 sha3_224 code = 32 27 sha3_256 = 33 28 sha3_384 = 34 29 sha3_512 = 35 30 shake_128 = 36 31 shake_256 = 37 32 nopad = 0x100 33 ) 34 35 // kimd is a wrapper for the 'compute intermediate message digest' instruction. 36 // src must be a multiple of the rate for the given function code. 37 // 38 //go:noescape 39 func kimd(function code, chain *[200]byte, src []byte) 40 41 // klmd is a wrapper for the 'compute last message digest' instruction. 42 // src padding is handled by the instruction. 43 // 44 //go:noescape 45 func klmd(function code, chain *[200]byte, dst, src []byte) 46 47 type asmState struct { 48 a [200]byte // 1600 bit state 49 buf []byte // care must be taken to ensure cap(buf) is a multiple of rate 50 rate int // equivalent to block size 51 storage [3072]byte // underlying storage for buf 52 outputLen int // output length if fixed, 0 if not 53 function code // KIMD/KLMD function code 54 state spongeDirection // whether the sponge is absorbing or squeezing 55 } 56 57 func newAsmState(function code) *asmState { 58 var s asmState 59 s.function = function 60 switch function { 61 case sha3_224: 62 s.rate = 144 63 s.outputLen = 28 64 case sha3_256: 65 s.rate = 136 66 s.outputLen = 32 67 case sha3_384: 68 s.rate = 104 69 s.outputLen = 48 70 case sha3_512: 71 s.rate = 72 72 s.outputLen = 64 73 case shake_128: 74 s.rate = 168 75 case shake_256: 76 s.rate = 136 77 default: 78 panic("sha3: unrecognized function code") 79 } 80 81 // limit s.buf size to a multiple of s.rate 82 s.resetBuf() 83 return &s 84 } 85 86 func (s *asmState) clone() *asmState { 87 c := *s 88 c.buf = c.storage[:len(s.buf):cap(s.buf)] 89 return &c 90 } 91 92 // copyIntoBuf copies b into buf. It will panic if there is not enough space to 93 // store all of b. 94 func (s *asmState) copyIntoBuf(b []byte) { 95 bufLen := len(s.buf) 96 s.buf = s.buf[:len(s.buf)+len(b)] 97 copy(s.buf[bufLen:], b) 98 } 99 100 // resetBuf points buf at storage, sets the length to 0 and sets cap to be a 101 // multiple of the rate. 102 func (s *asmState) resetBuf() { 103 max := (cap(s.storage) / s.rate) * s.rate 104 s.buf = s.storage[:0:max] 105 } 106 107 // Write (via the embedded io.Writer interface) adds more data to the running hash. 108 // It never returns an error. 109 func (s *asmState) Write(b []byte) (int, error) { 110 if s.state != spongeAbsorbing { 111 panic("sha3: write to sponge after read") 112 } 113 length := len(b) 114 for len(b) > 0 { 115 if len(s.buf) == 0 && len(b) >= cap(s.buf) { 116 // Hash the data directly and push any remaining bytes 117 // into the buffer. 118 remainder := len(b) % s.rate 119 kimd(s.function, &s.a, b[:len(b)-remainder]) 120 if remainder != 0 { 121 s.copyIntoBuf(b[len(b)-remainder:]) 122 } 123 return length, nil 124 } 125 126 if len(s.buf) == cap(s.buf) { 127 // flush the buffer 128 kimd(s.function, &s.a, s.buf) 129 s.buf = s.buf[:0] 130 } 131 132 // copy as much as we can into the buffer 133 n := len(b) 134 if len(b) > cap(s.buf)-len(s.buf) { 135 n = cap(s.buf) - len(s.buf) 136 } 137 s.copyIntoBuf(b[:n]) 138 b = b[n:] 139 } 140 return length, nil 141 } 142 143 // Read squeezes an arbitrary number of bytes from the sponge. 144 func (s *asmState) Read(out []byte) (n int, err error) { 145 n = len(out) 146 147 // need to pad if we were absorbing 148 if s.state == spongeAbsorbing { 149 s.state = spongeSqueezing 150 151 // write hash directly into out if possible 152 if len(out)%s.rate == 0 { 153 klmd(s.function, &s.a, out, s.buf) // len(out) may be 0 154 s.buf = s.buf[:0] 155 return 156 } 157 158 // write hash into buffer 159 max := cap(s.buf) 160 if max > len(out) { 161 max = (len(out)/s.rate)*s.rate + s.rate 162 } 163 klmd(s.function, &s.a, s.buf[:max], s.buf) 164 s.buf = s.buf[:max] 165 } 166 167 for len(out) > 0 { 168 // flush the buffer 169 if len(s.buf) != 0 { 170 c := copy(out, s.buf) 171 out = out[c:] 172 s.buf = s.buf[c:] 173 continue 174 } 175 176 // write hash directly into out if possible 177 if len(out)%s.rate == 0 { 178 klmd(s.function|nopad, &s.a, out, nil) 179 return 180 } 181 182 // write hash into buffer 183 s.resetBuf() 184 if cap(s.buf) > len(out) { 185 s.buf = s.buf[:(len(out)/s.rate)*s.rate+s.rate] 186 } 187 klmd(s.function|nopad, &s.a, s.buf, nil) 188 } 189 return 190 } 191 192 // Sum appends the current hash to b and returns the resulting slice. 193 // It does not change the underlying hash state. 194 func (s *asmState) Sum(b []byte) []byte { 195 if s.outputLen == 0 { 196 panic("sha3: cannot call Sum on SHAKE functions") 197 } 198 199 // Copy the state to preserve the original. 200 a := s.a 201 202 // Hash the buffer. Note that we don't clear it because we 203 // aren't updating the state. 204 klmd(s.function, &a, nil, s.buf) 205 return append(b, a[:s.outputLen]...) 206 } 207 208 // Reset resets the Hash to its initial state. 209 func (s *asmState) Reset() { 210 for i := range s.a { 211 s.a[i] = 0 212 } 213 s.resetBuf() 214 s.state = spongeAbsorbing 215 } 216 217 // Size returns the number of bytes Sum will return. 218 func (s *asmState) Size() int { 219 return s.outputLen 220 } 221 222 // BlockSize returns the hash's underlying block size. 223 // The Write method must be able to accept any amount 224 // of data, but it may operate more efficiently if all writes 225 // are a multiple of the block size. 226 func (s *asmState) BlockSize() int { 227 return s.rate 228 } 229 230 // Clone returns a copy of the ShakeHash in its current state. 231 func (s *asmState) Clone() ShakeHash { 232 return s.clone() 233 } 234 235 // new224Asm returns an assembly implementation of SHA3-224 if available, 236 // otherwise it returns nil. 237 func new224Asm() hash.Hash { 238 if cpu.S390X.HasSHA3 { 239 return newAsmState(sha3_224) 240 } 241 return nil 242 } 243 244 // new256Asm returns an assembly implementation of SHA3-256 if available, 245 // otherwise it returns nil. 246 func new256Asm() hash.Hash { 247 if cpu.S390X.HasSHA3 { 248 return newAsmState(sha3_256) 249 } 250 return nil 251 } 252 253 // new384Asm returns an assembly implementation of SHA3-384 if available, 254 // otherwise it returns nil. 255 func new384Asm() hash.Hash { 256 if cpu.S390X.HasSHA3 { 257 return newAsmState(sha3_384) 258 } 259 return nil 260 } 261 262 // new512Asm returns an assembly implementation of SHA3-512 if available, 263 // otherwise it returns nil. 264 func new512Asm() hash.Hash { 265 if cpu.S390X.HasSHA3 { 266 return newAsmState(sha3_512) 267 } 268 return nil 269 } 270 271 // newShake128Asm returns an assembly implementation of SHAKE-128 if available, 272 // otherwise it returns nil. 273 func newShake128Asm() ShakeHash { 274 if cpu.S390X.HasSHA3 { 275 return newAsmState(shake_128) 276 } 277 return nil 278 } 279 280 // newShake256Asm returns an assembly implementation of SHAKE-256 if available, 281 // otherwise it returns nil. 282 func newShake256Asm() ShakeHash { 283 if cpu.S390X.HasSHA3 { 284 return newAsmState(shake_256) 285 } 286 return nil 287 }