Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

internal: add TurboShake{128,256} #430

Merged
merged 1 commit into from May 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 10 additions & 2 deletions internal/sha3/keccakf.go
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
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
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
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
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
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
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