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