github.com/luckypickle/go-ethereum-vet@v1.14.2/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 // structs used to marshal JSON test-cases. 57 type KeccakKats struct { 58 Kats map[string][]struct { 59 Digest string `json:"digest"` 60 Length int64 `json:"length"` 61 Message string `json:"message"` 62 } 63 } 64 65 func testUnalignedAndGeneric(t *testing.T, testf func(impl string)) { 66 xorInOrig, copyOutOrig := xorIn, copyOut 67 xorIn, copyOut = xorInGeneric, copyOutGeneric 68 testf("generic") 69 if xorImplementationUnaligned != "generic" { 70 xorIn, copyOut = xorInUnaligned, copyOutUnaligned 71 testf("unaligned") 72 } 73 xorIn, copyOut = xorInOrig, copyOutOrig 74 } 75 76 // TestKeccakKats tests the SHA-3 and Shake implementations against all the 77 // ShortMsgKATs from https://github.com/gvanas/KeccakCodePackage 78 // (The testvectors are stored in keccakKats.json.deflate due to their length.) 79 func TestKeccakKats(t *testing.T) { 80 testUnalignedAndGeneric(t, func(impl string) { 81 // Read the KATs. 82 deflated, err := os.Open(katFilename) 83 if err != nil { 84 t.Errorf("error opening %s: %s", katFilename, err) 85 } 86 file := flate.NewReader(deflated) 87 dec := json.NewDecoder(file) 88 var katSet KeccakKats 89 err = dec.Decode(&katSet) 90 if err != nil { 91 t.Errorf("error decoding KATs: %s", err) 92 } 93 94 // Do the KATs. 95 for functionName, kats := range katSet.Kats { 96 d := testDigests[functionName]() 97 for _, kat := range kats { 98 d.Reset() 99 in, err := hex.DecodeString(kat.Message) 100 if err != nil { 101 t.Errorf("error decoding KAT: %s", err) 102 } 103 d.Write(in[:kat.Length/8]) 104 got := strings.ToUpper(hex.EncodeToString(d.Sum(nil))) 105 if got != kat.Digest { 106 t.Errorf("function=%s, implementation=%s, length=%d\nmessage:\n %s\ngot:\n %s\nwanted:\n %s", 107 functionName, impl, kat.Length, kat.Message, got, kat.Digest) 108 t.Logf("wanted %+v", kat) 109 t.FailNow() 110 } 111 continue 112 } 113 } 114 }) 115 } 116 117 // TestUnalignedWrite tests that writing data in an arbitrary pattern with 118 // small input buffers. 119 func TestUnalignedWrite(t *testing.T) { 120 testUnalignedAndGeneric(t, func(impl string) { 121 buf := sequentialBytes(0x10000) 122 for alg, df := range testDigests { 123 d := df() 124 d.Reset() 125 d.Write(buf) 126 want := d.Sum(nil) 127 d.Reset() 128 for i := 0; i < len(buf); { 129 // Cycle through offsets which make a 137 byte sequence. 130 // Because 137 is prime this sequence should exercise all corner cases. 131 offsets := [17]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1} 132 for _, j := range offsets { 133 if v := len(buf) - i; v < j { 134 j = v 135 } 136 d.Write(buf[i : i+j]) 137 i += j 138 } 139 } 140 got := d.Sum(nil) 141 if !bytes.Equal(got, want) { 142 t.Errorf("Unaligned writes, implementation=%s, alg=%s\ngot %q, want %q", impl, alg, got, want) 143 } 144 } 145 }) 146 } 147 148 // TestAppend checks that appending works when reallocation is necessary. 149 func TestAppend(t *testing.T) { 150 testUnalignedAndGeneric(t, func(impl string) { 151 d := New224() 152 153 for capacity := 2; capacity <= 66; capacity += 64 { 154 // The first time around the loop, Sum will have to reallocate. 155 // The second time, it will not. 156 buf := make([]byte, 2, capacity) 157 d.Reset() 158 d.Write([]byte{0xcc}) 159 buf = d.Sum(buf) 160 expected := "0000DF70ADC49B2E76EEE3A6931B93FA41841C3AF2CDF5B32A18B5478C39" 161 if got := strings.ToUpper(hex.EncodeToString(buf)); got != expected { 162 t.Errorf("got %s, want %s", got, expected) 163 } 164 } 165 }) 166 } 167 168 // TestAppendNoRealloc tests that appending works when no reallocation is necessary. 169 func TestAppendNoRealloc(t *testing.T) { 170 testUnalignedAndGeneric(t, func(impl string) { 171 buf := make([]byte, 1, 200) 172 d := New224() 173 d.Write([]byte{0xcc}) 174 buf = d.Sum(buf) 175 expected := "00DF70ADC49B2E76EEE3A6931B93FA41841C3AF2CDF5B32A18B5478C39" 176 if got := strings.ToUpper(hex.EncodeToString(buf)); got != expected { 177 t.Errorf("%s: got %s, want %s", impl, got, expected) 178 } 179 }) 180 } 181 182 // TestSqueezing checks that squeezing the full output a single time produces 183 // the same output as repeatedly squeezing the instance. 184 func TestSqueezing(t *testing.T) { 185 testUnalignedAndGeneric(t, func(impl string) { 186 for functionName, newShakeHash := range testShakes { 187 d0 := newShakeHash() 188 d0.Write([]byte(testString)) 189 ref := make([]byte, 32) 190 d0.Read(ref) 191 192 d1 := newShakeHash() 193 d1.Write([]byte(testString)) 194 var multiple []byte 195 for range ref { 196 one := make([]byte, 1) 197 d1.Read(one) 198 multiple = append(multiple, one...) 199 } 200 if !bytes.Equal(ref, multiple) { 201 t.Errorf("%s (%s): squeezing %d bytes one at a time failed", functionName, impl, len(ref)) 202 } 203 } 204 }) 205 } 206 207 // sequentialBytes produces a buffer of size consecutive bytes 0x00, 0x01, ..., used for testing. 208 func sequentialBytes(size int) []byte { 209 result := make([]byte, size) 210 for i := range result { 211 result[i] = byte(i) 212 } 213 return result 214 } 215 216 // BenchmarkPermutationFunction measures the speed of the permutation function 217 // with no input data. 218 func BenchmarkPermutationFunction(b *testing.B) { 219 b.SetBytes(int64(200)) 220 var lanes [25]uint64 221 for i := 0; i < b.N; i++ { 222 keccakF1600(&lanes) 223 } 224 } 225 226 // benchmarkHash tests the speed to hash num buffers of buflen each. 227 func benchmarkHash(b *testing.B, h hash.Hash, size, num int) { 228 b.StopTimer() 229 h.Reset() 230 data := sequentialBytes(size) 231 b.SetBytes(int64(size * num)) 232 b.StartTimer() 233 234 var state []byte 235 for i := 0; i < b.N; i++ { 236 for j := 0; j < num; j++ { 237 h.Write(data) 238 } 239 state = h.Sum(state[:0]) 240 } 241 b.StopTimer() 242 h.Reset() 243 } 244 245 // benchmarkShake is specialized to the Shake instances, which don't 246 // require a copy on reading output. 247 func benchmarkShake(b *testing.B, h ShakeHash, size, num int) { 248 b.StopTimer() 249 h.Reset() 250 data := sequentialBytes(size) 251 d := make([]byte, 32) 252 253 b.SetBytes(int64(size * num)) 254 b.StartTimer() 255 256 for i := 0; i < b.N; i++ { 257 h.Reset() 258 for j := 0; j < num; j++ { 259 h.Write(data) 260 } 261 h.Read(d) 262 } 263 } 264 265 func BenchmarkSha3_512_MTU(b *testing.B) { benchmarkHash(b, New512(), 1350, 1) } 266 func BenchmarkSha3_384_MTU(b *testing.B) { benchmarkHash(b, New384(), 1350, 1) } 267 func BenchmarkSha3_256_MTU(b *testing.B) { benchmarkHash(b, New256(), 1350, 1) } 268 func BenchmarkSha3_224_MTU(b *testing.B) { benchmarkHash(b, New224(), 1350, 1) } 269 270 func BenchmarkShake128_MTU(b *testing.B) { benchmarkShake(b, NewShake128(), 1350, 1) } 271 func BenchmarkShake256_MTU(b *testing.B) { benchmarkShake(b, NewShake256(), 1350, 1) } 272 func BenchmarkShake256_16x(b *testing.B) { benchmarkShake(b, NewShake256(), 16, 1024) } 273 func BenchmarkShake256_1MiB(b *testing.B) { benchmarkShake(b, NewShake256(), 1024, 1024) } 274 275 func BenchmarkSha3_512_1MiB(b *testing.B) { benchmarkHash(b, New512(), 1024, 1024) } 276 277 func Example_sum() { 278 buf := []byte("some data to hash") 279 // A hash needs to be 64 bytes long to have 256-bit collision resistance. 280 h := make([]byte, 64) 281 // Compute a 64-byte hash of buf and put it in h. 282 ShakeSum256(h, buf) 283 } 284 285 func Example_mac() { 286 k := []byte("this is a secret key; you should generate a strong random key that's at least 32 bytes long") 287 buf := []byte("and this is some data to authenticate") 288 // A MAC with 32 bytes of output has 256-bit security strength -- if you use at least a 32-byte-long key. 289 h := make([]byte, 32) 290 d := NewShake256() 291 // Write the key into the hash. 292 d.Write(k) 293 // Now write the data. 294 d.Write(buf) 295 // Read 32 bytes of output from the hash into h. 296 d.Read(h) 297 }