@@ -91,7 +91,48 @@ CPubKey CWallet::GenerateNewKey()
91
91
bool fCompressed = CanSupportFeature (FEATURE_COMPRPUBKEY); // default to compressed public keys if we want 0.6.0 wallets
92
92
93
93
CKey secret;
94
- secret.MakeNewKey (fCompressed );
94
+
95
+ // Create new metadata
96
+ int64_t nCreationTime = GetTime ();
97
+ CKeyMetadata metadata (nCreationTime);
98
+
99
+ // use HD key derivation if HD was enabled during wallet creation
100
+ if (!hdChain.masterKeyID .IsNull ()) {
101
+ // for now we use a fixed keypath scheme of m/0'/0'/k
102
+ CKey key; // master key seed (256bit)
103
+ CExtKey masterKey; // hd master key
104
+ CExtKey accountKey; // key at m/0'
105
+ CExtKey externalChainChildKey; // key at m/0'/0'
106
+ CExtKey childKey; // key at m/0'/0'/<n>'
107
+
108
+ // try to get the master key
109
+ if (!GetKey (hdChain.masterKeyID , key))
110
+ throw std::runtime_error (" CWallet::GenerateNewKey(): Master key not found" );
111
+
112
+ masterKey.SetMaster (key.begin (), key.size ());
113
+
114
+ // derive m/0'
115
+ // use hardened derivation (child keys > 0x80000000 are hardened after bip32)
116
+ masterKey.Derive (accountKey, 0 | 0x80000000 );
117
+
118
+ // derive m/0'/0'
119
+ accountKey.Derive (externalChainChildKey, 0 | 0x80000000 );
120
+
121
+ // derive child key at next index, skip keys already known to the wallet
122
+ do
123
+ {
124
+ externalChainChildKey.Derive (childKey, hdChain.nExternalChainCounter | 0x80000000 );
125
+ // increment childkey index
126
+ hdChain.nExternalChainCounter ++;
127
+ } while (HaveKey (childKey.key .GetPubKey ().GetID ()));
128
+ secret = childKey.key ;
129
+
130
+ // update the chain model in the database
131
+ if (!CWalletDB (strWalletFile).WriteHDChain (hdChain))
132
+ throw std::runtime_error (" CWallet::GenerateNewKey(): Writing HD chain model failed" );
133
+ } else {
134
+ secret.MakeNewKey (fCompressed );
135
+ }
95
136
96
137
// Compressed public keys were introduced in version 0.6.0
97
138
if (fCompressed )
@@ -100,9 +141,7 @@ CPubKey CWallet::GenerateNewKey()
100
141
CPubKey pubkey = secret.GetPubKey ();
101
142
assert (secret.VerifyPubKey (pubkey));
102
143
103
- // Create new metadata
104
- int64_t nCreationTime = GetTime ();
105
- mapKeyMetadata[pubkey.GetID ()] = CKeyMetadata (nCreationTime);
144
+ mapKeyMetadata[pubkey.GetID ()] = metadata;
106
145
if (!nTimeFirstKey || nCreationTime < nTimeFirstKey)
107
146
nTimeFirstKey = nCreationTime;
108
147
@@ -1049,6 +1088,37 @@ CAmount CWallet::GetChange(const CTransaction& tx) const
1049
1088
return nChange;
1050
1089
}
1051
1090
1091
+ bool CWallet::SetHDMasterKey (const CKey& key)
1092
+ {
1093
+ LOCK (cs_wallet);
1094
+
1095
+ // store the key as normal "key"/"ckey" object
1096
+ // in the database
1097
+ // key metadata is not required
1098
+ CPubKey pubkey = key.GetPubKey ();
1099
+ if (!AddKeyPubKey (key, pubkey))
1100
+ throw std::runtime_error (" CWallet::GenerateNewKey(): AddKey failed" );
1101
+
1102
+ // store the keyid (hash160) together with
1103
+ // the child index counter in the database
1104
+ // as a hdchain object
1105
+ CHDChain newHdChain;
1106
+ newHdChain.masterKeyID = pubkey.GetID ();
1107
+ SetHDChain (newHdChain, false );
1108
+
1109
+ return true ;
1110
+ }
1111
+
1112
+ bool CWallet::SetHDChain (const CHDChain& chain, bool memonly)
1113
+ {
1114
+ LOCK (cs_wallet);
1115
+ if (!memonly && !CWalletDB (strWalletFile).WriteHDChain (chain))
1116
+ throw runtime_error (" AddHDChain(): writing chain failed" );
1117
+
1118
+ hdChain = chain;
1119
+ return true ;
1120
+ }
1121
+
1052
1122
int64_t CWalletTx::GetTxTime () const
1053
1123
{
1054
1124
int64_t n = nTimeSmart;
@@ -3058,6 +3128,7 @@ std::string CWallet::GetWalletHelpString(bool showDebug)
3058
3128
strUsage += HelpMessageOpt (" -sendfreetransactions" , strprintf (_ (" Send transactions as zero-fee transactions if possible (default: %u)" ), DEFAULT_SEND_FREE_TRANSACTIONS));
3059
3129
strUsage += HelpMessageOpt (" -spendzeroconfchange" , strprintf (_ (" Spend unconfirmed change when sending transactions (default: %u)" ), DEFAULT_SPEND_ZEROCONF_CHANGE));
3060
3130
strUsage += HelpMessageOpt (" -txconfirmtarget=<n>" , strprintf (_ (" If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)" ), DEFAULT_TX_CONFIRM_TARGET));
3131
+ strUsage += HelpMessageOpt (" -usehd" , _ (" Use hierarchical deterministic key generation (HD) after bip32. Only has effect during wallet creation/first start" ) + " " + strprintf (_ (" (default: %u)" ), DEFAULT_USE_HD_WALLET));
3061
3132
strUsage += HelpMessageOpt (" -upgradewallet" , _ (" Upgrade wallet to latest format on startup" ));
3062
3133
strUsage += HelpMessageOpt (" -wallet=<file>" , _ (" Specify wallet file (within data directory)" ) + " " + strprintf (_ (" (default: %s)" ), DEFAULT_WALLET_DAT));
3063
3134
strUsage += HelpMessageOpt (" -walletbroadcast" , _ (" Make the wallet broadcast transactions" ) + " " + strprintf (_ (" (default: %u)" ), DEFAULT_WALLETBROADCAST));
@@ -3145,6 +3216,13 @@ bool CWallet::InitLoadWallet()
3145
3216
if (fFirstRun )
3146
3217
{
3147
3218
// Create new keyUser and set as default key
3219
+ if (GetBoolArg (" -usehd" , DEFAULT_USE_HD_WALLET)) {
3220
+ // generate a new master key
3221
+ CKey key;
3222
+ key.MakeNewKey (true );
3223
+ if (!walletInstance->SetHDMasterKey (key))
3224
+ throw std::runtime_error (" CWallet::GenerateNewKey(): Storing master key failed" );
3225
+ }
3148
3226
CPubKey newDefaultKey;
3149
3227
if (walletInstance->GetKeyFromPool (newDefaultKey)) {
3150
3228
walletInstance->SetDefaultKey (newDefaultKey);
0 commit comments