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

     1  package crypto
     2  
     3  import (
     4  	crand "crypto/rand"
     5  	"fmt"
     6  	mrand "math/rand"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/stretchr/testify/assert"
    11  	"github.com/stretchr/testify/require"
    12  
    13  	"github.com/onflow/flow-go/crypto/hash"
    14  )
    15  
    16  func getPRG(t *testing.T) *mrand.Rand {
    17  	random := time.Now().UnixNano()
    18  	t.Logf("rng seed is %d", random)
    19  	rng := mrand.New(mrand.NewSource(random))
    20  	return rng
    21  }
    22  
    23  func TestKeyGenErrors(t *testing.T) {
    24  	seed := make([]byte, 50)
    25  	invalidSigAlgo := SigningAlgorithm(20)
    26  	sk, err := GeneratePrivateKey(invalidSigAlgo, seed)
    27  	assert.Nil(t, sk)
    28  	assert.Error(t, err)
    29  	assert.True(t, IsInvalidInputsError(err))
    30  }
    31  
    32  func TestHasherErrors(t *testing.T) {
    33  	t.Run("nilHasher error sanity", func(t *testing.T) {
    34  		err := nilHasherError
    35  		invInpError := invalidInputsErrorf("")
    36  		otherError := fmt.Errorf("some error")
    37  		assert.True(t, IsNilHasherError(err))
    38  		assert.False(t, IsInvalidInputsError(err))
    39  		assert.False(t, IsNilHasherError(invInpError))
    40  		assert.False(t, IsNilHasherError(otherError))
    41  		assert.False(t, IsNilHasherError(nil))
    42  	})
    43  
    44  	t.Run("nilHasher error sanity", func(t *testing.T) {
    45  		err := invalidHasherSizeErrorf("")
    46  		invInpError := invalidInputsErrorf("")
    47  		otherError := fmt.Errorf("some error")
    48  		assert.True(t, IsInvalidHasherSizeError(err))
    49  		assert.False(t, IsInvalidInputsError(err))
    50  		assert.False(t, IsInvalidHasherSizeError(invInpError))
    51  		assert.False(t, IsInvalidHasherSizeError(otherError))
    52  		assert.False(t, IsInvalidHasherSizeError(nil))
    53  	})
    54  }
    55  
    56  // tests sign and verify are consistent for multiple generated keys and messages
    57  func testGenSignVerify(t *testing.T, salg SigningAlgorithm, halg hash.Hasher) {
    58  	t.Logf("Testing Generation/Signature/Verification for %s", salg)
    59  	// make sure the length is larger than minimum lengths of all the signaure algos
    60  	seedMinLength := 48
    61  	seed := make([]byte, seedMinLength)
    62  	input := make([]byte, 100)
    63  	rand := getPRG(t)
    64  
    65  	loops := 50
    66  	for j := 0; j < loops; j++ {
    67  		n, err := rand.Read(seed)
    68  		require.Equal(t, n, seedMinLength)
    69  		require.NoError(t, err)
    70  		sk, err := GeneratePrivateKey(salg, seed)
    71  		require.NoError(t, err)
    72  		_, err = rand.Read(input)
    73  		require.NoError(t, err)
    74  		s, err := sk.Sign(input, halg)
    75  		require.NoError(t, err)
    76  		pk := sk.PublicKey()
    77  
    78  		// test a valid signature
    79  		result, err := pk.Verify(s, input, halg)
    80  		require.NoError(t, err)
    81  		assert.True(t, result, fmt.Sprintf(
    82  			"Verification should succeed:\n signature:%s\n message:%x\n private key:%s", s, input, sk))
    83  
    84  		// test with a different message
    85  		input[0] ^= 1
    86  		result, err = pk.Verify(s, input, halg)
    87  		require.NoError(t, err)
    88  		assert.False(t, result, fmt.Sprintf(
    89  			"Verification should fail:\n signature:%s\n message:%x\n private key:%s", s, input, sk))
    90  		input[0] ^= 1
    91  
    92  		// test with a valid but different key
    93  		seed[0] ^= 1
    94  		wrongSk, err := GeneratePrivateKey(salg, seed)
    95  		require.NoError(t, err)
    96  		result, err = wrongSk.PublicKey().Verify(s, input, halg)
    97  		require.NoError(t, err)
    98  		assert.False(t, result, fmt.Sprintf(
    99  			"Verification should fail:\n signature:%s\n message:%x\n private key:%s", s, input, sk))
   100  
   101  		// test a wrong signature length
   102  		invalidLen := rand.Intn(2 * len(s)) // try random invalid lengths
   103  		if invalidLen == len(s) {           // map to an invalid length
   104  			invalidLen = 0
   105  		}
   106  		invalidSig := make([]byte, invalidLen)
   107  		result, err = pk.Verify(invalidSig, input, halg)
   108  		require.NoError(t, err)
   109  		assert.False(t, result, fmt.Sprintf(
   110  			"Verification should fail:\n signature:%s\n with invalid length %d", invalidSig, invalidLen))
   111  	}
   112  }
   113  
   114  // tests the key generation constraints with regards to the input seed, mainly
   115  // the seed length constraints and the result determinicity.
   116  func testKeyGenSeed(t *testing.T, salg SigningAlgorithm, minLen int, maxLen int) {
   117  	t.Run("seed length check", func(t *testing.T) {
   118  		// valid seed lengths
   119  		seed := make([]byte, minLen)
   120  		_, err := GeneratePrivateKey(salg, seed)
   121  		assert.NoError(t, err)
   122  		if maxLen > 0 {
   123  			seed = make([]byte, maxLen)
   124  			_, err = GeneratePrivateKey(salg, seed)
   125  			assert.NoError(t, err)
   126  		}
   127  		// invalid seed lengths
   128  		seed = make([]byte, minLen-1)
   129  		_, err = GeneratePrivateKey(salg, seed)
   130  		assert.Error(t, err)
   131  		assert.True(t, IsInvalidInputsError(err))
   132  		if maxLen > 0 {
   133  			seed = make([]byte, maxLen+1)
   134  			_, err = GeneratePrivateKey(salg, seed)
   135  			assert.Error(t, err)
   136  			assert.True(t, IsInvalidInputsError(err))
   137  		}
   138  	})
   139  
   140  	t.Run("deterministic generation", func(t *testing.T) {
   141  
   142  		// same seed results in the same key
   143  		seed := make([]byte, minLen)
   144  		read, err := crand.Read(seed)
   145  		require.Equal(t, read, minLen)
   146  		require.NoError(t, err)
   147  		sk1, err := GeneratePrivateKey(salg, seed)
   148  		require.NoError(t, err)
   149  		sk2, err := GeneratePrivateKey(salg, seed)
   150  		require.NoError(t, err)
   151  		assert.True(t, sk1.Equals(sk2))
   152  		// different seed results in a different key
   153  		seed[0] ^= 1 // alter a seed bit
   154  		sk2, err = GeneratePrivateKey(salg, seed)
   155  		require.NoError(t, err)
   156  		assert.False(t, sk1.Equals(sk2))
   157  	})
   158  }
   159  
   160  var BLS12381Order = []byte{0x73, 0xED, 0xA7, 0x53, 0x29, 0x9D, 0x7D, 0x48, 0x33, 0x39,
   161  	0xD8, 0x08, 0x09, 0xA1, 0xD8, 0x05, 0x53, 0xBD, 0xA4, 0x02, 0xFF, 0xFE,
   162  	0x5B, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01}
   163  
   164  func testEncodeDecode(t *testing.T, salg SigningAlgorithm) {
   165  	t.Logf("Testing encode/decode for %s", salg)
   166  	rand := getPRG(t)
   167  	// make sure the length is larger than minimum lengths of all the signaure algos
   168  	seedMinLength := 48
   169  
   170  	t.Run("happy path tests", func(t *testing.T) {
   171  		loops := 50
   172  		for j := 0; j < loops; j++ {
   173  			// generate a private key
   174  			seed := make([]byte, seedMinLength)
   175  			read, err := rand.Read(seed)
   176  			require.Equal(t, read, seedMinLength)
   177  			require.NoError(t, err)
   178  			sk, err := GeneratePrivateKey(salg, seed)
   179  			assert.Nil(t, err, "the key generation failed")
   180  			seed[0] ^= 1 // alter the seed to get a new private key
   181  			distinctSk, err := GeneratePrivateKey(salg, seed)
   182  			require.NoError(t, err)
   183  
   184  			// check private key encoding
   185  			skBytes := sk.Encode()
   186  			skCheck, err := DecodePrivateKey(salg, skBytes)
   187  			require.Nil(t, err, "the key decoding failed")
   188  			assert.True(t, sk.Equals(skCheck), "key equality check failed")
   189  			skCheckBytes := skCheck.Encode()
   190  			assert.Equal(t, skBytes, skCheckBytes, "keys should be equal")
   191  			distinctSkBytes := distinctSk.Encode()
   192  			assert.NotEqual(t, skBytes, distinctSkBytes, "keys should be different")
   193  
   194  			// check public key encoding
   195  			pk := sk.PublicKey()
   196  			pkBytes := pk.Encode()
   197  			pkCheck, err := DecodePublicKey(salg, pkBytes)
   198  			require.Nil(t, err, "the key decoding failed")
   199  			assert.True(t, pk.Equals(pkCheck), "key equality check failed")
   200  			pkCheckBytes := pkCheck.Encode()
   201  			assert.Equal(t, pkBytes, pkCheckBytes, "keys should be equal")
   202  			distinctPkBytes := distinctSk.PublicKey().Encode()
   203  			assert.NotEqual(t, pkBytes, distinctPkBytes, "keys should be different")
   204  
   205  			// same for the compressed encoding
   206  			pkComprBytes := pk.EncodeCompressed()
   207  			pkComprCheck, err := DecodePublicKeyCompressed(salg, pkComprBytes)
   208  			require.Nil(t, err, "the key decoding failed")
   209  			assert.True(t, pk.Equals(pkComprCheck), "key equality check failed")
   210  			pkCheckComprBytes := pkComprCheck.EncodeCompressed()
   211  			assert.Equal(t, pkComprBytes, pkCheckComprBytes, "keys should be equal")
   212  			distinctPkComprBytes := distinctSk.PublicKey().EncodeCompressed()
   213  			assert.NotEqual(t, pkComprBytes, distinctPkComprBytes, "keys should be different")
   214  		}
   215  	})
   216  
   217  	// test invalid private keys (equal to the curve group order)
   218  	t.Run("private keys equal to the group order", func(t *testing.T) {
   219  		groupOrder := make(map[SigningAlgorithm][]byte)
   220  		groupOrder[ECDSAP256] = []byte{255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255,
   221  			255, 255, 255, 255, 255, 188, 230, 250, 173, 167,
   222  			23, 158, 132, 243, 185, 202, 194, 252, 99, 37, 81}
   223  
   224  		groupOrder[ECDSASecp256k1] = []byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
   225  			255, 255, 255, 255, 255, 254, 186, 174, 220, 230,
   226  			175, 72, 160, 59, 191, 210, 94, 140, 208, 54, 65, 65}
   227  
   228  		groupOrder[BLSBLS12381] = BLS12381Order
   229  
   230  		sk, err := DecodePrivateKey(salg, groupOrder[salg])
   231  		require.Error(t, err, "the key decoding should fail - private key value is too large")
   232  		assert.True(t, IsInvalidInputsError(err))
   233  		assert.Nil(t, sk)
   234  	})
   235  
   236  	// test invalid private and public keys (invalid length)
   237  	t.Run("invalid key length", func(t *testing.T) {
   238  		// private key
   239  		skLens := make(map[SigningAlgorithm]int)
   240  		skLens[ECDSAP256] = PrKeyLenECDSAP256
   241  		skLens[ECDSASecp256k1] = PrKeyLenECDSASecp256k1
   242  		skLens[BLSBLS12381] = 32
   243  
   244  		bytes := make([]byte, skLens[salg]+1)
   245  		sk, err := DecodePrivateKey(salg, bytes)
   246  		require.Error(t, err)
   247  		assert.True(t, IsInvalidInputsError(err))
   248  		assert.Nil(t, sk)
   249  
   250  		// public key
   251  		pkLens := make(map[SigningAlgorithm]int)
   252  		pkLens[ECDSAP256] = PubKeyLenECDSAP256
   253  		pkLens[ECDSASecp256k1] = PubKeyLenECDSASecp256k1
   254  		pkLens[BLSBLS12381] = 96
   255  
   256  		bytes = make([]byte, pkLens[salg]+1)
   257  		pk, err := DecodePublicKey(salg, bytes)
   258  		require.Error(t, err)
   259  		assert.True(t, IsInvalidInputsError(err))
   260  		assert.Nil(t, pk)
   261  	})
   262  }
   263  
   264  func testEquals(t *testing.T, salg SigningAlgorithm, otherSigAlgo SigningAlgorithm) {
   265  	t.Logf("Testing Equals for %s", salg)
   266  	rand := getPRG(t)
   267  	// make sure the length is larger than minimum lengths of all the signaure algos
   268  	seedMinLength := 48
   269  
   270  	// generate a key pair
   271  	seed := make([]byte, seedMinLength)
   272  	n, err := rand.Read(seed)
   273  	require.Equal(t, n, seedMinLength)
   274  	require.NoError(t, err)
   275  
   276  	// first pair
   277  	sk1, err := GeneratePrivateKey(salg, seed)
   278  	require.NoError(t, err)
   279  	pk1 := sk1.PublicKey()
   280  
   281  	// second pair without changing the seed
   282  	sk2, err := GeneratePrivateKey(salg, seed)
   283  	require.NoError(t, err)
   284  	pk2 := sk2.PublicKey()
   285  
   286  	// unrelated algo pair
   287  	sk3, err := GeneratePrivateKey(otherSigAlgo, seed)
   288  	require.NoError(t, err)
   289  	pk3 := sk3.PublicKey()
   290  
   291  	// fourth pair with same algo but a different seed
   292  	seed[0] ^= 1
   293  	sk4, err := GeneratePrivateKey(salg, seed)
   294  	require.NoError(t, err)
   295  	pk4 := sk4.PublicKey()
   296  
   297  	// tests
   298  	assert.True(t, sk1.Equals(sk2), "key equality should return true")
   299  	assert.True(t, pk1.Equals(pk2), "key equality should return true")
   300  	assert.False(t, sk1.Equals(sk3), "key equality should return false")
   301  	assert.False(t, pk1.Equals(pk3), "key equality should return false")
   302  	assert.False(t, sk1.Equals(sk4), "key equality should return false")
   303  	assert.False(t, pk1.Equals(pk4), "key equality should return false")
   304  }
   305  
   306  func testKeysAlgorithm(t *testing.T, sk PrivateKey, salg SigningAlgorithm) {
   307  	t.Logf("Testing key.Algorithm for %s", salg)
   308  	alg := sk.Algorithm()
   309  	assert.Equal(t, alg, salg)
   310  	alg = sk.PublicKey().Algorithm()
   311  	assert.Equal(t, alg, salg)
   312  }
   313  
   314  func testKeySize(t *testing.T, sk PrivateKey, skLen int, pkLen int) {
   315  	t.Logf("Testing key.Size for %s", sk.Algorithm())
   316  	size := sk.Size()
   317  	assert.Equal(t, size, skLen)
   318  	size = sk.PublicKey().Size()
   319  	assert.Equal(t, size, pkLen)
   320  }
   321  
   322  func benchVerify(b *testing.B, algo SigningAlgorithm, halg hash.Hasher) {
   323  	seed := make([]byte, 48)
   324  	for j := 0; j < len(seed); j++ {
   325  		seed[j] = byte(j)
   326  	}
   327  	sk, err := GeneratePrivateKey(algo, seed)
   328  	require.NoError(b, err)
   329  	pk := sk.PublicKey()
   330  
   331  	input := []byte("Bench input")
   332  	s, err := sk.Sign(input, halg)
   333  	require.NoError(b, err)
   334  	var result bool
   335  
   336  	b.ResetTimer()
   337  	for i := 0; i < b.N; i++ {
   338  		result, err = pk.Verify(s, input, halg)
   339  		require.NoError(b, err)
   340  	}
   341  	// sanity check
   342  	require.True(b, result)
   343  
   344  	b.StopTimer()
   345  }
   346  
   347  func benchSign(b *testing.B, algo SigningAlgorithm, halg hash.Hasher) {
   348  	seed := make([]byte, 48)
   349  	for j := 0; j < len(seed); j++ {
   350  		seed[j] = byte(j)
   351  	}
   352  	sk, err := GeneratePrivateKey(algo, seed)
   353  	require.NoError(b, err)
   354  
   355  	input := []byte("Bench input")
   356  	var signature []byte
   357  
   358  	b.ResetTimer()
   359  	for i := 0; i < b.N; i++ {
   360  		signature, err = sk.Sign(input, halg)
   361  		require.NoError(b, err)
   362  	}
   363  	// sanity check
   364  	result, err := sk.PublicKey().Verify(signature, input, halg)
   365  	require.NoError(b, err)
   366  	require.True(b, result)
   367  
   368  	b.StopTimer()
   369  }