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  }