Browse Source

SHAKE: Don't use function pointers (#20)

* xorIn and copyOut function pointers cause input and output data
  to be moved to heap. This degrades performance of calling code.

* This change removes usage of those function pointers. We will always
  use unaligned implementation as it's faster (but may crash on some
  systems)

* Benchmark compares generic vs unaligned xorIn and copyOut

benchmark                          old ns/op     new ns/op     delta
BenchmarkPermutationFunction-4     463           815           +76.03%
BenchmarkShake128_MTU-4            4443          8180          +84.11%
BenchmarkShake256_MTU-4            4739          9060          +91.18%
BenchmarkShake256_16x-4            71886         132629        +84.50%
BenchmarkShake256_1MiB-4           3695138       6649012       +79.94%
BenchmarkCShake128_448_16x-4       21210         24611         +16.03%
BenchmarkCShake128_1MiB-4          3009342       3396496       +12.87%
BenchmarkCShake256_448_16x-4       26034         27785         +6.73%
BenchmarkCShake256_1MiB-4          3654713       3829404       +4.78%
pull/21/head
Henry Case 5 years ago
parent
commit
49bf0db8fd
7 changed files with 27 additions and 72 deletions
  1. +0
    -16
      hash/sha3/sha3_test.go
  2. +0
    -27
      hash/shake/hashes_generic.go
  3. +4
    -4
      hash/shake/sha3.go
  4. +20
    -3
      hash/shake/sha3_test.go
  5. +0
    -16
      hash/shake/xor.go
  6. +2
    -0
      hash/shake/xor_generic.go
  7. +1
    -6
      hash/shake/xor_unaligned.go

+ 0
- 16
hash/sha3/sha3_test.go View File

@@ -472,19 +472,3 @@ func ExampleCShake256() {
//a90a4c6ca9af2156eba43dc8398279e6b60dcd56fb21837afe6c308fd4ceb05b9dd98c6ee866ca7dc5a39d53e960f400bcd5a19c8a2d6ec6459f63696543a0d8
//85e73a72228d08b46515553ca3a29d47df3047e5d84b12d6c2c63e579f4fd1105716b7838e92e981863907f434bfd4443c9e56ea09da998d2f9b47db71988109
}

func TestXXX(t *testing.T) {
var out1, out2 [32]byte
h := NewCShake256([]byte("CSHAKE256"), []byte("CustomStrign"))

h.Write([]byte{0x1, 0x2, 0x3})
h.Read(out1[:])

h.Reset()

h.Write([]byte{0x1, 0x2, 0x3})
h.Read(out2[:])

fmt.Println(out1)
fmt.Println(out2)
}

+ 0
- 27
hash/shake/hashes_generic.go View File

@@ -1,27 +0,0 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//+build gccgo appengine !s390x

package shake

import (
"hash"
)

// new224Asm returns an assembly implementation of SHA3-224 if available,
// otherwise it returns nil.
func new224Asm() hash.Hash { return nil }

// new256Asm returns an assembly implementation of SHA3-256 if available,
// otherwise it returns nil.
func new256Asm() hash.Hash { return nil }

// new384Asm returns an assembly implementation of SHA3-384 if available,
// otherwise it returns nil.
func new384Asm() hash.Hash { return nil }

// new512Asm returns an assembly implementation of SHA3-512 if available,
// otherwise it returns nil.
func new512Asm() hash.Hash { return nil }

+ 4
- 4
hash/shake/sha3.go View File

@@ -83,7 +83,7 @@ func (d *state) permute() {
case spongeAbsorbing:
// If we're absorbing, we need to xor the input into the state
// before applying the permutation.
xorIn(d, d.buf)
xorInUnaligned(d, d.buf)
d.buf = d.storage[:0]
keccakF1600(&d.a)
case spongeSqueezing:
@@ -91,7 +91,7 @@ func (d *state) permute() {
// copying more output.
keccakF1600(&d.a)
d.buf = d.storage[:d.rate]
copyOut(d, d.buf)
copyOutUnaligned(d, d.buf)
}
}

@@ -119,7 +119,7 @@ func (d *state) padAndPermute(dsbyte byte) {
d.permute()
d.state = spongeSqueezing
d.buf = d.storage[:d.rate]
copyOut(d, d.buf)
copyOutUnaligned(d, d.buf)
}

