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.

112 lines
4.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 := NewThresholdMultiSignaturePubKey(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 := NewThresholdMultiSignaturePubKey(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 := NewThresholdMultiSignaturePubKey(2, pubkeys)
  78. var unmarshalledMultisig *ThresholdMultiSignaturePubKey
  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 := NewThresholdMultiSignaturePubKey(2, pubkeysCpy)
  87. require.False(t, multisigKey.Equals(multisigKey2))
  88. }
  89. func generatePubKeysAndSignatures(n int, msg []byte) (pubkeys []crypto.PubKey, signatures [][]byte) {
  90. pubkeys = make([]crypto.PubKey, n)
  91. signatures = make([][]byte, n)
  92. for i := 0; i < n; i++ {
  93. var privkey crypto.PrivKey
  94. if rand.Int63()%2 == 0 {
  95. privkey = ed25519.GenPrivKey()
  96. } else {
  97. privkey = secp256k1.GenPrivKey()
  98. }
  99. pubkeys[i] = privkey.PubKey()
  100. signatures[i], _ = privkey.Sign(msg)
  101. }
  102. return
  103. }