diff options
author | root <sina@snix.ir> | 2022-07-19 04:29:51 +0000 |
---|---|---|
committer | root <sina@snix.ir> | 2022-07-19 04:29:51 +0000 |
commit | 1c5dc8ea997b8cd42bf40c7638a52fd0f7fb530a (patch) | |
tree | 59415ec755f8d9e6f0449192d86572ee92eb3539 /poly1305_test.go |
poly1305 snix repo
Diffstat (limited to 'poly1305_test.go')
-rw-r--r-- | poly1305_test.go | 276 |
1 files changed, 276 insertions, 0 deletions
diff --git a/poly1305_test.go b/poly1305_test.go new file mode 100644 index 0000000..e7ec6d1 --- /dev/null +++ b/poly1305_test.go @@ -0,0 +1,276 @@ +// Copyright 2012 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. + +package poly1305 + +import ( + "crypto/rand" + "encoding/binary" + "encoding/hex" + "flag" + "testing" + "unsafe" +) + +var stressFlag = flag.Bool("stress", false, "run slow stress tests") + +type test struct { + in string + key string + tag string + state string +} + +func (t *test) Input() []byte { + in, err := hex.DecodeString(t.in) + if err != nil { + panic(err) + } + return in +} + +func (t *test) Key() [32]byte { + buf, err := hex.DecodeString(t.key) + if err != nil { + panic(err) + } + var key [32]byte + copy(key[:], buf[:32]) + return key +} + +func (t *test) Tag() [16]byte { + buf, err := hex.DecodeString(t.tag) + if err != nil { + panic(err) + } + var tag [16]byte + copy(tag[:], buf[:16]) + return tag +} + +func (t *test) InitialState() [3]uint64 { + // state is hex encoded in big-endian byte order + if t.state == "" { + return [3]uint64{0, 0, 0} + } + buf, err := hex.DecodeString(t.state) + if err != nil { + panic(err) + } + if len(buf) != 3*8 { + panic("incorrect state length") + } + return [3]uint64{ + binary.BigEndian.Uint64(buf[16:24]), + binary.BigEndian.Uint64(buf[8:16]), + binary.BigEndian.Uint64(buf[0:8]), + } +} + +func testSum(t *testing.T, unaligned bool, sumImpl func(tag *[TagSize]byte, msg []byte, key *[32]byte)) { + var tag [16]byte + for i, v := range testData { + // cannot set initial state before calling sum, so skip those tests + if v.InitialState() != [3]uint64{0, 0, 0} { + continue + } + + in := v.Input() + if unaligned { + in = unalignBytes(in) + } + key := v.Key() + sumImpl(&tag, in, &key) + if tag != v.Tag() { + t.Errorf("%d: expected %x, got %x", i, v.Tag(), tag[:]) + } + if !Verify(&tag, in, &key) { + t.Errorf("%d: tag didn't verify", i) + } + // If the key is zero, the tag will always be zero, independent of the input. + if len(in) > 0 && key != [32]byte{} { + in[0] ^= 0xff + if Verify(&tag, in, &key) { + t.Errorf("%d: tag verified after altering the input", i) + } + in[0] ^= 0xff + } + // If the input is empty, the tag only depends on the second half of the key. + if len(in) > 0 { + key[0] ^= 0xff + if Verify(&tag, in, &key) { + t.Errorf("%d: tag verified after altering the key", i) + } + key[0] ^= 0xff + } + tag[0] ^= 0xff + if Verify(&tag, in, &key) { + t.Errorf("%d: tag verified after altering the tag", i) + } + tag[0] ^= 0xff + } +} + +func TestBurnin(t *testing.T) { + // This test can be used to sanity-check significant changes. It can + // take about many minutes to run, even on fast machines. It's disabled + // by default. + if !*stressFlag { + t.Skip("skipping without -stress") + } + + var key [32]byte + var input [25]byte + var output [16]byte + + for i := range key { + key[i] = 1 + } + for i := range input { + input[i] = 2 + } + + for i := uint64(0); i < 1e10; i++ { + Sum(&output, input[:], &key) + copy(key[0:], output[:]) + copy(key[16:], output[:]) + copy(input[:], output[:]) + copy(input[16:], output[:]) + } + + const expected = "5e3b866aea0b636d240c83c428f84bfa" + if got := hex.EncodeToString(output[:]); got != expected { + t.Errorf("expected %s, got %s", expected, got) + } +} + +func TestSum(t *testing.T) { testSum(t, false, Sum) } +func TestSumUnaligned(t *testing.T) { testSum(t, true, Sum) } +func TestSumGeneric(t *testing.T) { testSum(t, false, sumGeneric) } +func TestSumGenericUnaligned(t *testing.T) { testSum(t, true, sumGeneric) } + +func TestWriteGeneric(t *testing.T) { testWriteGeneric(t, false) } +func TestWriteGenericUnaligned(t *testing.T) { testWriteGeneric(t, true) } +func TestWrite(t *testing.T) { testWrite(t, false) } +func TestWriteUnaligned(t *testing.T) { testWrite(t, true) } + +func testWriteGeneric(t *testing.T, unaligned bool) { + for i, v := range testData { + key := v.Key() + input := v.Input() + var out [16]byte + + if unaligned { + input = unalignBytes(input) + } + h := newMACGeneric(&key) + if s := v.InitialState(); s != [3]uint64{0, 0, 0} { + h.macState.h = s + } + n, err := h.Write(input[:len(input)/3]) + if err != nil || n != len(input[:len(input)/3]) { + t.Errorf("#%d: unexpected Write results: n = %d, err = %v", i, n, err) + } + n, err = h.Write(input[len(input)/3:]) + if err != nil || n != len(input[len(input)/3:]) { + t.Errorf("#%d: unexpected Write results: n = %d, err = %v", i, n, err) + } + h.Sum(&out) + if tag := v.Tag(); out != tag { + t.Errorf("%d: expected %x, got %x", i, tag[:], out[:]) + } + } +} + +func testWrite(t *testing.T, unaligned bool) { + for i, v := range testData { + key := v.Key() + input := v.Input() + var out [16]byte + + if unaligned { + input = unalignBytes(input) + } + h := New(&key) + if s := v.InitialState(); s != [3]uint64{0, 0, 0} { + h.macState.h = s + } + n, err := h.Write(input[:len(input)/3]) + if err != nil || n != len(input[:len(input)/3]) { + t.Errorf("#%d: unexpected Write results: n = %d, err = %v", i, n, err) + } + n, err = h.Write(input[len(input)/3:]) + if err != nil || n != len(input[len(input)/3:]) { + t.Errorf("#%d: unexpected Write results: n = %d, err = %v", i, n, err) + } + h.Sum(out[:0]) + tag := v.Tag() + if out != tag { + t.Errorf("%d: expected %x, got %x", i, tag[:], out[:]) + } + if !h.Verify(tag[:]) { + t.Errorf("%d: Verify failed", i) + } + tag[0] ^= 0xff + if h.Verify(tag[:]) { + t.Errorf("%d: Verify succeeded after modifying the tag", i) + } + } +} + +func benchmarkSum(b *testing.B, size int, unaligned bool) { + var out [16]byte + var key [32]byte + in := make([]byte, size) + if unaligned { + in = unalignBytes(in) + } + rand.Read(in) + b.SetBytes(int64(len(in))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + Sum(&out, in, &key) + } +} + +func benchmarkWrite(b *testing.B, size int, unaligned bool) { + var key [32]byte + h := New(&key) + in := make([]byte, size) + if unaligned { + in = unalignBytes(in) + } + rand.Read(in) + b.SetBytes(int64(len(in))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + h.Write(in) + } +} + +func Benchmark64(b *testing.B) { benchmarkSum(b, 64, false) } +func Benchmark1K(b *testing.B) { benchmarkSum(b, 1024, false) } +func Benchmark2M(b *testing.B) { benchmarkSum(b, 2*1024*1024, false) } +func Benchmark64Unaligned(b *testing.B) { benchmarkSum(b, 64, true) } +func Benchmark1KUnaligned(b *testing.B) { benchmarkSum(b, 1024, true) } +func Benchmark2MUnaligned(b *testing.B) { benchmarkSum(b, 2*1024*1024, true) } + +func BenchmarkWrite64(b *testing.B) { benchmarkWrite(b, 64, false) } +func BenchmarkWrite1K(b *testing.B) { benchmarkWrite(b, 1024, false) } +func BenchmarkWrite2M(b *testing.B) { benchmarkWrite(b, 2*1024*1024, false) } +func BenchmarkWrite64Unaligned(b *testing.B) { benchmarkWrite(b, 64, true) } +func BenchmarkWrite1KUnaligned(b *testing.B) { benchmarkWrite(b, 1024, true) } +func BenchmarkWrite2MUnaligned(b *testing.B) { benchmarkWrite(b, 2*1024*1024, true) } + +func unalignBytes(in []byte) []byte { + out := make([]byte, len(in)+1) + if uintptr(unsafe.Pointer(&out[0]))&(unsafe.Alignof(uint32(0))-1) == 0 { + out = out[1:] + } else { + out = out[:len(in)] + } + copy(out, in) + return out +} |