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.

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