github.com/onflow/flow-go/crypto@v0.24.8/hash/hash_test.go (about)

     1  package hash
     2  
     3  import (
     4  	"crypto/rand"
     5  	"crypto/sha256"
     6  	"crypto/sha512"
     7  	"encoding/hex"
     8  	"testing"
     9  
    10  	"github.com/stretchr/testify/assert"
    11  	"github.com/stretchr/testify/require"
    12  	"golang.org/x/crypto/sha3"
    13  )
    14  
    15  // Sanity check of SHA3_256
    16  func TestSanitySHA3_256(t *testing.T) {
    17  	input := []byte("test")
    18  	expected, _ := hex.DecodeString("36f028580bb02cc8272a9a020f4200e346e276ae664e45ee80745574e2f5ab80")
    19  
    20  	alg := NewSHA3_256()
    21  	hash := alg.ComputeHash(input)
    22  	assert.Equal(t, Hash(expected), hash)
    23  }
    24  
    25  // Sanity check of SHA3_384
    26  func TestSanitySHA3_384(t *testing.T) {
    27  	input := []byte("test")
    28  	expected, _ := hex.DecodeString("e516dabb23b6e30026863543282780a3ae0dccf05551cf0295178d7ff0f1b41eecb9db3ff219007c4e097260d58621bd")
    29  
    30  	alg := NewSHA3_384()
    31  	hash := alg.ComputeHash(input)
    32  	assert.Equal(t, Hash(expected), hash)
    33  }
    34  
    35  // Sanity check of SHA2_256
    36  func TestSanitySHA2_256(t *testing.T) {
    37  	input := []byte("test")
    38  	expected, _ := hex.DecodeString("9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08")
    39  
    40  	alg := NewSHA2_256()
    41  	hash := alg.ComputeHash(input)
    42  	assert.Equal(t, Hash(expected), hash)
    43  }
    44  
    45  // Sanity check of SHA2_384
    46  func TestSanitySHA2_384(t *testing.T) {
    47  	input := []byte("test")
    48  	expected, _ := hex.DecodeString("768412320f7b0aa5812fce428dc4706b3cae50e02a64caa16a782249bfe8efc4b7ef1ccb126255d196047dfedf17a0a9")
    49  
    50  	alg := NewSHA2_384()
    51  	hash := alg.ComputeHash(input)
    52  	assert.Equal(t, Hash(expected), hash)
    53  }
    54  
    55  // Sanity check of Keccak_256
    56  func TestSanityKeccak_256(t *testing.T) {
    57  	input := []byte("test")
    58  	expected, _ := hex.DecodeString("9c22ff5f21f0b81b113e63f7db6da94fedef11b2119b4088b89664fb9a3cb658")
    59  
    60  	alg := NewKeccak_256()
    61  	hash := alg.ComputeHash(input)
    62  	assert.Equal(t, Hash(expected), hash)
    63  }
    64  
    65  // Sanity checks of KMAC128
    66  // the test vector is taken from the NIST document
    67  // https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/Kmac_samples.pdf
    68  func TestSanityKmac128(t *testing.T) {
    69  
    70  	input := []byte{0x00, 0x01, 0x02, 0x03}
    71  	expected := []Hash{
    72  		{0xE5, 0x78, 0x0B, 0x0D, 0x3E, 0xA6, 0xF7, 0xD3, 0xA4, 0x29, 0xC5, 0x70, 0x6A, 0xA4, 0x3A, 0x00,
    73  			0xFA, 0xDB, 0xD7, 0xD4, 0x96, 0x28, 0x83, 0x9E, 0x31, 0x87, 0x24, 0x3F, 0x45, 0x6E, 0xE1, 0x4E},
    74  		{0x3B, 0x1F, 0xBA, 0x96, 0x3C, 0xD8, 0xB0, 0xB5, 0x9E, 0x8C, 0x1A, 0x6D, 0x71, 0x88, 0x8B, 0x71,
    75  			0x43, 0x65, 0x1A, 0xF8, 0xBA, 0x0A, 0x70, 0x70, 0xC0, 0x97, 0x9E, 0x28, 0x11, 0x32, 0x4A, 0xA5},
    76  	}
    77  	key := []byte{0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
    78  		0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F}
    79  	customizers := [][]byte{
    80  		[]byte(""),
    81  		[]byte("My Tagged Application"),
    82  	}
    83  	outputSize := 32
    84  
    85  	alg, err := NewKMAC_128(key, customizers[0], outputSize)
    86  	require.Nil(t, err)
    87  	_, _ = alg.Write(input[0:2])
    88  	_, _ = alg.Write(input[2:])
    89  	hash := alg.SumHash()
    90  	assert.Equal(t, expected[0], hash)
    91  
    92  	for i := 0; i < len(customizers); i++ {
    93  		alg, err = NewKMAC_128(key, customizers[i], outputSize)
    94  		require.Nil(t, err)
    95  		hash = alg.ComputeHash(input)
    96  		assert.Equal(t, expected[i], hash)
    97  	}
    98  
    99  	// test short key length
   100  	_, err = NewKMAC_128(key[:15], customizers[0], outputSize)
   101  	assert.Error(t, err)
   102  }
   103  
   104  // TestHashersAPI tests the expected definition of the hashers APIs
   105  func TestHashersAPI(t *testing.T) {
   106  
   107  	newKmac128 := func() Hasher {
   108  		kmac, err := NewKMAC_128([]byte("test_key________"), []byte("test_custommizer"), 32)
   109  		if err != nil {
   110  			panic("new kmac hasher failed")
   111  		}
   112  		return kmac
   113  	}
   114  
   115  	newHasherFunctions := [](func() Hasher){
   116  		NewSHA2_256,
   117  		NewSHA2_384,
   118  		NewSHA3_256,
   119  		NewSHA3_384,
   120  		newKmac128,
   121  		NewKeccak_256,
   122  	}
   123  
   124  	data := make([]byte, 1801)
   125  	_, err := rand.Read(data)
   126  	require.NoError(t, err)
   127  
   128  	for _, newFunction := range newHasherFunctions {
   129  		// Reset should empty the state
   130  		h := newFunction()
   131  		expectedEmptyHash := h.SumHash()
   132  		_, _ = h.Write(data)
   133  		h.Reset()
   134  		emptyHash := h.SumHash()
   135  		assert.Equal(t, expectedEmptyHash, emptyHash)
   136  
   137  		// SumHash on an empty state is equal to compute hash with empty data
   138  		emptyHash = h.ComputeHash(nil)
   139  		assert.Equal(t, expectedEmptyHash, emptyHash)
   140  
   141  		// successive writes of data are equivalent to compute hash
   142  		// of the concatenated data
   143  		h = newFunction()
   144  		hash1 := h.ComputeHash(data)
   145  
   146  		h.Reset()
   147  		_, _ = h.Write(data[:355])
   148  		_, _ = h.Write(data[355:902])
   149  		_, _ = h.Write(data[902:])
   150  		hash2 := h.SumHash()
   151  		assert.Equal(t, hash1, hash2)
   152  
   153  		// ComputeHash output does not depend on the hasher state
   154  		h = newFunction()
   155  
   156  		_, _ = h.Write([]byte("dummy data"))
   157  		hash1 = h.ComputeHash(data)
   158  		assert.Equal(t, hash1, hash2)
   159  	}
   160  }
   161  
   162  // TestSHA2 is a specific test of SHA2-256 and SHA2-384.
   163  // It compares the hashes of random data of different lengths to
   164  // the output of standard Go sha2.
   165  func TestSHA2(t *testing.T) {
   166  
   167  	t.Run("SHA2_256", func(t *testing.T) {
   168  		for i := 0; i < 5000; i++ {
   169  			value := make([]byte, i)
   170  			_, err := rand.Read(value)
   171  			require.NoError(t, err)
   172  			expected := sha256.Sum256(value)
   173  
   174  			// test hash computation using the hasher
   175  			hasher := NewSHA2_256()
   176  			h := hasher.ComputeHash(value)
   177  			assert.Equal(t, expected[:], []byte(h))
   178  
   179  			// test hash computation using the light api
   180  			var res [HashLenSHA2_256]byte
   181  			ComputeSHA2_256(&res, value)
   182  			assert.Equal(t, expected[:], res[:])
   183  		}
   184  	})
   185  
   186  	t.Run("SHA2_384", func(t *testing.T) {
   187  		for i := 0; i < 5000; i++ {
   188  			value := make([]byte, i)
   189  			_, err := rand.Read(value)
   190  			require.NoError(t, err)
   191  			expected := sha512.Sum384(value)
   192  
   193  			hasher := NewSHA2_384()
   194  			h := hasher.ComputeHash(value)
   195  			assert.Equal(t, expected[:], []byte(h))
   196  		}
   197  	})
   198  }
   199  
   200  // TestSHA3 is a specific test of SHA3-256 and SHA3-384.
   201  // It compares the hashes of random data of different lengths to
   202  // the output of standard Go sha3.
   203  func TestSHA3(t *testing.T) {
   204  	t.Run("SHA3_256", func(t *testing.T) {
   205  		for i := 0; i < 5000; i++ {
   206  			value := make([]byte, i)
   207  			_, err := rand.Read(value)
   208  			require.NoError(t, err)
   209  			expected := sha3.Sum256(value)
   210  
   211  			// test hash computation using the hasher
   212  			hasher := NewSHA3_256()
   213  			h := hasher.ComputeHash(value)
   214  			assert.Equal(t, expected[:], []byte(h))
   215  
   216  			// test hash computation using the light api
   217  			var res [HashLenSHA3_256]byte
   218  			ComputeSHA3_256(&res, value)
   219  			assert.Equal(t, expected[:], res[:])
   220  		}
   221  	})
   222  
   223  	t.Run("SHA3_384", func(t *testing.T) {
   224  		for i := 0; i < 5000; i++ {
   225  			value := make([]byte, i)
   226  			_, err := rand.Read(value)
   227  			require.NoError(t, err)
   228  			expected := sha3.Sum384(value)
   229  
   230  			hasher := NewSHA3_384()
   231  			h := hasher.ComputeHash(value)
   232  			assert.Equal(t, expected[:], []byte(h))
   233  		}
   234  	})
   235  }
   236  
   237  // TestKeccak is a specific test of Keccak-256.
   238  // It compares the hashes of random data of different lengths to
   239  // the output of Go LegacyKeccak.
   240  func TestKeccak(t *testing.T) {
   241  	for i := 0; i < 5000; i++ {
   242  		value := make([]byte, i)
   243  		_, err := rand.Read(value)
   244  		require.NoError(t, err)
   245  		k := sha3.NewLegacyKeccak256()
   246  		k.Write(value)
   247  		expected := k.Sum(nil)
   248  
   249  		// test hash computation using the hasher
   250  		hasher := NewKeccak_256()
   251  		h := hasher.ComputeHash(value)
   252  		assert.Equal(t, expected[:], []byte(h))
   253  	}
   254  }
   255  
   256  // Benchmark of all hashers' ComputeHash function
   257  func BenchmarkComputeHash(b *testing.B) {
   258  
   259  	m := make([]byte, 32)
   260  	_, err := rand.Read(m)
   261  	require.NoError(b, err)
   262  
   263  	b.Run("SHA2_256", func(b *testing.B) {
   264  		b.ResetTimer()
   265  		for i := 0; i < b.N; i++ {
   266  			alg := NewSHA2_256()
   267  			_ = alg.ComputeHash(m)
   268  		}
   269  		b.StopTimer()
   270  	})
   271  
   272  	b.Run("SHA2_256_light", func(b *testing.B) {
   273  		var h [HashLenSHA2_256]byte
   274  		b.ResetTimer()
   275  		for i := 0; i < b.N; i++ {
   276  			ComputeSHA2_256(&h, m)
   277  		}
   278  		b.StopTimer()
   279  	})
   280  
   281  	b.Run("SHA2_384", func(b *testing.B) {
   282  		b.ResetTimer()
   283  		for i := 0; i < b.N; i++ {
   284  			alg := NewSHA2_384()
   285  			_ = alg.ComputeHash(m)
   286  		}
   287  		b.StopTimer()
   288  	})
   289  
   290  	b.Run("SHA3_256", func(b *testing.B) {
   291  		b.ResetTimer()
   292  		for i := 0; i < b.N; i++ {
   293  			alg := NewSHA3_256()
   294  			alg.ComputeHash(m)
   295  		}
   296  		b.StopTimer()
   297  	})
   298  
   299  	b.Run("SHA3_256_light", func(b *testing.B) {
   300  		var h [HashLenSHA3_256]byte
   301  		b.ResetTimer()
   302  		for i := 0; i < b.N; i++ {
   303  			ComputeSHA3_256(&h, m)
   304  		}
   305  		b.StopTimer()
   306  	})
   307  
   308  	b.Run("SHA3_384", func(b *testing.B) {
   309  		b.ResetTimer()
   310  		for i := 0; i < b.N; i++ {
   311  			alg := NewSHA3_384()
   312  			_ = alg.ComputeHash(m)
   313  		}
   314  		b.StopTimer()
   315  	})
   316  
   317  	b.Run("Keccak_256", func(b *testing.B) {
   318  		b.ResetTimer()
   319  		for i := 0; i < b.N; i++ {
   320  			alg := NewKeccak_256()
   321  			alg.ComputeHash(m)
   322  		}
   323  		b.StopTimer()
   324  	})
   325  
   326  	// KMAC128 with 128 bytes output
   327  	b.Run("KMAC128_128", func(b *testing.B) {
   328  		alg, _ := NewKMAC_128([]byte("bench_key________"), []byte("bench_custommizer"), 128)
   329  		b.ResetTimer()
   330  		for i := 0; i < b.N; i++ {
   331  			_ = alg.ComputeHash(m)
   332  		}
   333  		b.StopTimer()
   334  	})
   335  }