Skip to content

Commit

Permalink
Add TurboShake{128,256}
Browse files Browse the repository at this point in the history
  • Loading branch information
bwesterb authored and armfazh committed May 3, 2023
1 parent 3bef500 commit 90d7565
Show file tree
Hide file tree
Showing 23 changed files with 271 additions and 94 deletions.
12 changes: 10 additions & 2 deletions internal/sha3/keccakf.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,21 @@ package sha3

// KeccakF1600 applies the Keccak permutation to a 1600b-wide
// state represented as a slice of 25 uint64s.
// If turbo is true, applies the 12-round variant instead of the
// regular 24-round variant.
// nolint:funlen
func KeccakF1600(a *[25]uint64) {
func KeccakF1600(a *[25]uint64, turbo bool) {
// Implementation translated from Keccak-inplace.c
// in the keccak reference code.
var t, bc0, bc1, bc2, bc3, bc4, d0, d1, d2, d3, d4 uint64

for i := 0; i < 24; i += 4 {
i := 0

if turbo {
i = 12
}

for ; i < 24; i += 4 {
// Combines the 5 steps in each round into 2 steps.
// Unrolls 4 rounds per loop and spreads some steps across rounds.

Expand Down
7 changes: 4 additions & 3 deletions internal/sha3/sha3.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ type State struct {
// Specific to SHA-3 and SHAKE.
outputLen int // the default output size in bytes
state spongeDirection // whether the sponge is absorbing or squeezing
turbo bool // Whether we're using 12 rounds instead of 24
}

// BlockSize returns the rate of sponge underlying this hash function.
Expand Down Expand Up @@ -86,11 +87,11 @@ func (d *State) permute() {
xorIn(d, d.buf())
d.bufe = 0
d.bufo = 0
KeccakF1600(&d.a)
KeccakF1600(&d.a, d.turbo)
case spongeSqueezing:
// If we're squeezing, we need to apply the permutation before
// copying more output.
KeccakF1600(&d.a)
KeccakF1600(&d.a, d.turbo)
d.bufe = d.rate
d.bufo = 0
copyOut(d, d.buf())
Expand Down Expand Up @@ -136,7 +137,7 @@ func (d *State) Write(p []byte) (written int, err error) {
// The fast path; absorb a full "rate" bytes of input and apply the permutation.
xorIn(d, p[:d.rate])
p = p[d.rate:]
KeccakF1600(&d.a)
KeccakF1600(&d.a, d.turbo)
} else {
// The slow path; buffer the input until we can fill the sponge, and then xor it in.
todo := d.rate - bufl
Expand Down
38 changes: 37 additions & 1 deletion internal/sha3/sha3_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,13 +161,23 @@ func sequentialBytes(size int) []byte {
return result
}

// BenchmarkPermutationFunctionTurbo measures the speed of the permutation
// function with no input data.
func BenchmarkPermutationFunctionTurbo(b *testing.B) {
b.SetBytes(int64(200))
var lanes [25]uint64
for i := 0; i < b.N; i++ {
KeccakF1600(&lanes, true)
}
}

// BenchmarkPermutationFunction measures the speed of the permutation function
// with no input data.
func BenchmarkPermutationFunction(b *testing.B) {
b.SetBytes(int64(200))
var lanes [25]uint64
for i := 0; i < b.N; i++ {
KeccakF1600(&lanes)
KeccakF1600(&lanes, false)
}
}

Expand Down Expand Up @@ -220,6 +230,9 @@ func BenchmarkShake256_MTU(b *testing.B) { benchmarkShake(b, NewShake256(), 135
func BenchmarkShake256_16x(b *testing.B) { benchmarkShake(b, NewShake256(), 16, 1024) }
func BenchmarkShake256_1MiB(b *testing.B) { benchmarkShake(b, NewShake256(), 1024, 1024) }

func BenchmarkTurboShake128_1MiB(b *testing.B) { benchmarkShake(b, NewTurboShake128(0x37), 1024, 1024) }
func BenchmarkTurboShake256_1MiB(b *testing.B) { benchmarkShake(b, NewTurboShake256(0x37), 1024, 1024) }

func BenchmarkSha3_512_1MiB(b *testing.B) { benchmarkHash(b, New512(), 1024, 1024) }

func Example_sum() {
Expand Down Expand Up @@ -247,3 +260,26 @@ func Example_mac() {
fmt.Printf("%x\n", h)
// Output: 78de2974bd2711d5549ffd32b753ef0f5fa80a0db2556db60f0987eb8a9218ff
}

func TestTurboShake128(t *testing.T) {
out := make([]byte, 64)
TurboShakeSum128(out, []byte{}, 0x07)
if hex.EncodeToString(out) != "5a223ad30b3b8c66a243048cfced430f54e7529287d15150b973133adfac6a2ffe2708e73061e09a4000168ba9c8ca1813198f7bbed4984b4185f2c2580ee623" {
t.Fatal()
}

h := NewTurboShake128(0x07)
out = make([]byte, 10032)
_, _ = h.Read(out)
if hex.EncodeToString(out[len(out)-32:]) != "7593a28020a3c4ae0d605fd61f5eb56eccd27cc3d12ff09f78369772a460c55d" {
t.Fatal()
}

out = make([]byte, 32)
TurboShakeSum128(out, []byte{0xff}, 0x06)
if hex.EncodeToString(out) != "8ec9c66465ed0d4a6c35d13506718d687a25cb05c74cca1e42501abd83874a67" {
t.Fatal()
}

// TODO all tests
}
36 changes: 36 additions & 0 deletions internal/sha3/shake.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,35 @@ func NewShake128() State {
return State{rate: rate128, dsbyte: dsbyteShake}
}

// NewTurboShake128 creates a new TurboSHAKE128 variable-output-length ShakeHash.
// Its generic security strength is 128 bits against all attacks if at
// least 32 bytes of its output are used.
// D is the domain separation byte and must be between 0x01 and 0x7f inclusive.
func NewTurboShake128(D byte) State {
if D == 0 || D > 0x7f {
panic("turboshake: D out of range")
}
return State{rate: rate128, dsbyte: D, turbo: true}
}

// NewShake256 creates a new SHAKE256 variable-output-length ShakeHash.
// Its generic security strength is 256 bits against all attacks if
// at least 64 bytes of its output are used.
func NewShake256() State {
return State{rate: rate256, dsbyte: dsbyteShake}
}

// NewTurboShake256 creates a new TurboSHAKE256 variable-output-length ShakeHash.
// Its generic security strength is 256 bits against all attacks if
// at least 64 bytes of its output are used.
// D is the domain separation byte and must be between 0x01 and 0x7f inclusive.
func NewTurboShake256(D byte) State {
if D == 0 || D > 0x7f {
panic("turboshake: D out of range")
}
return State{rate: rate256, dsbyte: D, turbo: true}
}

// ShakeSum128 writes an arbitrary-length digest of data into hash.
func ShakeSum128(hash, data []byte) {
h := NewShake128()
Expand All @@ -77,3 +99,17 @@ func ShakeSum256(hash, data []byte) {
_, _ = h.Write(data)
_, _ = h.Read(hash)
}

// TurboShakeSum128 writes an arbitrary-length digest of data into hash.
func TurboShakeSum128(hash, data []byte, D byte) {
h := NewTurboShake128(D)
_, _ = h.Write(data)
_, _ = h.Read(hash)
}

// TurboShakeSum256 writes an arbitrary-length digest of data into hash.
func TurboShakeSum256(hash, data []byte, D byte) {
h := NewTurboShake256(D)
_, _ = h.Write(data)
_, _ = h.Read(hash)
}
2 changes: 1 addition & 1 deletion pke/kyber/internal/common/sample.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ func (p *Poly) DeriveNoise2(seed []byte, nonce uint8) {
// Can only be called when DeriveX4Available is true.
func PolyDeriveUniformX4(ps [4]*Poly, seed *[32]byte, xs, ys [4]uint8) {
var perm keccakf1600.StateX4
state := perm.Initialize()
state := perm.Initialize(false)

// Absorb the seed in the four states
for i := 0; i < 4; i++ {
Expand Down
4 changes: 2 additions & 2 deletions sign/dilithium/mode2/internal/sample.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions sign/dilithium/mode2aes/internal/sample.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions sign/dilithium/mode3/internal/sample.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ var DeriveX4Available = keccakf1600.IsEnabledX4() && !UseAES
// Can only be called when DeriveX4Available is true.
func PolyDeriveUniformX4(ps [4]*common.Poly, seed *[32]byte, nonces [4]uint16) {
var perm keccakf1600.StateX4
state := perm.Initialize()
state := perm.Initialize(false)

// Absorb the seed in the four states
for i := 0; i < 4; i++ {
Expand Down Expand Up @@ -246,7 +246,7 @@ func PolyDeriveUniformLeGamma1(p *common.Poly, seed *[64]byte, nonce uint16) {
// This function is currently not used (yet).
func PolyDeriveUniformBallX4(ps [4]*common.Poly, seed *[32]byte) {
var perm keccakf1600.StateX4
state := perm.Initialize()
state := perm.Initialize(false)

// Absorb the seed in the four states
for i := 0; i < 4; i++ {
Expand Down
4 changes: 2 additions & 2 deletions sign/dilithium/mode3aes/internal/sample.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions sign/dilithium/mode5/internal/sample.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions sign/dilithium/mode5aes/internal/sample.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion simd/keccakf1600/example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func Example() {
// type is used to ensure that the encapsulated [100]uint64 is aligned
// properly to be used efficiently with vector instructions.)
var perm keccakf1600.StateX4
state := perm.Initialize()
state := perm.Initialize(false)

// state is initialized with zeroes. As the messages fit within one
// block, we only need to write the messages, domain separators
Expand Down
Loading

0 comments on commit 90d7565

Please sign in to comment.