OSDN Git Service

new repo
[bytom/vapor.git] / vendor / github.com / tendermint / go-crypto / nano / keys.go
1 package nano
2
3 import (
4         "bytes"
5         "encoding/hex"
6
7         "github.com/pkg/errors"
8
9         ledger "github.com/ethanfrey/ledger"
10
11         crypto "github.com/tendermint/go-crypto"
12         wire "github.com/tendermint/go-wire"
13 )
14
15 //nolint
16 const (
17         NameLedgerEd25519 = "ledger-ed25519"
18         TypeLedgerEd25519 = 0x10
19
20         // Timeout is the number of seconds to wait for a response from the ledger
21         // if eg. waiting for user confirmation on button push
22         Timeout = 20
23 )
24
25 var device *ledger.Ledger
26
27 // getLedger gets a copy of the device, and caches it
28 func getLedger() (*ledger.Ledger, error) {
29         var err error
30         if device == nil {
31                 device, err = ledger.FindLedger()
32         }
33         return device, err
34 }
35
36 func signLedger(device *ledger.Ledger, msg []byte) (pk crypto.PubKey, sig crypto.Signature, err error) {
37         var resp []byte
38
39         packets := generateSignRequests(msg)
40         for _, pack := range packets {
41                 resp, err = device.Exchange(pack, Timeout)
42                 if err != nil {
43                         return pk, sig, err
44                 }
45         }
46
47         // the last call is the result we want and needs to be parsed
48         key, bsig, err := parseDigest(resp)
49         if err != nil {
50                 return pk, sig, err
51         }
52
53         var b [32]byte
54         copy(b[:], key)
55         return PubKeyLedgerEd25519FromBytes(b), crypto.SignatureEd25519FromBytes(bsig), nil
56 }
57
58 // PrivKeyLedgerEd25519 implements PrivKey, calling the ledger nano
59 // we cache the PubKey from the first call to use it later
60 type PrivKeyLedgerEd25519 struct {
61         // PubKey should be private, but we want to encode it via go-wire
62         // so we can view the address later, even without having the ledger
63         // attached
64         CachedPubKey crypto.PubKey
65 }
66
67 // NewPrivKeyLedgerEd25519Ed25519 will generate a new key and store the
68 // public key for later use.
69 func NewPrivKeyLedgerEd25519Ed25519() (crypto.PrivKey, error) {
70         var pk PrivKeyLedgerEd25519
71         // getPubKey will cache the pubkey for later use,
72         // this allows us to return an error early if the ledger
73         // is not plugged in
74         _, err := pk.getPubKey()
75         return pk.Wrap(), err
76 }
77
78 // ValidateKey allows us to verify the sanity of a key
79 // after loading it from disk
80 func (pk *PrivKeyLedgerEd25519) ValidateKey() error {
81         // getPubKey will return an error if the ledger is not
82         // properly set up...
83         pub, err := pk.forceGetPubKey()
84         if err != nil {
85                 return err
86         }
87         // verify this matches cached address
88         if !pub.Equals(pk.CachedPubKey) {
89                 return errors.New("ledger doesn't match cached key")
90         }
91         return nil
92 }
93
94 // AssertIsPrivKeyInner fulfils PrivKey Interface
95 func (pk *PrivKeyLedgerEd25519) AssertIsPrivKeyInner() {}
96
97 // Bytes fulfils pk Interface - stores the cached pubkey so we can verify
98 // the same key when we reconnect to a ledger
99 func (pk *PrivKeyLedgerEd25519) Bytes() []byte {
100         return wire.BinaryBytes(pk.Wrap())
101 }
102
103 // Sign calls the ledger and stores the pk for future use
104 //
105 // XXX/TODO: panics if there is an error communicating with the ledger.
106 //
107 // Communication is checked on NewPrivKeyLedger and PrivKeyFromBytes,
108 // returning an error, so this should only trigger if the privkey is held
109 // in memory for a while before use.
110 func (pk *PrivKeyLedgerEd25519) Sign(msg []byte) crypto.Signature {
111         // oh, I wish there was better error handling
112         dev, err := getLedger()
113         if err != nil {
114                 panic(err)
115         }
116
117         pub, sig, err := signLedger(dev, msg)
118         if err != nil {
119                 panic(err)
120         }
121
122         // if we have no pubkey yet, store it for future queries
123         if pk.CachedPubKey.Empty() {
124                 pk.CachedPubKey = pub
125         } else if !pk.CachedPubKey.Equals(pub) {
126                 panic("signed with a different key than stored")
127         }
128         return sig
129 }
130
131 // PubKey returns the stored PubKey
132 // TODO: query the ledger if not there, once it is not volatile
133 func (pk *PrivKeyLedgerEd25519) PubKey() crypto.PubKey {
134         key, err := pk.getPubKey()
135         if err != nil {
136                 panic(err)
137         }
138         return key
139 }
140
141 // getPubKey reads the pubkey from cache or from the ledger itself
142 // since this involves IO, it may return an error, which is not exposed
143 // in the PubKey interface, so this function allows better error handling
144 func (pk *PrivKeyLedgerEd25519) getPubKey() (key crypto.PubKey, err error) {
145         // if we have no pubkey, set it
146         if pk.CachedPubKey.Empty() {
147                 pk.CachedPubKey, err = pk.forceGetPubKey()
148         }
149         return pk.CachedPubKey, err
150 }
151
152 // forceGetPubKey is like getPubKey but ignores any cached key
153 // and ensures we get it from the ledger itself.
154 func (pk *PrivKeyLedgerEd25519) forceGetPubKey() (key crypto.PubKey, err error) {
155         dev, err := getLedger()
156         if err != nil {
157                 return key, errors.New("Can't connect to ledger device")
158         }
159         key, _, err = signLedger(dev, []byte{0})
160         if err != nil {
161                 return key, errors.New("Please open cosmos app on the ledger")
162         }
163         return key, err
164 }
165
166 // Equals fulfils PrivKey Interface - makes sure both keys refer to the
167 // same
168 func (pk *PrivKeyLedgerEd25519) Equals(other crypto.PrivKey) bool {
169         if ledger, ok := other.Unwrap().(*PrivKeyLedgerEd25519); ok {
170                 return pk.CachedPubKey.Equals(ledger.CachedPubKey)
171         }
172         return false
173 }
174
175 // MockPrivKeyLedgerEd25519 behaves as the ledger, but stores a pre-packaged call-response
176 // for use in test cases
177 type MockPrivKeyLedgerEd25519 struct {
178         Msg []byte
179         Pub [KeyLength]byte
180         Sig [SigLength]byte
181 }
182
183 // NewMockKey returns
184 func NewMockKey(msg, pubkey, sig string) (pk MockPrivKeyLedgerEd25519) {
185         var err error
186         pk.Msg, err = hex.DecodeString(msg)
187         if err != nil {
188                 panic(err)
189         }
190
191         bpk, err := hex.DecodeString(pubkey)
192         if err != nil {
193                 panic(err)
194         }
195         bsig, err := hex.DecodeString(sig)
196         if err != nil {
197                 panic(err)
198         }
199
200         copy(pk.Pub[:], bpk)
201         copy(pk.Sig[:], bsig)
202         return pk
203 }
204
205 var _ crypto.PrivKeyInner = MockPrivKeyLedgerEd25519{}
206
207 // AssertIsPrivKeyInner fulfils PrivKey Interface
208 func (pk MockPrivKeyLedgerEd25519) AssertIsPrivKeyInner() {}
209
210 // Bytes fulfils PrivKey Interface - not supported
211 func (pk MockPrivKeyLedgerEd25519) Bytes() []byte {
212         return nil
213 }
214
215 // Sign returns a real SignatureLedger, if the msg matches what we expect
216 func (pk MockPrivKeyLedgerEd25519) Sign(msg []byte) crypto.Signature {
217         if !bytes.Equal(pk.Msg, msg) {
218                 panic("Mock key is for different msg")
219         }
220         return crypto.SignatureEd25519(pk.Sig).Wrap()
221 }
222
223 // PubKey returns a real PubKeyLedgerEd25519, that will verify this signature
224 func (pk MockPrivKeyLedgerEd25519) PubKey() crypto.PubKey {
225         return PubKeyLedgerEd25519FromBytes(pk.Pub)
226 }
227
228 // Equals compares that two Mocks have the same data
229 func (pk MockPrivKeyLedgerEd25519) Equals(other crypto.PrivKey) bool {
230         if mock, ok := other.Unwrap().(MockPrivKeyLedgerEd25519); ok {
231                 return bytes.Equal(mock.Pub[:], pk.Pub[:]) &&
232                         bytes.Equal(mock.Sig[:], pk.Sig[:]) &&
233                         bytes.Equal(mock.Msg, pk.Msg)
234         }
235         return false
236 }
237
238 ////////////////////////////////////////////
239 // pubkey
240
241 // PubKeyLedgerEd25519 works like a normal Ed25519 except a hash before the verify bytes
242 type PubKeyLedgerEd25519 struct {
243         crypto.PubKeyEd25519
244 }
245
246 // PubKeyLedgerEd25519FromBytes creates a PubKey from the raw bytes
247 func PubKeyLedgerEd25519FromBytes(key [32]byte) crypto.PubKey {
248         return PubKeyLedgerEd25519{crypto.PubKeyEd25519(key)}.Wrap()
249 }
250
251 // Bytes fulfils pk Interface - no data, just type info
252 func (pk PubKeyLedgerEd25519) Bytes() []byte {
253         return wire.BinaryBytes(pk.Wrap())
254 }
255
256 // VerifyBytes uses the normal Ed25519 algorithm but a sha512 hash beforehand
257 func (pk PubKeyLedgerEd25519) VerifyBytes(msg []byte, sig crypto.Signature) bool {
258         hmsg := hashMsg(msg)
259         return pk.PubKeyEd25519.VerifyBytes(hmsg, sig)
260 }
261
262 // Equals implements PubKey interface
263 func (pk PubKeyLedgerEd25519) Equals(other crypto.PubKey) bool {
264         if ledger, ok := other.Unwrap().(PubKeyLedgerEd25519); ok {
265                 return pk.PubKeyEd25519.Equals(ledger.PubKeyEd25519.Wrap())
266         }
267         return false
268 }
269
270 /*** registration with go-data ***/
271
272 func init() {
273         crypto.PrivKeyMapper.
274                 RegisterImplementation(&PrivKeyLedgerEd25519{}, NameLedgerEd25519, TypeLedgerEd25519).
275                 RegisterImplementation(MockPrivKeyLedgerEd25519{}, "mock-ledger", 0x11)
276
277         crypto.PubKeyMapper.
278                 RegisterImplementation(PubKeyLedgerEd25519{}, NameLedgerEd25519, TypeLedgerEd25519)
279 }
280
281 // Wrap fulfils interface for PrivKey struct
282 func (pk *PrivKeyLedgerEd25519) Wrap() crypto.PrivKey {
283         return crypto.PrivKey{PrivKeyInner: pk}
284 }
285
286 // Wrap fulfils interface for PrivKey struct
287 func (pk MockPrivKeyLedgerEd25519) Wrap() crypto.PrivKey {
288         return crypto.PrivKey{PrivKeyInner: pk}
289 }
290
291 // Wrap fulfils interface for PubKey struct
292 func (pk PubKeyLedgerEd25519) Wrap() crypto.PubKey {
293         return crypto.PubKey{PubKeyInner: pk}
294 }