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