sha3: align (*state).storage
Even on platforms that allow unaligned reads, the Go runtime assumes
that a pointer to a given type has the alignment required by that
type.
Fixes golang/go#35173
Updates golang/go#34972
Updates golang/go#34964
Change-Id: I90361e096e59162e42ebde2914985af92f777ece
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/203837
Run-TryBot: Bryan C. Mills <bcmills@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
diff --git a/sha3/sha3.go b/sha3/sha3.go
index b12a35c..ba269a0 100644
--- a/sha3/sha3.go
+++ b/sha3/sha3.go
@@ -38,8 +38,9 @@
// [1] http://csrc.nist.gov/publications/drafts/fips-202/fips_202_draft.pdf
// "Draft FIPS 202: SHA-3 Standard: Permutation-Based Hash and
// Extendable-Output Functions (May 2014)"
- dsbyte byte
- storage [maxRate]byte
+ dsbyte byte
+
+ storage storageBuf
// Specific to SHA-3 and SHAKE.
outputLen int // the default output size in bytes
@@ -60,15 +61,15 @@
d.a[i] = 0
}
d.state = spongeAbsorbing
- d.buf = d.storage[:0]
+ d.buf = d.storage.asBytes()[:0]
}
func (d *state) clone() *state {
ret := *d
if ret.state == spongeAbsorbing {
- ret.buf = ret.storage[:len(ret.buf)]
+ ret.buf = ret.storage.asBytes()[:len(ret.buf)]
} else {
- ret.buf = ret.storage[d.rate-cap(d.buf) : d.rate]
+ ret.buf = ret.storage.asBytes()[d.rate-cap(d.buf) : d.rate]
}
return &ret
@@ -82,13 +83,13 @@
// If we're absorbing, we need to xor the input into the state
// before applying the permutation.
xorIn(d, d.buf)
- d.buf = d.storage[:0]
+ d.buf = d.storage.asBytes()[:0]
keccakF1600(&d.a)
case spongeSqueezing:
// If we're squeezing, we need to apply the permutatin before
// copying more output.
keccakF1600(&d.a)
- d.buf = d.storage[:d.rate]
+ d.buf = d.storage.asBytes()[:d.rate]
copyOut(d, d.buf)
}
}
@@ -97,7 +98,7 @@
// the multi-bitrate 10..1 padding rule, and permutes the state.
func (d *state) padAndPermute(dsbyte byte) {
if d.buf == nil {
- d.buf = d.storage[:0]
+ d.buf = d.storage.asBytes()[:0]
}
// Pad with this instance's domain-separator bits. We know that there's
// at least one byte of space in d.buf because, if it were full,
@@ -105,7 +106,7 @@
// first one bit for the padding. See the comment in the state struct.
d.buf = append(d.buf, dsbyte)
zerosStart := len(d.buf)
- d.buf = d.storage[:d.rate]
+ d.buf = d.storage.asBytes()[:d.rate]
for i := zerosStart; i < d.rate; i++ {
d.buf[i] = 0
}
@@ -116,7 +117,7 @@
// Apply the permutation
d.permute()
d.state = spongeSqueezing
- d.buf = d.storage[:d.rate]
+ d.buf = d.storage.asBytes()[:d.rate]
copyOut(d, d.buf)
}
@@ -127,7 +128,7 @@
panic("sha3: write to sponge after read")
}
if d.buf == nil {
- d.buf = d.storage[:0]
+ d.buf = d.storage.asBytes()[:0]
}
written = len(p)
diff --git a/sha3/xor.go b/sha3/xor.go
index 46a0d63..079b650 100644
--- a/sha3/xor.go
+++ b/sha3/xor.go
@@ -6,6 +6,13 @@
package sha3
+// A storageBuf is an aligned array of maxRate bytes.
+type storageBuf [maxRate]byte
+
+func (b *storageBuf) asBytes() *[maxRate]byte {
+ return (*[maxRate]byte)(b)
+}
+
var (
xorIn = xorInGeneric
copyOut = copyOutGeneric
diff --git a/sha3/xor_unaligned.go b/sha3/xor_unaligned.go
index 929a486..a3d0686 100644
--- a/sha3/xor_unaligned.go
+++ b/sha3/xor_unaligned.go
@@ -9,9 +9,16 @@
import "unsafe"
+// A storageBuf is an aligned array of maxRate bytes.
+type storageBuf [maxRate / 8]uint64
+
+func (b *storageBuf) asBytes() *[maxRate]byte {
+ return (*[maxRate]byte)(unsafe.Pointer(b))
+}
+
func xorInUnaligned(d *state, buf []byte) {
- bw := (*[maxRate / 8]uint64)(unsafe.Pointer(&buf[0]))
n := len(buf)
+ bw := (*[maxRate / 8]uint64)(unsafe.Pointer(&buf[0]))[: n/8 : n/8]
if n >= 72 {
d.a[0] ^= bw[0]
d.a[1] ^= bw[1]