...

Source file src/golang.org/x/crypto/sha3/sha3_test.go

Documentation: golang.org/x/crypto/sha3

     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  	"hash"
    20  	"math/rand"
    21  	"os"
    22  	"strings"
    23  	"testing"
    24  )
    25  
    26  const (
    27  	testString  = "brekeccakkeccak koax koax"
    28  	katFilename = "testdata/keccakKats.json.deflate"
    29  )
    30  
    31  // testDigests contains functions returning hash.Hash instances
    32  // with output-length equal to the KAT length for SHA-3, Keccak
    33  // and SHAKE instances.
    34  var testDigests = map[string]func() hash.Hash{
    35  	"SHA3-224":   New224,
    36  	"SHA3-256":   New256,
    37  	"SHA3-384":   New384,
    38  	"SHA3-512":   New512,
    39  	"Keccak-256": NewLegacyKeccak256,
    40  	"Keccak-512": NewLegacyKeccak512,
    41  }
    42  
    43  // testShakes contains functions that return sha3.ShakeHash instances for
    44  // with output-length equal to the KAT length.
    45  var testShakes = map[string]struct {
    46  	constructor  func(N []byte, S []byte) ShakeHash
    47  	defAlgoName  string
    48  	defCustomStr string
    49  }{
    50  	// NewCShake without customization produces same result as SHAKE
    51  	"SHAKE128":  {NewCShake128, "", ""},
    52  	"SHAKE256":  {NewCShake256, "", ""},
    53  	"cSHAKE128": {NewCShake128, "CSHAKE128", "CustomStrign"},
    54  	"cSHAKE256": {NewCShake256, "CSHAKE256", "CustomStrign"},
    55  }
    56  
    57  // decodeHex converts a hex-encoded string into a raw byte string.
    58  func decodeHex(s string) []byte {
    59  	b, err := hex.DecodeString(s)
    60  	if err != nil {
    61  		panic(err)
    62  	}
    63  	return b
    64  }
    65  
    66  // structs used to marshal JSON test-cases.
    67  type KeccakKats struct {
    68  	Kats map[string][]struct {
    69  		Digest  string `json:"digest"`
    70  		Length  int64  `json:"length"`
    71  		Message string `json:"message"`
    72  
    73  		// Defined only for cSHAKE
    74  		N string `json:"N"`
    75  		S string `json:"S"`
    76  	}
    77  }
    78  
    79  func testUnalignedAndGeneric(t *testing.T, testf func(impl string)) {
    80  	xorInOrig, copyOutOrig := xorIn, copyOut
    81  	xorIn, copyOut = xorInGeneric, copyOutGeneric
    82  	testf("generic")
    83  	if xorImplementationUnaligned != "generic" {
    84  		xorIn, copyOut = xorInUnaligned, copyOutUnaligned
    85  		testf("unaligned")
    86  	}
    87  	xorIn, copyOut = xorInOrig, copyOutOrig
    88  }
    89  
    90  // TestKeccakKats tests the SHA-3 and Shake implementations against all the
    91  // ShortMsgKATs from https://github.com/gvanas/KeccakCodePackage
    92  // (The testvectors are stored in keccakKats.json.deflate due to their length.)
    93  func TestKeccakKats(t *testing.T) {
    94  	testUnalignedAndGeneric(t, func(impl string) {
    95  		// Read the KATs.
    96  		deflated, err := os.Open(katFilename)
    97  		if err != nil {
    98  			t.Errorf("error opening %s: %s", katFilename, err)
    99  		}
   100  		file := flate.NewReader(deflated)
   101  		dec := json.NewDecoder(file)
   102  		var katSet KeccakKats
   103  		err = dec.Decode(&katSet)
   104  		if err != nil {
   105  			t.Errorf("error decoding KATs: %s", err)
   106  		}
   107  
   108  		for algo, function := range testDigests {
   109  			d := function()
   110  			for _, kat := range katSet.Kats[algo] {
   111  				d.Reset()
   112  				in, err := hex.DecodeString(kat.Message)
   113  				if err != nil {
   114  					t.Errorf("error decoding KAT: %s", err)
   115  				}
   116  				d.Write(in[:kat.Length/8])
   117  				got := strings.ToUpper(hex.EncodeToString(d.Sum(nil)))
   118  				if got != kat.Digest {
   119  					t.Errorf("function=%s, implementation=%s, length=%d\nmessage:\n %s\ngot:\n  %s\nwanted:\n %s",
   120  						algo, impl, kat.Length, kat.Message, got, kat.Digest)
   121  					t.Logf("wanted %+v", kat)
   122  					t.FailNow()
   123  				}
   124  				continue
   125  			}
   126  		}
   127  
   128  		for algo, v := range testShakes {
   129  			for _, kat := range katSet.Kats[algo] {
   130  				N, err := hex.DecodeString(kat.N)
   131  				if err != nil {
   132  					t.Errorf("error decoding KAT: %s", err)
   133  				}
   134  
   135  				S, err := hex.DecodeString(kat.S)
   136  				if err != nil {
   137  					t.Errorf("error decoding KAT: %s", err)
   138  				}
   139  				d := v.constructor(N, S)
   140  				in, err := hex.DecodeString(kat.Message)
   141  				if err != nil {
   142  					t.Errorf("error decoding KAT: %s", err)
   143  				}
   144  
   145  				d.Write(in[:kat.Length/8])
   146  				out := make([]byte, len(kat.Digest)/2)
   147  				d.Read(out)
   148  				got := strings.ToUpper(hex.EncodeToString(out))
   149  				if got != kat.Digest {
   150  					t.Errorf("function=%s, implementation=%s, length=%d N:%s\n S:%s\nmessage:\n %s \ngot:\n  %s\nwanted:\n %s",
   151  						algo, impl, kat.Length, kat.N, kat.S, kat.Message, got, kat.Digest)
   152  					t.Logf("wanted %+v", kat)
   153  					t.FailNow()
   154  				}
   155  				continue
   156  			}
   157  		}
   158  	})
   159  }
   160  
   161  // TestKeccak does a basic test of the non-standardized Keccak hash functions.
   162  func TestKeccak(t *testing.T) {
   163  	tests := []struct {
   164  		fn   func() hash.Hash
   165  		data []byte
   166  		want string
   167  	}{
   168  		{
   169  			NewLegacyKeccak256,
   170  			[]byte("abc"),
   171  			"4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45",
   172  		},
   173  		{
   174  			NewLegacyKeccak512,
   175  			[]byte("abc"),
   176  			"18587dc2ea106b9a1563e32b3312421ca164c7f1f07bc922a9c83d77cea3a1e5d0c69910739025372dc14ac9642629379540c17e2a65b19d77aa511a9d00bb96",
   177  		},
   178  	}
   179  
   180  	for _, u := range tests {
   181  		h := u.fn()
   182  		h.Write(u.data)
   183  		got := h.Sum(nil)
   184  		want := decodeHex(u.want)
   185  		if !bytes.Equal(got, want) {
   186  			t.Errorf("unexpected hash for size %d: got '%x' want '%s'", h.Size()*8, got, u.want)
   187  		}
   188  	}
   189  }
   190  
   191  // TestUnalignedWrite tests that writing data in an arbitrary pattern with
   192  // small input buffers.
   193  func TestUnalignedWrite(t *testing.T) {
   194  	testUnalignedAndGeneric(t, func(impl string) {
   195  		buf := sequentialBytes(0x10000)
   196  		for alg, df := range testDigests {
   197  			d := df()
   198  			d.Reset()
   199  			d.Write(buf)
   200  			want := d.Sum(nil)
   201  			d.Reset()
   202  			for i := 0; i < len(buf); {
   203  				// Cycle through offsets which make a 137 byte sequence.
   204  				// Because 137 is prime this sequence should exercise all corner cases.
   205  				offsets := [17]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1}
   206  				for _, j := range offsets {
   207  					if v := len(buf) - i; v < j {
   208  						j = v
   209  					}
   210  					d.Write(buf[i : i+j])
   211  					i += j
   212  				}
   213  			}
   214  			got := d.Sum(nil)
   215  			if !bytes.Equal(got, want) {
   216  				t.Errorf("Unaligned writes, implementation=%s, alg=%s\ngot %q, want %q", impl, alg, got, want)
   217  			}
   218  		}
   219  
   220  		// Same for SHAKE
   221  		for alg, df := range testShakes {
   222  			want := make([]byte, 16)
   223  			got := make([]byte, 16)
   224  			d := df.constructor([]byte(df.defAlgoName), []byte(df.defCustomStr))
   225  
   226  			d.Reset()
   227  			d.Write(buf)
   228  			d.Read(want)
   229  			d.Reset()
   230  			for i := 0; i < len(buf); {
   231  				// Cycle through offsets which make a 137 byte sequence.
   232  				// Because 137 is prime this sequence should exercise all corner cases.
   233  				offsets := [17]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1}
   234  				for _, j := range offsets {
   235  					if v := len(buf) - i; v < j {
   236  						j = v
   237  					}
   238  					d.Write(buf[i : i+j])
   239  					i += j
   240  				}
   241  			}
   242  			d.Read(got)
   243  			if !bytes.Equal(got, want) {
   244  				t.Errorf("Unaligned writes, implementation=%s, alg=%s\ngot %q, want %q", impl, alg, got, want)
   245  			}
   246  		}
   247  	})
   248  }
   249  
   250  // TestAppend checks that appending works when reallocation is necessary.
   251  func TestAppend(t *testing.T) {
   252  	testUnalignedAndGeneric(t, func(impl string) {
   253  		d := New224()
   254  
   255  		for capacity := 2; capacity <= 66; capacity += 64 {
   256  			// The first time around the loop, Sum will have to reallocate.
   257  			// The second time, it will not.
   258  			buf := make([]byte, 2, capacity)
   259  			d.Reset()
   260  			d.Write([]byte{0xcc})
   261  			buf = d.Sum(buf)
   262  			expected := "0000DF70ADC49B2E76EEE3A6931B93FA41841C3AF2CDF5B32A18B5478C39"
   263  			if got := strings.ToUpper(hex.EncodeToString(buf)); got != expected {
   264  				t.Errorf("got %s, want %s", got, expected)
   265  			}
   266  		}
   267  	})
   268  }
   269  
   270  // TestAppendNoRealloc tests that appending works when no reallocation is necessary.
   271  func TestAppendNoRealloc(t *testing.T) {
   272  	testUnalignedAndGeneric(t, func(impl string) {
   273  		buf := make([]byte, 1, 200)
   274  		d := New224()
   275  		d.Write([]byte{0xcc})
   276  		buf = d.Sum(buf)
   277  		expected := "00DF70ADC49B2E76EEE3A6931B93FA41841C3AF2CDF5B32A18B5478C39"
   278  		if got := strings.ToUpper(hex.EncodeToString(buf)); got != expected {
   279  			t.Errorf("%s: got %s, want %s", impl, got, expected)
   280  		}
   281  	})
   282  }
   283  
   284  // TestSqueezing checks that squeezing the full output a single time produces
   285  // the same output as repeatedly squeezing the instance.
   286  func TestSqueezing(t *testing.T) {
   287  	testUnalignedAndGeneric(t, func(impl string) {
   288  		for algo, v := range testShakes {
   289  			d0 := v.constructor([]byte(v.defAlgoName), []byte(v.defCustomStr))
   290  			d0.Write([]byte(testString))
   291  			ref := make([]byte, 32)
   292  			d0.Read(ref)
   293  
   294  			d1 := v.constructor([]byte(v.defAlgoName), []byte(v.defCustomStr))
   295  			d1.Write([]byte(testString))
   296  			var multiple []byte
   297  			for range ref {
   298  				one := make([]byte, 1)
   299  				d1.Read(one)
   300  				multiple = append(multiple, one...)
   301  			}
   302  			if !bytes.Equal(ref, multiple) {
   303  				t.Errorf("%s (%s): squeezing %d bytes one at a time failed", algo, impl, len(ref))
   304  			}
   305  		}
   306  	})
   307  }
   308  
   309  // sequentialBytes produces a buffer of size consecutive bytes 0x00, 0x01, ..., used for testing.
   310  //
   311  // The alignment of each slice is intentionally randomized to detect alignment
   312  // issues in the implementation. See https://golang.org/issue/37644.
   313  // Ideally, the compiler should fuzz the alignment itself.
   314  // (See https://golang.org/issue/35128.)
   315  func sequentialBytes(size int) []byte {
   316  	alignmentOffset := rand.Intn(8)
   317  	result := make([]byte, size+alignmentOffset)[alignmentOffset:]
   318  	for i := range result {
   319  		result[i] = byte(i)
   320  	}
   321  	return result
   322  }
   323  
   324  func TestReset(t *testing.T) {
   325  	out1 := make([]byte, 32)
   326  	out2 := make([]byte, 32)
   327  
   328  	for _, v := range testShakes {
   329  		// Calculate hash for the first time
   330  		c := v.constructor(nil, []byte{0x99, 0x98})
   331  		c.Write(sequentialBytes(0x100))
   332  		c.Read(out1)
   333  
   334  		// Calculate hash again
   335  		c.Reset()
   336  		c.Write(sequentialBytes(0x100))
   337  		c.Read(out2)
   338  
   339  		if !bytes.Equal(out1, out2) {
   340  			t.Error("\nExpected:\n", out1, "\ngot:\n", out2)
   341  		}
   342  	}
   343  }
   344  
   345  func TestClone(t *testing.T) {
   346  	out1 := make([]byte, 16)
   347  	out2 := make([]byte, 16)
   348  
   349  	// Test for sizes smaller and larger than block size.
   350  	for _, size := range []int{0x1, 0x100} {
   351  		in := sequentialBytes(size)
   352  		for _, v := range testShakes {
   353  			h1 := v.constructor(nil, []byte{0x01})
   354  			h1.Write([]byte{0x01})
   355  
   356  			h2 := h1.Clone()
   357  
   358  			h1.Write(in)
   359  			h1.Read(out1)
   360  
   361  			h2.Write(in)
   362  			h2.Read(out2)
   363  
   364  			if !bytes.Equal(out1, out2) {
   365  				t.Error("\nExpected:\n", hex.EncodeToString(out1), "\ngot:\n", hex.EncodeToString(out2))
   366  			}
   367  		}
   368  	}
   369  }
   370  
   371  // BenchmarkPermutationFunction measures the speed of the permutation function
   372  // with no input data.
   373  func BenchmarkPermutationFunction(b *testing.B) {
   374  	b.SetBytes(int64(200))
   375  	var lanes [25]uint64
   376  	for i := 0; i < b.N; i++ {
   377  		keccakF1600(&lanes)
   378  	}
   379  }
   380  
   381  // benchmarkHash tests the speed to hash num buffers of buflen each.
   382  func benchmarkHash(b *testing.B, h hash.Hash, size, num int) {
   383  	b.StopTimer()
   384  	h.Reset()
   385  	data := sequentialBytes(size)
   386  	b.SetBytes(int64(size * num))
   387  	b.StartTimer()
   388  
   389  	var state []byte
   390  	for i := 0; i < b.N; i++ {
   391  		for j := 0; j < num; j++ {
   392  			h.Write(data)
   393  		}
   394  		state = h.Sum(state[:0])
   395  	}
   396  	b.StopTimer()
   397  	h.Reset()
   398  }
   399  
   400  // benchmarkShake is specialized to the Shake instances, which don't
   401  // require a copy on reading output.
   402  func benchmarkShake(b *testing.B, h ShakeHash, size, num int) {
   403  	b.StopTimer()
   404  	h.Reset()
   405  	data := sequentialBytes(size)
   406  	d := make([]byte, 32)
   407  
   408  	b.SetBytes(int64(size * num))
   409  	b.StartTimer()
   410  
   411  	for i := 0; i < b.N; i++ {
   412  		h.Reset()
   413  		for j := 0; j < num; j++ {
   414  			h.Write(data)
   415  		}
   416  		h.Read(d)
   417  	}
   418  }
   419  
   420  func BenchmarkSha3_512_MTU(b *testing.B) { benchmarkHash(b, New512(), 1350, 1) }
   421  func BenchmarkSha3_384_MTU(b *testing.B) { benchmarkHash(b, New384(), 1350, 1) }
   422  func BenchmarkSha3_256_MTU(b *testing.B) { benchmarkHash(b, New256(), 1350, 1) }
   423  func BenchmarkSha3_224_MTU(b *testing.B) { benchmarkHash(b, New224(), 1350, 1) }
   424  
   425  func BenchmarkShake128_MTU(b *testing.B)  { benchmarkShake(b, NewShake128(), 1350, 1) }
   426  func BenchmarkShake256_MTU(b *testing.B)  { benchmarkShake(b, NewShake256(), 1350, 1) }
   427  func BenchmarkShake256_16x(b *testing.B)  { benchmarkShake(b, NewShake256(), 16, 1024) }
   428  func BenchmarkShake256_1MiB(b *testing.B) { benchmarkShake(b, NewShake256(), 1024, 1024) }
   429  
   430  func BenchmarkSha3_512_1MiB(b *testing.B) { benchmarkHash(b, New512(), 1024, 1024) }
   431  
   432  func Example_sum() {
   433  	buf := []byte("some data to hash")
   434  	// A hash needs to be 64 bytes long to have 256-bit collision resistance.
   435  	h := make([]byte, 64)
   436  	// Compute a 64-byte hash of buf and put it in h.
   437  	ShakeSum256(h, buf)
   438  	fmt.Printf("%x\n", h)
   439  	// Output: 0f65fe41fc353e52c55667bb9e2b27bfcc8476f2c413e9437d272ee3194a4e3146d05ec04a25d16b8f577c19b82d16b1424c3e022e783d2b4da98de3658d363d
   440  }
   441  
   442  func Example_mac() {
   443  	k := []byte("this is a secret key; you should generate a strong random key that's at least 32 bytes long")
   444  	buf := []byte("and this is some data to authenticate")
   445  	// A MAC with 32 bytes of output has 256-bit security strength -- if you use at least a 32-byte-long key.
   446  	h := make([]byte, 32)
   447  	d := NewShake256()
   448  	// Write the key into the hash.
   449  	d.Write(k)
   450  	// Now write the data.
   451  	d.Write(buf)
   452  	// Read 32 bytes of output from the hash into h.
   453  	d.Read(h)
   454  	fmt.Printf("%x\n", h)
   455  	// Output: 78de2974bd2711d5549ffd32b753ef0f5fa80a0db2556db60f0987eb8a9218ff
   456  }
   457  
   458  func ExampleNewCShake256() {
   459  	out := make([]byte, 32)
   460  	msg := []byte("The quick brown fox jumps over the lazy dog")
   461  
   462  	// Example 1: Simple cshake
   463  	c1 := NewCShake256([]byte("NAME"), []byte("Partition1"))
   464  	c1.Write(msg)
   465  	c1.Read(out)
   466  	fmt.Println(hex.EncodeToString(out))
   467  
   468  	// Example 2: Different customization string produces different digest
   469  	c1 = NewCShake256([]byte("NAME"), []byte("Partition2"))
   470  	c1.Write(msg)
   471  	c1.Read(out)
   472  	fmt.Println(hex.EncodeToString(out))
   473  
   474  	// Example 3: Longer output length produces longer digest
   475  	out = make([]byte, 64)
   476  	c1 = NewCShake256([]byte("NAME"), []byte("Partition1"))
   477  	c1.Write(msg)
   478  	c1.Read(out)
   479  	fmt.Println(hex.EncodeToString(out))
   480  
   481  	// Example 4: Next read produces different result
   482  	c1.Read(out)
   483  	fmt.Println(hex.EncodeToString(out))
   484  
   485  	// Output:
   486  	//a90a4c6ca9af2156eba43dc8398279e6b60dcd56fb21837afe6c308fd4ceb05b
   487  	//a8db03e71f3e4da5c4eee9d28333cdd355f51cef3c567e59be5beb4ecdbb28f0
   488  	//a90a4c6ca9af2156eba43dc8398279e6b60dcd56fb21837afe6c308fd4ceb05b9dd98c6ee866ca7dc5a39d53e960f400bcd5a19c8a2d6ec6459f63696543a0d8
   489  	//85e73a72228d08b46515553ca3a29d47df3047e5d84b12d6c2c63e579f4fd1105716b7838e92e981863907f434bfd4443c9e56ea09da998d2f9b47db71988109
   490  }
   491  

View as plain text