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.

125 lines
3.6 KiB

  1. package keys
  2. import (
  3. "fmt"
  4. "sort"
  5. crypto "github.com/tendermint/go-crypto"
  6. wire "github.com/tendermint/go-wire"
  7. data "github.com/tendermint/go-wire/data"
  8. )
  9. // Info is the public information about a key
  10. type Info struct {
  11. Name string `json:"name"`
  12. Address data.Bytes `json:"address"`
  13. PubKey crypto.PubKey `json:"pubkey"`
  14. }
  15. func (i *Info) Format() Info {
  16. if !i.PubKey.Empty() {
  17. i.Address = i.PubKey.Address()
  18. }
  19. return *i
  20. }
  21. // Infos is a wrapper to allows alphabetical sorting of the keys
  22. type Infos []Info
  23. func (k Infos) Len() int { return len(k) }
  24. func (k Infos) Less(i, j int) bool { return k[i].Name < k[j].Name }
  25. func (k Infos) Swap(i, j int) { k[i], k[j] = k[j], k[i] }
  26. func (k Infos) Sort() {
  27. if k != nil {
  28. sort.Sort(k)
  29. }
  30. }
  31. // Signable represents any transaction we wish to send to tendermint core
  32. // These methods allow us to sign arbitrary Tx with the KeyStore
  33. type Signable interface {
  34. // SignBytes is the immutable data, which needs to be signed
  35. SignBytes() []byte
  36. // Sign will add a signature and pubkey.
  37. //
  38. // Depending on the Signable, one may be able to call this multiple times for multisig
  39. // Returns error if called with invalid data or too many times
  40. Sign(pubkey crypto.PubKey, sig crypto.Signature) error
  41. // Signers will return the public key(s) that signed if the signature
  42. // is valid, or an error if there is any issue with the signature,
  43. // including if there are no signatures
  44. Signers() ([]crypto.PubKey, error)
  45. // TxBytes returns the transaction data as well as all signatures
  46. // It should return an error if Sign was never called
  47. TxBytes() ([]byte, error)
  48. }
  49. // Signer allows one to use a keystore to sign transactions
  50. type Signer interface {
  51. Sign(name, passphrase string, tx Signable) error
  52. }
  53. // Manager allows simple CRUD on a keystore, as an aid to signing
  54. type Manager interface {
  55. Signer
  56. // Create also returns a seed phrase for cold-storage
  57. Create(name, passphrase, algo string) (Info, string, error)
  58. // Recover takes a seedphrase and loads in the private key
  59. Recover(name, passphrase, seedphrase string) (Info, error)
  60. List() (Infos, error)
  61. Get(name string) (Info, error)
  62. Update(name, oldpass, newpass string) error
  63. Delete(name, passphrase string) error
  64. }
  65. /**** MockSignable allows us to view data ***/
  66. // MockSignable lets us wrap arbitrary data with a go-crypto signature
  67. type MockSignable struct {
  68. Data []byte
  69. PubKey crypto.PubKey
  70. Signature crypto.Signature
  71. }
  72. var _ Signable = &MockSignable{}
  73. // NewMockSignable sets the data to sign
  74. func NewMockSignable(data []byte) *MockSignable {
  75. return &MockSignable{Data: data}
  76. }
  77. // TxBytes returns the full data with signatures
  78. func (s *MockSignable) TxBytes() ([]byte, error) {
  79. return wire.BinaryBytes(s), nil
  80. }
  81. // SignBytes returns the original data passed into `NewSig`
  82. func (s *MockSignable) SignBytes() []byte {
  83. return s.Data
  84. }
  85. // Sign will add a signature and pubkey.
  86. //
  87. // Depending on the Signable, one may be able to call this multiple times for multisig
  88. // Returns error if called with invalid data or too many times
  89. func (s *MockSignable) Sign(pubkey crypto.PubKey, sig crypto.Signature) error {
  90. s.PubKey = pubkey
  91. s.Signature = sig
  92. return nil
  93. }
  94. // Signers will return the public key(s) that signed if the signature
  95. // is valid, or an error if there is any issue with the signature,
  96. // including if there are no signatures
  97. func (s *MockSignable) Signers() ([]crypto.PubKey, error) {
  98. if s.PubKey.Empty() {
  99. return nil, fmt.Errorf("no signers")
  100. }
  101. if !s.PubKey.VerifyBytes(s.SignBytes(), s.Signature) {
  102. return nil, fmt.Errorf("invalid signature")
  103. }
  104. return []crypto.PubKey{s.PubKey}, nil
  105. }