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