...
1
2
3
4
5 package sha3
6
7 import (
8 "crypto/subtle"
9 "encoding/binary"
10 "errors"
11 "unsafe"
12
13 "golang.org/x/sys/cpu"
14 )
15
16
17 type spongeDirection int
18
19 const (
20
21 spongeAbsorbing spongeDirection = iota
22
23 spongeSqueezing
24 )
25
26 type state struct {
27 a [1600 / 8]byte
28
29
30
31
32 n, rate int
33
34
35
36
37
38
39
40
41
42
43
44
45
46 dsbyte byte
47
48 outputLen int
49 state spongeDirection
50 }
51
52
53 func (d *state) BlockSize() int { return d.rate }
54
55
56 func (d *state) Size() int { return d.outputLen }
57
58
59
60 func (d *state) Reset() {
61
62 for i := range d.a {
63 d.a[i] = 0
64 }
65 d.state = spongeAbsorbing
66 d.n = 0
67 }
68
69 func (d *state) clone() *state {
70 ret := *d
71 return &ret
72 }
73
74
75 func (d *state) permute() {
76 var a *[25]uint64
77 if cpu.IsBigEndian {
78 a = new([25]uint64)
79 for i := range a {
80 a[i] = binary.LittleEndian.Uint64(d.a[i*8:])
81 }
82 } else {
83 a = (*[25]uint64)(unsafe.Pointer(&d.a))
84 }
85
86 keccakF1600(a)
87 d.n = 0
88
89 if cpu.IsBigEndian {
90 for i := range a {
91 binary.LittleEndian.PutUint64(d.a[i*8:], a[i])
92 }
93 }
94 }
95
96
97
98 func (d *state) padAndPermute() {
99
100
101
102
103 d.a[d.n] ^= d.dsbyte
104
105
106
107 d.a[d.rate-1] ^= 0x80
108
109 d.permute()
110 d.state = spongeSqueezing
111 }
112
113
114
115 func (d *state) Write(p []byte) (n int, err error) {
116 if d.state != spongeAbsorbing {
117 panic("sha3: Write after Read")
118 }
119
120 n = len(p)
121
122 for len(p) > 0 {
123 x := subtle.XORBytes(d.a[d.n:d.rate], d.a[d.n:d.rate], p)
124 d.n += x
125 p = p[x:]
126
127
128 if d.n == d.rate {
129 d.permute()
130 }
131 }
132
133 return
134 }
135
136
137 func (d *state) Read(out []byte) (n int, err error) {
138
139 if d.state == spongeAbsorbing {
140 d.padAndPermute()
141 }
142
143 n = len(out)
144
145
146 for len(out) > 0 {
147
148 if d.n == d.rate {
149 d.permute()
150 }
151
152 x := copy(out, d.a[d.n:d.rate])
153 d.n += x
154 out = out[x:]
155 }
156
157 return
158 }
159
160
161
162 func (d *state) Sum(in []byte) []byte {
163 if d.state != spongeAbsorbing {
164 panic("sha3: Sum after Read")
165 }
166
167
168
169 dup := d.clone()
170 hash := make([]byte, dup.outputLen, 64)
171 dup.Read(hash)
172 return append(in, hash...)
173 }
174
175 const (
176 magicSHA3 = "sha\x08"
177 magicShake = "sha\x09"
178 magicCShake = "sha\x0a"
179 magicKeccak = "sha\x0b"
180
181 marshaledSize = len(magicSHA3) + 1 + 200 + 1 + 1
182 )
183
184 func (d *state) MarshalBinary() ([]byte, error) {
185 return d.AppendBinary(make([]byte, 0, marshaledSize))
186 }
187
188 func (d *state) AppendBinary(b []byte) ([]byte, error) {
189 switch d.dsbyte {
190 case dsbyteSHA3:
191 b = append(b, magicSHA3...)
192 case dsbyteShake:
193 b = append(b, magicShake...)
194 case dsbyteCShake:
195 b = append(b, magicCShake...)
196 case dsbyteKeccak:
197 b = append(b, magicKeccak...)
198 default:
199 panic("unknown dsbyte")
200 }
201
202 b = append(b, byte(d.rate))
203 b = append(b, d.a[:]...)
204 b = append(b, byte(d.n), byte(d.state))
205 return b, nil
206 }
207
208 func (d *state) UnmarshalBinary(b []byte) error {
209 if len(b) != marshaledSize {
210 return errors.New("sha3: invalid hash state")
211 }
212
213 magic := string(b[:len(magicSHA3)])
214 b = b[len(magicSHA3):]
215 switch {
216 case magic == magicSHA3 && d.dsbyte == dsbyteSHA3:
217 case magic == magicShake && d.dsbyte == dsbyteShake:
218 case magic == magicCShake && d.dsbyte == dsbyteCShake:
219 case magic == magicKeccak && d.dsbyte == dsbyteKeccak:
220 default:
221 return errors.New("sha3: invalid hash state identifier")
222 }
223
224 rate := int(b[0])
225 b = b[1:]
226 if rate != d.rate {
227 return errors.New("sha3: invalid hash state function")
228 }
229
230 copy(d.a[:], b)
231 b = b[len(d.a):]
232
233 n, state := int(b[0]), spongeDirection(b[1])
234 if n > d.rate {
235 return errors.New("sha3: invalid hash state")
236 }
237 d.n = n
238 if state != spongeAbsorbing && state != spongeSqueezing {
239 return errors.New("sha3: invalid hash state")
240 }
241 d.state = state
242
243 return nil
244 }
245
View as plain text