From 4ec6f4b876c9abab3a8cbc77e4d458bebc0443c9 Mon Sep 17 00:00:00 2001 From: Henry Case Date: Tue, 14 May 2019 16:10:19 +0100 Subject: [PATCH] PoC on CShakeSum and no-heap initialization --- hash/shake/hashes_generic.go | 27 ----------- hash/shake/sha3.go | 8 ++-- hash/shake/sha3_test.go | 90 ++++++++++++++++++++++++++++++++++-- hash/shake/shake.go | 59 +++++++++++++++++++++++ hash/shake/xor.go | 16 ------- hash/shake/xor_unaligned.go | 5 -- 6 files changed, 150 insertions(+), 55 deletions(-) delete mode 100644 hash/shake/hashes_generic.go delete mode 100644 hash/shake/xor.go diff --git a/hash/shake/hashes_generic.go b/hash/shake/hashes_generic.go deleted file mode 100644 index c6da68a..0000000 --- a/hash/shake/hashes_generic.go +++ /dev/null @@ -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 } diff --git a/hash/shake/sha3.go b/hash/shake/sha3.go index 2c01bb8..8c8a945 100644 --- a/hash/shake/sha3.go +++ b/hash/shake/sha3.go @@ -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 { diff --git a/hash/shake/sha3_test.go b/hash/shake/sha3_test.go index 9176a20..1480837 100644 --- a/hash/shake/sha3_test.go +++ b/hash/shake/sha3_test.go @@ -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,53 @@ 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 BenchmarkCShake256_1MiB(b *testing.B) { + benchmarkShake(b, NewCShake256([]byte("ABC"), nil), 1024, 1024) +} + +func BenchmarkCShakeSum(b *testing.B) { + //benchmarkShake(b, NewCShake256([]byte("ABC"), nil), 1024, 1024) + data := sequentialBytes(1024) + var d [32]byte + + //var c CShake + //c.Init(CSHAKE_256, ) + c := NewCShake256([]byte("ABC"), nil) + for i := 0; i < b.N; i++ { + c.CShakeSum(d[:], data) + } +} + +func BenchmarkCShakeSum3(b *testing.B) { + //benchmarkShake(b, NewCShake256([]byte("ABC"), nil), 1024, 1024) + data := sequentialBytes(1024) + var d [32]byte + + c := NewCShake256([]byte("ABC"), nil) + for i := 0; i < b.N; i++ { + c.Reset() + for i := 0; i < 10; i++ { + c.Write(data) + } + c.Read(d[:]) + } +} + +func BenchmarkCShakeSum4(b *testing.B) { + //benchmarkShake(b, NewCShake256([]byte("ABC"), nil), 1024, 1024) + data := sequentialBytes(1024) + var d [32]byte + + var c CShake //:= NewCShake256([]byte("ABC"), nil) + c.Init(CSHAKE_256, []byte("ABC"), nil) + for i := 0; i < b.N; i++ { + c.Reset() + for i := 0; i < 10; i++ { + c.Write(data) + } + c.Read(d[:]) + } +} func Example_sum() { buf := []byte("some data to hash") @@ -414,3 +466,35 @@ func ExampleCShake256() { //a90a4c6ca9af2156eba43dc8398279e6b60dcd56fb21837afe6c308fd4ceb05b9dd98c6ee866ca7dc5a39d53e960f400bcd5a19c8a2d6ec6459f63696543a0d8 //85e73a72228d08b46515553ca3a29d47df3047e5d84b12d6c2c63e579f4fd1105716b7838e92e981863907f434bfd4443c9e56ea09da998d2f9b47db71988109 } + +func TestDoubleInit(t *testing.T) { + var h1 CShake + + h1.Init(CSHAKE_256, []byte("ABC"), []byte("DEF")) + h2 := NewCShake256([]byte("ABC"), []byte("DEF")) + + h1.Write([]byte("FUCKOFF")) + h2.Write([]byte("FUCKOFF")) + + var out1, out2 [32]byte + h1.Read(out1[:]) + h2.Read(out2[:]) + + if !bytes.Equal(out1[:], out2[:]) { + t.FailNow() + } +} + +func BenchmarkCShakeSum2(b *testing.B) { + var f = []byte{0x02, 0x00} + var o1 [32]byte + var i1 [449]byte + + var c CShake + c.Init(CSHAKE_256, nil, f) + + for i := 0; i < b.N; i++ { + c.CShakeSum(o1[:], i1[:]) + } + +} diff --git a/hash/shake/shake.go b/hash/shake/shake.go index 726d97a..de7e83d 100644 --- a/hash/shake/shake.go +++ b/hash/shake/shake.go @@ -131,6 +131,65 @@ func NewCShake256(N, S []byte) *CShake { return newCShake(N, S, rate256, dsbyteCShake) } +const ( + CSHAKE_256 = 0 + CSHAKE_128 = 1 + SHAKE_128 = 2 + SHAKE_256 = 2 +) + +func (c *CShake) Init(id int, N, S []byte) { + // leftEncode returns max 9 bytes + initBlock := make([]byte, 0, 9*2+len(N)+len(S)) + initBlock = append(initBlock, leftEncode(uint64(len(N)*8))...) + initBlock = append(initBlock, N...) + initBlock = append(initBlock, leftEncode(uint64(len(S)*8))...) + initBlock = append(initBlock, S...) + + switch id { + case CSHAKE_256: + c.state.rate = rate256 + c.state.dsbyte = dsbyteCShake + } + + c.initBlock = bytepad(initBlock, c.state.rate) + c.Write(c.initBlock) +} + +func (cs CShake) CShakeSum(out []byte, in []byte) (n int) { + d := cs.state + blocks := int(len(in) / d.rate) + + // Reset + d.buf = d.storage[:0] + d.state = spongeAbsorbing + for i, _ := range d.a { + d.a[i] = 0 + } + + // Absorb + for i := 0; i < blocks; i++ { + xorInUnaligned(&d, in[i*d.rate:(i+1)*d.rate]) + keccakF1600(&d.a) + } + d.buf = append(d.buf, in[blocks*d.rate:]...) + d.padAndPermute(d.dsbyte) + + // Now, do the squeezing. + n = len(out) + for len(out) > 0 { + n := copy(out[:], d.buf) + d.buf = d.buf[n:] + out = out[n:] + + // Apply the permutation if we've squeezed the sponge dry. + if len(d.buf) == 0 { + d.permute() + } + } + return n +} + // ShakeSum128 writes an arbitrary-length digest of data into hash. func ShakeSum128(hash, data []byte) { h := NewShake128() diff --git a/hash/shake/xor.go b/hash/shake/xor.go deleted file mode 100644 index b6b4370..0000000 --- a/hash/shake/xor.go +++ /dev/null @@ -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" diff --git a/hash/shake/xor_unaligned.go b/hash/shake/xor_unaligned.go index d5dd014..972966b 100644 --- a/hash/shake/xor_unaligned.go +++ b/hash/shake/xor_unaligned.go @@ -50,9 +50,4 @@ func copyOutUnaligned(d *state, buf []byte) { copy(buf, ab[:]) } -var ( - xorIn = xorInUnaligned - copyOut = copyOutUnaligned -) - const xorImplementationUnaligned = "unaligned"