Skip to content

Commit

Permalink
multi: verifySeed RPC (#1037)
Browse files Browse the repository at this point in the history
fixup:
  • Loading branch information
githubsands committed Aug 19, 2018
1 parent 926e030 commit a4c45de
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 48 deletions.
9 changes: 9 additions & 0 deletions internal/rpchelp/helpdescs_en_US.go
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,15 @@ var helpDescsEnUS = map[string]string{
"verifymessage-message": "The message to verify",
"verifymessage--result0": "Whether the message was signed with the private key of 'address'",

// VerifySeedCmd help.
"verifyseed--synopsis": "Verifys if a seed is the same as the running wallet.",
"verifyseed-seed": "Seed to be inputted to check against the wallets master public key, after derivation.",
"verifyseed-account": "Account number, of potential branch of the master public key, this is an optional input.",

// VerifySeedResults help.
"verifyseedresult-keyresult": "Whether or not if the inputted seed is the same as the running wallets",
"verifyseedresult-cointype": "Outputs the current cointype of the running wallet.",

// Version help
"version--synopsis": "Returns application and API versions (semver) keyed by their names",
"version--result0--desc": "Version objects keyed by the program or API name",
Expand Down
1 change: 1 addition & 0 deletions internal/rpchelp/methods.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ var Methods = []struct {
{"sweepaccount", []interface{}{(*dcrjson.SweepAccountResult)(nil)}},
{"validateaddress", []interface{}{(*dcrjson.ValidateAddressWalletResult)(nil)}},
{"verifymessage", returnsBool},
{"verifyseed", []interface{}{(*dcrjson.VerifySeedResult)(nil)}},
{"version", []interface{}{(*map[string]dcrjson.VersionResult)(nil)}},
{"walletlock", nil},
{"walletpassphrase", nil},
Expand Down
103 changes: 103 additions & 0 deletions rpc/legacyrpc/methods.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import (
"github.com/decred/dcrwallet/wallet"
"github.com/decred/dcrwallet/wallet/txrules"
"github.com/decred/dcrwallet/wallet/udb"
"github.com/decred/dcrwallet/walletseed"
)

// API version constants
Expand Down Expand Up @@ -122,6 +123,7 @@ var handlers = map[string]handler{
"ticketsforaddress": {fn: ticketsForAddress},
"validateaddress": {fn: validateAddress},
"verifymessage": {fn: verifyMessage},
"verifyseed": {fn: verifySeed},
"version": {fn: version},
"walletinfo": {fn: walletInfo},
"walletlock": {fn: walletLock},
Expand Down Expand Up @@ -3442,6 +3444,107 @@ WrongAddrKind:
return nil, rpcErrorf(dcrjson.ErrRPCInvalidParameter, "address must be secp256k1 P2PK or P2PKH")
}

func deriveCoinTypeKey(seed []byte, coinType uint32, params *chaincfg.Params) (*hdkeychain.ExtendedKey, error) {
// Create new root from the inputted seed and the current net
root, err := hdkeychain.NewMaster(seed[:], params)
if err != nil {
return nil, err
}

// BIP0032 hierarchy: m/<purpose>'/
// Where purpose = 44 and the ' indicates hardening with the HardenedKeyStart 0x80000000
purpose, err := root.Child(44 + hdkeychain.HardenedKeyStart)
if err != nil {
return nil, err
}
defer purpose.Zero()

// BIP0044 hierarchy: m/44'/<coin type>'
// Where coin type is either the legacy coin type, 20, or the coin type described in SLIP0044, 44.
coinTypePrivKey, err := purpose.Child(coinType + hdkeychain.HardenedKeyStart)
if err != nil {
return nil, err
}
defer coinTypePrivKey.Zero()

return coinTypePrivKey, nil
}

// verifySeed checks if a user inputted seed is that of the wallet by comparing their child key derivatied
// public keys. It returns a bool if this the case as well as the current coin type of the wallet. An optional
// parameter is also avalaible that checks beyond default accounts. It returns the result using the RPC api.
func verifySeed(s *Server, icmd interface{}) (interface{}, error) {
cmd := icmd.(*dcrjson.VerifySeedCmd)
w, ok := s.walletLoader.LoadedWallet()
if !ok {
return nil, errUnloadedWallet
}

coinType, err := w.CoinType()
if err != nil {
return nil, err
}

decodedSeed, err := walletseed.DecodeUserInput(cmd.Seed)
if err != nil {
return nil, err
}

// Changed inputted seed, type string, to type byte[] so hdkeychain methods can be utilize using DecodeUserInput
// and run then derivedCoinTypeKey to receive the coin type private key.
coinTypePrivKey, err := deriveCoinTypeKey(decodedSeed, coinType, w.ChainParams())
if err != nil {
return nil, err
}
defer coinTypePrivKey.Zero()

// Grab coin type private key from wallet for future comparison to the derived inputted coin type private key
walletCoinTypePrivKey, err := w.CoinTypeKey()
if err != nil {
return nil, err
}
defer walletCoinTypePrivKey.Zero()

var matches bool
switch {
case cmd.Account != nil:
// Both derivedAccountKey and walletDerivedAccountKey use the BIP044 hierachy: m/44'/<coin type>'/<account>'
// If the child is a private extended key it is neutered
accountKey, err := coinTypePrivKey.Child(*cmd.Account + hdkeychain.HardenedKeyStart)
if err != nil {
return nil, err
}
defer accountKey.Zero()

xPubKey, err := accountKey.Neuter()
if err != nil {
return nil, err
}

walletAccountKey, err := walletCoinTypePrivKey.Child(*cmd.Account + hdkeychain.HardenedKeyStart)
if err != nil {
return nil, err
}
defer walletAccountKey.Zero()

walletxPubKey, err := walletAccountKey.Neuter()
if err != nil {
return nil, err
}

// Since the field, key, within the type struct, ExtendedKey, is private - keys must be converted
// to type string for comparison.
matches = xPubKey.String() == walletxPubKey.String()
default:
matches = coinTypePrivKey.String() == walletCoinTypePrivKey.String()
}

return &dcrjson.VerifySeedResult{
Result: matches,
CoinType: coinType,
}, nil
}

// version handles the version command by returning the RPC API versions of the
// wallet and, optionally, the consensus RPC server as well if it is associated
// with the server. The chainClient is optional, and this is simply a helper
Expand Down

0 comments on commit a4c45de

Please sign in to comment.