Skip to content

Commit

Permalink
Stop using CBase58Data for ext keys
Browse files Browse the repository at this point in the history
  • Loading branch information
sipa committed Feb 20, 2018
1 parent 32e69fa commit ebfe217
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 138 deletions.
108 changes: 47 additions & 61 deletions src/base58.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,67 +152,6 @@ bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRe
return DecodeBase58Check(str.c_str(), vchRet);
}

CBase58Data::CBase58Data()
{
vchVersion.clear();
vchData.clear();
}

void CBase58Data::SetData(const std::vector<unsigned char>& vchVersionIn, const void* pdata, size_t nSize)
{
vchVersion = vchVersionIn;
vchData.resize(nSize);
if (!vchData.empty())
memcpy(vchData.data(), pdata, nSize);
}

void CBase58Data::SetData(const std::vector<unsigned char>& vchVersionIn, const unsigned char* pbegin, const unsigned char* pend)
{
SetData(vchVersionIn, (void*)pbegin, pend - pbegin);
}

bool CBase58Data::SetString(const char* psz, unsigned int nVersionBytes)
{
std::vector<unsigned char> vchTemp;
bool rc58 = DecodeBase58Check(psz, vchTemp);
if ((!rc58) || (vchTemp.size() < nVersionBytes)) {
vchData.clear();
vchVersion.clear();
return false;
}
vchVersion.assign(vchTemp.begin(), vchTemp.begin() + nVersionBytes);
vchData.resize(vchTemp.size() - nVersionBytes);
if (!vchData.empty())
memcpy(vchData.data(), vchTemp.data() + nVersionBytes, vchData.size());
memory_cleanse(vchTemp.data(), vchTemp.size());
return true;
}

bool CBase58Data::SetString(const std::string& str)
{
return SetString(str.c_str());
}

std::string CBase58Data::ToString() const
{
std::vector<unsigned char> vch = vchVersion;
vch.insert(vch.end(), vchData.begin(), vchData.end());
return EncodeBase58Check(vch);
}

int CBase58Data::CompareTo(const CBase58Data& b58) const
{
if (vchVersion < b58.vchVersion)
return -1;
if (vchVersion > b58.vchVersion)
return 1;
if (vchData < b58.vchData)
return -1;
if (vchData > b58.vchData)
return 1;
return 0;
}

namespace
{
class DestinationEncoder : public boost::static_visitor<std::string>
Expand Down Expand Up @@ -352,6 +291,53 @@ std::string EncodeSecret(const CKey& key)
return ret;
}

CExtPubKey DecodeExtPubKey(const std::string& str)
{
CExtPubKey key;
std::vector<unsigned char> data;
if (DecodeBase58Check(str, data)) {
const std::vector<unsigned char>& prefix = Params().Base58Prefix(CChainParams::EXT_PUBLIC_KEY);
if (data.size() == BIP32_EXTKEY_SIZE + prefix.size() && std::equal(prefix.begin(), prefix.end(), data.begin())) {
key.Decode(data.data() + prefix.size());
}
}
return key;
}

std::string EncodeExtPubKey(const CExtPubKey& key)
{
std::vector<unsigned char> data = Params().Base58Prefix(CChainParams::EXT_PUBLIC_KEY);
size_t size = data.size();
data.resize(size + BIP32_EXTKEY_SIZE);
key.Encode(data.data() + size);
std::string ret = EncodeBase58Check(data);
return ret;
}

CExtKey DecodeExtKey(const std::string& str)
{
CExtKey key;
std::vector<unsigned char> data;
if (DecodeBase58Check(str, data)) {
const std::vector<unsigned char>& prefix = Params().Base58Prefix(CChainParams::EXT_SECRET_KEY);
if (data.size() == BIP32_EXTKEY_SIZE + prefix.size() && std::equal(prefix.begin(), prefix.end(), data.begin())) {
key.Decode(data.data() + prefix.size());
}
}
return key;
}

std::string EncodeExtKey(const CExtKey& key)
{
std::vector<unsigned char> data = Params().Base58Prefix(CChainParams::EXT_SECRET_KEY);
size_t size = data.size();
data.resize(size + BIP32_EXTKEY_SIZE);
key.Encode(data.data() + size);
std::string ret = EncodeBase58Check(data);
memory_cleanse(data.data(), data.size());
return ret;
}

std::string EncodeDestination(const CTxDestination& dest)
{
return boost::apply_visitor(DestinationEncoder(Params()), dest);
Expand Down
65 changes: 4 additions & 61 deletions src/base58.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,70 +64,13 @@ inline bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRe
*/
inline bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet);

