| 1095 | } |
| 1096 | |
| 1097 | void LegacyScriptPubKeyMan::DeriveNewChildKey(WalletBatch &batch, CKeyMetadata& metadata, CKey& secret, CHDChain& hd_chain, bool internal) |
| 1098 | { |
| 1099 | // for now we use a fixed keypath scheme of m/0'/0'/k |
| 1100 | CKey seed; //seed (256bit) |
| 1101 | CExtKey masterKey; //hd master key |
| 1102 | CExtKey accountKey; //key at m/0' |
| 1103 | CExtKey chainChildKey; //key at m/0'/0' (external) or m/0'/1' (internal) |
| 1104 | CExtKey childKey; //key at m/0'/0'/<n>' |
| 1105 | |
| 1106 | // try to get the seed |
| 1107 | if (!GetKey(hd_chain.seed_id, seed)) |
| 1108 | throw std::runtime_error(std::string(__func__) + ": seed not found"); |
| 1109 | |
| 1110 | masterKey.SetSeed(seed); |
| 1111 | |
| 1112 | // derive m/0' |
| 1113 | // use hardened derivation (child keys >= 0x80000000 are hardened after bip32) |
| 1114 | masterKey.Derive(accountKey, BIP32_HARDENED_KEY_LIMIT); |
| 1115 | |
| 1116 | // derive m/0'/0' (external chain) OR m/0'/1' (internal chain) |
| 1117 | assert(internal ? m_storage.CanSupportFeature(FEATURE_HD_SPLIT) : true); |
| 1118 | accountKey.Derive(chainChildKey, BIP32_HARDENED_KEY_LIMIT+(internal ? 1 : 0)); |
| 1119 | |
| 1120 | // derive child key at next index, skip keys already known to the wallet |
| 1121 | do { |
| 1122 | // always derive hardened keys |
| 1123 | // childIndex | BIP32_HARDENED_KEY_LIMIT = derive childIndex in hardened child-index-range |
| 1124 | // example: 1 | BIP32_HARDENED_KEY_LIMIT == 0x80000001 == 2147483649 |
| 1125 | if (internal) { |
| 1126 | chainChildKey.Derive(childKey, hd_chain.nInternalChainCounter | BIP32_HARDENED_KEY_LIMIT); |
| 1127 | metadata.hdKeypath = "m/0'/1'/" + ToString(hd_chain.nInternalChainCounter) + "'"; |
| 1128 | metadata.key_origin.path.push_back(0 | BIP32_HARDENED_KEY_LIMIT); |
| 1129 | metadata.key_origin.path.push_back(1 | BIP32_HARDENED_KEY_LIMIT); |
| 1130 | metadata.key_origin.path.push_back(hd_chain.nInternalChainCounter | BIP32_HARDENED_KEY_LIMIT); |
| 1131 | hd_chain.nInternalChainCounter++; |
| 1132 | } |
| 1133 | else { |
| 1134 | chainChildKey.Derive(childKey, hd_chain.nExternalChainCounter | BIP32_HARDENED_KEY_LIMIT); |
| 1135 | metadata.hdKeypath = "m/0'/0'/" + ToString(hd_chain.nExternalChainCounter) + "'"; |
| 1136 | metadata.key_origin.path.push_back(0 | BIP32_HARDENED_KEY_LIMIT); |
| 1137 | metadata.key_origin.path.push_back(0 | BIP32_HARDENED_KEY_LIMIT); |
| 1138 | metadata.key_origin.path.push_back(hd_chain.nExternalChainCounter | BIP32_HARDENED_KEY_LIMIT); |
| 1139 | hd_chain.nExternalChainCounter++; |
| 1140 | } |
| 1141 | } while (HaveKey(childKey.key.GetPubKey().GetID())); |
| 1142 | secret = childKey.key; |
| 1143 | metadata.hd_seed_id = hd_chain.seed_id; |
| 1144 | CKeyID master_id = masterKey.key.GetPubKey().GetID(); |
| 1145 | std::copy(master_id.begin(), master_id.begin() + 4, metadata.key_origin.fingerprint); |
| 1146 | metadata.has_key_origin = true; |
| 1147 | // update the chain model in the database |
| 1148 | if (hd_chain.seed_id == m_hd_chain.seed_id && !batch.WriteHDChain(hd_chain)) |
| 1149 | throw std::runtime_error(std::string(__func__) + ": writing HD chain model failed"); |
| 1150 | } |
| 1151 | |
| 1152 | void LegacyScriptPubKeyMan::LoadKeyPool(int64_t nIndex, const CKeyPool &keypool) |
| 1153 | { |