diff options
| author | mtg0001 <106211915+mtg0001@users.noreply.github.com> | 2026-08-03 15:11:55 -0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-08-03 15:11:55 -0300 |
| commit | aba252206bf39ac81e6627354062c28fae05b0aa (patch) | |
| tree | 751691f0baaf925c54a2c03f9f02ca87fb29956f /src/main.h | |
| parent | 1aee805b232a33484e3db1dc8ea4bfb3f585212e (diff) | |
Activate BIP44 wallet derivation (#124)
* Add BIP32 path derivation foundation
* Add HD wallet schema metadata
* Add provisional BIP44 coin type metadata
* Activate BIP44 wallet derivation
* wallet: scan BIP44 restore depth per branch
* wallet: widen default BIP44 restore lookahead
---------
Co-authored-by: Gilcimar Duarte <ti@gpm.infra>
Diffstat (limited to 'src/main.h')
| -rw-r--r-- | src/main.h | 55 |
1 files changed, 45 insertions, 10 deletions
| @@ -147,21 +147,45 @@ extern map<int64, vector<unsigned char> > mapKeyPool; | |||
| 147 | 147 | ||
| 148 | // --- Deterministic wallet (BIP32) ----------------------------------------- | 148 | // --- Deterministic wallet (BIP32) ----------------------------------------- |
| 149 | // | 149 | // |
| 150 | // When a seed is present the key pool is derived from it -- m/0'/n, hardened, | 150 | // When a seed is present today, the key pool is derived from it by the legacy |
| 151 | // n increasing -- instead of being made of random keys. That is what lets a | 151 | // Bitflash path -- m/index', hardened, index increasing -- instead of being |
| 152 | // recovery phrase bring a wallet back: the same twelve words reproduce the same | 152 | // made of random keys. That is what lets a recovery phrase bring a wallet back: |
| 153 | // keys in the same order. | 153 | // the same twelve words reproduce the same keys in the same order. |
| 154 | // | 154 | // |
| 155 | // A wallet without a seed keeps working exactly as before. Nothing here | 155 | // BIP44 uses a different path family and separate receive/change counters. |
| 156 | // migrates an existing wallet on its own: the seed is created only when the | 156 | // The schema fields below let new wallets opt into that without making old |
| 157 | // user asks for a phrase and confirms they have written it down, because a | 157 | // m/index' coins disappear. |
| 158 | // phrase generated silently is a backup nobody has. | 158 | // |
| 159 | // A wallet without a seed keeps working exactly as before. Existing seeded | ||
| 160 | // wallets keep their recorded schema. A new phrase uses BIP44, but it is still | ||
| 161 | // created only when the user asks for a phrase and confirms they have written | ||
| 162 | // it down, because a phrase generated silently is a backup nobody has. | ||
| 159 | // | 163 | // |
| 160 | // Empty until a seed exists. | 164 | // Empty until a seed exists. |
| 161 | extern vector<unsigned char> vchHDMaster; // 32-byte master private key (IL) | 165 | extern vector<unsigned char> vchHDMaster; // 32-byte master private key (IL) |
| 162 | extern vector<unsigned char> vchHDChainCode; // 32 bytes (IR) | 166 | extern vector<unsigned char> vchHDChainCode; // 32 bytes (IR) |
| 163 | extern unsigned int nHDNext; // next child index to derive | 167 | extern unsigned int nHDNext; // next child index to derive |
| 168 | static const int HD_SCHEMA_NONE = 0; | ||
| 169 | static const int HD_SCHEMA_LEGACY = 1; // m/index' | ||
| 170 | static const int HD_SCHEMA_BIP44 = 2; // m/44'/coin_type'/account'/change/index | ||
| 171 | static const unsigned int HD_BIP44_PURPOSE = 44; | ||
| 172 | static const unsigned int HD_BIP44_ACCOUNT = 0; | ||
| 173 | static const unsigned int HD_BIP44_CHAIN_RECEIVE = 0; | ||
| 174 | static const unsigned int HD_BIP44_CHAIN_CHANGE = 1; | ||
| 175 | // Provisional until Bitflash has an official SLIP-0044 assignment. | ||
| 176 | // Proposed registry row: 4346950 | BITFLASH | Bitflash. | ||
| 177 | static const unsigned int HD_BIP44_COIN_TYPE_BITFLASH_PROVISIONAL = 4346950; | ||
| 178 | extern int nHDKeySchema; | ||
| 179 | extern unsigned int nHDReceiveNext; // BIP44 external chain | ||
| 180 | extern unsigned int nHDChangeNext; // BIP44 internal chain | ||
| 181 | extern unsigned int nHDCoinType; // BIP44 coin_type' | ||
| 164 | inline bool HaveHDSeed() { return vchHDMaster.size() == 32 && vchHDChainCode.size() == 32; } | 182 | inline bool HaveHDSeed() { return vchHDMaster.size() == 32 && vchHDChainCode.size() == 32; } |
| 183 | string HDKeySchemaName(int nSchema); | ||
| 184 | std::vector<unsigned int> HDLegacyPath(unsigned int nIndex); | ||
| 185 | std::vector<unsigned int> HDBIP44Path(unsigned int nCoinType, | ||
| 186 | unsigned int nAccount, | ||
| 187 | unsigned int nChain, | ||
| 188 | unsigned int nIndex); | ||
| 165 | 189 | ||
| 166 | // Install a seed derived from a mnemonic, replacing any existing one. The | 190 | // Install a seed derived from a mnemonic, replacing any existing one. The |
| 167 | // default receiving key is derived immediately, so the next visible address is | 191 | // default receiving key is derived immediately, so the next visible address is |
| @@ -169,9 +193,12 @@ inline bool HaveHDSeed() { return vchHDMaster.size() == 32 && vchHDChainCode.siz | |||
| 169 | // wallet untouched if the phrase is not valid. | 193 | // wallet untouched if the phrase is not valid. |
| 170 | bool SetHDSeedFromMnemonic(const string& strMnemonic, string& strErrorRet); | 194 | bool SetHDSeedFromMnemonic(const string& strMnemonic, string& strErrorRet); |
| 171 | 195 | ||
| 172 | // Derive the child at nIndex and return it as a key. Used by the key pool and | 196 | // Derive the receiving child at nIndex for the wallet's active schema and |
| 173 | // by restore, which needs to run ahead of the pool. | 197 | // return it as a key. Legacy seeded wallets use m/index'. BIP44 wallets use |
| 198 | // m/44'/coin_type'/0'/0/index. Used by the key pool and restore, which needs | ||
| 199 | // to run ahead of the pool. | ||
| 174 | bool DeriveHDKey(unsigned int nIndex, CKey& keyRet, string& strErrorRet); | 200 | bool DeriveHDKey(unsigned int nIndex, CKey& keyRet, string& strErrorRet); |
| 201 | bool DeriveHDChangeKey(unsigned int nIndex, CKey& keyRet, string& strErrorRet); | ||
| 175 | 202 | ||
| 176 | // Fill the pool back up to KEYPOOL_SIZE. Every key it creates is written to | 203 | // Fill the pool back up to KEYPOOL_SIZE. Every key it creates is written to |
| 177 | // wallet.dat before it is offered to anybody. | 204 | // wallet.dat before it is offered to anybody. |
| @@ -221,7 +248,11 @@ struct WalletRecoveryAudit | |||
| 221 | { | 248 | { |
| 222 | bool fHaveSeed; | 249 | bool fHaveSeed; |
| 223 | bool fDeriveComplete; | 250 | bool fDeriveComplete; |
| 251 | int nSchema; | ||
| 224 | unsigned int nDerivedKnown; | 252 | unsigned int nDerivedKnown; |
| 253 | unsigned int nReceiveNext; | ||
| 254 | unsigned int nChangeNext; | ||
| 255 | unsigned int nCoinType; | ||
| 225 | int nRecoverableTx; | 256 | int nRecoverableTx; |
| 226 | int nLegacyTx; | 257 | int nLegacyTx; |
| 227 | int nRecoverableImmatureTx; | 258 | int nRecoverableImmatureTx; |
| @@ -236,7 +267,11 @@ struct WalletRecoveryAudit | |||
| 236 | { | 267 | { |
| 237 | fHaveSeed = false; | 268 | fHaveSeed = false; |
| 238 | fDeriveComplete = true; | 269 | fDeriveComplete = true; |
| 270 | nSchema = HD_SCHEMA_NONE; | ||
| 239 | nDerivedKnown = 0; | 271 | nDerivedKnown = 0; |
| 272 | nReceiveNext = 0; | ||
| 273 | nChangeNext = 0; | ||
| 274 | nCoinType = HD_BIP44_COIN_TYPE_BITFLASH_PROVISIONAL; | ||
| 240 | nRecoverableTx = 0; | 275 | nRecoverableTx = 0; |
| 241 | nLegacyTx = 0; | 276 | nLegacyTx = 0; |
| 242 | nRecoverableImmatureTx = 0; | 277 | nRecoverableImmatureTx = 0; |