/**
* Base class for all base58-encoded data
*/
class CBase58Data
{
protected:
//! the version byte(s)
std::vector<unsigned char> vchVersion;

//! the actually encoded data
typedef std::vector<unsigned char, zero_after_free_allocator<unsigned char> > vector_uchar;
vector_uchar vchData;

CBase58Data();
void SetData(const std::vector<unsigned char> &vchVersionIn, const void* pdata, size_t nSize);
void SetData(const std::vector<unsigned char> &vchVersionIn, const unsigned char *pbegin, const unsigned char *pend);

public:
bool SetString(const char* psz, unsigned int nVersionBytes = 1);
bool SetString(const std::string& str);
std::string ToString() const;
int CompareTo(const CBase58Data& b58) const;

bool operator==(const CBase58Data& b58) const { return CompareTo(b58) == 0; }
bool operator<=(const CBase58Data& b58) const { return CompareTo(b58) <= 0; }
bool operator>=(const CBase58Data& b58) const { return CompareTo(b58) >= 0; }
bool operator< (const CBase58Data& b58) const { return CompareTo(b58) < 0; }
bool operator> (const CBase58Data& b58) const { return CompareTo(b58) > 0; }
};

CKey DecodeSecret(const std::string& str);
std::string EncodeSecret(const CKey& key);

template<typename K, int Size, CChainParams::Base58Type Type> class CBitcoinExtKeyBase : public CBase58Data
{
public:
void SetKey(const K &key) {
unsigned char vch[Size];
key.Encode(vch);
SetData(Params().Base58Prefix(Type), vch, vch+Size);
}

K GetKey() {
K ret;
if (vchData.size() == Size) {
// If base58 encoded data does not hold an ext key, return a !IsValid() key
ret.Decode(vchData.data());
}
return ret;
}

CBitcoinExtKeyBase(const K &key) {
SetKey(key);
}

CBitcoinExtKeyBase(const std::string& strBase58c) {
SetString(strBase58c.c_str(), Params().Base58Prefix(Type).size());
}

CBitcoinExtKeyBase() {}
};

typedef CBitcoinExtKeyBase<CExtKey, BIP32_EXTKEY_SIZE, CChainParams::EXT_SECRET_KEY> CBitcoinExtKey;
typedef CBitcoinExtKeyBase<CExtPubKey, BIP32_EXTKEY_SIZE, CChainParams::EXT_PUBLIC_KEY> CBitcoinExtPubKey;
CExtKey DecodeExtKey(const std::string& str);
std::string EncodeExtKey(const CExtKey& extkey);
CExtPubKey DecodeExtPubKey(const std::string& str);
std::string EncodeExtPubKey(const CExtPubKey& extpubkey);

std::string EncodeDestination(const CTxDestination& dest);
CTxDestination DecodeDestination(const std::string& str);
Expand Down
16 changes: 4 additions & 12 deletions src/test/bip32_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,20 +99,12 @@ void RunTest(const TestVector &test) {
pubkey.Encode(data);

// Test private key
CBitcoinExtKey b58key; b58key.SetKey(key);
BOOST_CHECK(b58key.ToString() == derive.prv);

CBitcoinExtKey b58keyDecodeCheck(derive.prv);
CExtKey checkKey = b58keyDecodeCheck.GetKey();
assert(checkKey == key); //ensure a base58 decoded key also matches
BOOST_CHECK(EncodeExtKey(key) == derive.prv);
BOOST_CHECK(DecodeExtKey(derive.prv) == key); //ensure a base58 decoded key also matches

// Test public key
CBitcoinExtPubKey b58pubkey; b58pubkey.SetKey(pubkey);
BOOST_CHECK(b58pubkey.ToString() == derive.pub);

CBitcoinExtPubKey b58PubkeyDecodeCheck(derive.pub);
CExtPubKey checkPubKey = b58PubkeyDecodeCheck.GetKey();
assert(checkPubKey == pubkey); //ensure a base58 decoded pubkey also matches
BOOST_CHECK(EncodeExtPubKey(pubkey) == derive.pub);
BOOST_CHECK(DecodeExtPubKey(derive.pub) == pubkey); //ensure a base58 decoded pubkey also matches

// Derive new keys
CExtKey keyNew;
Expand Down
5 changes: 1 addition & 4 deletions src/wallet/rpcdump.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -736,10 +736,7 @@ UniValue dumpwallet(const JSONRPCRequest& request)
CExtKey masterKey;
masterKey.SetMaster(key.begin(), key.size());

CBitcoinExtKey b58extkey;
b58extkey.SetKey(masterKey);

file << "# extended private masterkey: " << b58extkey.ToString() << "\n\n";
file << "# extended private masterkey: " << EncodeExtKey(masterKey) << "\n\n";
}
}
for (std::vector<std::pair<int64_t, CKeyID> >::const_iterator it = vKeyBirth.begin(); it != vKeyBirth.end(); it++) {
Expand Down

0 comments on commit ebfe217

Please sign in to comment.