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

View File

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

View File

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