upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.cpp')
-rw-r--r--src/main.cpp232
1 files changed, 215 insertions, 17 deletions
diff --git a/src/main.cpp b/src/main.cpp
index 75647ba..efece6c 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -181,7 +181,7 @@ static bool AddKeyIfMissing(const CKey& key)
181 return AddKey(key); 181 return AddKey(key);
182} 182}
183 183
184static bool DeriveNextHDWalletKey(vector<unsigned char>& vchPubKeyRet, string& strErrorRet) 184static bool DeriveNextHDReceiveKey(vector<unsigned char>& vchPubKeyRet, string& strErrorRet)
185{ 185{
186 vchPubKeyRet.clear(); 186 vchPubKeyRet.clear();
187 CRITICAL_BLOCK(cs_keyPool) 187 CRITICAL_BLOCK(cs_keyPool)
@@ -193,7 +193,12 @@ static bool DeriveNextHDWalletKey(vector<unsigned char>& vchPubKeyRet, string& s
193 } 193 }
194 194
195 CKey key; 195 CKey key;
196 if (!DeriveHDKey(nHDNext, key, strErrorRet)) 196 unsigned int nIndex = 0;
197 if (nHDKeySchema == HD_SCHEMA_BIP44)
198 nIndex = nHDReceiveNext;
199 else
200 nIndex = nHDNext;
201 if (!DeriveHDKey(nIndex, key, strErrorRet))
197 return false; 202 return false;
198 if (!AddKeyIfMissing(key)) 203 if (!AddKeyIfMissing(key))
199 { 204 {
@@ -201,14 +206,77 @@ static bool DeriveNextHDWalletKey(vector<unsigned char>& vchPubKeyRet, string& s
201 return false; 206 return false;
202 } 207 }
203 208
204 unsigned int nNext = nHDNext + 1; 209 unsigned int nNext = nIndex + 1;
205 if (!CWalletDB().WriteHDNext(nNext)) 210 if (nHDKeySchema == HD_SCHEMA_BIP44)
211 {
212 if (!CWalletDB().WriteHDReceiveNext(nNext))
213 {
214 strErrorRet = "could not advance the receive derivation counter";
215 return false;
216 }
217 nHDReceiveNext = nNext;
218 }
219 else
220 {
221 if (!CWalletDB().WriteHDNext(nNext))
222 {
223 strErrorRet = "could not advance the derivation counter";
224 return false;
225 }
226 nHDNext = nNext;
227 }
228
229 vchPubKeyRet = key.GetPubKey();
230 }
231 return true;
232}
233
234static bool DeriveNextHDChangeKey(vector<unsigned char>& vchPubKeyRet, string& strErrorRet)
235{
236 vchPubKeyRet.clear();
237 CRITICAL_BLOCK(cs_keyPool)
238 {
239 if (!HaveHDSeed())
206 { 240 {
207 strErrorRet = "could not advance the derivation counter"; 241 strErrorRet = "no seed";
208 return false; 242 return false;
209 } 243 }
210 244
211 nHDNext = nNext; 245 CKey key;
246 if (nHDKeySchema == HD_SCHEMA_BIP44)
247 {
248 if (!DeriveHDChangeKey(nHDChangeNext, key, strErrorRet))
249 return false;
250 if (!AddKeyIfMissing(key))
251 {
252 strErrorRet = "could not write the derived change key to wallet.dat";
253 return false;
254 }
255 unsigned int nNext = nHDChangeNext + 1;
256 if (!CWalletDB().WriteHDChangeNext(nNext))
257 {
258 strErrorRet = "could not advance the change derivation counter";
259 return false;
260 }
261 nHDChangeNext = nNext;
262 }
263 else
264 {
265 if (!DeriveHDKey(nHDNext, key, strErrorRet))
266 return false;
267 if (!AddKeyIfMissing(key))
268 {
269 strErrorRet = "could not write the derived change key to wallet.dat";
270 return false;
271 }
272 unsigned int nNext = nHDNext + 1;
273 if (!CWalletDB().WriteHDNext(nNext))
274 {
275 strErrorRet = "could not advance the derivation counter";
276 return false;
277 }
278 nHDNext = nNext;
279 }
212 vchPubKeyRet = key.GetPubKey(); 280 vchPubKeyRet = key.GetPubKey();
213 } 281 }
214 return true; 282 return true;
@@ -229,6 +297,40 @@ map<int64, vector<unsigned char> > mapKeyPool;
229vector<unsigned char> vchHDMaster; 297vector<unsigned char> vchHDMaster;
230vector<unsigned char> vchHDChainCode; 298vector<unsigned char> vchHDChainCode;
231unsigned int nHDNext = 0; 299unsigned int nHDNext = 0;
300int nHDKeySchema = HD_SCHEMA_NONE;
301unsigned int nHDReceiveNext = 0;
302unsigned int nHDChangeNext = 0;
303unsigned int nHDCoinType = HD_BIP44_COIN_TYPE_BITFLASH_PROVISIONAL;
304
305string HDKeySchemaName(int nSchema)
306{
307 if (nSchema == HD_SCHEMA_LEGACY)
308 return "legacy-hd";
309 if (nSchema == HD_SCHEMA_BIP44)
310 return "bip44";
311 return "none";
312}
313
314std::vector<unsigned int> HDLegacyPath(unsigned int nIndex)
315{
316 std::vector<unsigned int> path;
317 path.push_back(nIndex | bitflash::BIP32_HARDENED);
318 return path;
319}
320
321std::vector<unsigned int> HDBIP44Path(unsigned int nCoinType,
322 unsigned int nAccount,
323 unsigned int nChain,
324 unsigned int nIndex)
325{
326 std::vector<unsigned int> path;
327 path.push_back(HD_BIP44_PURPOSE | bitflash::BIP32_HARDENED);
328 path.push_back(nCoinType | bitflash::BIP32_HARDENED);
329 path.push_back(nAccount | bitflash::BIP32_HARDENED);
330 path.push_back(nChain);
331 path.push_back(nIndex);
332 return path;
333}
232 334
233static bool ClearKeyPoolRecords(string& strErrorRet) 335static bool ClearKeyPoolRecords(string& strErrorRet)
234{ 336{
@@ -254,13 +356,59 @@ bool DeriveHDKey(unsigned int nIndex, CKey& keyRet, string& strErrorRet)
254 strErrorRet = "no seed"; 356 strErrorRet = "no seed";
255 return false; 357 return false;
256 } 358 }
359 if (nIndex >= bitflash::BIP32_HARDENED)
360 {
361 strErrorRet = "child index must be non-hardened; hardening is applied here";
362 return false;
363 }
364
365 bitflash::BIP32PrivateNode parent;
366 parent.privateKey = vchHDMaster;
367 parent.chainCode = vchHDChainCode;
368
369 bitflash::BIP32PrivateNode child;
370 std::vector<unsigned int> path = nHDKeySchema == HD_SCHEMA_BIP44
371 ? HDBIP44Path(nHDCoinType, HD_BIP44_ACCOUNT, HD_BIP44_CHAIN_RECEIVE, nIndex)
372 : HDLegacyPath(nIndex);
373 if (!bitflash::BIP32DerivePath(parent, path, child, strErrorRet))
374 return false;
375
376 if (!keyRet.SetSecret(child.privateKey))
377 {
378 strErrorRet = "derived scalar is not a usable key";
379 return false;
380 }
381 return true;
382}
383
384bool DeriveHDChangeKey(unsigned int nIndex, CKey& keyRet, string& strErrorRet)
385{
386 if (!HaveHDSeed())
387 {
388 strErrorRet = "no seed";
389 return false;
390 }
391 if (nIndex >= bitflash::BIP32_HARDENED)
392 {
393 strErrorRet = "child index must be non-hardened; hardening is applied here";
394 return false;
395 }
396
397 if (nHDKeySchema != HD_SCHEMA_BIP44)
398 return DeriveHDKey(nIndex, keyRet, strErrorRet);
257 399
258 bitflash::BIP32PrivateNode parent; 400 bitflash::BIP32PrivateNode parent;
259 parent.privateKey = vchHDMaster; 401 parent.privateKey = vchHDMaster;
260 parent.chainCode = vchHDChainCode; 402 parent.chainCode = vchHDChainCode;
261 403
262 bitflash::BIP32PrivateNode child; 404 bitflash::BIP32PrivateNode child;
263 if (!bitflash::BIP32DeriveHardenedChild(parent, nIndex, child, strErrorRet)) 405 if (!bitflash::BIP32DerivePath(parent,
406 HDBIP44Path(nHDCoinType,
407 HD_BIP44_ACCOUNT,
408 HD_BIP44_CHAIN_CHANGE,
409 nIndex),
410 child,
411 strErrorRet))
264 return false; 412 return false;
265 413
266 if (!keyRet.SetSecret(child.privateKey)) 414 if (!keyRet.SetSecret(child.privateKey))
@@ -307,20 +455,28 @@ bool SetHDSeedFromMnemonic(const string& strMnemonic, string& strErrorRet)
307 return false; 455 return false;
308 456
309 if (!CWalletDB().WriteHDMaster(master.privateKey, master.chainCode) || 457 if (!CWalletDB().WriteHDMaster(master.privateKey, master.chainCode) ||
310 !CWalletDB().WriteHDNext(1)) 458 !CWalletDB().WriteHDSchema(HD_SCHEMA_BIP44) ||
459 !CWalletDB().WriteHDCoinType(HD_BIP44_COIN_TYPE_BITFLASH_PROVISIONAL) ||
460 !CWalletDB().WriteHDNext(0) ||
461 !CWalletDB().WriteHDReceiveNext(1) ||
462 !CWalletDB().WriteHDChangeNext(0))
311 { 463 {
312 strErrorRet = "could not write the seed to wallet.dat"; 464 strErrorRet = "could not write the seed metadata to wallet.dat";
313 return false; 465 return false;
314 } 466 }
315 vchHDMaster = master.privateKey; 467 vchHDMaster = master.privateKey;
316 vchHDChainCode = master.chainCode; 468 vchHDChainCode = master.chainCode;
469 nHDKeySchema = HD_SCHEMA_BIP44;
470 nHDReceiveNext = 1;
471 nHDChangeNext = 0;
472 nHDCoinType = HD_BIP44_COIN_TYPE_BITFLASH_PROVISIONAL;
317 473
318 // Index 0 is spoken for before it is derived, so a failure below cannot 474 // Index 0 is spoken for before it is derived, so a failure below cannot
319 // leave the pool free to hand it out as an ordinary key. The cost of 475 // leave the pool free to hand it out as an ordinary key. The cost of
320 // the counter being ahead of the derivation is one unused index; the 476 // the counter being ahead of the derivation is one unused index; the
321 // cost of the reverse is the default address and a pool key sharing a 477 // cost of the reverse is the default address and a pool key sharing a
322 // derivation path. 478 // derivation path.
323 nHDNext = 1; 479 nHDNext = 0;
324 480
325 // Remember which address stops being the default, so it can be named 481 // Remember which address stops being the default, so it can be named
326 // for what it is. Two entries reading "Your Address" -- one covered by 482 // for what it is. Two entries reading "Your Address" -- one covered by
@@ -372,15 +528,18 @@ void TopUpKeyPool()
372 // without a seed uses anyway. It will not come back from the 528 // without a seed uses anyway. It will not come back from the
373 // phrase, and that is better than a node that cannot mine. 529 // phrase, and that is better than a node that cannot mine.
374 string strError; 530 string strError;
375 if (DeriveHDKey(nHDNext, key, strError)) 531 vector<unsigned char> vchPubKey;
532 if (DeriveNextHDReceiveKey(vchPubKey, strError))
376 { 533 {
377 nHDNext++; 534 if (!CWalletDB().WritePool(nIndex, vchPubKey))
378 CWalletDB().WriteHDNext(nHDNext); 535 return;
536 mapKeyPool[nIndex] = vchPubKey;
537 continue;
379 } 538 }
380 else 539 else
381 { 540 {
382 printf("TopUpKeyPool() : derivation at index %u failed (%s), " 541 printf("TopUpKeyPool() : receive derivation failed (%s), "
383 "falling back to a random key\n", nHDNext, strError.c_str()); 542 "falling back to a random key\n", strError.c_str());
384 key.MakeNewKey(); 543 key.MakeNewKey();
385 } 544 }
386 } 545 }
@@ -3668,11 +3827,20 @@ WalletRecoveryAudit GetWalletRecoveryAudit()
3668 CRITICAL_BLOCK(cs_keyPool) 3827 CRITICAL_BLOCK(cs_keyPool)
3669 { 3828 {
3670 audit.fHaveSeed = HaveHDSeed(); 3829 audit.fHaveSeed = HaveHDSeed();
3830 audit.nSchema = nHDKeySchema;
3671 audit.nDerivedKnown = nHDNext; 3831 audit.nDerivedKnown = nHDNext;
3832 audit.nReceiveNext = nHDReceiveNext;
3833 audit.nChangeNext = nHDChangeNext;
3834 audit.nCoinType = nHDCoinType;
3835 if (nHDKeySchema == HD_SCHEMA_BIP44)
3836 audit.nDerivedKnown = nHDReceiveNext + nHDChangeNext + nHDNext;
3672 if (audit.fHaveSeed) 3837 if (audit.fHaveSeed)
3673 { 3838 {
3674 string strError; 3839 string strError;
3675 for (unsigned int i = 0; i < nHDNext; i++) 3840 unsigned int nReceiveDepth = nHDKeySchema == HD_SCHEMA_BIP44
3841 ? nHDReceiveNext
3842 : nHDNext;
3843 for (unsigned int i = 0; i < nReceiveDepth; i++)
3676 { 3844 {
3677 CKey key; 3845 CKey key;
3678 if (!DeriveHDKey(i, key, strError)) 3846 if (!DeriveHDKey(i, key, strError))
@@ -3684,6 +3852,36 @@ WalletRecoveryAudit GetWalletRecoveryAudit()
3684 } 3852 }
3685 setDerivedPubKeys.insert(key.GetPubKey()); 3853 setDerivedPubKeys.insert(key.GetPubKey());
3686 } 3854 }
3855 if (nHDKeySchema == HD_SCHEMA_BIP44)
3856 {
3857 int nSavedSchema = nHDKeySchema;
3858 for (unsigned int i = 0; i < nHDChangeNext; i++)
3859 {
3860 CKey key;
3861 if (!DeriveHDChangeKey(i, key, strError))
3862 {
3863 audit.fDeriveComplete = false;
3864 audit.strDeriveError = strprintf("change derivation failed at index %u: %s",
3865 i, strError.c_str());
3866 break;
3867 }
3868 setDerivedPubKeys.insert(key.GetPubKey());
3869 }
3870 nHDKeySchema = HD_SCHEMA_LEGACY;
3871 for (unsigned int i = 0; i < nHDNext; i++)
3872 {
3873 CKey key;
3874 if (!DeriveHDKey(i, key, strError))
3875 {
3876 audit.fDeriveComplete = false;
3877 audit.strDeriveError = strprintf("legacy compatibility derivation failed at index %u: %s",
3878 i, strError.c_str());
3879 break;
3880 }
3881 setDerivedPubKeys.insert(key.GetPubKey());
3882 }
3883 nHDKeySchema = nSavedSchema;
3884 }
3687 } 3885 }
3688 } 3886 }
3689 3887
@@ -3926,7 +4124,7 @@ bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, in
3926 if (HaveHDSeed()) 4124 if (HaveHDSeed())
3927 { 4125 {
3928 string strError; 4126 string strError;
3929 if (!DeriveNextHDWalletKey(vchPubKey, strError)) 4127 if (!DeriveNextHDChangeKey(vchPubKey, strError))
3930 { 4128 {
3931 printf("CreateTransaction() : could not derive a phrase-backed change key: %s\n", 4129 printf("CreateTransaction() : could not derive a phrase-backed change key: %s\n",
3932 strError.c_str()); 4130 strError.c_str());