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.

70 lines
2.2 KiB

  1. package multisig
  2. import (
  3. "errors"
  4. "github.com/tendermint/tendermint/crypto"
  5. "github.com/tendermint/tendermint/crypto/multisig/bitarray"
  6. )
  7. // Multisignature is used to represent the signature object used in the multisigs.
  8. // Sigs is a list of signatures, sorted by corresponding index.
  9. type Multisignature struct {
  10. BitArray *bitarray.CompactBitArray
  11. Sigs [][]byte
  12. }
  13. // NewMultisig returns a new Multisignature of size n.
  14. func NewMultisig(n int) *Multisignature {
  15. // Default the signature list to have a capacity of two, since we can
  16. // expect that most multisigs will require multiple signers.
  17. return &Multisignature{bitarray.NewCompactBitArray(n), make([][]byte, 0, 2)}
  18. }
  19. // GetIndex returns the index of pk in keys. Returns -1 if not found
  20. func getIndex(pk crypto.PubKey, keys []crypto.PubKey) int {
  21. for i := 0; i < len(keys); i++ {
  22. if pk.Equals(keys[i]) {
  23. return i
  24. }
  25. }
  26. return -1
  27. }
  28. // AddSignature adds a signature to the multisig, at the corresponding index.
  29. // If the signature already exists, replace it.
  30. func (mSig *Multisignature) AddSignature(sig []byte, index int) {
  31. newSigIndex := mSig.BitArray.NumTrueBitsBefore(index)
  32. // Signature already exists, just replace the value there
  33. if mSig.BitArray.GetIndex(index) {
  34. mSig.Sigs[newSigIndex] = sig
  35. return
  36. }
  37. mSig.BitArray.SetIndex(index, true)
  38. // Optimization if the index is the greatest index
  39. if newSigIndex == len(mSig.Sigs) {
  40. mSig.Sigs = append(mSig.Sigs, sig)
  41. return
  42. }
  43. // Expand slice by one with a dummy element, move all elements after i
  44. // over by one, then place the new signature in that gap.
  45. mSig.Sigs = append(mSig.Sigs, make([]byte, 0))
  46. copy(mSig.Sigs[newSigIndex+1:], mSig.Sigs[newSigIndex:])
  47. mSig.Sigs[newSigIndex] = sig
  48. }
  49. // AddSignatureFromPubKey adds a signature to the multisig,
  50. // at the index in keys corresponding to the provided pubkey.
  51. func (mSig *Multisignature) AddSignatureFromPubKey(sig []byte, pubkey crypto.PubKey, keys []crypto.PubKey) error {
  52. index := getIndex(pubkey, keys)
  53. if index == -1 {
  54. return errors.New("provided key didn't exist in pubkeys")
  55. }
  56. mSig.AddSignature(sig, index)
  57. return nil
  58. }
  59. // Marshal the multisignature with amino
  60. func (mSig *Multisignature) Marshal() []byte {
  61. return cdc.MustMarshalBinaryBare(mSig)
  62. }