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