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.

77 lines
2.4 KiB

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