Introduce KeyOriginInfo for fingerprint + path

This commit is contained in:
Pieter Wuille 2018-07-19 23:15:53 -07:00
parent 5df6f089b5
commit 611ab307fb
3 changed files with 34 additions and 28 deletions

View file

@ -1460,11 +1460,8 @@ UniValue decodepsbt(const JSONRPCRequest& request)
UniValue keypath(UniValue::VOBJ);
keypath.pushKV("pubkey", HexStr(entry.first));
uint32_t fingerprint = entry.second.at(0);
keypath.pushKV("master_fingerprint", strprintf("%08x", bswap_32(fingerprint)));
entry.second.erase(entry.second.begin());
keypath.pushKV("path", WriteHDKeypath(entry.second));
keypath.pushKV("master_fingerprint", strprintf("%08x", ReadBE32(entry.second.fingerprint)));
keypath.pushKV("path", WriteHDKeypath(entry.second.path));
keypaths.push_back(keypath);
}
in.pushKV("bip32_derivs", keypaths);
@ -1522,12 +1519,8 @@ UniValue decodepsbt(const JSONRPCRequest& request)
for (auto entry : output.hd_keypaths) {
UniValue keypath(UniValue::VOBJ);
keypath.pushKV("pubkey", HexStr(entry.first));
uint32_t fingerprint = entry.second.at(0);
keypath.pushKV("master_fingerprint", strprintf("%08x", bswap_32(fingerprint)));
entry.second.erase(entry.second.begin());
keypath.pushKV("path", WriteHDKeypath(entry.second));
keypath.pushKV("master_fingerprint", strprintf("%08x", ReadBE32(entry.second.fingerprint)));
keypath.pushKV("path", WriteHDKeypath(entry.second.path));
keypaths.push_back(keypath);
}
out.pushKV("bip32_derivs", keypaths);

View file

@ -20,6 +20,12 @@ class CTransaction;
struct CMutableTransaction;
struct KeyOriginInfo
{
unsigned char fingerprint[4];
std::vector<uint32_t> path;
};
/** An interface to be implemented by keystores that support signing. */
class SigningProvider
{
@ -155,7 +161,7 @@ void UnserializeFromVector(Stream& s, X&... args)
// Deserialize HD keypaths into a map
template<typename Stream>
void DeserializeHDKeypaths(Stream& s, const std::vector<unsigned char>& key, std::map<CPubKey, std::vector<uint32_t>>& hd_keypaths)
void DeserializeHDKeypaths(Stream& s, const std::vector<unsigned char>& key, std::map<CPubKey, KeyOriginInfo>& hd_keypaths)
{
// Make sure that the key is the size of pubkey + 1
if (key.size() != CPubKey::PUBLIC_KEY_SIZE + 1 && key.size() != CPubKey::COMPRESSED_PUBLIC_KEY_SIZE + 1) {
@ -172,25 +178,31 @@ void DeserializeHDKeypaths(Stream& s, const std::vector<unsigned char>& key, std
// Read in key path
uint64_t value_len = ReadCompactSize(s);
std::vector<uint32_t> keypath;
for (unsigned int i = 0; i < value_len; i += sizeof(uint32_t)) {
if (value_len % 4 || value_len == 0) {
throw std::ios_base::failure("Invalid length for HD key path");
}
KeyOriginInfo keypath;
s >> keypath.fingerprint;
for (unsigned int i = 4; i < value_len; i += sizeof(uint32_t)) {
uint32_t index;
s >> index;
keypath.push_back(index);
keypath.path.push_back(index);
}
// Add to map
hd_keypaths.emplace(pubkey, keypath);
hd_keypaths.emplace(pubkey, std::move(keypath));
}
// Serialize HD keypaths to a stream from a map
template<typename Stream>
void SerializeHDKeypaths(Stream& s, const std::map<CPubKey, std::vector<uint32_t>>& hd_keypaths, uint8_t type)
void SerializeHDKeypaths(Stream& s, const std::map<CPubKey, KeyOriginInfo>& hd_keypaths, uint8_t type)
{
for (auto keypath_pair : hd_keypaths) {
SerializeToVector(s, type, MakeSpan(keypath_pair.first));
WriteCompactSize(s, keypath_pair.second.size() * sizeof(uint32_t));
for (auto& path : keypath_pair.second) {
WriteCompactSize(s, (keypath_pair.second.path.size() + 1) * sizeof(uint32_t));
s << keypath_pair.second.fingerprint;
for (const auto& path : keypath_pair.second.path) {
s << path;
}
}
@ -205,7 +217,7 @@ struct PSBTInput
CScript witness_script;
CScript final_script_sig;
CScriptWitness final_script_witness;
std::map<CPubKey, std::vector<uint32_t>> hd_keypaths;
std::map<CPubKey, KeyOriginInfo> hd_keypaths;
std::map<CKeyID, SigPair> partial_sigs;
std::map<std::vector<unsigned char>, std::vector<unsigned char>> unknown;
int sighash_type = 0;
@ -413,7 +425,7 @@ struct PSBTOutput
{
CScript redeem_script;
CScript witness_script;
std::map<CPubKey, std::vector<uint32_t>> hd_keypaths;
std::map<CPubKey, KeyOriginInfo> hd_keypaths;
std::map<std::vector<unsigned char>, std::vector<unsigned char>> unknown;
bool IsNull() const;

View file

@ -4464,7 +4464,7 @@ bool ParseHDKeypath(std::string keypath_str, std::vector<uint32_t>& keypath)
return true;
}
void AddKeypathToMap(const CWallet* pwallet, const CKeyID& keyID, std::map<CPubKey, std::vector<uint32_t>>& hd_keypaths)
void AddKeypathToMap(const CWallet* pwallet, const CKeyID& keyID, std::map<CPubKey, KeyOriginInfo>& hd_keypaths)
{
CPubKey vchPubKey;
if (!pwallet->GetPubKey(keyID, vchPubKey)) {
@ -4475,9 +4475,9 @@ void AddKeypathToMap(const CWallet* pwallet, const CKeyID& keyID, std::map<CPubK
if (it != pwallet->mapKeyMetadata.end()) {
meta = it->second;
}
std::vector<uint32_t> keypath;
KeyOriginInfo info;
if (!meta.hdKeypath.empty()) {
if (!ParseHDKeypath(meta.hdKeypath, keypath)) {
if (!ParseHDKeypath(meta.hdKeypath, info.path)) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "Internal keypath is broken");
}
// Get the proper master key id
@ -4485,12 +4485,13 @@ void AddKeypathToMap(const CWallet* pwallet, const CKeyID& keyID, std::map<CPubK
pwallet->GetKey(meta.hd_seed_id, key);
CExtKey masterKey;
masterKey.SetSeed(key.begin(), key.size());
// Add to map
keypath.insert(keypath.begin(), ReadLE32(masterKey.key.GetPubKey().GetID().begin()));
// Compute identifier
CKeyID masterid = masterKey.key.GetPubKey().GetID();
std::copy(masterid.begin(), masterid.begin() + 4, info.fingerprint);
} else { // Single pubkeys get the master fingerprint of themselves
keypath.insert(keypath.begin(), ReadLE32(vchPubKey.GetID().begin()));
std::copy(keyID.begin(), keyID.begin() + 4, info.fingerprint);
}
hd_keypaths.emplace(vchPubKey, keypath);
hd_keypaths.emplace(vchPubKey, std::move(info));
}
bool FillPSBT(const CWallet* pwallet, PartiallySignedTransaction& psbtx, const CTransaction* txConst, int sighash_type, bool sign, bool bip32derivs)