podman

Форк
0
288 строк · 6.8 Кб
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

7
package 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

13
import (
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.
21
type code uint64
22

23
const (
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
38
func 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
44
func klmd(function code, chain *[200]byte, dst, src []byte)
45

46
type 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

56
func 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

87
func (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.
95
func (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.
103
func (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.
110
func (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.
145
func (s *asmState) Read(out []byte) (n int, err error) {
146
	n = len(out)
147

148
	// need to pad if we were absorbing
149
	if s.state == spongeAbsorbing {
150
		s.state = spongeSqueezing
151

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
155
			s.buf = s.buf[:0]
156
			return
157
		}
158

159
		// write hash into buffer
160
		max := cap(s.buf)
161
		if max > len(out) {
162
			max = (len(out)/s.rate)*s.rate + s.rate
163
		}
164
		klmd(s.function, &s.a, s.buf[:max], s.buf)
165
		s.buf = s.buf[:max]
166
	}
167

168
	for len(out) > 0 {
169
		// flush the buffer
170
		if len(s.buf) != 0 {
171
			c := copy(out, s.buf)
172
			out = out[c:]
173
			s.buf = s.buf[c:]
174
			continue
175
		}
176

177
		// write hash directly into out if possible
178
		if len(out)%s.rate == 0 {
179
			klmd(s.function|nopad, &s.a, out, nil)
180
			return
181
		}
182

183
		// write hash into buffer
184
		s.resetBuf()
185
		if cap(s.buf) > len(out) {
186
			s.buf = s.buf[:(len(out)/s.rate)*s.rate+s.rate]
187
		}
188
		klmd(s.function|nopad, &s.a, s.buf, nil)
189
	}
190
	return
191
}
192

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")
198
	}
199

200
	// Copy the state to preserve the original.
201
	a := s.a
202

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]...)
207
}
208

209
// Reset resets the Hash to its initial state.
210
func (s *asmState) Reset() {
211
	for i := range s.a {
212
		s.a[i] = 0
213
	}
214
	s.resetBuf()
215
	s.state = spongeAbsorbing
216
}
217

218
// Size returns the number of bytes Sum will return.
219
func (s *asmState) Size() int {
220
	return s.outputLen
221
}
222

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 {
228
	return s.rate
229
}
230

231
// Clone returns a copy of the ShakeHash in its current state.
232
func (s *asmState) Clone() ShakeHash {
233
	return s.clone()
234
}
235

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)
241
	}
242
	return nil
243
}
244

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)
250
	}
251
	return nil
252
}
253

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)
259
	}
260
	return nil
261
}
262

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)
268
	}
269
	return nil
270
}
271

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)
277
	}
278
	return nil
279
}
280

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)
286
	}
287
	return nil
288
}
289

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.