44
55package sha3
66
7+ import (
8+ "crypto/subtle"
9+ "encoding/binary"
10+ "unsafe"
11+
12+ "golang.org/x/sys/cpu"
13+ )
14+
715// spongeDirection indicates the direction bytes are flowing through the sponge.
816type spongeDirection int
917
@@ -14,16 +22,13 @@ const (
1422 spongeSqueezing
1523)
1624
17- const (
18- // maxRate is the maximum size of the internal buffer. SHAKE-256
19- // currently needs the largest buffer.
20- maxRate = 168
21- )
22-
2325type state struct {
24- // Generic sponge components.
25- a [25 ]uint64 // main state of the hash
26- rate int // the number of bytes of state to use
26+ a [1600 / 8 ]byte // main state of the hash
27+
28+ // a[n:rate] is the buffer. If absorbing, it's the remaining space to XOR
29+ // into before running the permutation. If squeezing, it's the remaining
30+ // output to produce before running the permutation.
31+ n , rate int
2732
2833 // dsbyte contains the "domain separation" bits and the first bit of
2934 // the padding. Sections 6.1 and 6.2 of [1] separate the outputs of the
@@ -39,10 +44,6 @@ type state struct {
3944 // Extendable-Output Functions (May 2014)"
4045 dsbyte byte
4146
42- i , n int // storage[i:n] is the buffer, i is only used while squeezing
43- storage [maxRate ]byte
44-
45- // Specific to SHA-3 and SHAKE.
4647 outputLen int // the default output size in bytes
4748 state spongeDirection // whether the sponge is absorbing or squeezing
4849}
@@ -61,84 +62,70 @@ func (d *state) Reset() {
6162 d .a [i ] = 0
6263 }
6364 d .state = spongeAbsorbing
64- d .i , d . n = 0 , 0
65+ d .n = 0
6566}
6667
6768func (d * state ) clone () * state {
6869 ret := * d
6970 return & ret
7071}
7172
72- // permute applies the KeccakF-1600 permutation. It handles
73- // any input-output buffering.
73+ // permute applies the KeccakF-1600 permutation.
7474func (d * state ) permute () {
75- switch d .state {
76- case spongeAbsorbing :
77- // If we're absorbing, we need to xor the input into the state
78- // before applying the permutation.
79- xorIn (d , d .storage [:d .rate ])
80- d .n = 0
81- keccakF1600 (& d .a )
82- case spongeSqueezing :
83- // If we're squeezing, we need to apply the permutation before
84- // copying more output.
85- keccakF1600 (& d .a )
86- d .i = 0
87- copyOut (d , d .storage [:d .rate ])
75+ var a * [25 ]uint64
76+ if cpu .IsBigEndian {
77+ a = new ([25 ]uint64 )
78+ for i := range a {
79+ a [i ] = binary .LittleEndian .Uint64 (d .a [i * 8 :])
80+ }
81+ } else {
82+ a = (* [25 ]uint64 )(unsafe .Pointer (& d .a ))
83+ }
84+
85+ keccakF1600 (a )
86+ d .n = 0
87+
88+ if cpu .IsBigEndian {
89+ for i := range a {
90+ binary .LittleEndian .PutUint64 (d .a [i * 8 :], a [i ])
91+ }
8892 }
8993}
9094
9195// pads appends the domain separation bits in dsbyte, applies
9296// the multi-bitrate 10..1 padding rule, and permutes the state.
9397func (d * state ) padAndPermute () {
9498 // Pad with this instance's domain-separator bits. We know that there's
95- // at least one byte of space in d.buf because, if it were full,
99+ // at least one byte of space in the sponge because, if it were full,
96100 // permute would have been called to empty it. dsbyte also contains the
97101 // first one bit for the padding. See the comment in the state struct.
98- d .storage [d .n ] = d .dsbyte
99- d .n ++
100- for d .n < d .rate {
101- d .storage [d .n ] = 0
102- d .n ++
103- }
102+ d .a [d .n ] ^= d .dsbyte
104103 // This adds the final one bit for the padding. Because of the way that
105104 // bits are numbered from the LSB upwards, the final bit is the MSB of
106105 // the last byte.
107- d .storage [d .rate - 1 ] ^= 0x80
106+ d .a [d .rate - 1 ] ^= 0x80
108107 // Apply the permutation
109108 d .permute ()
110109 d .state = spongeSqueezing
111- d .n = d .rate
112- copyOut (d , d .storage [:d .rate ])
113110}
114111
115112// Write absorbs more data into the hash's state. It panics if any
116113// output has already been read.
117- func (d * state ) Write (p []byte ) (written int , err error ) {
114+ func (d * state ) Write (p []byte ) (n int , err error ) {
118115 if d .state != spongeAbsorbing {
119116 panic ("sha3: Write after Read" )
120117 }
121- written = len (p )
118+
119+ n = len (p )
122120
123121 for len (p ) > 0 {
124- if d .n == 0 && len (p ) >= d .rate {
125- // The fast path; absorb a full "rate" bytes of input and apply the permutation.
126- xorIn (d , p [:d .rate ])
127- p = p [d .rate :]
128- keccakF1600 (& d .a )
129- } else {
130- // The slow path; buffer the input until we can fill the sponge, and then xor it in.
131- todo := d .rate - d .n
132- if todo > len (p ) {
133- todo = len (p )
134- }
135- d .n += copy (d .storage [d .n :], p [:todo ])
136- p = p [todo :]
137-
138- // If the sponge is full, apply the permutation.
139- if d .n == d .rate {
140- d .permute ()
141- }
122+ x := subtle .XORBytes (d .a [d .n :d .rate ], d .a [d .n :d .rate ], p )
123+ d .n += x
124+ p = p [x :]
125+
126+ // If the sponge is full, apply the permutation.
127+ if d .n == d .rate {
128+ d .permute ()
142129 }
143130 }
144131
@@ -156,12 +143,12 @@ func (d *state) Read(out []byte) (n int, err error) {
156143
157144 // Now, do the squeezing.
158145 for len (out ) > 0 {
159- n := copy (out , d .storage [d .i :d .n ])
160- d .i += n
161- out = out [n :]
146+ x := copy (out , d .a [d .n :d .rate ])
147+ d .n += x
148+ out = out [x :]
162149
163150 // Apply the permutation if we've squeezed the sponge dry.
164- if d .i == d .rate {
151+ if d .n == d .rate {
165152 d .permute ()
166153 }
167154 }
0 commit comments