Skip to content

Commit

Permalink
Introduce KeyOriginInfo for fingerprint + path
Browse files Browse the repository at this point in the history
  • Loading branch information
sipa committed Aug 13, 2018
1 parent 5df6f08 commit 611ab30
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 28 deletions.
15 changes: 4 additions & 11 deletions src/rpc/rawtransaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
32 changes: 22 additions & 10 deletions src/script/sign.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -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) {
Expand All @@ -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;
}
}
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
15 changes: 8 additions & 7 deletions src/wallet/rpcwallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand All @@ -4475,22 +4475,23 @@ 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
CKey key;
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)
Expand Down

0 comments on commit 611ab30

Please sign in to comment.