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.

96 lines
2.7 KiB

  1. package multisig
  2. import (
  3. "github.com/tendermint/tendermint/crypto"
  4. )
  5. // PubKeyMultisigThreshold implements a K of N threshold multisig.
  6. type PubKeyMultisigThreshold struct {
  7. K uint `json:"threshold"`
  8. PubKeys []crypto.PubKey `json:"pubkeys"`
  9. }
  10. var _ crypto.PubKey = PubKeyMultisigThreshold{}
  11. // NewPubKeyMultisigThreshold returns a new PubKeyMultisigThreshold.
  12. // Panics if len(pubkeys) < k or 0 >= k.
  13. func NewPubKeyMultisigThreshold(k int, pubkeys []crypto.PubKey) crypto.PubKey {
  14. if k <= 0 {
  15. panic("threshold k of n multisignature: k <= 0")
  16. }
  17. if len(pubkeys) < k {
  18. panic("threshold k of n multisignature: len(pubkeys) < k")
  19. }
  20. for _, pubkey := range pubkeys {
  21. if pubkey == nil {
  22. panic("nil pubkey")
  23. }
  24. }
  25. return PubKeyMultisigThreshold{uint(k), pubkeys}
  26. }
  27. // VerifyBytes expects sig to be an amino encoded version of a MultiSignature.
  28. // Returns true iff the multisignature contains k or more signatures
  29. // for the correct corresponding keys,
  30. // and all signatures are valid. (Not just k of the signatures)
  31. // The multisig uses a bitarray, so multiple signatures for the same key is not
  32. // a concern.
  33. func (pk PubKeyMultisigThreshold) VerifyBytes(msg []byte, marshalledSig []byte) bool {
  34. var sig Multisignature
  35. err := cdc.UnmarshalBinaryBare(marshalledSig, &sig)
  36. if err != nil {
  37. return false
  38. }
  39. size := sig.BitArray.Size()
  40. // ensure bit array is the correct size
  41. if len(pk.PubKeys) != size {
  42. return false
  43. }
  44. // ensure size of signature list
  45. if len(sig.Sigs) < int(pk.K) || len(sig.Sigs) > size {
  46. return false
  47. }
  48. // ensure at least k signatures are set
  49. if sig.BitArray.NumTrueBitsBefore(size) < int(pk.K) {
  50. return false
  51. }
  52. // index in the list of signatures which we are concerned with.
  53. sigIndex := 0
  54. for i := 0; i < size; i++ {
  55. if sig.BitArray.GetIndex(i) {
  56. if !pk.PubKeys[i].VerifyBytes(msg, sig.Sigs[sigIndex]) {
  57. return false
  58. }
  59. sigIndex++
  60. }
  61. }
  62. return true
  63. }
  64. // Bytes returns the amino encoded version of the PubKeyMultisigThreshold
  65. func (pk PubKeyMultisigThreshold) Bytes() []byte {
  66. return cdc.MustMarshalBinaryBare(pk)
  67. }
  68. // Address returns tmhash(PubKeyMultisigThreshold.Bytes())
  69. func (pk PubKeyMultisigThreshold) Address() crypto.Address {
  70. return crypto.AddressHash(pk.Bytes())
  71. }
  72. // Equals returns true iff pk and other both have the same number of keys, and
  73. // all constituent keys are the same, and in the same order.
  74. func (pk PubKeyMultisigThreshold) Equals(other crypto.PubKey) bool {
  75. otherKey, sameType := other.(PubKeyMultisigThreshold)
  76. if !sameType {
  77. return false
  78. }
  79. if pk.K != otherKey.K || len(pk.PubKeys) != len(otherKey.PubKeys) {
  80. return false
  81. }
  82. for i := 0; i < len(pk.PubKeys); i++ {
  83. if !pk.PubKeys[i].Equals(otherKey.PubKeys[i]) {
  84. return false
  85. }
  86. }
  87. return true
  88. }