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.

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