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  }