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