// Write absorbs more data into the hash's state. It produces an error
@@ -136,7 +136,7 @@ func (d *state) Write(p []byte) (written int, err error) {
for len(p) > 0 {
if len(d.buf) == 0 && len(p) >= d.rate {
// The fast path; absorb a full "rate" bytes of input and apply the permutation.
xorIn(d, p[:d.rate])
xorInUnaligned(d, p[:d.rate])
p = p[d.rate:]
keccakF1600(&d.a)
} else {


+ 20
- 3
hash/shake/sha3_test.go View File

@@ -22,6 +22,11 @@ import (
"testing"
)

var (
xorIn = xorInUnaligned
copyOut = copyOutUnaligned
)

const (
testString = "brekeccakkeccak koax koax"
katFilename = "testdata/keccakKats.json.deflate"
@@ -68,7 +73,7 @@ func testUnalignedAndGeneric(t *testing.T, testf func(impl string)) {
xorIn, copyOut = xorInGeneric, copyOutGeneric
testf("generic")
if xorImplementationUnaligned != "generic" {
xorIn, copyOut = xorInUnaligned, copyOutUnaligned
xorIn, copyOut = xorInGeneric, copyOutGeneric
testf("unaligned")
}
xorIn, copyOut = xorInOrig, copyOutOrig
@@ -336,7 +341,7 @@ func benchmarkShake(b *testing.B, h *CShake, size, num int) {
b.StopTimer()
h.Reset()
data := sequentialBytes(size)
d := make([]byte, 32)
var d [32]byte

b.SetBytes(int64(size * num))
b.StartTimer()
@@ -346,7 +351,7 @@ func benchmarkShake(b *testing.B, h *CShake, size, num int) {
for j := 0; j < num; j++ {
h.Write(data)
}
h.Read(d)
h.Read(d[:])
}
}

@@ -354,6 +359,18 @@ func BenchmarkShake128_MTU(b *testing.B) { benchmarkShake(b, NewShake128(), 135
func BenchmarkShake256_MTU(b *testing.B) { benchmarkShake(b, NewShake256(), 1350, 1) }
func BenchmarkShake256_16x(b *testing.B) { benchmarkShake(b, NewShake256(), 16, 1024) }
func BenchmarkShake256_1MiB(b *testing.B) { benchmarkShake(b, NewShake256(), 1024, 1024) }
func BenchmarkCShake128_448_16x(b *testing.B) {
benchmarkShake(b, NewCShake128([]byte("ABC"), []byte("DEF")), 448, 16)
}
func BenchmarkCShake128_1MiB(b *testing.B) {
benchmarkShake(b, NewCShake128([]byte("ABC"), []byte("DEF")), 1024, 1024)
}
func BenchmarkCShake256_448_16x(b *testing.B) {
benchmarkShake(b, NewCShake256([]byte("ABC"), []byte("DEF")), 448, 16)
}
func BenchmarkCShake256_1MiB(b *testing.B) {
benchmarkShake(b, NewCShake256([]byte("ABC"), []byte("DEF")), 1024, 1024)
}

func Example_sum() {
buf := []byte("some data to hash")


+ 0
- 16
hash/shake/xor.go View File

@@ -1,16 +0,0 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build !amd64,!386,!ppc64le appengine

package shake

var (
xorIn = xorInGeneric
copyOut = copyOutGeneric
xorInUnaligned = xorInGeneric
copyOutUnaligned = copyOutGeneric
)

const xorImplementationUnaligned = "generic"

+ 2
- 0
hash/shake/xor_generic.go View File

@@ -26,3 +26,5 @@ func copyOutGeneric(d *state, b []byte) {
b = b[8:]
}
}

const xorImplementationGeneric = "generic"

+ 1
- 6
hash/shake/xor_unaligned.go View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build amd64 386 ppc64le
// +build amd64 arm64 386 ppc64le
// +build !appengine

package shake
@@ -50,9 +50,4 @@ func copyOutUnaligned(d *state, buf []byte) {
copy(buf, ab[:])
}

var (
xorIn = xorInUnaligned
copyOut = copyOutUnaligned
)

const xorImplementationUnaligned = "unaligned"

Loading…
Cancel
Save