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.
5
//go:build gc && !purego
9
// This file contains code for using the 'compute intermediate
10
// message digest' (KIMD) and 'compute last message digest' (KLMD)
11
// instructions to compute SHA-3 and SHAKE hashes on IBM Z.
16
"golang.org/x/sys/cpu"
19
// codes represent 7-bit KIMD/KLMD function codes as defined in
20
// the Principles of Operation.
24
// function codes for KIMD/KLMD
34
// kimd is a wrapper for the 'compute intermediate message digest' instruction.
35
// src must be a multiple of the rate for the given function code.
38
func kimd(function code, chain *[200]byte, src []byte)
40
// klmd is a wrapper for the 'compute last message digest' instruction.
41
// src padding is handled by the instruction.
44
func klmd(function code, chain *[200]byte, dst, src []byte)
47
a [200]byte // 1600 bit state
48
buf []byte // care must be taken to ensure cap(buf) is a multiple of rate
49
rate int // equivalent to block size
50
storage [3072]byte // underlying storage for buf
51
outputLen int // output length for full security
52
function code // KIMD/KLMD function code
53
state spongeDirection // whether the sponge is absorbing or squeezing
56
func newAsmState(function code) *asmState {
79
panic("sha3: unrecognized function code")
82
// limit s.buf size to a multiple of s.rate
87
func (s *asmState) clone() *asmState {
89
c.buf = c.storage[:len(s.buf):cap(s.buf)]
93
// copyIntoBuf copies b into buf. It will panic if there is not enough space to
95
func (s *asmState) copyIntoBuf(b []byte) {
97
s.buf = s.buf[:len(s.buf)+len(b)]
98
copy(s.buf[bufLen:], b)
101
// resetBuf points buf at storage, sets the length to 0 and sets cap to be a
102
// multiple of the rate.
103
func (s *asmState) resetBuf() {
104
max := (cap(s.storage) / s.rate) * s.rate
105
s.buf = s.storage[:0:max]
108
// Write (via the embedded io.Writer interface) adds more data to the running hash.
109
// It never returns an error.
110
func (s *asmState) Write(b []byte) (int, error) {
111
if s.state != spongeAbsorbing {
112
panic("sha3: Write after Read")
116
if len(s.buf) == 0 && len(b) >= cap(s.buf) {
117
// Hash the data directly and push any remaining bytes
119
remainder := len(b) % s.rate
120
kimd(s.function, &s.a, b[:len(b)-remainder])
122
s.copyIntoBuf(b[len(b)-remainder:])
127
if len(s.buf) == cap(s.buf) {
129
kimd(s.function, &s.a, s.buf)
133
// copy as much as we can into the buffer
135
if len(b) > cap(s.buf)-len(s.buf) {
136
n = cap(s.buf) - len(s.buf)
144
// Read squeezes an arbitrary number of bytes from the sponge.
145
func (s *asmState) Read(out []byte) (n int, err error) {
148
// need to pad if we were absorbing
149
if s.state == spongeAbsorbing {
150
s.state = spongeSqueezing
152
// write hash directly into out if possible
153
if len(out)%s.rate == 0 {
154
klmd(s.function, &s.a, out, s.buf) // len(out) may be 0
159
// write hash into buffer
162
max = (len(out)/s.rate)*s.rate + s.rate
164
klmd(s.function, &s.a, s.buf[:max], s.buf)
171
c := copy(out, s.buf)
177
// write hash directly into out if possible
178
if len(out)%s.rate == 0 {
179
klmd(s.function|nopad, &s.a, out, nil)
183
// write hash into buffer
185
if cap(s.buf) > len(out) {
186
s.buf = s.buf[:(len(out)/s.rate)*s.rate+s.rate]
188
klmd(s.function|nopad, &s.a, s.buf, nil)
193
// Sum appends the current hash to b and returns the resulting slice.
194
// It does not change the underlying hash state.
195
func (s *asmState) Sum(b []byte) []byte {
196
if s.state != spongeAbsorbing {
197
panic("sha3: Sum after Read")
200
// Copy the state to preserve the original.
203
// Hash the buffer. Note that we don't clear it because we
204
// aren't updating the state.
205
klmd(s.function, &a, nil, s.buf)
206
return append(b, a[:s.outputLen]...)
209
// Reset resets the Hash to its initial state.
210
func (s *asmState) Reset() {
215
s.state = spongeAbsorbing
218
// Size returns the number of bytes Sum will return.
219
func (s *asmState) Size() int {
223
// BlockSize returns the hash's underlying block size.
224
// The Write method must be able to accept any amount
225
// of data, but it may operate more efficiently if all writes
226
// are a multiple of the block size.
227
func (s *asmState) BlockSize() int {
231
// Clone returns a copy of the ShakeHash in its current state.
232
func (s *asmState) Clone() ShakeHash {
236
// new224Asm returns an assembly implementation of SHA3-224 if available,
237
// otherwise it returns nil.
238
func new224Asm() hash.Hash {
239
if cpu.S390X.HasSHA3 {
240
return newAsmState(sha3_224)
245
// new256Asm returns an assembly implementation of SHA3-256 if available,
246
// otherwise it returns nil.
247
func new256Asm() hash.Hash {
248
if cpu.S390X.HasSHA3 {
249
return newAsmState(sha3_256)
254
// new384Asm returns an assembly implementation of SHA3-384 if available,
255
// otherwise it returns nil.
256
func new384Asm() hash.Hash {
257
if cpu.S390X.HasSHA3 {
258
return newAsmState(sha3_384)
263
// new512Asm returns an assembly implementation of SHA3-512 if available,
264
// otherwise it returns nil.
265
func new512Asm() hash.Hash {
266
if cpu.S390X.HasSHA3 {
267
return newAsmState(sha3_512)
272
// newShake128Asm returns an assembly implementation of SHAKE-128 if available,
273
// otherwise it returns nil.
274
func newShake128Asm() ShakeHash {
275
if cpu.S390X.HasSHA3 {
276
return newAsmState(shake_128)
281
// newShake256Asm returns an assembly implementation of SHAKE-256 if available,
282
// otherwise it returns nil.
283
func newShake256Asm() ShakeHash {
284
if cpu.S390X.HasSHA3 {
285
return newAsmState(shake_256)