You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

135 lines
5.2 KiB

  1. package multisig
  2. import (
  3. "math/rand"
  4. "testing"
  5. "github.com/stretchr/testify/require"
  6. "github.com/tendermint/tendermint/crypto"
  7. "github.com/tendermint/tendermint/crypto/ed25519"
  8. "github.com/tendermint/tendermint/crypto/secp256k1"
  9. )
  10. // This tests multisig functionality, but it expects the first k signatures to be valid
  11. // TODO: Adapt it to give more flexibility about first k signatures being valid
  12. func TestThresholdMultisigValidCases(t *testing.T) {
  13. pkSet1, sigSet1 := generatePubKeysAndSignatures(5, []byte{1, 2, 3, 4})
  14. cases := []struct {
  15. msg []byte
  16. k int
  17. pubkeys []crypto.PubKey
  18. signingIndices []int
  19. // signatures should be the same size as signingIndices.
  20. signatures [][]byte
  21. passAfterKSignatures []bool
  22. }{
  23. {
  24. msg: []byte{1, 2, 3, 4},
  25. k: 2,
  26. pubkeys: pkSet1,
  27. signingIndices: []int{0, 3, 1},
  28. signatures: sigSet1,
  29. passAfterKSignatures: []bool{false},
  30. },
  31. }
  32. for tcIndex, tc := range cases {
  33. multisigKey := NewPubKeyMultisigThreshold(tc.k, tc.pubkeys)
  34. multisignature := NewMultisig(len(tc.pubkeys))
  35. for i := 0; i < tc.k-1; i++ {
  36. signingIndex := tc.signingIndices[i]
  37. multisignature.AddSignatureFromPubKey(tc.signatures[signingIndex], tc.pubkeys[signingIndex], tc.pubkeys)
  38. require.False(t, multisigKey.VerifyBytes(tc.msg, multisignature.Marshal()),
  39. "multisig passed when i < k, tc %d, i %d", tcIndex, i)
  40. multisignature.AddSignatureFromPubKey(tc.signatures[signingIndex], tc.pubkeys[signingIndex], tc.pubkeys)
  41. require.Equal(t, i+1, len(multisignature.Sigs),
  42. "adding a signature for the same pubkey twice increased signature count by 2, tc %d", tcIndex)
  43. }
  44. require.False(t, multisigKey.VerifyBytes(tc.msg, multisignature.Marshal()),
  45. "multisig passed with k - 1 sigs, tc %d", tcIndex)
  46. multisignature.AddSignatureFromPubKey(tc.signatures[tc.signingIndices[tc.k]], tc.pubkeys[tc.signingIndices[tc.k]], tc.pubkeys)
  47. require.True(t, multisigKey.VerifyBytes(tc.msg, multisignature.Marshal()),
  48. "multisig failed after k good signatures, tc %d", tcIndex)
  49. for i := tc.k + 1; i < len(tc.signingIndices); i++ {
  50. signingIndex := tc.signingIndices[i]
  51. multisignature.AddSignatureFromPubKey(tc.signatures[signingIndex], tc.pubkeys[signingIndex], tc.pubkeys)
  52. require.Equal(t, tc.passAfterKSignatures[i-tc.k-1],
  53. multisigKey.VerifyBytes(tc.msg, multisignature.Marshal()),
  54. "multisig didn't verify as expected after k sigs, tc %d, i %d", tcIndex, i)
  55. multisignature.AddSignatureFromPubKey(tc.signatures[signingIndex], tc.pubkeys[signingIndex], tc.pubkeys)
  56. require.Equal(t, i+1, len(multisignature.Sigs),
  57. "adding a signature for the same pubkey twice increased signature count by 2, tc %d", tcIndex)
  58. }
  59. }
  60. }
  61. // TODO: Fully replace this test with table driven tests
  62. func TestThresholdMultisigDuplicateSignatures(t *testing.T) {
  63. msg := []byte{1, 2, 3, 4, 5}
  64. pubkeys, sigs := generatePubKeysAndSignatures(5, msg)
  65. multisigKey := NewPubKeyMultisigThreshold(2, pubkeys)
  66. multisignature := NewMultisig(5)
  67. require.False(t, multisigKey.VerifyBytes(msg, multisignature.Marshal()))
  68. multisignature.AddSignatureFromPubKey(sigs[0], pubkeys[0], pubkeys)
  69. // Add second signature manually
  70. multisignature.Sigs = append(multisignature.Sigs, sigs[0])
  71. require.False(t, multisigKey.VerifyBytes(msg, multisignature.Marshal()))
  72. }
  73. // TODO: Fully replace this test with table driven tests
  74. func TestMultiSigPubKeyEquality(t *testing.T) {
  75. msg := []byte{1, 2, 3, 4}
  76. pubkeys, _ := generatePubKeysAndSignatures(5, msg)
  77. multisigKey := NewPubKeyMultisigThreshold(2, pubkeys)
  78. var unmarshalledMultisig PubKeyMultisigThreshold
  79. cdc.MustUnmarshalBinaryBare(multisigKey.Bytes(), &unmarshalledMultisig)
  80. require.True(t, multisigKey.Equals(unmarshalledMultisig))
  81. // Ensure that reordering pubkeys is treated as a different pubkey
  82. pubkeysCpy := make([]crypto.PubKey, 5)
  83. copy(pubkeysCpy, pubkeys)
  84. pubkeysCpy[4] = pubkeys[3]
  85. pubkeysCpy[3] = pubkeys[4]
  86. multisigKey2 := NewPubKeyMultisigThreshold(2, pubkeysCpy)
  87. require.False(t, multisigKey.Equals(multisigKey2))
  88. }
  89. func TestAddress(t *testing.T) {
  90. msg := []byte{1, 2, 3, 4}
  91. pubkeys, _ := generatePubKeysAndSignatures(5, msg)
  92. multisigKey := NewPubKeyMultisigThreshold(2, pubkeys)
  93. require.Len(t, multisigKey.Address().Bytes(), 20)
  94. }
  95. func TestPubKeyMultisigThresholdAminoToIface(t *testing.T) {
  96. msg := []byte{1, 2, 3, 4}
  97. pubkeys, _ := generatePubKeysAndSignatures(5, msg)
  98. multisigKey := NewPubKeyMultisigThreshold(2, pubkeys)
  99. ab, err := cdc.MarshalBinaryLengthPrefixed(multisigKey)
  100. require.NoError(t, err)
  101. // like other crypto.Pubkey implementations (e.g. ed25519.PubKeyEd25519),
  102. // PubKeyMultisigThreshold should be deserializable into a crypto.PubKey:
  103. var pubKey crypto.PubKey
  104. err = cdc.UnmarshalBinaryLengthPrefixed(ab, &pubKey)
  105. require.NoError(t, err)
  106. require.Equal(t, multisigKey, pubKey)
  107. }
  108. func generatePubKeysAndSignatures(n int, msg []byte) (pubkeys []crypto.PubKey, signatures [][]byte) {
  109. pubkeys = make([]crypto.PubKey, n)
  110. signatures = make([][]byte, n)
  111. for i := 0; i < n; i++ {
  112. var privkey crypto.PrivKey
  113. if rand.Int63()%2 == 0 {
  114. privkey = ed25519.GenPrivKey()
  115. } else {
  116. privkey = secp256k1.GenPrivKey()
  117. }
  118. pubkeys[i] = privkey.PubKey()
  119. signatures[i], _ = privkey.Sign(msg)
  120. }
  121. return
  122. }