diff --git a/CHANGELOG.md b/CHANGELOG.md index 6384005aca8a..60412e47152d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -105,6 +105,7 @@ be used to retrieve the actual proposal `Content`. Also the `NewMsgSubmitProposa ### Features +* (crypto/multisig) [\#6241](https://github.com/cosmos/cosmos-sdk/pull/6241) Add Multisig type directly to the repo. Previously this was in tendermint. * (rest) [\#6167](https://github.com/cosmos/cosmos-sdk/pull/6167) Support `max-body-bytes` CLI flag for the REST service. * (x/ibc) [\#5588](https://github.com/cosmos/cosmos-sdk/pull/5588) Add [ICS 024 - Host State Machine Requirements](https://github.com/cosmos/ics/tree/master/spec/ics-024-host-requirements) subpackage to `x/ibc` module. * (x/ibc) [\#5277](https://github.com/cosmos/cosmos-sdk/pull/5277) `x/ibc` changes from IBC alpha. For more details check the the [`x/ibc/spec`](https://github.com/cosmos/tree/master/x/ibc/spec) directory: diff --git a/crypto/types/compact_bit_array.go b/crypto/types/compact_bit_array.go new file mode 100644 index 000000000000..f2d68100eec3 --- /dev/null +++ b/crypto/types/compact_bit_array.go @@ -0,0 +1,248 @@ +package types + +import ( + "bytes" + "encoding/binary" + "errors" + "fmt" + "regexp" + "strings" +) + +// CompactBitArray is an implementation of a space efficient bit array. +// This is used to ensure that the encoded data takes up a minimal amount of +// space after amino encoding. +// This is not thread safe, and is not intended for concurrent usage. + +// NewCompactBitArray returns a new compact bit array. +// It returns nil if the number of bits is zero. +func NewCompactBitArray(bits int) *CompactBitArray { + if bits <= 0 { + return nil + } + return &CompactBitArray{ + ExtraBitsStored: uint32(bits % 8), + Elems: make([]byte, (bits+7)/8), + } +} + +// Size returns the number of bits in the bitarray +func (bA *CompactBitArray) Size() int { + if bA == nil { + return 0 + } else if bA.ExtraBitsStored == uint32(0) { + return len(bA.Elems) * 8 + } + + return (len(bA.Elems)-1)*8 + int(bA.ExtraBitsStored) +} + +// GetIndex returns the bit at index i within the bit array. +// The behavior is undefined if i >= bA.Size() +func (bA *CompactBitArray) GetIndex(i int) bool { + if bA == nil { + return false + } + if i >= bA.Size() { + return false + } + + return bA.Elems[i>>3]&(uint8(1)< 0 +} + +// SetIndex sets the bit at index i within the bit array. +// The behavior is undefined if i >= bA.Size() +func (bA *CompactBitArray) SetIndex(i int, v bool) bool { + if bA == nil { + return false + } + + if i >= bA.Size() { + return false + } + + if v { + bA.Elems[i>>3] |= (uint8(1) << uint8(7-(i%8))) + } else { + bA.Elems[i>>3] &= ^(uint8(1) << uint8(7-(i%8))) + } + + return true +} + +// NumTrueBitsBefore returns the number of bits set to true before the +// given index. e.g. if bA = _XX__XX, NumOfTrueBitsBefore(4) = 2, since +// there are two bits set to true before index 4. +func (bA *CompactBitArray) NumTrueBitsBefore(index int) int { + numTrueValues := 0 + for i := 0; i < index; i++ { + if bA.GetIndex(i) { + numTrueValues++ + } + } + + return numTrueValues +} + +// Copy returns a copy of the provided bit array. +func (bA *CompactBitArray) Copy() *CompactBitArray { + if bA == nil { + return nil + } + + c := make([]byte, len(bA.Elems)) + copy(c, bA.Elems) + + return &CompactBitArray{ + ExtraBitsStored: bA.ExtraBitsStored, + Elems: c, + } +} + +// String returns a string representation of CompactBitArray: BA{}, +// where is a sequence of 'x' (1) and '_' (0). +// The includes spaces and newlines to help people. +// For a simple sequence of 'x' and '_' characters with no spaces or newlines, +// see the MarshalJSON() method. +// Example: "BA{_x_}" or "nil-BitArray" for nil. +func (bA *CompactBitArray) String() string { return bA.StringIndented("") } + +// StringIndented returns the same thing as String(), but applies the indent +// at every 10th bit, and twice at every 50th bit. +func (bA *CompactBitArray) StringIndented(indent string) string { + if bA == nil { + return "nil-BitArray" + } + lines := []string{} + bits := "" + size := bA.Size() + for i := 0; i < size; i++ { + if bA.GetIndex(i) { + bits += "x" + } else { + bits += "_" + } + + if i%100 == 99 { + lines = append(lines, bits) + bits = "" + } + + if i%10 == 9 { + bits += indent + } + + if i%50 == 49 { + bits += indent + } + } + + if len(bits) > 0 { + lines = append(lines, bits) + } + + return fmt.Sprintf("BA{%v:%v}", size, strings.Join(lines, indent)) +} + +// MarshalJSON implements json.Marshaler interface by marshaling bit array +// using a custom format: a string of '-' or 'x' where 'x' denotes the 1 bit. +func (bA *CompactBitArray) MarshalJSON() ([]byte, error) { + if bA == nil { + return []byte("null"), nil + } + + bits := `"` + size := bA.Size() + for i := 0; i < size; i++ { + if bA.GetIndex(i) { + bits += `x` + } else { + bits += `_` + } + } + + bits += `"` + + return []byte(bits), nil +} + +var bitArrayJSONRegexp = regexp.MustCompile(`\A"([_x]*)"\z`) + +// UnmarshalJSON implements json.Unmarshaler interface by unmarshaling a custom +// JSON description. +func (bA *CompactBitArray) UnmarshalJSON(bz []byte) error { + b := string(bz) + if b == "null" { + // This is required e.g. for encoding/json when decoding + // into a pointer with pre-allocated BitArray. + bA.ExtraBitsStored = 0 + bA.Elems = nil + + return nil + } + + match := bitArrayJSONRegexp.FindStringSubmatch(b) + if match == nil { + return fmt.Errorf("bitArray in JSON should be a string of format %q but got %s", bitArrayJSONRegexp.String(), b) + } + + bits := match[1] + + // Construct new CompactBitArray and copy over. + numBits := len(bits) + bA2 := NewCompactBitArray(numBits) + for i := 0; i < numBits; i++ { + if bits[i] == 'x' { + bA2.SetIndex(i, true) + } + } + *bA = *bA2 + + return nil +} + +// CompactMarshal is a space efficient encoding for CompactBitArray. +// It is not amino compatible. +func (bA *CompactBitArray) CompactMarshal() []byte { + size := bA.Size() + if size <= 0 { + return []byte("null") + } + + bz := make([]byte, 0, size/8) + // length prefix number of bits, not number of bytes. This difference + // takes 3-4 bits in encoding, as opposed to instead encoding the number of + // bytes (saving 3-4 bits) and including the offset as a full byte. + bz = appendUvarint(bz, uint64(size)) + bz = append(bz, bA.Elems...) + + return bz +} + +// CompactUnmarshal is a space efficient decoding for CompactBitArray. +// It is not amino compatible. +func CompactUnmarshal(bz []byte) (*CompactBitArray, error) { + if len(bz) < 2 { + return nil, errors.New("compact bit array: invalid compact unmarshal size") + } else if bytes.Equal(bz, []byte("null")) { + return NewCompactBitArray(0), nil + } + + size, n := binary.Uvarint(bz) + bz = bz[n:] + + if len(bz) != int(size+7)/8 { + return nil, errors.New("compact bit array: invalid compact unmarshal size") + } + + bA := &CompactBitArray{uint32(size % 8), bz} + + return bA, nil +} + +func appendUvarint(b []byte, x uint64) []byte { + var a [binary.MaxVarintLen64]byte + n := binary.PutUvarint(a[:], x) + + return append(b, a[:n]...) +} diff --git a/crypto/types/compact_bit_array_test.go b/crypto/types/compact_bit_array_test.go new file mode 100644 index 000000000000..44408e43ae06 --- /dev/null +++ b/crypto/types/compact_bit_array_test.go @@ -0,0 +1,202 @@ +package types + +import ( + "encoding/json" + "math/rand" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + tmrand "github.com/tendermint/tendermint/libs/rand" +) + +func randCompactBitArray(bits int) (*CompactBitArray, []byte) { + numBytes := (bits + 7) / 8 + src := tmrand.Bytes((bits + 7) / 8) + bA := NewCompactBitArray(bits) + + for i := 0; i < numBytes-1; i++ { + for j := uint8(0); j < 8; j++ { + bA.SetIndex(i*8+int(j), src[i]&(uint8(1)<<(8-j)) > 0) + } + } + // Set remaining bits + for i := uint32(0); i < 8-bA.ExtraBitsStored; i++ { + bA.SetIndex(numBytes*8+int(i), src[numBytes-1]&(uint8(1)<<(8-i)) > 0) + } + return bA, src +} + +func TestNewBitArrayNeverCrashesOnNegatives(t *testing.T) { + bitList := []int{-127, -128, -1 << 31} + for _, bits := range bitList { + bA := NewCompactBitArray(bits) + require.Nil(t, bA) + } +} + +func TestJSONMarshalUnmarshal(t *testing.T) { + + bA1 := NewCompactBitArray(0) + bA2 := NewCompactBitArray(1) + + bA3 := NewCompactBitArray(1) + bA3.SetIndex(0, true) + + bA4 := NewCompactBitArray(5) + bA4.SetIndex(0, true) + bA4.SetIndex(1, true) + + bA5 := NewCompactBitArray(9) + bA5.SetIndex(0, true) + bA5.SetIndex(1, true) + bA5.SetIndex(8, true) + + bA6 := NewCompactBitArray(16) + bA6.SetIndex(0, true) + bA6.SetIndex(1, true) + bA6.SetIndex(8, false) + bA6.SetIndex(15, true) + + testCases := []struct { + bA *CompactBitArray + marshalledBA string + }{ + {nil, `null`}, + {bA1, `null`}, + {bA2, `"_"`}, + {bA3, `"x"`}, + {bA4, `"xx___"`}, + {bA5, `"xx______x"`}, + {bA6, `"xx_____________x"`}, + } + + for _, tc := range testCases { + tc := tc + t.Run(tc.bA.String(), func(t *testing.T) { + bz, err := json.Marshal(tc.bA) + require.NoError(t, err) + + assert.Equal(t, tc.marshalledBA, string(bz)) + + var unmarshalledBA *CompactBitArray + err = json.Unmarshal(bz, &unmarshalledBA) + require.NoError(t, err) + + if tc.bA == nil { + require.Nil(t, unmarshalledBA) + } else { + require.NotNil(t, unmarshalledBA) + assert.EqualValues(t, tc.bA.Elems, unmarshalledBA.Elems) + if assert.EqualValues(t, tc.bA.String(), unmarshalledBA.String()) { + assert.EqualValues(t, tc.bA.Elems, unmarshalledBA.Elems) + } + } + }) + } +} + +func TestCompactMarshalUnmarshal(t *testing.T) { + bA1 := NewCompactBitArray(0) + bA2 := NewCompactBitArray(1) + + bA3 := NewCompactBitArray(1) + bA3.SetIndex(0, true) + + bA4 := NewCompactBitArray(5) + bA4.SetIndex(0, true) + bA4.SetIndex(1, true) + + bA5 := NewCompactBitArray(9) + bA5.SetIndex(0, true) + bA5.SetIndex(1, true) + bA5.SetIndex(8, true) + + bA6 := NewCompactBitArray(16) + bA6.SetIndex(0, true) + bA6.SetIndex(1, true) + bA6.SetIndex(8, false) + bA6.SetIndex(15, true) + + testCases := []struct { + bA *CompactBitArray + marshalledBA []byte + }{ + {nil, []byte("null")}, + {bA1, []byte("null")}, + {bA2, []byte{byte(1), byte(0)}}, + {bA3, []byte{byte(1), byte(128)}}, + {bA4, []byte{byte(5), byte(192)}}, + {bA5, []byte{byte(9), byte(192), byte(128)}}, + {bA6, []byte{byte(16), byte(192), byte(1)}}, + } + + for _, tc := range testCases { + tc := tc + t.Run(tc.bA.String(), func(t *testing.T) { + bz := tc.bA.CompactMarshal() + + assert.Equal(t, tc.marshalledBA, bz) + + unmarshalledBA, err := CompactUnmarshal(bz) + require.NoError(t, err) + if tc.bA == nil { + require.Nil(t, unmarshalledBA) + } else { + require.NotNil(t, unmarshalledBA) + assert.EqualValues(t, tc.bA.Elems, unmarshalledBA.Elems) + if assert.EqualValues(t, tc.bA.String(), unmarshalledBA.String()) { + assert.EqualValues(t, tc.bA.Elems, unmarshalledBA.Elems) + } + } + }) + } +} + +func TestCompactBitArrayNumOfTrueBitsBefore(t *testing.T) { + testCases := []struct { + marshalledBA string + bAIndex []int + trueValueIndex []int + }{ + {`"_____"`, []int{0, 1, 2, 3, 4}, []int{0, 0, 0, 0, 0}}, + {`"x"`, []int{0}, []int{0}}, + {`"_x"`, []int{1}, []int{0}}, + {`"x___xxxx"`, []int{0, 4, 5, 6, 7}, []int{0, 1, 2, 3, 4}}, + {`"__x_xx_x__x_x___"`, []int{2, 4, 5, 7, 10, 12}, []int{0, 1, 2, 3, 4, 5}}, + {`"______________xx"`, []int{14, 15}, []int{0, 1}}, + } + for tcIndex, tc := range testCases { + tc := tc + tcIndex := tcIndex + t.Run(tc.marshalledBA, func(t *testing.T) { + var bA *CompactBitArray + err := json.Unmarshal([]byte(tc.marshalledBA), &bA) + require.NoError(t, err) + + for i := 0; i < len(tc.bAIndex); i++ { + + require.Equal(t, tc.trueValueIndex[i], bA.NumTrueBitsBefore(tc.bAIndex[i]), "tc %d, i %d", tcIndex, i) + } + }) + } +} + +func TestCompactBitArrayGetSetIndex(t *testing.T) { + r := rand.New(rand.NewSource(100)) + numTests := 10 + numBitsPerArr := 100 + for i := 0; i < numTests; i++ { + bits := r.Intn(1000) + bA, _ := randCompactBitArray(bits) + + for j := 0; j < numBitsPerArr; j++ { + copy := bA.Copy() + index := r.Intn(bits) + val := (r.Int63() % 2) == 0 + bA.SetIndex(index, val) + require.Equal(t, val, bA.GetIndex(index), "bA.SetIndex(%d, %v) failed on bit array: %s", index, val, copy) + } + } +} diff --git a/crypto/types/multisig/codec.go b/crypto/types/multisig/codec.go new file mode 100644 index 000000000000..3c34b6ca0162 --- /dev/null +++ b/crypto/types/multisig/codec.go @@ -0,0 +1,30 @@ +package multisig + +import ( + amino "github.com/tendermint/go-amino" + + "github.com/tendermint/tendermint/crypto" + "github.com/tendermint/tendermint/crypto/ed25519" + "github.com/tendermint/tendermint/crypto/secp256k1" + "github.com/tendermint/tendermint/crypto/sr25519" +) + +// TODO: Figure out API for others to either add their own pubkey types, or +// to make verify / marshal accept a cdc. +const ( + PubKeyAminoRoute = "tendermint/PubKeyMultisigThreshold" +) + +var cdc = amino.NewCodec() + +func init() { + cdc.RegisterInterface((*crypto.PubKey)(nil), nil) + cdc.RegisterConcrete(PubKey{}, + PubKeyAminoRoute, nil) + cdc.RegisterConcrete(ed25519.PubKeyEd25519{}, + ed25519.PubKeyAminoName, nil) + cdc.RegisterConcrete(sr25519.PubKeySr25519{}, + sr25519.PubKeyAminoName, nil) + cdc.RegisterConcrete(secp256k1.PubKeySecp256k1{}, + secp256k1.PubKeyAminoName, nil) +} diff --git a/crypto/types/multisig/multisignature.go b/crypto/types/multisig/multisignature.go new file mode 100644 index 000000000000..cef36be3a635 --- /dev/null +++ b/crypto/types/multisig/multisignature.go @@ -0,0 +1,77 @@ +package multisig + +import ( + "fmt" + "strings" + + "github.com/cosmos/cosmos-sdk/crypto/types" + "github.com/tendermint/tendermint/crypto" +) + +// Multisignature is used to represent the signature object used in the multisigs. +// Sigs is a list of signatures, sorted by corresponding index. +type Multisignature struct { + BitArray *types.CompactBitArray + Sigs [][]byte +} + +// NewMultisig returns a new Multisignature of size n. +func NewMultisig(n int) *Multisignature { + // Default the signature list to have a capacity of two, since we can + // expect that most multisigs will require multiple signers. + return &Multisignature{types.NewCompactBitArray(n), make([][]byte, 0, 2)} +} + +// GetIndex returns the index of pk in keys. Returns -1 if not found +func getIndex(pk crypto.PubKey, keys []crypto.PubKey) int { + for i := 0; i < len(keys); i++ { + if pk.Equals(keys[i]) { + return i + } + } + return -1 +} + +// AddSignature adds a signature to the multisig, at the corresponding index. +// If the signature already exists, replace it. +func (mSig *Multisignature) AddSignature(sig []byte, index int) { + newSigIndex := mSig.BitArray.NumTrueBitsBefore(index) + // Signature already exists, just replace the value there + if mSig.BitArray.GetIndex(index) { + mSig.Sigs[newSigIndex] = sig + return + } + mSig.BitArray.SetIndex(index, true) + // Optimization if the index is the greatest index + if newSigIndex == len(mSig.Sigs) { + mSig.Sigs = append(mSig.Sigs, sig) + return + } + // Expand slice by one with a dummy element, move all elements after i + // over by one, then place the new signature in that gap. + mSig.Sigs = append(mSig.Sigs, make([]byte, 0)) + copy(mSig.Sigs[newSigIndex+1:], mSig.Sigs[newSigIndex:]) + mSig.Sigs[newSigIndex] = sig +} + +// AddSignatureFromPubKey adds a signature to the multisig, at the index in +// keys corresponding to the provided pubkey. +func (mSig *Multisignature) AddSignatureFromPubKey(sig []byte, pubkey crypto.PubKey, keys []crypto.PubKey) error { + index := getIndex(pubkey, keys) + if index == -1 { + keysStr := make([]string, len(keys)) + for i, k := range keys { + keysStr[i] = fmt.Sprintf("%X", k.Bytes()) + } + + return fmt.Errorf("provided key %X doesn't exist in pubkeys: \n%s", pubkey.Bytes(), strings.Join(keysStr, "\n")) + } + + mSig.AddSignature(sig, index) + return nil +} + +// Marshal the multisignature with amino +func (mSig *Multisignature) Marshal() []byte { + return cdc.MustMarshalBinaryBare(mSig) +} diff --git a/crypto/types/multisig/threshold_pubkey.go b/crypto/types/multisig/threshold_pubkey.go new file mode 100644 index 000000000000..3e0deb83b594 --- /dev/null +++ b/crypto/types/multisig/threshold_pubkey.go @@ -0,0 +1,96 @@ +package multisig + +import ( + "github.com/tendermint/tendermint/crypto" +) + +// PubKey implements a K of N threshold multisig. +type PubKey struct { + K uint `json:"threshold"` + PubKeys []crypto.PubKey `json:"pubkeys"` +} + +var _ crypto.PubKey = PubKey{} + +// NewPubKeyMultisigThreshold returns a new PubKeyMultisigThreshold. +// Panics if len(pubkeys) < k or 0 >= k. +func NewPubKeyMultisigThreshold(k int, pubkeys []crypto.PubKey) crypto.PubKey { + if k <= 0 { + panic("threshold k of n multisignature: k <= 0") + } + if len(pubkeys) < k { + panic("threshold k of n multisignature: len(pubkeys) < k") + } + for _, pubkey := range pubkeys { + if pubkey == nil { + panic("nil pubkey") + } + } + return PubKey{uint(k), pubkeys} +} + +// VerifyBytes expects sig to be an amino encoded version of a MultiSignature. +// Returns true iff the multisignature contains k or more signatures +// for the correct corresponding keys, +// and all signatures are valid. (Not just k of the signatures) +// The multisig uses a bitarray, so multiple signatures for the same key is not +// a concern. +func (pk PubKey) VerifyBytes(msg []byte, marshalledSig []byte) bool { + var sig Multisignature + err := cdc.UnmarshalBinaryBare(marshalledSig, &sig) + if err != nil { + return false + } + size := sig.BitArray.Size() + // ensure bit array is the correct size + if len(pk.PubKeys) != size { + return false + } + // ensure size of signature list + if len(sig.Sigs) < int(pk.K) || len(sig.Sigs) > size { + return false + } + // ensure at least k signatures are set + if sig.BitArray.NumTrueBitsBefore(size) < int(pk.K) { + return false + } + // index in the list of signatures which we are concerned with. + sigIndex := 0 + for i := 0; i < size; i++ { + if sig.BitArray.GetIndex(i) { + if !pk.PubKeys[i].VerifyBytes(msg, sig.Sigs[sigIndex]) { + return false + } + sigIndex++ + } + } + return true +} + +// Bytes returns the amino encoded version of the PubKey +func (pk PubKey) Bytes() []byte { + return cdc.MustMarshalBinaryBare(pk) +} + +// Address returns tmhash(PubKey.Bytes()) +func (pk PubKey) Address() crypto.Address { + return crypto.AddressHash(pk.Bytes()) +} + +// Equals returns true iff pk and other both have the same number of keys, and +// all constituent keys are the same, and in the same order. +func (pk PubKey) Equals(other crypto.PubKey) bool { + otherKey, sameType := other.(PubKey) + if !sameType { + return false + } + if pk.K != otherKey.K || len(pk.PubKeys) != len(otherKey.PubKeys) { + return false + } + for i := 0; i < len(pk.PubKeys); i++ { + if !pk.PubKeys[i].Equals(otherKey.PubKeys[i]) { + return false + } + } + return true +} diff --git a/crypto/types/multisig/threshold_pubkey_test.go b/crypto/types/multisig/threshold_pubkey_test.go new file mode 100644 index 000000000000..11ea2f0c4536 --- /dev/null +++ b/crypto/types/multisig/threshold_pubkey_test.go @@ -0,0 +1,186 @@ +package multisig + +import ( + "math/rand" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/tendermint/tendermint/crypto" + "github.com/tendermint/tendermint/crypto/ed25519" + "github.com/tendermint/tendermint/crypto/secp256k1" + "github.com/tendermint/tendermint/crypto/sr25519" +) + +// This tests multisig functionality, but it expects the first k signatures to be valid +// TODO: Adapt it to give more flexibility about first k signatures being valid +func TestThresholdMultisigValidCases(t *testing.T) { + pkSet1, sigSet1 := generatePubKeysAndSignatures(5, []byte{1, 2, 3, 4}) + cases := []struct { + msg []byte + k int + pubkeys []crypto.PubKey + signingIndices []int + // signatures should be the same size as signingIndices. + signatures [][]byte + passAfterKSignatures []bool + }{ + { + msg: []byte{1, 2, 3, 4}, + k: 2, + pubkeys: pkSet1, + signingIndices: []int{0, 3, 1}, + signatures: sigSet1, + passAfterKSignatures: []bool{false}, + }, + } + for tcIndex, tc := range cases { + multisigKey := NewPubKeyMultisigThreshold(tc.k, tc.pubkeys) + multisignature := NewMultisig(len(tc.pubkeys)) + + for i := 0; i < tc.k-1; i++ { + signingIndex := tc.signingIndices[i] + require.NoError( + t, + multisignature.AddSignatureFromPubKey(tc.signatures[signingIndex], tc.pubkeys[signingIndex], tc.pubkeys), + ) + bz := multisignature.Marshal() + require.False( + t, + multisigKey.VerifyBytes(tc.msg, bz), + "multisig passed when i < k, tc %d, i %d", tcIndex, i, + ) + require.NoError( + t, + multisignature.AddSignatureFromPubKey(tc.signatures[signingIndex], tc.pubkeys[signingIndex], tc.pubkeys), + ) + require.Equal( + t, + i+1, + len(multisignature.Sigs), + "adding a signature for the same pubkey twice increased signature count by 2, tc %d", tcIndex, + ) + } + bz := multisignature.Marshal() + require.False( + t, + multisigKey.VerifyBytes(tc.msg, bz), + "multisig passed with k - 1 sigs, tc %d", tcIndex, + ) + require.NoError( + t, + multisignature.AddSignatureFromPubKey( + tc.signatures[tc.signingIndices[tc.k]], + tc.pubkeys[tc.signingIndices[tc.k]], + tc.pubkeys, + ), + ) + bz = multisignature.Marshal() + require.True( + t, + multisigKey.VerifyBytes(tc.msg, bz), + "multisig failed after k good signatures, tc %d", tcIndex, + ) + + for i := tc.k + 1; i < len(tc.signingIndices); i++ { + signingIndex := tc.signingIndices[i] + + require.NoError( + t, + multisignature.AddSignatureFromPubKey(tc.signatures[signingIndex], tc.pubkeys[signingIndex], tc.pubkeys), + ) + bz := multisignature.Marshal() + require.Equal( + t, + tc.passAfterKSignatures[i-tc.k-1], + multisigKey.VerifyBytes(tc.msg, bz), + "multisig didn't verify as expected after k sigs, tc %d, i %d", tcIndex, i, + ) + require.NoError( + t, + multisignature.AddSignatureFromPubKey(tc.signatures[signingIndex], tc.pubkeys[signingIndex], tc.pubkeys), + ) + require.Equal( + t, + i+1, + len(multisignature.Sigs), + "adding a signature for the same pubkey twice increased signature count by 2, tc %d", tcIndex, + ) + } + } +} + +// TODO: Fully replace this test with table driven tests +func TestThresholdMultisigDuplicateSignatures(t *testing.T) { + msg := []byte{1, 2, 3, 4, 5} + pubkeys, sigs := generatePubKeysAndSignatures(5, msg) + multisigKey := NewPubKeyMultisigThreshold(2, pubkeys) + multisignature := NewMultisig(5) + bz := multisignature.Marshal() + + require.False(t, multisigKey.VerifyBytes(msg, bz)) + multisignature.AddSignatureFromPubKey(sigs[0], pubkeys[0], pubkeys) + // Add second signature manually + multisignature.Sigs = append(multisignature.Sigs, sigs[0]) + require.False(t, multisigKey.VerifyBytes(msg, bz)) +} + +// TODO: Fully replace this test with table driven tests +func TestMultiSigPubKeyEquality(t *testing.T) { + msg := []byte{1, 2, 3, 4} + pubkeys, _ := generatePubKeysAndSignatures(5, msg) + multisigKey := NewPubKeyMultisigThreshold(2, pubkeys) + var unmarshalledMultisig PubKey + cdc.MustUnmarshalBinaryBare(multisigKey.Bytes(), &unmarshalledMultisig) + require.True(t, multisigKey.Equals(unmarshalledMultisig)) + + // Ensure that reordering pubkeys is treated as a different pubkey + pubkeysCpy := make([]crypto.PubKey, 5) + copy(pubkeysCpy, pubkeys) + pubkeysCpy[4] = pubkeys[3] + pubkeysCpy[3] = pubkeys[4] + multisigKey2 := NewPubKeyMultisigThreshold(2, pubkeysCpy) + require.False(t, multisigKey.Equals(multisigKey2)) +} + +func TestAddress(t *testing.T) { + msg := []byte{1, 2, 3, 4} + pubkeys, _ := generatePubKeysAndSignatures(5, msg) + multisigKey := NewPubKeyMultisigThreshold(2, pubkeys) + require.Len(t, multisigKey.Address().Bytes(), 20) +} + +func TestPubKeyMultisigThresholdAminoToIface(t *testing.T) { + msg := []byte{1, 2, 3, 4} + pubkeys, _ := generatePubKeysAndSignatures(5, msg) + multisigKey := NewPubKeyMultisigThreshold(2, pubkeys) + + ab, err := cdc.MarshalBinaryLengthPrefixed(multisigKey) + require.NoError(t, err) + // like other crypto.Pubkey implementations (e.g. ed25519.PubKey), + // PubKey should be deserializable into a crypto.PubKey: + var pubKey crypto.PubKey + err = cdc.UnmarshalBinaryLengthPrefixed(ab, &pubKey) + require.NoError(t, err) + + require.Equal(t, multisigKey, pubKey) +} + +func generatePubKeysAndSignatures(n int, msg []byte) (pubkeys []crypto.PubKey, signatures [][]byte) { + pubkeys = make([]crypto.PubKey, n) + signatures = make([][]byte, n) + for i := 0; i < n; i++ { + var privkey crypto.PrivKey + switch rand.Int63() % 3 { + case 0: + privkey = ed25519.GenPrivKey() + case 1: + privkey = secp256k1.GenPrivKey() + case 2: + privkey = sr25519.GenPrivKey() + } + pubkeys[i] = privkey.PubKey() + signatures[i], _ = privkey.Sign(msg) + } + return +} diff --git a/crypto/types/types.pb.go b/crypto/types/types.pb.go index 394067599fca..6887feafd90f 100644 --- a/crypto/types/types.pb.go +++ b/crypto/types/types.pb.go @@ -274,9 +274,8 @@ type CompactBitArray struct { Elems []byte `protobuf:"bytes,2,opt,name=elems,proto3" json:"elems,omitempty"` } -func (m *CompactBitArray) Reset() { *m = CompactBitArray{} } -func (m *CompactBitArray) String() string { return proto.CompactTextString(m) } -func (*CompactBitArray) ProtoMessage() {} +func (m *CompactBitArray) Reset() { *m = CompactBitArray{} } +func (*CompactBitArray) ProtoMessage() {} func (*CompactBitArray) Descriptor() ([]byte, []int) { return fileDescriptor_2165b2a1badb1b0c, []int{3} } @@ -299,7 +298,7 @@ func (m *CompactBitArray) XXX_Merge(src proto.Message) { xxx_messageInfo_CompactBitArray.Merge(m, src) } func (m *CompactBitArray) XXX_Size() int { - return m.Size() + return xxx_messageInfo_CompactBitArray.Size(m) } func (m *CompactBitArray) XXX_DiscardUnknown() { xxx_messageInfo_CompactBitArray.DiscardUnknown(m) @@ -331,38 +330,39 @@ func init() { func init() { proto.RegisterFile("crypto/types/types.proto", fileDescriptor_2165b2a1badb1b0c) } var fileDescriptor_2165b2a1badb1b0c = []byte{ - // 488 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x52, 0xdd, 0x8a, 0xd3, 0x40, - 0x18, 0x4d, 0xda, 0xad, 0xb5, 0xb3, 0xeb, 0x56, 0x87, 0x82, 0xd9, 0x82, 0x49, 0x09, 0x22, 0x55, - 0xd8, 0x84, 0x54, 0xaa, 0xe8, 0xdd, 0x66, 0x6f, 0x16, 0x8a, 0x50, 0x52, 0x2f, 0xc4, 0x9b, 0x90, - 0x9f, 0x31, 0x1d, 0x9a, 0x64, 0xc2, 0xcc, 0x44, 0x9c, 0x97, 0x10, 0x1f, 0xc4, 0x07, 0xf1, 0x72, - 0x2f, 0xbd, 0x2a, 0x92, 0xbe, 0xc1, 0x3e, 0x81, 0x6c, 0x26, 0xd9, 0x2e, 0x62, 0x6f, 0x92, 0x99, - 0xef, 0x9c, 0xef, 0xe4, 0x9c, 0xef, 0x0b, 0xd0, 0x22, 0x2a, 0x0a, 0x4e, 0x6c, 0x2e, 0x0a, 0xc4, - 0xe4, 0xd3, 0x2a, 0x28, 0xe1, 0x04, 0x8e, 0x22, 0xc2, 0x32, 0xc2, 0x7c, 0x16, 0x6f, 0x2c, 0x49, - 0xb2, 0xbe, 0x3a, 0xe3, 0x17, 0x7c, 0x8d, 0x69, 0xec, 0x17, 0x01, 0xe5, 0xc2, 0xae, 0x89, 0x76, - 0x42, 0x12, 0xb2, 0x3f, 0xc9, 0xee, 0xf1, 0x59, 0x42, 0x48, 0x92, 0x22, 0x49, 0x09, 0xcb, 0x2f, - 0x76, 0x90, 0x0b, 0x09, 0x99, 0xdf, 0x3b, 0x60, 0xb0, 0x2c, 0xc3, 0x14, 0x47, 0x0b, 0x24, 0xa0, - 0x0e, 0x06, 0x0c, 0x45, 0xc5, 0x6c, 0xfe, 0x66, 0xe3, 0x68, 0xea, 0x44, 0x9d, 0x9e, 0x5c, 0x29, - 0xde, 0xbe, 0x04, 0xc7, 0xa0, 0x8f, 0xe2, 0xd9, 0x7c, 0xee, 0xbc, 0xd3, 0x3a, 0x0d, 0xda, 0x16, - 0x6e, 0x31, 0x46, 0x25, 0xd6, 0x6d, 0xb1, 0xa6, 0x00, 0x17, 0xe0, 0x61, 0x56, 0xa6, 0x1c, 0x33, - 0x9c, 0x68, 0x47, 0x13, 0x75, 0x7a, 0x3c, 0x3b, 0xb7, 0xfe, 0x97, 0xc8, 0x5a, 0x96, 0xe1, 0x02, - 0x89, 0x0f, 0x0d, 0xf7, 0xe3, 0x9a, 0x22, 0xb6, 0x26, 0x69, 0x7c, 0xa5, 0x78, 0x77, 0x02, 0xf7, - 0x4c, 0x52, 0x47, 0xeb, 0xfd, 0x63, 0x92, 0x3a, 0x70, 0x0e, 0x40, 0x90, 0x0b, 0xbf, 0x28, 0xc3, - 0x0d, 0x12, 0xda, 0xb0, 0xfe, 0xdc, 0xc8, 0x92, 0x23, 0xb0, 0xda, 0x11, 0x58, 0x17, 0xb9, 0xb8, - 0x6d, 0x0b, 0x72, 0xb1, 0xac, 0x89, 0x6e, 0x0f, 0x74, 0x59, 0x99, 0x99, 0x3f, 0x55, 0xf0, 0xf4, - 0x80, 0x0b, 0xf8, 0x16, 0x0c, 0x78, 0x7b, 0xa9, 0xc7, 0xf3, 0xc8, 0x3d, 0xab, 0xb6, 0x86, 0xba, - 0xb8, 0xd9, 0x1a, 0x8f, 0x45, 0x90, 0xa5, 0xef, 0xcd, 0x3b, 0xdc, 0xf4, 0xf6, 0x5c, 0xf8, 0x09, - 0xf4, 0xa5, 0x1d, 0xa6, 0x75, 0x26, 0xdd, 0xe9, 0xf1, 0xcc, 0x38, 0x18, 0x5f, 0x6e, 0xc2, 0x7d, - 0x56, 0x6d, 0x8d, 0xbe, 0xf4, 0xc1, 0x6e, 0xb6, 0xc6, 0xa9, 0x54, 0x6f, 0x44, 0x4c, 0xaf, 0x95, - 0x33, 0x9f, 0x83, 0xd3, 0xda, 0xe7, 0x0a, 0x27, 0x79, 0xc0, 0x4b, 0x8a, 0x20, 0x04, 0x47, 0x0c, - 0x27, 0x4c, 0x53, 0x27, 0xdd, 0xe9, 0x89, 0x57, 0x9f, 0xcd, 0x15, 0x18, 0x5e, 0x92, 0xac, 0x08, - 0x22, 0xee, 0x62, 0x7e, 0x41, 0x69, 0x20, 0xe0, 0x2b, 0xf0, 0x04, 0x7d, 0xe3, 0x34, 0xf0, 0x43, - 0xcc, 0x99, 0xcf, 0x38, 0xa1, 0xa8, 0xc9, 0xe4, 0x0d, 0x6b, 0xc0, 0xc5, 0x9c, 0xad, 0xea, 0x32, - 0x1c, 0x81, 0x1e, 0x4a, 0x51, 0xc6, 0xe4, 0xd2, 0x3d, 0x79, 0x71, 0x2f, 0x7f, 0x55, 0xba, 0x7a, - 0x5d, 0xe9, 0xea, 0x9f, 0x4a, 0x57, 0x7f, 0xec, 0x74, 0xe5, 0x7a, 0xa7, 0x2b, 0xbf, 0x77, 0xba, - 0xf2, 0xf9, 0x65, 0x82, 0xf9, 0xba, 0x0c, 0xad, 0x88, 0x64, 0xb6, 0xcc, 0xd9, 0xbc, 0xce, 0x59, - 0xbc, 0xb1, 0xef, 0xff, 0xe4, 0xe1, 0x83, 0x7a, 0x21, 0xaf, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, - 0x82, 0xd0, 0x7b, 0xf3, 0xfb, 0x02, 0x00, 0x00, + // 501 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x52, 0xcd, 0x6a, 0xdb, 0x40, + 0x18, 0x94, 0xec, 0xb8, 0x8e, 0x37, 0x69, 0xdc, 0x2e, 0x86, 0x2a, 0x86, 0x4a, 0x46, 0x94, 0xe2, + 0x16, 0x22, 0x61, 0x17, 0xb7, 0x34, 0xb7, 0x28, 0x97, 0x80, 0x29, 0x18, 0xa5, 0x87, 0x52, 0x28, + 0x42, 0x3f, 0x5b, 0x79, 0xb1, 0xa4, 0x15, 0xbb, 0xab, 0xd2, 0x7d, 0x89, 0xd2, 0x63, 0x8f, 0xe9, + 0xbd, 0x0f, 0xd2, 0x63, 0x8e, 0x3d, 0x99, 0x22, 0xbf, 0x41, 0x9e, 0xa0, 0x44, 0x2b, 0xc5, 0xa1, + 0x24, 0x17, 0x69, 0xf7, 0x9b, 0xf9, 0x46, 0x33, 0xdf, 0x27, 0xa0, 0x85, 0x54, 0xe4, 0x9c, 0xd8, + 0x5c, 0xe4, 0x88, 0xc9, 0xa7, 0x95, 0x53, 0xc2, 0x09, 0x1c, 0x84, 0x84, 0xa5, 0x84, 0x79, 0x2c, + 0x5a, 0x59, 0x92, 0x64, 0x7d, 0x99, 0x0c, 0x9f, 0xf3, 0x25, 0xa6, 0x91, 0x97, 0xfb, 0x94, 0x0b, + 0xbb, 0x22, 0xda, 0x31, 0x89, 0xc9, 0xf6, 0x24, 0xbb, 0x87, 0x87, 0x31, 0x21, 0x71, 0x82, 0x24, + 0x25, 0x28, 0x3e, 0xdb, 0x7e, 0x26, 0x24, 0x64, 0x7e, 0x6b, 0x81, 0xde, 0xa2, 0x08, 0x12, 0x1c, + 0xce, 0x91, 0x80, 0x3a, 0xe8, 0x31, 0x14, 0xe6, 0xd3, 0xd9, 0xeb, 0xd5, 0x44, 0x53, 0x47, 0xea, + 0x78, 0xff, 0x4c, 0x71, 0xb7, 0x25, 0x38, 0x04, 0x5d, 0x14, 0x4d, 0x67, 0xb3, 0xc9, 0x5b, 0xad, + 0x55, 0xa3, 0x4d, 0xe1, 0x1a, 0x63, 0x54, 0x62, 0xed, 0x06, 0xab, 0x0b, 0x70, 0x0e, 0x76, 0xd3, + 0x22, 0xe1, 0x98, 0xe1, 0x58, 0xdb, 0x19, 0xa9, 0xe3, 0xbd, 0xe9, 0x91, 0x75, 0x57, 0x22, 0x6b, + 0x51, 0x04, 0x73, 0x24, 0xde, 0xd5, 0xdc, 0xf7, 0x4b, 0x8a, 0xd8, 0x92, 0x24, 0xd1, 0x99, 0xe2, + 0xde, 0x08, 0xdc, 0x32, 0x49, 0x27, 0x5a, 0xe7, 0x3f, 0x93, 0x74, 0x02, 0x67, 0x00, 0xf8, 0x99, + 0xf0, 0xf2, 0x22, 0x58, 0x21, 0xa1, 0xf5, 0xab, 0xcf, 0x0d, 0x2c, 0x39, 0x02, 0xab, 0x19, 0x81, + 0x75, 0x92, 0x89, 0xeb, 0x36, 0x3f, 0x13, 0x8b, 0x8a, 0xe8, 0x74, 0x40, 0x9b, 0x15, 0xa9, 0xf9, + 0x4b, 0x05, 0x4f, 0xee, 0x71, 0x01, 0xdf, 0x80, 0x1e, 0x6f, 0x2e, 0xd5, 0x78, 0x1e, 0x3a, 0x87, + 0xe5, 0xda, 0x50, 0xe7, 0x57, 0x6b, 0xe3, 0x91, 0xf0, 0xd3, 0xe4, 0xd8, 0xbc, 0xc1, 0x4d, 0x77, + 0xcb, 0x85, 0x1f, 0x40, 0x57, 0xda, 0x61, 0x5a, 0x6b, 0xd4, 0x1e, 0xef, 0x4d, 0x8d, 0x7b, 0xe3, + 0xcb, 0x4d, 0x38, 0x4f, 0xcb, 0xb5, 0xd1, 0x95, 0x3e, 0xd8, 0xd5, 0xda, 0x38, 0x90, 0xea, 0xb5, + 0x88, 0xe9, 0x36, 0x72, 0xe6, 0x33, 0x70, 0x50, 0xf9, 0x3c, 0xc7, 0x71, 0xe6, 0xf3, 0x82, 0x22, + 0x08, 0xc1, 0x0e, 0xc3, 0x31, 0xd3, 0xd4, 0x51, 0x7b, 0xbc, 0xef, 0x56, 0x67, 0xf3, 0x13, 0xe8, + 0x9f, 0x92, 0x34, 0xf7, 0x43, 0xee, 0x60, 0x7e, 0x42, 0xa9, 0x2f, 0xe0, 0x4b, 0xf0, 0x18, 0x7d, + 0xe5, 0xd4, 0xf7, 0x02, 0xcc, 0x99, 0xc7, 0x38, 0xa1, 0xa8, 0xce, 0xe4, 0xf6, 0x2b, 0xc0, 0xc1, + 0x9c, 0x9d, 0x57, 0x65, 0x38, 0x00, 0x1d, 0x94, 0xa0, 0x94, 0xc9, 0xa5, 0xbb, 0xf2, 0x72, 0xbc, + 0xfb, 0xe3, 0xc2, 0x50, 0x2e, 0x7e, 0x1a, 0x8a, 0x73, 0xfa, 0xbb, 0xd4, 0xd5, 0xcb, 0x52, 0x57, + 0xff, 0x96, 0xba, 0xfa, 0x7d, 0xa3, 0x2b, 0x97, 0x1b, 0x5d, 0xf9, 0xb3, 0xd1, 0x95, 0x8f, 0x2f, + 0x62, 0xcc, 0x97, 0x45, 0x60, 0x85, 0x24, 0xb5, 0x65, 0xe2, 0xfa, 0x75, 0xc4, 0xa2, 0x95, 0x7d, + 0xfb, 0x77, 0x0f, 0x1e, 0x54, 0xab, 0x79, 0xf5, 0x2f, 0x00, 0x00, 0xff, 0xff, 0x1e, 0xd7, 0x43, + 0xb2, 0x05, 0x03, 0x00, 0x00, } func (m *PublicKey) Marshal() (dAtA []byte, err error) { @@ -740,22 +740,6 @@ func (m *MultiSignature) Size() (n int) { return n } -func (m *CompactBitArray) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.ExtraBitsStored != 0 { - n += 1 + sovTypes(uint64(m.ExtraBitsStored)) - } - l = len(m.Elems) - if l > 0 { - n += 1 + l + sovTypes(uint64(l)) - } - return n -} - func sovTypes(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } diff --git a/crypto/types/types.proto b/crypto/types/types.proto index a03228ca8799..2496ad8e30d6 100644 --- a/crypto/types/types.proto +++ b/crypto/types/types.proto @@ -8,33 +8,32 @@ option go_package = "github.com/cosmos/cosmos-sdk/crypto/types"; // PublicKey specifies a public key message PublicKey { - // sum specifies which type of public key is wrapped - oneof sum { - bytes secp256k1 = 1; - bytes ed25519 = 2; - bytes sr25519 = 3; - PubKeyMultisigThreshold multisig = 4; - bytes secp256r1 = 5; - - // any_pubkey can be used for any pubkey that an app may use which is - // not explicitly defined in the oneof - google.protobuf.Any any_pubkey = 15; // 15 is largest field that occupies one byte - } + // sum specifies which type of public key is wrapped + oneof sum { + bytes secp256k1 = 1; + bytes ed25519 = 2; + bytes sr25519 = 3; + PubKeyMultisigThreshold multisig = 4; + bytes secp256r1 = 5; + + // any_pubkey can be used for any pubkey that an app may use which is + // not explicitly defined in the oneof + google.protobuf.Any any_pubkey = 15; // 15 is largest field that occupies one byte + } } // PubKeyMultisigThreshold specifies a public key type which nests multiple public // keys and a threshold message PubKeyMultisigThreshold { - uint32 threshold = 1 [(gogoproto.customname) = "K", (gogoproto.moretags) = "yaml:\"threshold\""]; - repeated PublicKey pubkeys = 2 [(gogoproto.customname) = "PubKeys", (gogoproto.moretags) = "yaml:\"pubkeys\""]; + uint32 threshold = 1 [(gogoproto.customname) = "K", (gogoproto.moretags) = "yaml:\"threshold\""]; + repeated PublicKey pubkeys = 2 [(gogoproto.customname) = "PubKeys", (gogoproto.moretags) = "yaml:\"pubkeys\""]; } - // MultiSignature wraps the signatures from a PubKeyMultisigThreshold. // See cosmos_sdk.tx.v1.ModeInfo.Multi for how to specify which signers signed // and with which modes message MultiSignature { - repeated bytes sigs = 1; + repeated bytes sigs = 1; } // CompactBitArray is an implementation of a space efficient bit array. @@ -42,10 +41,9 @@ message MultiSignature { // space after proto encoding. // This is not thread safe, and is not intended for concurrent usage. message CompactBitArray { - // TODO: re-enable these when the actual implementation is added - // option (gogoproto.sizer) = false; - // option (gogoproto.goproto_stringer) = false; + option (gogoproto.sizer) = false; + option (gogoproto.goproto_stringer) = false; - uint32 extra_bits_stored = 1; - bytes elems = 2; + uint32 extra_bits_stored = 1; + bytes elems = 2; } diff --git a/types/tx/types.pb.go b/types/tx/types.pb.go index 303324b4ed23..16e2ac453b56 100644 --- a/types/tx/types.pb.go +++ b/types/tx/types.pb.go @@ -690,54 +690,54 @@ var fileDescriptor_1c6ac8fa65877134 = []byte{ 0x04, 0x04, 0xce, 0xb2, 0x7b, 0x60, 0x11, 0x87, 0x55, 0x92, 0xa6, 0xdb, 0x40, 0x9b, 0xa2, 0x49, 0x56, 0x82, 0x95, 0x90, 0xe5, 0xd8, 0x53, 0x67, 0xd4, 0x78, 0x26, 0x78, 0xc6, 0x28, 0xe1, 0x82, 0x38, 0x70, 0xe2, 0xc2, 0x85, 0x3f, 0xc1, 0x2f, 0x59, 0x71, 0xda, 0x23, 0x17, 0x3e, 0xd4, 0xfe, - 0x10, 0x90, 0xc7, 0xe3, 0xa4, 0x6a, 0x4a, 0xb8, 0x71, 0xca, 0xeb, 0x67, 0x9e, 0xe7, 0x99, 0xf7, - 0x2b, 0x36, 0xec, 0xc8, 0xf9, 0x94, 0x88, 0xa6, 0x9c, 0x35, 0x55, 0x60, 0x4d, 0x43, 0x2e, 0x39, + 0x10, 0x90, 0xc7, 0xe3, 0xa4, 0x6a, 0x4a, 0xb8, 0x71, 0xca, 0xeb, 0xc7, 0xcf, 0xf3, 0xcc, 0xfb, + 0x95, 0x31, 0xec, 0xc8, 0xf9, 0x94, 0x88, 0xa6, 0x9c, 0x35, 0x55, 0x60, 0x4d, 0x43, 0x2e, 0x39, 0x2a, 0xbb, 0x5c, 0x04, 0x5c, 0xd8, 0xc2, 0xbb, 0xb4, 0xe4, 0xcc, 0xfa, 0xe6, 0xc3, 0xca, 0xdb, 0x72, 0x4c, 0x43, 0xcf, 0x9e, 0x3a, 0xa1, 0x9c, 0x37, 0x15, 0xa9, 0xe9, 0x73, 0x9f, 0x2f, 0xa3, - 0x44, 0x59, 0xd9, 0xd6, 0x7e, 0x4b, 0xb3, 0x8a, 0xe9, 0x86, 0xf3, 0xa9, 0xe4, 0xcd, 0xd5, 0x93, - 0x3d, 0x9f, 0x73, 0x7f, 0x42, 0x12, 0xbf, 0x51, 0x74, 0xd1, 0x74, 0xd8, 0x3c, 0x39, 0xaa, 0xff, - 0x68, 0x40, 0x76, 0x38, 0x43, 0xef, 0x43, 0x7e, 0xc4, 0xbd, 0xb9, 0x69, 0xd4, 0x8c, 0xc6, 0xd6, - 0x63, 0xd3, 0xba, 0x9d, 0x97, 0x35, 0x9c, 0xb5, 0xb9, 0x37, 0xc7, 0x8a, 0x85, 0x3e, 0x82, 0x92, - 0x13, 0xc9, 0xb1, 0x4d, 0xd9, 0x05, 0x37, 0xb3, 0x4a, 0x52, 0x59, 0x95, 0xb4, 0x22, 0x39, 0xee, - 0xb1, 0x0b, 0x8e, 0x8b, 0x8e, 0x8e, 0x50, 0x15, 0x40, 0x50, 0x9f, 0x39, 0x32, 0x0a, 0x89, 0x30, - 0x73, 0xb5, 0x5c, 0xe3, 0x1e, 0xbe, 0x81, 0xd4, 0x7f, 0x37, 0x60, 0x73, 0x40, 0x7d, 0x76, 0xc4, - 0xdd, 0xff, 0x2b, 0xa5, 0x3d, 0x28, 0xba, 0x63, 0x87, 0x32, 0x9b, 0x7a, 0x66, 0xae, 0x66, 0x34, - 0x4a, 0x78, 0x53, 0x3d, 0xf7, 0x3c, 0x74, 0x08, 0x0f, 0x1c, 0xd7, 0xe5, 0x11, 0x93, 0x36, 0x8b, - 0x82, 0x11, 0x09, 0xcd, 0x7c, 0xcd, 0x68, 0xe4, 0xf1, 0x7d, 0x8d, 0xf6, 0x15, 0x88, 0xde, 0x85, - 0x72, 0x4a, 0x13, 0xe4, 0xeb, 0x88, 0x30, 0x97, 0x98, 0x1b, 0x8a, 0xf8, 0x50, 0xe3, 0x03, 0x0d, - 0xd7, 0x7f, 0xce, 0x42, 0x21, 0x49, 0x1b, 0x3d, 0x82, 0x62, 0x40, 0x84, 0x70, 0x7c, 0x22, 0x4c, - 0xa3, 0x96, 0x6b, 0x6c, 0x3d, 0xde, 0xb1, 0x92, 0x31, 0x59, 0xe9, 0x98, 0xac, 0x16, 0x9b, 0xe3, - 0x05, 0x0b, 0x21, 0xc8, 0x07, 0x24, 0x48, 0xaa, 0x2b, 0x61, 0x15, 0xc7, 0x29, 0x4a, 0x1a, 0x10, - 0x1e, 0x49, 0x7b, 0x4c, 0xa8, 0x3f, 0x96, 0xaa, 0x86, 0x1c, 0xbe, 0xaf, 0xd1, 0x13, 0x05, 0xa2, - 0x36, 0x6c, 0x93, 0x99, 0x24, 0x4c, 0x50, 0xce, 0x6c, 0x3e, 0x95, 0x94, 0x33, 0x61, 0xfe, 0xbd, - 0xb9, 0xe6, 0xda, 0xf2, 0x82, 0x7f, 0x9e, 0xd0, 0xd1, 0x4b, 0xa8, 0x32, 0xce, 0x6c, 0x37, 0xa4, - 0x92, 0xba, 0xce, 0xc4, 0xbe, 0xc3, 0xf0, 0xe1, 0x1a, 0xc3, 0x7d, 0xc6, 0x59, 0x47, 0x6b, 0xbb, - 0xb7, 0xbc, 0xeb, 0x12, 0x8a, 0xe9, 0x68, 0xd0, 0x33, 0xb8, 0x17, 0x6f, 0x04, 0x09, 0xd5, 0x2c, - 0xd3, 0xe6, 0xbc, 0xb9, 0x3a, 0xcc, 0x81, 0x62, 0xa9, 0x71, 0x6e, 0x89, 0x45, 0x2c, 0xd0, 0x3b, - 0x90, 0xbb, 0x20, 0x44, 0x2f, 0xc1, 0xee, 0xaa, 0xee, 0x98, 0x10, 0x1c, 0x33, 0xea, 0xdf, 0x02, - 0x2c, 0x3d, 0xd0, 0x13, 0x80, 0x69, 0x34, 0x9a, 0x50, 0xd7, 0xbe, 0x24, 0xe9, 0xd6, 0xdd, 0x5d, - 0x4a, 0x29, 0xe1, 0x7d, 0x46, 0xd4, 0xda, 0x05, 0xdc, 0x23, 0xff, 0xb1, 0x76, 0x67, 0xdc, 0x23, - 0xc9, 0xda, 0x05, 0x3a, 0xaa, 0xff, 0x9a, 0x85, 0x62, 0x0a, 0xa3, 0x4f, 0xa0, 0x20, 0x28, 0xf3, - 0x27, 0x44, 0x5f, 0xfb, 0xd6, 0xbf, 0x5b, 0x58, 0x03, 0x45, 0x3c, 0xc9, 0x60, 0x2d, 0x41, 0x4f, - 0x61, 0x23, 0x88, 0x26, 0x92, 0xea, 0xeb, 0x6b, 0x6b, 0xb4, 0x67, 0x31, 0xef, 0x24, 0x83, 0x13, - 0x41, 0xe5, 0x29, 0x14, 0x12, 0x37, 0x64, 0x41, 0x3e, 0xce, 0x4c, 0x5d, 0xff, 0xe0, 0xae, 0x0a, - 0xe2, 0x3e, 0xc5, 0x36, 0x58, 0xf1, 0x2a, 0x3f, 0x18, 0xb0, 0xa1, 0xcc, 0x50, 0x0b, 0x8a, 0x23, - 0x2a, 0x9d, 0x30, 0x74, 0xd2, 0x9e, 0x1d, 0xde, 0x54, 0x27, 0xaf, 0xa4, 0xd8, 0xa1, 0xc3, 0x83, - 0xa9, 0xe3, 0xca, 0x36, 0x95, 0xad, 0x98, 0x8c, 0x17, 0x32, 0xf4, 0x31, 0xc0, 0xa2, 0x87, 0xc2, - 0xcc, 0xaa, 0x71, 0xaf, 0x6b, 0x62, 0x29, 0x6d, 0xa2, 0x68, 0x6f, 0x40, 0x4e, 0x44, 0x41, 0xfd, - 0x7b, 0x03, 0x72, 0xc7, 0x84, 0xa0, 0xaf, 0xa0, 0xe0, 0x04, 0xf1, 0x1f, 0x4e, 0x2f, 0xcd, 0x1b, - 0x37, 0x5d, 0x54, 0x0e, 0x94, 0xb5, 0x1f, 0xbd, 0xfa, 0xe3, 0x20, 0xf3, 0xcb, 0x9f, 0x07, 0x0d, - 0x9f, 0xca, 0x71, 0x34, 0xb2, 0x5c, 0x1e, 0x34, 0x13, 0x9a, 0xfe, 0xf9, 0x40, 0x78, 0x97, 0xfa, - 0xf5, 0x19, 0x0b, 0x04, 0xd6, 0xa6, 0x68, 0x1f, 0x4a, 0xbe, 0x23, 0xec, 0x09, 0x0d, 0xa8, 0x54, - 0xdd, 0xce, 0xe3, 0xa2, 0xef, 0x88, 0xd3, 0xf8, 0xf9, 0x3d, 0x01, 0xc5, 0xb4, 0x49, 0x68, 0x0f, - 0x76, 0x07, 0xbd, 0xe7, 0x7d, 0xfb, 0xec, 0xfc, 0xa8, 0x6b, 0xbf, 0xe8, 0x0f, 0x3e, 0xef, 0x76, - 0x7a, 0xc7, 0xbd, 0xee, 0x51, 0x39, 0x83, 0x76, 0xa0, 0xbc, 0x3c, 0x3a, 0xea, 0xe1, 0x6e, 0x67, - 0x58, 0x36, 0xd0, 0x2e, 0x6c, 0x2f, 0xd1, 0x61, 0xf7, 0x8b, 0xe1, 0x8b, 0xd6, 0x69, 0x39, 0x8b, - 0x0e, 0x60, 0x7f, 0x09, 0x9f, 0x76, 0x9f, 0xb7, 0x3a, 0x5f, 0xda, 0xad, 0xb3, 0x5e, 0xff, 0xdc, - 0xfe, 0x74, 0x70, 0xde, 0x2f, 0x7f, 0xd7, 0x7e, 0xf6, 0xea, 0xaa, 0x6a, 0xbc, 0xbe, 0xaa, 0x1a, - 0x7f, 0x5d, 0x55, 0x8d, 0x9f, 0xae, 0xab, 0x99, 0xd7, 0xd7, 0xd5, 0xcc, 0x6f, 0xd7, 0xd5, 0xcc, - 0xcb, 0xc3, 0xf5, 0xd5, 0xe9, 0xcf, 0xd0, 0xa8, 0xa0, 0x16, 0xfb, 0xc9, 0x3f, 0x01, 0x00, 0x00, - 0xff, 0xff, 0xa9, 0x40, 0x9c, 0x90, 0x9f, 0x06, 0x00, 0x00, + 0x44, 0x59, 0x31, 0xdd, 0x70, 0x3e, 0x95, 0xbc, 0xa9, 0x6d, 0x97, 0x9e, 0x95, 0xed, 0x55, 0x68, + 0xcf, 0xe7, 0xdc, 0x9f, 0x90, 0xc4, 0x6f, 0x14, 0x5d, 0x34, 0x1d, 0x36, 0x4f, 0x5e, 0xd5, 0x7f, + 0x34, 0x20, 0x3b, 0x9c, 0xa1, 0xf7, 0x21, 0x3f, 0xe2, 0xde, 0xdc, 0x34, 0x6a, 0x46, 0x63, 0xeb, + 0xb1, 0x69, 0xdd, 0xce, 0xcb, 0x1a, 0xce, 0xda, 0xdc, 0x9b, 0x63, 0xc5, 0x42, 0x1f, 0x41, 0xc9, + 0x89, 0xe4, 0xd8, 0xa6, 0xec, 0x82, 0x9b, 0x59, 0x25, 0xa9, 0xac, 0x4a, 0x5a, 0x91, 0x1c, 0xf7, + 0xd8, 0x05, 0xc7, 0x45, 0x47, 0x47, 0xa8, 0x0a, 0x20, 0xa8, 0xcf, 0x1c, 0x19, 0x85, 0x44, 0x98, + 0xb9, 0x5a, 0xae, 0x71, 0x0f, 0xdf, 0x40, 0xea, 0xbf, 0x1b, 0xb0, 0x39, 0xa0, 0x3e, 0x3b, 0xe2, + 0xee, 0xff, 0x95, 0xd2, 0x1e, 0x14, 0xdd, 0xb1, 0x43, 0x99, 0x4d, 0x3d, 0x33, 0x57, 0x33, 0x1a, + 0x25, 0xbc, 0xa9, 0x9e, 0x7b, 0x1e, 0x3a, 0x84, 0x07, 0x8e, 0xeb, 0xf2, 0x88, 0x49, 0x9b, 0x45, + 0xc1, 0x88, 0x84, 0x66, 0xbe, 0x66, 0x34, 0xf2, 0xf8, 0xbe, 0x46, 0xfb, 0x0a, 0x44, 0xef, 0x42, + 0x39, 0xa5, 0x09, 0xf2, 0x75, 0x44, 0x98, 0x4b, 0xcc, 0x0d, 0x45, 0x7c, 0xa8, 0xf1, 0x81, 0x86, + 0xeb, 0x3f, 0x67, 0xa1, 0x90, 0xa4, 0x8d, 0x1e, 0x41, 0x31, 0x20, 0x42, 0x38, 0x3e, 0x11, 0xa6, + 0x51, 0xcb, 0x35, 0xb6, 0x1e, 0xef, 0x58, 0xc9, 0x98, 0xac, 0x74, 0x4c, 0x56, 0x8b, 0xcd, 0xf1, + 0x82, 0x85, 0x10, 0xe4, 0x03, 0x12, 0x24, 0xd5, 0x95, 0xb0, 0x8a, 0xe3, 0x14, 0x25, 0x0d, 0x08, + 0x8f, 0xa4, 0x3d, 0x26, 0xd4, 0x1f, 0x4b, 0x55, 0x43, 0x0e, 0xdf, 0xd7, 0xe8, 0x89, 0x02, 0x51, + 0x1b, 0xb6, 0xc9, 0x4c, 0x12, 0x26, 0x28, 0x67, 0x36, 0x9f, 0x4a, 0xca, 0x99, 0x30, 0xff, 0xde, + 0x5c, 0x73, 0x6c, 0x79, 0xc1, 0x3f, 0x4f, 0xe8, 0xe8, 0x25, 0x54, 0x19, 0x67, 0xb6, 0x1b, 0x52, + 0x49, 0x5d, 0x67, 0x62, 0xdf, 0x61, 0xf8, 0x70, 0x8d, 0xe1, 0x3e, 0xe3, 0xac, 0xa3, 0xb5, 0xdd, + 0x5b, 0xde, 0x75, 0x09, 0xc5, 0x74, 0x34, 0xe8, 0x19, 0xdc, 0x8b, 0x37, 0x82, 0x84, 0x6a, 0x96, + 0x69, 0x73, 0xde, 0x5c, 0x1d, 0xe6, 0x40, 0xb1, 0xd4, 0x38, 0xb7, 0xc4, 0x22, 0x16, 0xe8, 0x1d, + 0xc8, 0x5d, 0x10, 0xa2, 0x97, 0x60, 0x77, 0x55, 0x77, 0x4c, 0x08, 0x8e, 0x19, 0xf5, 0x6f, 0x01, + 0x96, 0x1e, 0xe8, 0x09, 0xc0, 0x34, 0x1a, 0x4d, 0xa8, 0x6b, 0x5f, 0x92, 0x74, 0xeb, 0xee, 0x2e, + 0xa5, 0x94, 0xf0, 0x3e, 0x23, 0x6a, 0xed, 0x02, 0xee, 0x91, 0xff, 0x58, 0xbb, 0x33, 0xee, 0x91, + 0x64, 0xed, 0x02, 0x1d, 0xd5, 0x7f, 0xcd, 0x42, 0x31, 0x85, 0xd1, 0x27, 0x50, 0x10, 0x94, 0xf9, + 0x13, 0xa2, 0x8f, 0x7d, 0xeb, 0xdf, 0x2d, 0xac, 0x81, 0x22, 0x9e, 0x64, 0xb0, 0x96, 0xa0, 0xa7, + 0xb0, 0x11, 0x44, 0x13, 0x49, 0xf5, 0xf1, 0xb5, 0x35, 0xda, 0xb3, 0x98, 0x77, 0x92, 0xc1, 0x89, + 0xa0, 0xf2, 0x14, 0x0a, 0x89, 0x1b, 0xb2, 0x20, 0x1f, 0x67, 0xa6, 0x8e, 0x7f, 0x70, 0x57, 0x05, + 0x71, 0x9f, 0x62, 0x1b, 0xac, 0x78, 0x95, 0x1f, 0x0c, 0xd8, 0x50, 0x66, 0xa8, 0x05, 0xc5, 0x11, + 0x95, 0x4e, 0x18, 0x3a, 0x69, 0xcf, 0x0e, 0x6f, 0xaa, 0x93, 0x5b, 0x2a, 0x76, 0xe8, 0xf0, 0x60, + 0xea, 0xb8, 0xb2, 0x4d, 0x65, 0x2b, 0x26, 0xe3, 0x85, 0x0c, 0x7d, 0x0c, 0xb0, 0xe8, 0xa1, 0x30, + 0xb3, 0x6a, 0xdc, 0xeb, 0x9a, 0x58, 0x4a, 0x9b, 0x28, 0xda, 0x1b, 0x90, 0x13, 0x51, 0x50, 0xff, + 0xde, 0x80, 0xdc, 0x31, 0x21, 0xe8, 0x2b, 0x28, 0x38, 0x41, 0xfc, 0x87, 0xd3, 0x4b, 0xf3, 0xc6, + 0x4d, 0x17, 0x95, 0x03, 0x65, 0xed, 0x47, 0xaf, 0xfe, 0x38, 0xc8, 0xfc, 0xf2, 0xe7, 0x41, 0xc3, + 0xa7, 0x72, 0x1c, 0x8d, 0x2c, 0x97, 0x07, 0xcd, 0x84, 0xa6, 0x7f, 0x3e, 0x10, 0xde, 0xa5, 0xbe, + 0x3e, 0x63, 0x81, 0xc0, 0xda, 0x14, 0xed, 0x43, 0xc9, 0x77, 0x84, 0x3d, 0xa1, 0x01, 0x95, 0xaa, + 0xdb, 0x79, 0x5c, 0xf4, 0x1d, 0x71, 0x1a, 0x3f, 0xbf, 0x27, 0xa0, 0x98, 0x36, 0x09, 0xed, 0xc1, + 0xee, 0xa0, 0xf7, 0xbc, 0x6f, 0x9f, 0x9d, 0x1f, 0x75, 0xed, 0x17, 0xfd, 0xc1, 0xe7, 0xdd, 0x4e, + 0xef, 0xb8, 0xd7, 0x3d, 0x2a, 0x67, 0xd0, 0x0e, 0x94, 0x97, 0xaf, 0x8e, 0x7a, 0xb8, 0xdb, 0x19, + 0x96, 0x0d, 0xb4, 0x0b, 0xdb, 0x4b, 0x74, 0xd8, 0xfd, 0x62, 0xf8, 0xa2, 0x75, 0x5a, 0xce, 0xa2, + 0x03, 0xd8, 0x5f, 0xc2, 0xa7, 0xdd, 0xe7, 0xad, 0xce, 0x97, 0x76, 0xeb, 0xac, 0xd7, 0x3f, 0xb7, + 0x3f, 0x1d, 0x9c, 0xf7, 0xcb, 0xdf, 0xb5, 0x9f, 0xbd, 0xba, 0xaa, 0x1a, 0xaf, 0xaf, 0xaa, 0xc6, + 0x5f, 0x57, 0x55, 0xe3, 0xa7, 0xeb, 0x6a, 0xe6, 0xf5, 0x75, 0x35, 0xf3, 0xdb, 0x75, 0x35, 0xf3, + 0xf2, 0x70, 0x7d, 0x75, 0xfa, 0x33, 0x34, 0x2a, 0xa8, 0xc5, 0x7e, 0xf2, 0x4f, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x28, 0x03, 0x76, 0x89, 0x9f, 0x06, 0x00, 0x00, } func (m *Tx) Marshal() (dAtA []byte, err error) { diff --git a/types/tx/types.proto b/types/tx/types.proto index 4f9a468966ed..51ec4da84390 100644 --- a/types/tx/types.proto +++ b/types/tx/types.proto @@ -2,8 +2,8 @@ syntax = "proto3"; package cosmos_sdk.tx.v1; import "third_party/proto/gogoproto/gogo.proto"; -import "types/types.proto"; import "crypto/types/types.proto"; +import "types/types.proto"; import "google/protobuf/any.proto"; option go_package = "github.com/cosmos/cosmos-sdk/tx/types";