blob: caf72f279f1a475f5e6402b3f1244906ddd0af4d [file] [log] [blame]
David Leon Gil1b32d8b2014-09-03 12:04:00 -07001// Copyright 2014 The Go Authors. All rights reserved.
Joseph Bonneau0bc0bcc2013-03-22 14:59:59 -04002// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package sha3
6
David Leon Gil1b32d8b2014-09-03 12:04:00 -07007// Tests include all the ShortMsgKATs provided by the Keccak team at
8// https://github.com/gvanas/KeccakCodePackage
9//
David Leon Gil4ed45ec2014-12-26 19:04:10 -080010// They only include the zero-bit case of the bitwise testvectors
11// published by NIST in the draft of FIPS-202.
Joseph Bonneau0bc0bcc2013-03-22 14:59:59 -040012
13import (
14 "bytes"
David Leon Gil1b32d8b2014-09-03 12:04:00 -070015 "compress/flate"
Joseph Bonneau0bc0bcc2013-03-22 14:59:59 -040016 "encoding/hex"
David Leon Gil1b32d8b2014-09-03 12:04:00 -070017 "encoding/json"
Joseph Bonneau0bc0bcc2013-03-22 14:59:59 -040018 "hash"
David Leon Gil1b32d8b2014-09-03 12:04:00 -070019 "os"
Joseph Bonneau0bc0bcc2013-03-22 14:59:59 -040020 "strings"
21 "testing"
22)
23
David Leon Gil1b32d8b2014-09-03 12:04:00 -070024const (
25 testString = "brekeccakkeccak koax koax"
David Leon Gilbfc28692015-01-24 13:42:34 -080026 katFilename = "testdata/keccakKats.json.deflate"
David Leon Gil1b32d8b2014-09-03 12:04:00 -070027)
28
29// Internal-use instances of SHAKE used to test against KATs.
30func newHashShake128() hash.Hash {
31 return &state{rate: 168, dsbyte: 0x1f, outputLen: 512}
32}
33func newHashShake256() hash.Hash {
34 return &state{rate: 136, dsbyte: 0x1f, outputLen: 512}
Joseph Bonneau0bc0bcc2013-03-22 14:59:59 -040035}
36
David Leon Gil1b32d8b2014-09-03 12:04:00 -070037// testDigests contains functions returning hash.Hash instances
38// with output-length equal to the KAT length for both SHA-3 and
39// SHAKE instances.
40var testDigests = map[string]func() hash.Hash{
41 "SHA3-224": New224,
42 "SHA3-256": New256,
43 "SHA3-384": New384,
44 "SHA3-512": New512,
45 "SHAKE128": newHashShake128,
46 "SHAKE256": newHashShake256,
47}
48
David Leon Gil4ed45ec2014-12-26 19:04:10 -080049// testShakes contains functions that return ShakeHash instances for
David Leon Gil1b32d8b2014-09-03 12:04:00 -070050// testing the ShakeHash-specific interface.
51var testShakes = map[string]func() ShakeHash{
52 "SHAKE128": NewShake128,
53 "SHAKE256": NewShake256,
Joseph Bonneau0bc0bcc2013-03-22 14:59:59 -040054}
55
David Leon Gil4ed45ec2014-12-26 19:04:10 -080056// decodeHex converts a hex-encoded string into a raw byte string.
Joseph Bonneau0bc0bcc2013-03-22 14:59:59 -040057func decodeHex(s string) []byte {
58 b, err := hex.DecodeString(s)
59 if err != nil {
60 panic(err)
61 }
62 return b
63}
64
David Leon Gil1b32d8b2014-09-03 12:04:00 -070065// structs used to marshal JSON test-cases.
66type KeccakKats struct {
67 Kats map[string][]struct {
68 Digest string `json:"digest"`
69 Length int64 `json:"length"`
70 Message string `json:"message"`
Joseph Bonneau0bc0bcc2013-03-22 14:59:59 -040071 }
David Leon Gil1b32d8b2014-09-03 12:04:00 -070072}
73
David Leon Gil4ed45ec2014-12-26 19:04:10 -080074func testUnalignedAndGeneric(t *testing.T, testf func(impl string)) {
75 xorInOrig, copyOutOrig := xorIn, copyOut
76 xorIn, copyOut = xorInGeneric, copyOutGeneric
77 testf("generic")
78 if xorImplementationUnaligned != "generic" {
79 xorIn, copyOut = xorInUnaligned, copyOutUnaligned
80 testf("unaligned")
81 }
82 xorIn, copyOut = xorInOrig, copyOutOrig
83}
84
David Leon Gil1b32d8b2014-09-03 12:04:00 -070085// TestKeccakKats tests the SHA-3 and Shake implementations against all the
86// ShortMsgKATs from https://github.com/gvanas/KeccakCodePackage
87// (The testvectors are stored in keccakKats.json.deflate due to their length.)
88func TestKeccakKats(t *testing.T) {
David Leon Gil4ed45ec2014-12-26 19:04:10 -080089 testUnalignedAndGeneric(t, func(impl string) {
90 // Read the KATs.
91 deflated, err := os.Open(katFilename)
92 if err != nil {
93 t.Errorf("error opening %s: %s", katFilename, err)
94 }
95 file := flate.NewReader(deflated)
96 dec := json.NewDecoder(file)
97 var katSet KeccakKats
98 err = dec.Decode(&katSet)
99 if err != nil {
100 t.Errorf("error decoding KATs: %s", err)
101 }
David Leon Gil1b32d8b2014-09-03 12:04:00 -0700102
David Leon Gil4ed45ec2014-12-26 19:04:10 -0800103 // Do the KATs.
104 for functionName, kats := range katSet.Kats {
105 d := testDigests[functionName]()
106 for _, kat := range kats {
107 d.Reset()
108 in, err := hex.DecodeString(kat.Message)
109 if err != nil {
110 t.Errorf("error decoding KAT: %s", err)
111 }
112 d.Write(in[:kat.Length/8])
113 got := strings.ToUpper(hex.EncodeToString(d.Sum(nil)))
114 if got != kat.Digest {
115 t.Errorf("function=%s, implementation=%s, length=%d\nmessage:\n %s\ngot:\n %s\nwanted:\n %s",
116 functionName, impl, kat.Length, kat.Message, got, kat.Digest)
117 t.Logf("wanted %+v", kat)
118 t.FailNow()
119 }
120 continue
Joseph Bonneau0bc0bcc2013-03-22 14:59:59 -0400121 }
122 }
David Leon Gil4ed45ec2014-12-26 19:04:10 -0800123 })
Joseph Bonneau0bc0bcc2013-03-22 14:59:59 -0400124}
125
David Leon Gil1b32d8b2014-09-03 12:04:00 -0700126// TestUnalignedWrite tests that writing data in an arbitrary pattern with
127// small input buffers.
David Leon Gil4ed45ec2014-12-26 19:04:10 -0800128func testUnalignedWrite(t *testing.T) {
129 testUnalignedAndGeneric(t, func(impl string) {
130 buf := sequentialBytes(0x10000)
131 for alg, df := range testDigests {
132 d := df()
133 d.Reset()
134 d.Write(buf)
135 want := d.Sum(nil)
136 d.Reset()
137 for i := 0; i < len(buf); {
138 // Cycle through offsets which make a 137 byte sequence.
139 // Because 137 is prime this sequence should exercise all corner cases.
140 offsets := [17]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1}
141 for _, j := range offsets {
142 if v := len(buf) - i; v < j {
143 j = v
144 }
145 d.Write(buf[i : i+j])
146 i += j
David Leon Gil1b32d8b2014-09-03 12:04:00 -0700147 }
David Leon Gil4ed45ec2014-12-26 19:04:10 -0800148 }
149 got := d.Sum(nil)
150 if !bytes.Equal(got, want) {
151 t.Errorf("Unaligned writes, implementation=%s, alg=%s\ngot %q, want %q", impl, alg, got, want)
Joseph Bonneau0bc0bcc2013-03-22 14:59:59 -0400152 }
153 }
David Leon Gil4ed45ec2014-12-26 19:04:10 -0800154 })
Joseph Bonneau0bc0bcc2013-03-22 14:59:59 -0400155}
156
David Leon Gil4ed45ec2014-12-26 19:04:10 -0800157// TestAppend checks that appending works when reallocation is necessary.
Joseph Bonneau0bc0bcc2013-03-22 14:59:59 -0400158func TestAppend(t *testing.T) {
David Leon Gil4ed45ec2014-12-26 19:04:10 -0800159 testUnalignedAndGeneric(t, func(impl string) {
160 d := New224()
Joseph Bonneau0bc0bcc2013-03-22 14:59:59 -0400161
Glenn Brownbc65b902015-04-15 17:38:08 -0700162 for capacity := 2; capacity <= 66; capacity += 64 {
David Leon Gil4ed45ec2014-12-26 19:04:10 -0800163 // The first time around the loop, Sum will have to reallocate.
164 // The second time, it will not.
165 buf := make([]byte, 2, capacity)
166 d.Reset()
167 d.Write([]byte{0xcc})
168 buf = d.Sum(buf)
169 expected := "0000DF70ADC49B2E76EEE3A6931B93FA41841C3AF2CDF5B32A18B5478C39"
170 if got := strings.ToUpper(hex.EncodeToString(buf)); got != expected {
171 t.Errorf("got %s, want %s", got, expected)
172 }
173 }
174 })
175}
176
177// TestAppendNoRealloc tests that appending works when no reallocation is necessary.
178func TestAppendNoRealloc(t *testing.T) {
179 testUnalignedAndGeneric(t, func(impl string) {
180 buf := make([]byte, 1, 200)
181 d := New224()
Joseph Bonneau0bc0bcc2013-03-22 14:59:59 -0400182 d.Write([]byte{0xcc})
183 buf = d.Sum(buf)
David Leon Gil4ed45ec2014-12-26 19:04:10 -0800184 expected := "00DF70ADC49B2E76EEE3A6931B93FA41841C3AF2CDF5B32A18B5478C39"
Joseph Bonneau0bc0bcc2013-03-22 14:59:59 -0400185 if got := strings.ToUpper(hex.EncodeToString(buf)); got != expected {
David Leon Gil4ed45ec2014-12-26 19:04:10 -0800186 t.Errorf("%s: got %s, want %s", impl, got, expected)
Joseph Bonneau0bc0bcc2013-03-22 14:59:59 -0400187 }
David Leon Gil4ed45ec2014-12-26 19:04:10 -0800188 })
Joseph Bonneau0bc0bcc2013-03-22 14:59:59 -0400189}
190
David Leon Gil1b32d8b2014-09-03 12:04:00 -0700191// TestSqueezing checks that squeezing the full output a single time produces
192// the same output as repeatedly squeezing the instance.
193func TestSqueezing(t *testing.T) {
David Leon Gil4ed45ec2014-12-26 19:04:10 -0800194 testUnalignedAndGeneric(t, func(impl string) {
195 for functionName, newShakeHash := range testShakes {
196 d0 := newShakeHash()
197 d0.Write([]byte(testString))
198 ref := make([]byte, 32)
199 d0.Read(ref)
David Leon Gil1b32d8b2014-09-03 12:04:00 -0700200
David Leon Gil4ed45ec2014-12-26 19:04:10 -0800201 d1 := newShakeHash()
202 d1.Write([]byte(testString))
203 var multiple []byte
204 for _ = range ref {
205 one := make([]byte, 1)
206 d1.Read(one)
207 multiple = append(multiple, one...)
208 }
209 if !bytes.Equal(ref, multiple) {
210 t.Errorf("%s (%s): squeezing %d bytes one at a time failed", functionName, impl, len(ref))
211 }
David Leon Gil1b32d8b2014-09-03 12:04:00 -0700212 }
David Leon Gil4ed45ec2014-12-26 19:04:10 -0800213 })
David Leon Gil1b32d8b2014-09-03 12:04:00 -0700214}
215
Joseph Bonneau0bc0bcc2013-03-22 14:59:59 -0400216// sequentialBytes produces a buffer of size consecutive bytes 0x00, 0x01, ..., used for testing.
217func sequentialBytes(size int) []byte {
218 result := make([]byte, size)
219 for i := range result {
220 result[i] = byte(i)
221 }
222 return result
223}
224
David Leon Gil1b32d8b2014-09-03 12:04:00 -0700225// BenchmarkPermutationFunction measures the speed of the permutation function
226// with no input data.
Joseph Bonneau0bc0bcc2013-03-22 14:59:59 -0400227func BenchmarkPermutationFunction(b *testing.B) {
David Leon Gil1b32d8b2014-09-03 12:04:00 -0700228 b.SetBytes(int64(200))
229 var lanes [25]uint64
Joseph Bonneau0bc0bcc2013-03-22 14:59:59 -0400230 for i := 0; i < b.N; i++ {
David Leon Gil1b32d8b2014-09-03 12:04:00 -0700231 keccakF1600(&lanes)
Joseph Bonneau0bc0bcc2013-03-22 14:59:59 -0400232 }
Joseph Bonneau0bc0bcc2013-03-22 14:59:59 -0400233}
234
David Leon Gil4ed45ec2014-12-26 19:04:10 -0800235// benchmarkHash tests the speed to hash num buffers of buflen each.
236func benchmarkHash(b *testing.B, h hash.Hash, size, num int) {
Joseph Bonneau0bc0bcc2013-03-22 14:59:59 -0400237 b.StopTimer()
238 h.Reset()
Joseph Bonneau0bc0bcc2013-03-22 14:59:59 -0400239 data := sequentialBytes(size)
David Leon Gil4ed45ec2014-12-26 19:04:10 -0800240 b.SetBytes(int64(size * num))
Joseph Bonneau0bc0bcc2013-03-22 14:59:59 -0400241 b.StartTimer()
242
David Leon Gil1b32d8b2014-09-03 12:04:00 -0700243 var state []byte
Joseph Bonneau0bc0bcc2013-03-22 14:59:59 -0400244 for i := 0; i < b.N; i++ {
David Leon Gil4ed45ec2014-12-26 19:04:10 -0800245 for j := 0; j < num; j++ {
246 h.Write(data)
247 }
David Leon Gil1b32d8b2014-09-03 12:04:00 -0700248 state = h.Sum(state[:0])
Joseph Bonneau0bc0bcc2013-03-22 14:59:59 -0400249 }
250 b.StopTimer()
251 h.Reset()
252}
253
David Leon Gil4ed45ec2014-12-26 19:04:10 -0800254// benchmarkShake is specialized to the Shake instances, which don't
255// require a copy on reading output.
256func benchmarkShake(b *testing.B, h ShakeHash, size, num int) {
257 b.StopTimer()
258 h.Reset()
259 data := sequentialBytes(size)
260 d := make([]byte, 32)
David Leon Gil1b32d8b2014-09-03 12:04:00 -0700261
David Leon Gil4ed45ec2014-12-26 19:04:10 -0800262 b.SetBytes(int64(size * num))
263 b.StartTimer()
264
265 for i := 0; i < b.N; i++ {
266 h.Reset()
267 for j := 0; j < num; j++ {
268 h.Write(data)
269 }
270 h.Read(d)
271 }
272}
273
274func BenchmarkSha3_512_MTU(b *testing.B) { benchmarkHash(b, New512(), 1350, 1) }
275func BenchmarkSha3_384_MTU(b *testing.B) { benchmarkHash(b, New384(), 1350, 1) }
276func BenchmarkSha3_256_MTU(b *testing.B) { benchmarkHash(b, New256(), 1350, 1) }
277func BenchmarkSha3_224_MTU(b *testing.B) { benchmarkHash(b, New224(), 1350, 1) }
278
279func BenchmarkShake128_MTU(b *testing.B) { benchmarkShake(b, NewShake128(), 1350, 1) }
280func BenchmarkShake256_MTU(b *testing.B) { benchmarkShake(b, NewShake256(), 1350, 1) }
281func BenchmarkShake256_16x(b *testing.B) { benchmarkShake(b, NewShake256(), 16, 1024) }
282func BenchmarkShake256_1MiB(b *testing.B) { benchmarkShake(b, NewShake256(), 1024, 1024) }
283
284func BenchmarkSha3_512_1MiB(b *testing.B) { benchmarkHash(b, New512(), 1024, 1024) }
285
286func Example_sum() {
287 buf := []byte("some data to hash")
288 // A hash needs to be 64 bytes long to have 256-bit collision resistance.
289 h := make([]byte, 64)
290 // Compute a 64-byte hash of buf and put it in h.
291 ShakeSum256(h, buf)
292}
293
294func Example_mac() {
295 k := []byte("this is a secret key; you should generate a strong random key that's at least 32 bytes long")
296 buf := []byte("and this is some data to authenticate")
297 // A MAC with 32 bytes of output has 256-bit security strength -- if you use at least a 32-byte-long key.
298 h := make([]byte, 32)
299 d := NewShake256()
300 // Write the key into the hash.
301 d.Write(k)
302 // Now write the data.
303 d.Write(buf)
304 // Read 32 bytes of output from the hash into h.
305 d.Read(h)
306}