github.com/turingchain2020/turingchain@v1.1.21/common/crypto/sha3/sha3_test.go (about)

     1  // Copyright Turing Corp. 2018 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  // Copyright 2014 The Go Authors. All rights reserved.
     6  // Use of this source code is governed by a BSD-style
     7  // license that can be found in the LICENSE file.
     8  
     9  package sha3
    10  
    11  // Tests include all the ShortMsgKATs provided by the Keccak team at
    12  // https://github.com/gvanas/KeccakCodePackage
    13  //
    14  // They only include the zero-bit case of the bitwise testvectors
    15  // published by NIST in the draft of FIPS-202.
    16  
    17  import (
    18  	"bytes"
    19  	"compress/flate"
    20  	"encoding/hex"
    21  	"encoding/json"
    22  	"fmt"
    23  	"hash"
    24  	"os"
    25  	"strings"
    26  	"testing"
    27  
    28  	"github.com/stretchr/testify/assert"
    29  )
    30  
    31  const (
    32  	testString  = "brekeccakkeccak koax koax"
    33  	katFilename = "testdata/keccakKats.json.deflate"
    34  )
    35  
    36  // Internal-use instances of SHAKE used to test against KATs.
    37  func newHashShake128() hash.Hash {
    38  	return &state{rate: 168, dsbyte: 0x1f, outputLen: 512}
    39  }
    40  func newHashShake256() hash.Hash {
    41  	return &state{rate: 136, dsbyte: 0x1f, outputLen: 512}
    42  }
    43  
    44  // testDigests contains functions returning hash.Hash instances
    45  // with output-length equal to the KAT length for SHA-3, Keccak
    46  // and SHAKE instances.
    47  var testDigests = map[string]func() hash.Hash{
    48  	"SHA3-224":   New224,
    49  	"SHA3-256":   New256,
    50  	"SHA3-384":   New384,
    51  	"SHA3-512":   New512,
    52  	"Keccak-256": NewLegacyKeccak256,
    53  	"SHAKE128":   newHashShake128,
    54  	"SHAKE256":   newHashShake256,
    55  }
    56  
    57  // testShakes contains functions that return ShakeHash instances for
    58  // testing the ShakeHash-specific interface.
    59  var testShakes = map[string]func() ShakeHash{
    60  	"SHAKE128": NewShake128,
    61  	"SHAKE256": NewShake256,
    62  }
    63  
    64  // decodeHex converts a hex-encoded string into a raw byte string.
    65  func decodeHex(s string) []byte {
    66  	b, err := hex.DecodeString(s)
    67  	if err != nil {
    68  		panic(err)
    69  	}
    70  	return b
    71  }
    72  
    73  // structs used to marshal JSON test-cases.
    74  type KeccakKats struct {
    75  	Kats map[string][]struct {
    76  		Digest  string `json:"digest"`
    77  		Length  int64  `json:"length"`
    78  		Message string `json:"message"`
    79  	}
    80  }
    81  
    82  const xorImplementationUnaligned = "generic"
    83  
    84  func testUnalignedAndGeneric(t *testing.T, testf func(impl string)) {
    85  	xorInOrig, copyOutOrig := xorIn, copyOut
    86  	xorIn, copyOut = xorInGeneric, copyOutGeneric
    87  	testf("generic")
    88  	if xorImplementationUnaligned != "generic" {
    89  		xorIn, copyOut = xorInUnaligned, copyOutUnaligned
    90  		testf("unaligned")
    91  	}
    92  	xorIn, copyOut = xorInOrig, copyOutOrig
    93  }
    94  
    95  // TestKeccakKats tests the SHA-3 and Shake implementations against all the
    96  // ShortMsgKATs from https://github.com/gvanas/KeccakCodePackage
    97  // (The testvectors are stored in keccakKats.json.deflate due to their length.)
    98  func TestKeccakKats(t *testing.T) {
    99  	testUnalignedAndGeneric(t, func(impl string) {
   100  		// Read the KATs.
   101  		deflated, err := os.Open(katFilename)
   102  		if err != nil {
   103  			t.Errorf("error opening %s: %s", katFilename, err)
   104  		}
   105  		file := flate.NewReader(deflated)
   106  		dec := json.NewDecoder(file)
   107  		var katSet KeccakKats
   108  		err = dec.Decode(&katSet)
   109  		if err != nil {
   110  			t.Errorf("error decoding KATs: %s", err)
   111  		}
   112  
   113  		// Do the KATs.
   114  		for functionName, kats := range katSet.Kats {
   115  			d := testDigests[functionName]()
   116  			for _, kat := range kats {
   117  				d.Reset()
   118  				in, err := hex.DecodeString(kat.Message)
   119  				if err != nil {
   120  					t.Errorf("error decoding KAT: %s", err)
   121  				}
   122  				d.Write(in[:kat.Length/8])
   123  				got := strings.ToUpper(hex.EncodeToString(d.Sum(nil)))
   124  				if got != kat.Digest {
   125  					t.Errorf("function=%s, implementation=%s, length=%d\nmessage:\n  %s\ngot:\n  %s\nwanted:\n %s",
   126  						functionName, impl, kat.Length, kat.Message, got, kat.Digest)
   127  					t.Logf("wanted %+v", kat)
   128  					t.FailNow()
   129  				}
   130  				continue
   131  			}
   132  		}
   133  	})
   134  }
   135  
   136  // TestKeccak does a basic test of the non-standardized Keccak hash functions.
   137  func TestKeccak(t *testing.T) {
   138  	tests := []struct {
   139  		fn   func() hash.Hash
   140  		data []byte
   141  		want string
   142  	}{
   143  		{
   144  			NewLegacyKeccak256,
   145  			[]byte("abc"),
   146  			"4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45",
   147  		},
   148  	}
   149  
   150  	for _, u := range tests {
   151  		h := u.fn()
   152  		h.Write(u.data)
   153  		got := h.Sum(nil)
   154  		want := decodeHex(u.want)
   155  		if !bytes.Equal(got, want) {
   156  			t.Errorf("unexpected hash for size %d: got '%x' want '%s'", h.Size()*8, got, u.want)
   157  		}
   158  	}
   159  }
   160  
   161  // TestUnalignedWrite tests that writing data in an arbitrary pattern with
   162  // small input buffers.
   163  func TestUnalignedWrite(t *testing.T) {
   164  	testUnalignedAndGeneric(t, func(impl string) {
   165  		buf := sequentialBytes(0x10000)
   166  		for alg, df := range testDigests {
   167  			d := df()
   168  			d.Reset()
   169  			d.Write(buf)
   170  			want := d.Sum(nil)
   171  			d.Reset()
   172  			for i := 0; i < len(buf); {
   173  				// Cycle through offsets which make a 137 byte sequence.
   174  				// Because 137 is prime this sequence should exercise all corner cases.
   175  				offsets := [17]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1}
   176  				for _, j := range offsets {
   177  					if v := len(buf) - i; v < j {
   178  						j = v
   179  					}
   180  					d.Write(buf[i : i+j])
   181  					i += j
   182  				}
   183  			}
   184  			got := d.Sum(nil)
   185  			if !bytes.Equal(got, want) {
   186  				t.Errorf("Unaligned writes, implementation=%s, alg=%s\ngot %q, want %q", impl, alg, got, want)
   187  			}
   188  		}
   189  	})
   190  }
   191  
   192  // TestAppend checks that appending works when reallocation is necessary.
   193  func TestAppend(t *testing.T) {
   194  	testUnalignedAndGeneric(t, func(impl string) {
   195  		d := New224()
   196  
   197  		for capacity := 2; capacity <= 66; capacity += 64 {
   198  			// The first time around the loop, Sum will have to reallocate.
   199  			// The second time, it will not.
   200  			buf := make([]byte, 2, capacity)
   201  			d.Reset()
   202  			d.Write([]byte{0xcc})
   203  			buf = d.Sum(buf)
   204  			expected := "0000DF70ADC49B2E76EEE3A6931B93FA41841C3AF2CDF5B32A18B5478C39"
   205  			if got := strings.ToUpper(hex.EncodeToString(buf)); got != expected {
   206  				t.Errorf("got %s, want %s", got, expected)
   207  			}
   208  		}
   209  	})
   210  }
   211  
   212  // TestAppendNoRealloc tests that appending works when no reallocation is necessary.
   213  func TestAppendNoRealloc(t *testing.T) {
   214  	testUnalignedAndGeneric(t, func(impl string) {
   215  		buf := make([]byte, 1, 200)
   216  		d := New224()
   217  		d.Write([]byte{0xcc})
   218  		buf = d.Sum(buf)
   219  		expected := "00DF70ADC49B2E76EEE3A6931B93FA41841C3AF2CDF5B32A18B5478C39"
   220  		if got := strings.ToUpper(hex.EncodeToString(buf)); got != expected {
   221  			t.Errorf("%s: got %s, want %s", impl, got, expected)
   222  		}
   223  	})
   224  }
   225  
   226  // TestSqueezing checks that squeezing the full output a single time produces
   227  // the same output as repeatedly squeezing the instance.
   228  func TestSqueezing(t *testing.T) {
   229  	testUnalignedAndGeneric(t, func(impl string) {
   230  		for functionName, newShakeHash := range testShakes {
   231  			d0 := newShakeHash()
   232  			d0.Write([]byte(testString))
   233  			ref := make([]byte, 32)
   234  			d0.Read(ref)
   235  
   236  			d1 := newShakeHash()
   237  			d1.Write([]byte(testString))
   238  			var multiple []byte
   239  			for range ref {
   240  				one := make([]byte, 1)
   241  				d1.Read(one)
   242  				multiple = append(multiple, one...)
   243  			}
   244  			if !bytes.Equal(ref, multiple) {
   245  				t.Errorf("%s (%s): squeezing %d bytes one at a time failed", functionName, impl, len(ref))
   246  			}
   247  		}
   248  	})
   249  }
   250  
   251  // sequentialBytes produces a buffer of size consecutive bytes 0x00, 0x01, ..., used for testing.
   252  func sequentialBytes(size int) []byte {
   253  	result := make([]byte, size)
   254  	for i := range result {
   255  		result[i] = byte(i)
   256  	}
   257  	return result
   258  }
   259  
   260  // BenchmarkPermutationFunction measures the speed of the permutation function
   261  // with no input data.
   262  func BenchmarkPermutationFunction(b *testing.B) {
   263  	b.SetBytes(int64(200))
   264  	var lanes [25]uint64
   265  	for i := 0; i < b.N; i++ {
   266  		keccakF1600(&lanes)
   267  	}
   268  }
   269  
   270  // benchmarkHash tests the speed to hash num buffers of buflen each.
   271  func benchmarkHash(b *testing.B, h hash.Hash, size, num int) {
   272  	b.StopTimer()
   273  	h.Reset()
   274  	data := sequentialBytes(size)
   275  	b.SetBytes(int64(size * num))
   276  	b.StartTimer()
   277  
   278  	var state []byte
   279  	for i := 0; i < b.N; i++ {
   280  		for j := 0; j < num; j++ {
   281  			h.Write(data)
   282  		}
   283  		state = h.Sum(state[:0])
   284  	}
   285  	b.StopTimer()
   286  	h.Reset()
   287  }
   288  
   289  // benchmarkShake is specialized to the Shake instances, which don't
   290  // require a copy on reading output.
   291  func benchmarkShake(b *testing.B, h ShakeHash, size, num int) {
   292  	b.StopTimer()
   293  	h.Reset()
   294  	data := sequentialBytes(size)
   295  	d := make([]byte, 32)
   296  
   297  	b.SetBytes(int64(size * num))
   298  	b.StartTimer()
   299  
   300  	for i := 0; i < b.N; i++ {
   301  		h.Reset()
   302  		for j := 0; j < num; j++ {
   303  			h.Write(data)
   304  		}
   305  		h.Read(d)
   306  	}
   307  }
   308  
   309  func BenchmarkSha3_512_MTU(b *testing.B) { benchmarkHash(b, New512(), 1350, 1) }
   310  func BenchmarkSha3_384_MTU(b *testing.B) { benchmarkHash(b, New384(), 1350, 1) }
   311  func BenchmarkSha3_256_MTU(b *testing.B) { benchmarkHash(b, New256(), 1350, 1) }
   312  func BenchmarkSha3_224_MTU(b *testing.B) { benchmarkHash(b, New224(), 1350, 1) }
   313  
   314  func BenchmarkShake128_MTU(b *testing.B)  { benchmarkShake(b, NewShake128(), 1350, 1) }
   315  func BenchmarkShake256_MTU(b *testing.B)  { benchmarkShake(b, NewShake256(), 1350, 1) }
   316  func BenchmarkShake256_16x(b *testing.B)  { benchmarkShake(b, NewShake256(), 16, 1024) }
   317  func BenchmarkShake256_1MiB(b *testing.B) { benchmarkShake(b, NewShake256(), 1024, 1024) }
   318  
   319  func BenchmarkSha3_512_1MiB(b *testing.B) { benchmarkHash(b, New512(), 1024, 1024) }
   320  
   321  func Example_sum() {
   322  	buf := []byte("some data to hash")
   323  	// A hash needs to be 64 bytes long to have 256-bit collision resistance.
   324  	h := make([]byte, 64)
   325  	// Compute a 64-byte hash of buf and put it in h.
   326  	ShakeSum256(h, buf)
   327  	fmt.Printf("%x\n", h)
   328  	// Output: 0f65fe41fc353e52c55667bb9e2b27bfcc8476f2c413e9437d272ee3194a4e3146d05ec04a25d16b8f577c19b82d16b1424c3e022e783d2b4da98de3658d363d
   329  }
   330  
   331  func Example_mac() {
   332  	k := []byte("this is a secret key; you should generate a strong random key that's at least 32 bytes long")
   333  	buf := []byte("and this is some data to authenticate")
   334  	// A MAC with 32 bytes of output has 256-bit security strength -- if you use at least a 32-byte-long key.
   335  	h := make([]byte, 32)
   336  	d := NewShake256()
   337  	// Write the key into the hash.
   338  	d.Write(k)
   339  	// Now write the data.
   340  	d.Write(buf)
   341  	// Read 32 bytes of output from the hash into h.
   342  	d.Read(h)
   343  	fmt.Printf("%x\n", h)
   344  	// ProtoToJson: 78de2974bd2711d5549ffd32b753ef0f5fa80a0db2556db60f0987eb8a9218ff
   345  }
   346  
   347  func TestNew(t *testing.T) {
   348  	d28 := Sum224(nil)
   349  	assert.True(t, len(d28) == 28)
   350  
   351  	d32 := Sum256(nil)
   352  	assert.True(t, len(d32) == 32)
   353  
   354  	d48 := Sum384(nil)
   355  	assert.True(t, len(d48) == 48)
   356  
   357  	d64 := Sum512(nil)
   358  	assert.True(t, len(d64) == 64)
   359  
   360  	d32 = KeccakSum256(nil)
   361  	assert.True(t, len(d32) == 32)
   362  
   363  	d32 = KeccakSum512(nil)
   364  	assert.True(t, len(d32) == 32)
   365  }