Skip to content

Commit c87945d

Browse files
committed
support exporting xpub keys
1 parent 5bb74ca commit c87945d

File tree

2 files changed

+49
-17
lines changed

2 files changed

+49
-17
lines changed

command_set.go

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,23 @@ func (cs *CommandSet) DeriveKey(path string) error {
316316
}
317317

318318
func (cs *CommandSet) ExportKey(derive bool, makeCurrent bool, onlyPublic bool, path string) ([]byte, []byte, error) {
319+
var p2 uint8
320+
if onlyPublic {
321+
p2 = P2ExportKeyPublicOnly
322+
} else {
323+
p2 = P2ExportKeyPrivateAndPublic
324+
}
325+
326+
key, err := cs.ExportKeyExtended(derive, makeCurrent, p2, path)
327+
328+
if err != nil {
329+
return nil, nil, err
330+
}
331+
332+
return key.PrivKey(), key.PubKey(), err
333+
}
334+
335+
func (cs *CommandSet) ExportKeyExtended(derive bool, makeCurrent bool, p2 uint8, path string) (*types.ExportedKey, error) {
319336
var p1 uint8
320337
if !derive {
321338
p1 = P1ExportKeyCurrent
@@ -324,22 +341,16 @@ func (cs *CommandSet) ExportKey(derive bool, makeCurrent bool, onlyPublic bool,
324341
} else {
325342
p1 = P1ExportKeyDeriveAndMakeCurrent
326343
}
327-
var p2 uint8
328-
if onlyPublic {
329-
p2 = P2ExportKeyPublicOnly
330-
} else {
331-
p2 = P2ExportKeyPrivateAndPublic
332-
}
333344

334345
cmd, err := NewCommandExportKey(p1, p2, path)
335346
if err != nil {
336-
return nil, nil, err
347+
return nil, err
337348
}
338349

339350
resp, err := cs.sc.Send(cmd)
340351
err = cs.checkOK(resp, err)
341352
if err != nil {
342-
return nil, nil, err
353+
return nil, err
343354
}
344355

345356
return types.ParseExportKeyResponse(resp.Data)

types/exported_key.go

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,29 +8,50 @@ import (
88
)
99

1010
var (
11-
TagExportKeyTemplate = uint8(0xA1)
12-
TagExportKeyPublic = uint8(0x81)
11+
TagExportKeyTemplate = apdu.Tag{0xA1}
12+
TagExportKeyPublic = apdu.Tag{0x80}
13+
TagExportKeyPrivate = apdu.Tag{0x81}
14+
TagExportKeyPublicChain = apdu.Tag{0x82}
1315
)
1416

15-
func ParseExportKeyResponse(data []byte) ([]byte, []byte, error) {
16-
tpl, err := apdu.FindTag(data, apdu.Tag{0xA1})
17+
type ExportedKey struct {
18+
pubKey []byte
19+
privKey []byte
20+
chainCode []byte
21+
}
22+
23+
func (k *ExportedKey) PubKey() []byte {
24+
return k.pubKey
25+
}
26+
27+
func (k *ExportedKey) PrivKey() []byte {
28+
return k.privKey
29+
}
30+
31+
func (k *ExportedKey) ChainCode() []byte {
32+
return k.chainCode
33+
}
34+
35+
func ParseExportKeyResponse(data []byte) (*ExportedKey, error) {
36+
tpl, err := apdu.FindTag(data, TagExportKeyTemplate)
1737
if err != nil {
18-
return nil, nil, err
38+
return nil, err
1939
}
2040

21-
pubKey := tryFindTag(tpl, apdu.Tag{0x80})
22-
privKey := tryFindTag(tpl, apdu.Tag{0x81})
41+
pubKey := tryFindTag(tpl, TagExportKeyPublic)
42+
privKey := tryFindTag(tpl, TagExportKeyPrivate)
43+
chainCode := tryFindTag(tpl, TagExportKeyPublicChain)
2344

2445
if len(pubKey) == 0 && len(privKey) > 0 {
2546
ecdsaKey, err := ethcrypto.HexToECDSA(fmt.Sprintf("%x", privKey))
2647
if err != nil {
27-
return nil, nil, err
48+
return nil, err
2849
}
2950

3051
pubKey = ethcrypto.FromECDSAPub(&ecdsaKey.PublicKey)
3152
}
3253

33-
return privKey, pubKey, nil
54+
return &ExportedKey{pubKey, privKey, chainCode}, nil
3455
}
3556

3657
func tryFindTag(tpl []byte, tags ...apdu.Tag) []byte {

0 commit comments

Comments
 (0)