github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/crypto/sha3/sha3_test.go (about) 1 // Copyright 2014 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 // Tests include all the ShortMsgKATs provided by the Keccak team at 8 // https://github.com/gvanas/KeccakCodePackage 9 // 10 // They only include the zero-bit case of the bitwise testvectors 11 // published by NIST in the draft of FIPS-202. 12 13 import ( 14 "bytes" 15 "compress/flate" 16 "encoding/hex" 17 "encoding/json" 18 "hash" 19 "os" 20 "strings" 21 "testing" 22 ) 23 24 const ( 25 testString = "brekeccakkeccak koax koax" 26 katFilename = "testdata/keccakKats.json.deflate" 27 ) 28 29 // Internal-use instances of SHAKE used to test against KATs. 30 func newHashShake128() hash.Hash { 31 return &state{rate: 168, dsbyte: 0x1f, outputLen: 512} 32 } 33 func newHashShake256() hash.Hash { 34 return &state{rate: 136, dsbyte: 0x1f, outputLen: 512} 35 } 36 37 // testDigests contains functions returning hash.Hash instances 38 // with output-length equal to the KAT length for both SHA-3 and 39 // SHAKE instances. 40 var 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 49 // testShakes contains functions that return ShakeHash instances for 50 // testing the ShakeHash-specific interface. 51 var testShakes = map[string]func() ShakeHash{ 52 "SHAKE128": NewShake128, 53 "SHAKE256": NewShake256, 54 } 55 56 // decodeHex converts a hex-encoded string into a raw byte string. 57 func decodeHex(s string) []byte { 58 b, err := hex.DecodeString(s) 59 if err != nil { 60 panic(err) 61 } 62 return b 63 } 64 65 // structs used to marshal JSON test-cases. 66 type KeccakKats struct { 67 Kats map[string][]struct { 68 Digest string `json:"digest"` 69 Length int64 `json:"length"` 70 Message string `json:"message"` 71 } 72 } 73 74 func 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 85 // 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.) 88 func TestKeccakKats(t *testing.T) { 89 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 } 102 103 // 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 121 } 122 } 123 }) 124 } 125 126 // TestUnalignedWrite tests that writing data in an arbitrary pattern with 127 // small input buffers. 128 func 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 147 } 148 } 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) 152 } 153 } 154 }) 155 } 156 157 // TestAppend checks that appending works when reallocation is necessary. 158 func TestAppend(t *testing.T) { 159 testUnalignedAndGeneric(t, func(impl string) { 160 d := New224() 161 162 for capacity := 2; capacity <= 66; capacity += 64 { 163 // 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. 178 func TestAppendNoRealloc(t *testing.T) { 179 testUnalignedAndGeneric(t, func(impl string) { 180 buf := make([]byte, 1, 200) 181 d := New224() 182 d.Write([]byte{0xcc}) 183 buf = d.Sum(buf) 184 expected := "00DF70ADC49B2E76EEE3A6931B93FA41841C3AF2CDF5B32A18B5478C39" 185 if got := strings.ToUpper(hex.EncodeToString(buf)); got != expected { 186 t.Errorf("%s: got %s, want %s", impl, got, expected) 187 } 188 }) 189 } 190 191 // TestSqueezing checks that squeezing the full output a single time produces 192 // the same output as repeatedly squeezing the instance. 193 func TestSqueezing(t *testing.T) { 194 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) 200 201 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 } 212 } 213 }) 214 } 215 216 // sequentialBytes produces a buffer of size consecutive bytes 0x00, 0x01, ..., used for testing. 217 func 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 225 // BenchmarkPermutationFunction measures the speed of the permutation function 226 // with no input data. 227 func BenchmarkPermutationFunction(b *testing.B) { 228 b.SetBytes(int64(200)) 229 var lanes [25]uint64 230 for i := 0; i < b.N; i++ { 231 keccakF1600(&lanes) 232 } 233 } 234 235 // benchmarkHash tests the speed to hash num buffers of buflen each. 236 func benchmarkHash(b *testing.B, h hash.Hash, size, num int) { 237 b.StopTimer() 238 h.Reset() 239 data := sequentialBytes(size) 240 b.SetBytes(int64(size * num)) 241 b.StartTimer() 242 243 var state []byte 244 for i := 0; i < b.N; i++ { 245 for j := 0; j < num; j++ { 246 h.Write(data) 247 } 248 state = h.Sum(state[:0]) 249 } 250 b.StopTimer() 251 h.Reset() 252 } 253 254 // benchmarkShake is specialized to the Shake instances, which don't 255 // require a copy on reading output. 256 func benchmarkShake(b *testing.B, h ShakeHash, size, num int) { 257 b.StopTimer() 258 h.Reset() 259 data := sequentialBytes(size) 260 d := make([]byte, 32) 261 262 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 274 func BenchmarkSha3_512_MTU(b *testing.B) { benchmarkHash(b, New512(), 1350, 1) } 275 func BenchmarkSha3_384_MTU(b *testing.B) { benchmarkHash(b, New384(), 1350, 1) } 276 func BenchmarkSha3_256_MTU(b *testing.B) { benchmarkHash(b, New256(), 1350, 1) } 277 func BenchmarkSha3_224_MTU(b *testing.B) { benchmarkHash(b, New224(), 1350, 1) } 278 279 func BenchmarkShake128_MTU(b *testing.B) { benchmarkShake(b, NewShake128(), 1350, 1) } 280 func BenchmarkShake256_MTU(b *testing.B) { benchmarkShake(b, NewShake256(), 1350, 1) } 281 func BenchmarkShake256_16x(b *testing.B) { benchmarkShake(b, NewShake256(), 16, 1024) } 282 func BenchmarkShake256_1MiB(b *testing.B) { benchmarkShake(b, NewShake256(), 1024, 1024) } 283 284 func BenchmarkSha3_512_1MiB(b *testing.B) { benchmarkHash(b, New512(), 1024, 1024) } 285 286 func 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 294 func 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 }