podman

Форк
0
172 строки · 5.4 Кб
1
// Copyright 2014 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
package sha3
6

7
// This file defines the ShakeHash interface, and provides
8
// functions for creating SHAKE and cSHAKE instances, as well as utility
9
// functions for hashing bytes to arbitrary-length output.
10
//
11
//
12
// SHAKE implementation is based on FIPS PUB 202 [1]
13
// cSHAKE implementations is based on NIST SP 800-185 [2]
14
//
15
// [1] https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf
16
// [2] https://doi.org/10.6028/NIST.SP.800-185
17

18
import (
19
	"encoding/binary"
20
	"hash"
21
	"io"
22
)
23

24
// ShakeHash defines the interface to hash functions that support
25
// arbitrary-length output. When used as a plain [hash.Hash], it
26
// produces minimum-length outputs that provide full-strength generic
27
// security.
28
type ShakeHash interface {
29
	hash.Hash
30

31
	// Read reads more output from the hash; reading affects the hash's
32
	// state. (ShakeHash.Read is thus very different from Hash.Sum)
33
	// It never returns an error, but subsequent calls to Write or Sum
34
	// will panic.
35
	io.Reader
36

37
	// Clone returns a copy of the ShakeHash in its current state.
38
	Clone() ShakeHash
39
}
40

41
// cSHAKE specific context
42
type cshakeState struct {
43
	*state // SHA-3 state context and Read/Write operations
44

45
	// initBlock is the cSHAKE specific initialization set of bytes. It is initialized
46
	// by newCShake function and stores concatenation of N followed by S, encoded
47
	// by the method specified in 3.3 of [1].
48
	// It is stored here in order for Reset() to be able to put context into
49
	// initial state.
50
	initBlock []byte
51
}
52

53
// Consts for configuring initial SHA-3 state
54
const (
55
	dsbyteShake  = 0x1f
56
	dsbyteCShake = 0x04
57
	rate128      = 168
58
	rate256      = 136
59
)
60

61
func bytepad(input []byte, w int) []byte {
62
	// leftEncode always returns max 9 bytes
63
	buf := make([]byte, 0, 9+len(input)+w)
64
	buf = append(buf, leftEncode(uint64(w))...)
65
	buf = append(buf, input...)
66
	padlen := w - (len(buf) % w)
67
	return append(buf, make([]byte, padlen)...)
68
}
69

70
func leftEncode(value uint64) []byte {
71
	var b [9]byte
72
	binary.BigEndian.PutUint64(b[1:], value)
73
	// Trim all but last leading zero bytes
74
	i := byte(1)
75
	for i < 8 && b[i] == 0 {
76
		i++
77
	}
78
	// Prepend number of encoded bytes
79
	b[i-1] = 9 - i
80
	return b[i-1:]
81
}
82

83
func newCShake(N, S []byte, rate, outputLen int, dsbyte byte) ShakeHash {
84
	c := cshakeState{state: &state{rate: rate, outputLen: outputLen, dsbyte: dsbyte}}
85

86
	// leftEncode returns max 9 bytes
87
	c.initBlock = make([]byte, 0, 9*2+len(N)+len(S))
88
	c.initBlock = append(c.initBlock, leftEncode(uint64(len(N)*8))...)
89
	c.initBlock = append(c.initBlock, N...)
90
	c.initBlock = append(c.initBlock, leftEncode(uint64(len(S)*8))...)
91
	c.initBlock = append(c.initBlock, S...)
92
	c.Write(bytepad(c.initBlock, c.rate))
93
	return &c
94
}
95

96
// Reset resets the hash to initial state.
97
func (c *cshakeState) Reset() {
98
	c.state.Reset()
99
	c.Write(bytepad(c.initBlock, c.rate))
100
}
101

102
// Clone returns copy of a cSHAKE context within its current state.
103
func (c *cshakeState) Clone() ShakeHash {
104
	b := make([]byte, len(c.initBlock))
105
	copy(b, c.initBlock)
106
	return &cshakeState{state: c.clone(), initBlock: b}
107
}
108

109
// Clone returns copy of SHAKE context within its current state.
110
func (c *state) Clone() ShakeHash {
111
	return c.clone()
112
}
113

114
// NewShake128 creates a new SHAKE128 variable-output-length ShakeHash.
115
// Its generic security strength is 128 bits against all attacks if at
116
// least 32 bytes of its output are used.
117
func NewShake128() ShakeHash {
118
	if h := newShake128Asm(); h != nil {
119
		return h
120
	}
121
	return &state{rate: rate128, outputLen: 32, dsbyte: dsbyteShake}
122
}
123

124
// NewShake256 creates a new SHAKE256 variable-output-length ShakeHash.
125
// Its generic security strength is 256 bits against all attacks if
126
// at least 64 bytes of its output are used.
127
func NewShake256() ShakeHash {
128
	if h := newShake256Asm(); h != nil {
129
		return h
130
	}
131
	return &state{rate: rate256, outputLen: 64, dsbyte: dsbyteShake}
132
}
133

134
// NewCShake128 creates a new instance of cSHAKE128 variable-output-length ShakeHash,
135
// a customizable variant of SHAKE128.
136
// N is used to define functions based on cSHAKE, it can be empty when plain cSHAKE is
137
// desired. S is a customization byte string used for domain separation - two cSHAKE
138
// computations on same input with different S yield unrelated outputs.
139
// When N and S are both empty, this is equivalent to NewShake128.
140
func NewCShake128(N, S []byte) ShakeHash {
141
	if len(N) == 0 && len(S) == 0 {
142
		return NewShake128()
143
	}
144
	return newCShake(N, S, rate128, 32, dsbyteCShake)
145
}
146

147
// NewCShake256 creates a new instance of cSHAKE256 variable-output-length ShakeHash,
148
// a customizable variant of SHAKE256.
149
// N is used to define functions based on cSHAKE, it can be empty when plain cSHAKE is
150
// desired. S is a customization byte string used for domain separation - two cSHAKE
151
// computations on same input with different S yield unrelated outputs.
152
// When N and S are both empty, this is equivalent to NewShake256.
153
func NewCShake256(N, S []byte) ShakeHash {
154
	if len(N) == 0 && len(S) == 0 {
155
		return NewShake256()
156
	}
157
	return newCShake(N, S, rate256, 64, dsbyteCShake)
158
}
159

160
// ShakeSum128 writes an arbitrary-length digest of data into hash.
161
func ShakeSum128(hash, data []byte) {
162
	h := NewShake128()
163
	h.Write(data)
164
	h.Read(hash)
165
}
166

167
// ShakeSum256 writes an arbitrary-length digest of data into hash.
168
func ShakeSum256(hash, data []byte) {
169
	h := NewShake256()
170
	h.Write(data)
171
	h.Read(hash)
172
}
173

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

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

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

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