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