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