LEFT | RIGHT |
(no file at all) | |
| 1 // Copyright 2013 The Go Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style |
| 3 // license that can be found in the LICENSE file. |
| 4 |
| 5 package sha3 |
| 6 |
| 7 // These tests are a subset of those provided by the Keccak web site(http://kecc
ak.noekeon.org/). |
| 8 |
| 9 import ( |
| 10 "bytes" |
| 11 "encoding/hex" |
| 12 "fmt" |
| 13 "hash" |
| 14 "strings" |
| 15 "testing" |
| 16 ) |
| 17 |
| 18 // testDigests maintains a digest state of each standard type. |
| 19 var testDigests = map[string]*digest{ |
| 20 "Keccak224": {outputSize: 224 / 8, capacity: 2 * 224 / 8}, |
| 21 "Keccak256": {outputSize: 256 / 8, capacity: 2 * 256 / 8}, |
| 22 "Keccak384": {outputSize: 384 / 8, capacity: 2 * 384 / 8}, |
| 23 "Keccak512": {outputSize: 512 / 8, capacity: 2 * 512 / 8}, |
| 24 } |
| 25 |
| 26 // testVector represents a test input and expected outputs from multiple algorit
hm variants. |
| 27 type testVector struct { |
| 28 desc string |
| 29 input []byte |
| 30 repeat int // input will be concatenated the input this many times. |
| 31 want map[string]string |
| 32 } |
| 33 |
| 34 // decodeHex converts an hex-encoded string into a raw byte string. |
| 35 func decodeHex(s string) []byte { |
| 36 b, err := hex.DecodeString(s) |
| 37 if err != nil { |
| 38 panic(err) |
| 39 } |
| 40 return b |
| 41 } |
| 42 |
| 43 // shortTestVectors stores a series of short testVectors. |
| 44 // Inputs of 8, 248, and 264 bits from http://keccak.noekeon.org/ are included b
elow. |
| 45 // The standard defines additional test inputs of all sizes between 0 and 2047 b
its. |
| 46 // Because the current implementation can only handle an integral number of byte
s, |
| 47 // most of the standard test inputs can't be used. |
| 48 var shortKeccakTestVectors = []testVector{ |
| 49 { |
| 50 desc: "short-8b", |
| 51 input: decodeHex("CC"), |
| 52 repeat: 1, |
| 53 want: map[string]string{ |
| 54 "Keccak224": "A9CAB59EB40A10B246290F2D6086E32E3689FAF1D2
6B470C899F2802", |
| 55 "Keccak256": "EEAD6DBFC7340A56CAEDC044696A168870549A6A7F
6F56961E84A54BD9970B8A", |
| 56 "Keccak384": "1B84E62A46E5A201861754AF5DC95C4A1A69CAF4A7
96AE405680161E29572641F5FA1E8641D7958336EE7B11C58F73E9", |
| 57 "Keccak512": "8630C13CBD066EA74BBE7FE468FEC1DEE10EDC1254
FB4C1B7C5FD69B646E44160B8CE01D05A0908CA790DFB080F4B513BC3B6225ECE7A810371441A5AC
666EB9", |
| 58 }, |
| 59 }, |
| 60 { |
| 61 desc: "short-248b", |
| 62 input: decodeHex("84FB51B517DF6C5ACCB5D022F8F28DA09B10232D42320
FFC32DBECC3835B29"), |
| 63 repeat: 1, |
| 64 want: map[string]string{ |
| 65 "Keccak224": "81AF3A7A5BD4C1F948D6AF4B96F93C3B0CF9C0E7A6
DA6FCD71EEC7F6", |
| 66 "Keccak256": "D477FB02CAAA95B3280EC8EE882C29D9E8A654B21E
F178E0F97571BF9D4D3C1C", |
| 67 "Keccak384": "503DCAA4ADDA5A9420B2E436DD62D9AB2E0254295C
2982EF67FCE40F117A2400AB492F7BD5D133C6EC2232268BC27B42", |
| 68 "Keccak512": "9D8098D8D6EDBBAA2BCFC6FB2F89C3EAC67FEC25CD
FE75AA7BD570A648E8C8945FF2EC280F6DCF73386109155C5BBC444C707BB42EAB873F5F7476657B
1BC1A8", |
| 69 }, |
| 70 }, |
| 71 { |
| 72 desc: "short-264b", |
| 73 input: decodeHex("DE8F1B3FAA4B7040ED4563C3B8E598253178E87E4D0DF
75E4FF2F2DEDD5A0BE046"), |
| 74 repeat: 1, |
| 75 want: map[string]string{ |
| 76 "Keccak224": "F217812E362EC64D4DC5EACFABC165184BFA456E5C
32C2C7900253D0", |
| 77 "Keccak256": "E78C421E6213AFF8DE1F025759A4F2C943DB62BBDE
359C8737E19B3776ED2DD2", |
| 78 "Keccak384": "CF38764973F1EC1C34B5433AE75A3AAD1AAEF6AB19
7850C56C8617BCD6A882F6666883AC17B2DCCDBAA647075D0972B5", |
| 79 "Keccak512": "9A7688E31AAF40C15575FC58C6B39267AAD3722E69
6E518A9945CF7F7C0FEA84CB3CB2E9F0384A6B5DC671ADE7FB4D2B27011173F3EEEAF17CB451CF26
542031", |
| 80 }, |
| 81 }, |
| 82 } |
| 83 |
| 84 // longTestVectors stores a single 64 MiB long testVector. |
| 85 // This is a prefix of the "very long" 1 GiB test vector defined in the Keccak s
tandard at |
| 86 // http://keccak.noekeon.org/. We truncate here to keep the running time on the
order of seconds. |
| 87 var longKeccakTestVectors = []testVector{ |
| 88 { |
| 89 desc: "long-64MiB", |
| 90 input: []byte("abcdefghbcdefghicdefghijdefghijkefghijklfghijklm
ghijklmnhijklmno"), |
| 91 repeat: 1024 * 1024, |
| 92 want: map[string]string{ |
| 93 "Keccak224": "50E35E40980FEEFF1EA490957B0E970257F75EA0D4
10EE0F0B8A7A58", |
| 94 "Keccak256": "5015A4935F0B51E091C6550A94DCD262C08998232C
CAA22E7F0756DEAC0DC0D0", |
| 95 "Keccak384": "7907A8D0FAA7BC6A90FE14C6C958C956A0877E7514
55D8F13ACDB96F144B5896E716C06EC0CB56557A94EF5C3355F6F3", |
| 96 "Keccak512": "3EC327D6759F769DEB74E80CA70C831BC29CAB048A
4BF4190E4A1DD5C6507CF2B4B58937FDE81D36014E7DFE1B1DD8B0F27CB7614F9A645FEC114F1DAA
EFC056", |
| 97 }, |
| 98 }, |
| 99 } |
| 100 |
| 101 // TestKeccakVectors checks that correct output is produced for a set of known t
estVectors. |
| 102 func TestKeccakVectors(t *testing.T) { |
| 103 testCases := append([]testVector{}, shortKeccakTestVectors...) |
| 104 if !testing.Short() { |
| 105 testCases = append(testCases, longKeccakTestVectors...) |
| 106 } |
| 107 for _, tc := range testCases { |
| 108 for alg, want := range tc.want { |
| 109 testDigests[alg].Reset() |
| 110 // Write input data each digests, based on the test spec
ification t. |
| 111 for i := 0; i < tc.repeat; i++ { |
| 112 testDigests[alg].Write(tc.input) |
| 113 } |
| 114 // Verify that each algorithm version produced the expec
ted output. |
| 115 got := strings.ToUpper(hex.EncodeToString(testDigests[al
g].Sum(nil))) |
| 116 if got != want { |
| 117 t.Errorf("%s, alg=%s\ngot %q, want %q", tc.desc,
alg, got, want) |
| 118 } |
| 119 } |
| 120 } |
| 121 } |
| 122 |
| 123 // dumpState is a debugging function to pretty-print the internal state of the h
ash. |
| 124 func (d *digest) dumpState() { |
| 125 fmt.Printf("SHA3 hash, %d B output, %d B capacity (%d B rate)\n", d.outp
utSize, d.capacity, d.rate()) |
| 126 fmt.Printf("Internal state after absorbing %d B:\n", d.absorbed) |
| 127 |
| 128 for x := 0; x < sliceSize; x++ { |
| 129 for y := 0; y < sliceSize; y++ { |
| 130 fmt.Printf("%v, ", d.a[x*sliceSize+y]) |
| 131 } |
| 132 fmt.Println("") |
| 133 } |
| 134 } |
| 135 |
| 136 // TestUnalignedWrite tests that writing data in an arbitrary pattern with small
input buffers. |
| 137 func TestUnalignedWrite(t *testing.T) { |
| 138 buf := sequentialBytes(0x10000) |
| 139 for alg, d := range testDigests { |
| 140 d.Reset() |
| 141 d.Write(buf) |
| 142 want := d.Sum(nil) |
| 143 d.Reset() |
| 144 for i := 0; i < len(buf); { |
| 145 // Cycle through offsets which make a 137 byte sequence. |
| 146 // Because 137 is prime this sequence should exercise al
l corner cases. |
| 147 offsets := [17]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
, 13, 14, 15, 16, 1} |
| 148 for _, j := range offsets { |
| 149 j = minInt(j, len(buf)-i) |
| 150 d.Write(buf[i : i+j]) |
| 151 i += j |
| 152 } |
| 153 } |
| 154 got := d.Sum(nil) |
| 155 if !bytes.Equal(got, want) { |
| 156 t.Errorf("Unaligned writes, alg=%s\ngot %q, want %q", al
g, got, want) |
| 157 } |
| 158 } |
| 159 } |
| 160 |
| 161 // sequentialBytes produces a buffer of size consecutive bytes 0x00, 0x01, ...,
used for testing. |
| 162 func sequentialBytes(size int) []byte { |
| 163 result := make([]byte, size) |
| 164 for i := range result { |
| 165 result[i] = byte(i) |
| 166 } |
| 167 return result |
| 168 } |
| 169 |
| 170 // benchmarkBlockWrite tests the speed of writing data and never calling the per
mutation function. |
| 171 func benchmarkBlockWrite(b *testing.B, d *digest) { |
| 172 b.StopTimer() |
| 173 d.Reset() |
| 174 // Write all but the last byte of a block, to ensure that the permutatio
n is not called. |
| 175 data := sequentialBytes(d.rate() - 1) |
| 176 b.SetBytes(int64(len(data))) |
| 177 b.StartTimer() |
| 178 for i := 0; i < b.N; i++ { |
| 179 d.absorbed = 0 // Reset absorbed to avoid ever calling the permu
tation function |
| 180 d.Write(data) |
| 181 } |
| 182 b.StopTimer() |
| 183 d.Reset() |
| 184 } |
| 185 |
| 186 // BenchmarkPermutationFunction measures the speed of the permutation function w
ith no input data. |
| 187 func BenchmarkPermutationFunction(b *testing.B) { |
| 188 b.StopTimer() |
| 189 d := testDigests["Keccak512"] |
| 190 d.Reset() |
| 191 b.SetBytes(int64(stateSize)) |
| 192 b.StartTimer() |
| 193 for i := 0; i < b.N; i++ { |
| 194 d.keccakF() |
| 195 } |
| 196 b.StopTimer() |
| 197 d.Reset() |
| 198 } |
| 199 |
| 200 // BenchmarkSingleByteWrite tests the latency from writing a single byte |
| 201 func BenchmarkSingleByteWrite(b *testing.B) { |
| 202 b.StopTimer() |
| 203 d := testDigests["Keccak512"] |
| 204 d.Reset() |
| 205 data := sequentialBytes(1) //1 byte buffer |
| 206 b.SetBytes(int64(d.rate()) - 1) |
| 207 b.StartTimer() |
| 208 for i := 0; i < b.N; i++ { |
| 209 d.absorbed = 0 // Reset absorbed to avoid ever calling the permu
tation function |
| 210 |
| 211 // Write all but the last byte of a block, one byte at a time. |
| 212 for j := 0; j < d.rate()-1; j++ { |
| 213 d.Write(data) |
| 214 } |
| 215 } |
| 216 b.StopTimer() |
| 217 d.Reset() |
| 218 } |
| 219 |
| 220 // BenchmarkSingleByteX measures the block write speed for each size of the dige
st. |
| 221 func BenchmarkBlockWrite512(b *testing.B) { benchmarkBlockWrite(b, testDigests["
Keccak512"]) } |
| 222 func BenchmarkBlockWrite384(b *testing.B) { benchmarkBlockWrite(b, testDigests["
Keccak384"]) } |
| 223 func BenchmarkBlockWrite256(b *testing.B) { benchmarkBlockWrite(b, testDigests["
Keccak256"]) } |
| 224 func BenchmarkBlockWrite224(b *testing.B) { benchmarkBlockWrite(b, testDigests["
Keccak224"]) } |
| 225 |
| 226 // benchmarkBulkHash tests the speed to hash a 16 KiB buffer. |
| 227 func benchmarkBulkHash(b *testing.B, h hash.Hash) { |
| 228 b.StopTimer() |
| 229 h.Reset() |
| 230 size := 1 << 14 |
| 231 data := sequentialBytes(size) |
| 232 b.SetBytes(int64(size)) |
| 233 b.StartTimer() |
| 234 |
| 235 for i := 0; i < b.N; i++ { |
| 236 h.Write(data) |
| 237 h.Sum(nil) |
| 238 } |
| 239 b.StopTimer() |
| 240 h.Reset() |
| 241 } |
| 242 |
| 243 // benchmarkBulkKeccakX test the speed to hash a 16 KiB buffer by calling benchm
arkBulkHash. |
| 244 func BenchmarkBulkKeccak512(b *testing.B) { benchmarkBulkHash(b, NewKeccak512())
} |
| 245 func BenchmarkBulkKeccak384(b *testing.B) { benchmarkBulkHash(b, NewKeccak384())
} |
| 246 func BenchmarkBulkKeccak256(b *testing.B) { benchmarkBulkHash(b, NewKeccak256())
} |
| 247 func BenchmarkBulkKeccak224(b *testing.B) { benchmarkBulkHash(b, NewKeccak224())
} |
LEFT | RIGHT |