Skip to content

Commit

Permalink
support exporting xpub keys
Browse files Browse the repository at this point in the history
  • Loading branch information
bitgamma committed Nov 29, 2024
1 parent 5bb74ca commit c87945d
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 17 deletions.
27 changes: 19 additions & 8 deletions command_set.go
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,23 @@ func (cs *CommandSet) DeriveKey(path string) error {
}

func (cs *CommandSet) ExportKey(derive bool, makeCurrent bool, onlyPublic bool, path string) ([]byte, []byte, error) {
var p2 uint8
if onlyPublic {
p2 = P2ExportKeyPublicOnly
} else {
p2 = P2ExportKeyPrivateAndPublic
}

key, err := cs.ExportKeyExtended(derive, makeCurrent, p2, path)

if err != nil {
return nil, nil, err
}

return key.PrivKey(), key.PubKey(), err
}

func (cs *CommandSet) ExportKeyExtended(derive bool, makeCurrent bool, p2 uint8, path string) (*types.ExportedKey, error) {
var p1 uint8
if !derive {
p1 = P1ExportKeyCurrent
Expand All @@ -324,22 +341,16 @@ func (cs *CommandSet) ExportKey(derive bool, makeCurrent bool, onlyPublic bool,
} else {
p1 = P1ExportKeyDeriveAndMakeCurrent
}
var p2 uint8
if onlyPublic {
p2 = P2ExportKeyPublicOnly
} else {
p2 = P2ExportKeyPrivateAndPublic
}

cmd, err := NewCommandExportKey(p1, p2, path)
if err != nil {
return nil, nil, err
return nil, err
}

resp, err := cs.sc.Send(cmd)
err = cs.checkOK(resp, err)
if err != nil {
return nil, nil, err
return nil, err
}

return types.ParseExportKeyResponse(resp.Data)
Expand Down
39 changes: 30 additions & 9 deletions types/exported_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,50 @@ import (
)

var (
TagExportKeyTemplate = uint8(0xA1)
TagExportKeyPublic = uint8(0x81)
TagExportKeyTemplate = apdu.Tag{0xA1}
TagExportKeyPublic = apdu.Tag{0x80}
TagExportKeyPrivate = apdu.Tag{0x81}
TagExportKeyPublicChain = apdu.Tag{0x82}
)

func ParseExportKeyResponse(data []byte) ([]byte, []byte, error) {
tpl, err := apdu.FindTag(data, apdu.Tag{0xA1})
type ExportedKey struct {
pubKey []byte
privKey []byte
chainCode []byte
}

func (k *ExportedKey) PubKey() []byte {
return k.pubKey
}

func (k *ExportedKey) PrivKey() []byte {
return k.privKey
}

func (k *ExportedKey) ChainCode() []byte {
return k.chainCode
}

func ParseExportKeyResponse(data []byte) (*ExportedKey, error) {
tpl, err := apdu.FindTag(data, TagExportKeyTemplate)
if err != nil {
return nil, nil, err
return nil, err
}

pubKey := tryFindTag(tpl, apdu.Tag{0x80})
privKey := tryFindTag(tpl, apdu.Tag{0x81})
pubKey := tryFindTag(tpl, TagExportKeyPublic)
privKey := tryFindTag(tpl, TagExportKeyPrivate)
chainCode := tryFindTag(tpl, TagExportKeyPublicChain)

if len(pubKey) == 0 && len(privKey) > 0 {
ecdsaKey, err := ethcrypto.HexToECDSA(fmt.Sprintf("%x", privKey))
if err != nil {
return nil, nil, err
return nil, err
}

pubKey = ethcrypto.FromECDSAPub(&ecdsaKey.PublicKey)
}

return privKey, pubKey, nil
return &ExportedKey{pubKey, privKey, chainCode}, nil
}

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

0 comments on commit c87945d

Please sign in to comment.