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.

177 lines
5.5 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. require.NoError(
  38. t,
  39. multisignature.AddSignatureFromPubKey(tc.signatures[signingIndex], tc.pubkeys[signingIndex], tc.pubkeys),
  40. )
  41. require.False(
  42. t,
  43. multisigKey.VerifyBytes(tc.msg, multisignature.Marshal()),
  44. "multisig passed when i < k, tc %d, i %d", tcIndex, i,
  45. )
  46. require.NoError(
  47. t,
  48. multisignature.AddSignatureFromPubKey(tc.signatures[signingIndex], tc.pubkeys[signingIndex], tc.pubkeys),
  49. )
  50. require.Equal(
  51. t,
  52. i+1,
  53. len(multisignature.Sigs),
  54. "adding a signature for the same pubkey twice increased signature count by 2, tc %d", tcIndex,
  55. )
  56. }
  57. require.False(
  58. t,
  59. multisigKey.VerifyBytes(tc.msg, multisignature.Marshal()),
  60. "multisig passed with k - 1 sigs, tc %d", tcIndex,
  61. )
  62. require.NoError(
  63. t,
  64. multisignature.AddSignatureFromPubKey(
  65. tc.signatures[tc.signingIndices[tc.k]],
  66. tc.pubkeys[tc.signingIndices[tc.k]],
  67. tc.pubkeys,
  68. ),
  69. )
  70. require.True(
  71. t,
  72. multisigKey.VerifyBytes(tc.msg, multisignature.Marshal()),
  73. "multisig failed after k good signatures, tc %d", tcIndex,
  74. )
  75. for i := tc.k + 1; i < len(tc.signingIndices); i++ {
  76. signingIndex := tc.signingIndices[i]
  77. require.NoError(
  78. t,
  79. multisignature.AddSignatureFromPubKey(tc.signatures[signingIndex], tc.pubkeys[signingIndex], tc.pubkeys),
  80. )
  81. require.Equal(
  82. t,
  83. tc.passAfterKSignatures[i-tc.k-1],
  84. multisigKey.VerifyBytes(tc.msg, multisignature.Marshal()),
  85. "multisig didn't verify as expected after k sigs, tc %d, i %d", tcIndex, i,
  86. )
  87. require.NoError(
  88. t,
  89. multisignature.AddSignatureFromPubKey(tc.signatures[signingIndex], tc.pubkeys[signingIndex], tc.pubkeys),
  90. )
  91. require.Equal(
  92. t,
  93. i+1,
  94. len(multisignature.Sigs),
  95. "adding a signature for the same pubkey twice increased signature count by 2, tc %d", tcIndex,
  96. )
  97. }
  98. }
  99. }
  100. // TODO: Fully replace this test with table driven tests
  101. func TestThresholdMultisigDuplicateSignatures(t *testing.T) {
  102. msg := []byte{1, 2, 3, 4, 5}
  103. pubkeys, sigs := generatePubKeysAndSignatures(5, msg)
  104. multisigKey := NewPubKeyMultisigThreshold(2, pubkeys)
  105. multisignature := NewMultisig(5)
  106. require.False(t, multisigKey.VerifyBytes(msg, multisignature.Marshal()))
  107. multisignature.AddSignatureFromPubKey(sigs[0], pubkeys[0], pubkeys)
  108. // Add second signature manually
  109. multisignature.Sigs = append(multisignature.Sigs, sigs[0])
  110. require.False(t, multisigKey.VerifyBytes(msg, multisignature.Marshal()))
  111. }
  112. // TODO: Fully replace this test with table driven tests
  113. func TestMultiSigPubKeyEquality(t *testing.T) {
  114. msg := []byte{1, 2, 3, 4}
  115. pubkeys, _ := generatePubKeysAndSignatures(5, msg)
  116. multisigKey := NewPubKeyMultisigThreshold(2, pubkeys)
  117. var unmarshalledMultisig PubKeyMultisigThreshold
  118. cdc.MustUnmarshalBinaryBare(multisigKey.Bytes(), &unmarshalledMultisig)
  119. require.True(t, multisigKey.Equals(unmarshalledMultisig))
  120. // Ensure that reordering pubkeys is treated as a different pubkey
  121. pubkeysCpy := make([]crypto.PubKey, 5)
  122. copy(pubkeysCpy, pubkeys)
  123. pubkeysCpy[4] = pubkeys[3]
  124. pubkeysCpy[3] = pubkeys[4]
  125. multisigKey2 := NewPubKeyMultisigThreshold(2, pubkeysCpy)
  126. require.False(t, multisigKey.Equals(multisigKey2))
  127. }
  128. func TestAddress(t *testing.T) {
  129. msg := []byte{1, 2, 3, 4}
  130. pubkeys, _ := generatePubKeysAndSignatures(5, msg)
  131. multisigKey := NewPubKeyMultisigThreshold(2, pubkeys)
  132. require.Len(t, multisigKey.Address().Bytes(), 20)
  133. }
  134. func TestPubKeyMultisigThresholdAminoToIface(t *testing.T) {
  135. msg := []byte{1, 2, 3, 4}
  136. pubkeys, _ := generatePubKeysAndSignatures(5, msg)
  137. multisigKey := NewPubKeyMultisigThreshold(2, pubkeys)
  138. ab, err := cdc.MarshalBinaryLengthPrefixed(multisigKey)
  139. require.NoError(t, err)
  140. // like other crypto.Pubkey implementations (e.g. ed25519.PubKeyEd25519),
  141. // PubKeyMultisigThreshold should be deserializable into a crypto.PubKey:
  142. var pubKey crypto.PubKey
  143. err = cdc.UnmarshalBinaryLengthPrefixed(ab, &pubKey)
  144. require.NoError(t, err)
  145. require.Equal(t, multisigKey, pubKey)
  146. }
  147. func generatePubKeysAndSignatures(n int, msg []byte) (pubkeys []crypto.PubKey, signatures [][]byte) {
  148. pubkeys = make([]crypto.PubKey, n)
  149. signatures = make([][]byte, n)
  150. for i := 0; i < n; i++ {
  151. var privkey crypto.PrivKey
  152. if rand.Int63()%2 == 0 {
  153. privkey = ed25519.GenPrivKey()
  154. } else {
  155. privkey = secp256k1.GenPrivKey()
  156. }
  157. pubkeys[i] = privkey.PubKey()
  158. signatures[i], _ = privkey.Sign(msg)
  159. }
  160. return
  161. }