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.

92 lines
2.8 KiB

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