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.

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