Replace CBitcoinSecret with {Encode,Decode}Secret

This commit is contained in:
Pieter Wuille
2017-09-19 16:49:52 -07:00
committed by Jack Grigg
parent b1d2a69908
commit f146029b0a
8 changed files with 58 additions and 98 deletions

View File

@@ -257,39 +257,35 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par
} }
} // namespace } // namespace
void CBitcoinSecret::SetKey(const CKey& vchSecret) CKey DecodeSecret(const std::string& str)
{ {
assert(vchSecret.IsValid()); CKey key;
SetData(Params().Base58Prefix(CChainParams::SECRET_KEY), vchSecret.begin(), vchSecret.size()); std::vector<unsigned char> data;
if (vchSecret.IsCompressed()) if (DecodeBase58Check(str, data)) {
vchData.push_back(1); const std::vector<unsigned char>& privkey_prefix = Params().Base58Prefix(CChainParams::SECRET_KEY);
if ((data.size() == 32 + privkey_prefix.size() || (data.size() == 33 + privkey_prefix.size() && data.back() == 1)) &&
std::equal(privkey_prefix.begin(), privkey_prefix.end(), data.begin())) {
bool compressed = data.size() == 33 + privkey_prefix.size();
key.Set(data.begin() + privkey_prefix.size(), data.begin() + privkey_prefix.size() + 32, compressed);
}
}
memory_cleanse(data.data(), data.size());
return key;
} }
CKey CBitcoinSecret::GetKey() std::string EncodeSecret(const CKey& key)
{ {
CKey ret; assert(key.IsValid());
assert(vchData.size() >= 32); std::vector<unsigned char> data = Params().Base58Prefix(CChainParams::SECRET_KEY);
ret.Set(vchData.begin(), vchData.begin() + 32, vchData.size() > 32 && vchData[32] == 1); data.insert(data.end(), key.begin(), key.end());
if (key.IsCompressed()) {
data.push_back(1);
}
std::string ret = EncodeBase58Check(data);
memory_cleanse(data.data(), data.size());
return ret; return ret;
} }
bool CBitcoinSecret::IsValid() const
{
bool fExpectedFormat = vchData.size() == 32 || (vchData.size() == 33 && vchData[32] == 1);
bool fCorrectVersion = vchVersion == Params().Base58Prefix(CChainParams::SECRET_KEY);
return fExpectedFormat && fCorrectVersion;
}
bool CBitcoinSecret::SetString(const char* pszSecret)
{
return CBase58Data::SetString(pszSecret, 1) && IsValid();
}
bool CBitcoinSecret::SetString(const std::string& strSecret)
{
return SetString(strSecret.c_str());
}
std::string EncodeDestination(const CTxDestination& dest) std::string EncodeDestination(const CTxDestination& dest)
{ {
return boost::apply_visitor(DestinationEncoder(Params()), dest); return boost::apply_visitor(DestinationEncoder(Params()), dest);

View File

@@ -139,21 +139,8 @@ public:
CZCSpendingKey(const libzcash::SpendingKey& addr) { Set(addr); } CZCSpendingKey(const libzcash::SpendingKey& addr) { Set(addr); }
}; };
/** CKey DecodeSecret(const std::string& str);
* A base58-encoded secret key std::string EncodeSecret(const CKey& key);
*/
class CBitcoinSecret : public CBase58Data
{
public:
void SetKey(const CKey& vchSecret);
CKey GetKey();
bool IsValid() const;
bool SetString(const char* pszSecret);
bool SetString(const std::string& strSecret);
CBitcoinSecret(const CKey& vchSecret) { SetKey(vchSecret); }
CBitcoinSecret() {}
};
template<typename K, int Size, CChainParams::Base58Type Type> class CBitcoinExtKeyBase : public CBase58Data template<typename K, int Size, CChainParams::Base58Type Type> class CBitcoinExtKeyBase : public CBase58Data
{ {

View File

@@ -400,12 +400,10 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& strInput)
for (size_t kidx = 0; kidx < keysObj.size(); kidx++) { for (size_t kidx = 0; kidx < keysObj.size(); kidx++) {
if (!keysObj[kidx].isStr()) if (!keysObj[kidx].isStr())
throw std::runtime_error("privatekey not a std::string"); throw std::runtime_error("privatekey not a std::string");
CBitcoinSecret vchSecret; CKey key = DecodeSecret(keysObj[kidx].getValStr());
bool fGood = vchSecret.SetString(keysObj[kidx].getValStr()); if (!key.IsValid()) {
if (!fGood)
throw std::runtime_error("privatekey not valid"); throw std::runtime_error("privatekey not valid");
}
CKey key = vchSecret.GetKey();
tempKeystore.AddKey(key); tempKeystore.AddKey(key);
} }

View File

@@ -777,13 +777,9 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
UniValue keys = params[2].get_array(); UniValue keys = params[2].get_array();
for (size_t idx = 0; idx < keys.size(); idx++) { for (size_t idx = 0; idx < keys.size(); idx++) {
UniValue k = keys[idx]; UniValue k = keys[idx];
CBitcoinSecret vchSecret; CKey key = DecodeSecret(k.get_str());
bool fGood = vchSecret.SetString(k.get_str());
if (!fGood)
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
CKey key = vchSecret.GetKey();
if (!key.IsValid()) if (!key.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Private key outside allowed range"); throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
tempKeystore.AddKey(key); tempKeystore.AddKey(key);
} }
} }

View File

@@ -78,7 +78,7 @@ BOOST_AUTO_TEST_CASE(base58_DecodeBase58)
BOOST_AUTO_TEST_CASE(base58_keys_valid_parse) BOOST_AUTO_TEST_CASE(base58_keys_valid_parse)
{ {
UniValue tests = read_json(std::string(json_tests::base58_keys_valid, json_tests::base58_keys_valid + sizeof(json_tests::base58_keys_valid))); UniValue tests = read_json(std::string(json_tests::base58_keys_valid, json_tests::base58_keys_valid + sizeof(json_tests::base58_keys_valid)));
CBitcoinSecret secret; CKey privkey;
CTxDestination destination; CTxDestination destination;
SelectParams(CBaseChainParams::MAIN); SelectParams(CBaseChainParams::MAIN);
@@ -102,9 +102,8 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse)
if (isPrivkey) { if (isPrivkey) {
bool isCompressed = find_value(metadata, "isCompressed").get_bool(); bool isCompressed = find_value(metadata, "isCompressed").get_bool();
// Must be valid private key // Must be valid private key
BOOST_CHECK_MESSAGE(secret.SetString(exp_base58string), "!SetString:"+ strTest); privkey = DecodeSecret(exp_base58string);
BOOST_CHECK_MESSAGE(secret.IsValid(), "!IsValid:" + strTest); BOOST_CHECK_MESSAGE(privkey.IsValid(), "!IsValid:" + strTest);
CKey privkey = secret.GetKey();
BOOST_CHECK_MESSAGE(privkey.IsCompressed() == isCompressed, "compressed mismatch:" + strTest); BOOST_CHECK_MESSAGE(privkey.IsCompressed() == isCompressed, "compressed mismatch:" + strTest);
BOOST_CHECK_MESSAGE(privkey.size() == exp_payload.size() && std::equal(privkey.begin(), privkey.end(), exp_payload.begin()), "key mismatch:" + strTest); BOOST_CHECK_MESSAGE(privkey.size() == exp_payload.size() && std::equal(privkey.begin(), privkey.end(), exp_payload.begin()), "key mismatch:" + strTest);
@@ -119,8 +118,8 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse)
BOOST_CHECK_EQUAL(HexStr(script), HexStr(exp_payload)); BOOST_CHECK_EQUAL(HexStr(script), HexStr(exp_payload));
// Public key must be invalid private key // Public key must be invalid private key
secret.SetString(exp_base58string); privkey = DecodeSecret(exp_base58string);
BOOST_CHECK_MESSAGE(!secret.IsValid(), "IsValid pubkey as privkey:" + strTest); BOOST_CHECK_MESSAGE(!privkey.IsValid(), "IsValid pubkey as privkey:" + strTest);
} }
} }
} }
@@ -153,9 +152,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen)
CKey key; CKey key;
key.Set(exp_payload.begin(), exp_payload.end(), isCompressed); key.Set(exp_payload.begin(), exp_payload.end(), isCompressed);
assert(key.IsValid()); assert(key.IsValid());
CBitcoinSecret secret; BOOST_CHECK_MESSAGE(EncodeSecret(key) == exp_base58string, "result mismatch: " + strTest);
secret.SetKey(key);
BOOST_CHECK_MESSAGE(secret.ToString() == exp_base58string, "result mismatch: " + strTest);
} else { } else {
CTxDestination dest; CTxDestination dest;
CScript exp_script(exp_payload.begin(), exp_payload.end()); CScript exp_script(exp_payload.begin(), exp_payload.end());
@@ -172,7 +169,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen)
BOOST_AUTO_TEST_CASE(base58_keys_invalid) BOOST_AUTO_TEST_CASE(base58_keys_invalid)
{ {
UniValue tests = read_json(std::string(json_tests::base58_keys_invalid, json_tests::base58_keys_invalid + sizeof(json_tests::base58_keys_invalid))); // Negative testcases UniValue tests = read_json(std::string(json_tests::base58_keys_invalid, json_tests::base58_keys_invalid + sizeof(json_tests::base58_keys_invalid))); // Negative testcases
CBitcoinSecret secret; CKey privkey;
CTxDestination destination; CTxDestination destination;
for (size_t idx = 0; idx < tests.size(); idx++) { for (size_t idx = 0; idx < tests.size(); idx++) {
@@ -188,8 +185,8 @@ BOOST_AUTO_TEST_CASE(base58_keys_invalid)
// must be invalid as public and as private key // must be invalid as public and as private key
destination = DecodeDestination(exp_base58string); destination = DecodeDestination(exp_base58string);
BOOST_CHECK_MESSAGE(!IsValidDestination(destination), "IsValid pubkey:" + strTest); BOOST_CHECK_MESSAGE(!IsValidDestination(destination), "IsValid pubkey:" + strTest);
secret.SetString(exp_base58string); privkey = DecodeSecret(exp_base58string);
BOOST_CHECK_MESSAGE(!secret.IsValid(), "IsValid privkey:" + strTest); BOOST_CHECK_MESSAGE(!privkey.IsValid(), "IsValid privkey:" + strTest);
} }
} }

View File

@@ -86,11 +86,8 @@ BOOST_AUTO_TEST_CASE(bloom_create_insert_serialize_with_tweak)
BOOST_AUTO_TEST_CASE(bloom_create_insert_key) BOOST_AUTO_TEST_CASE(bloom_create_insert_key)
{ {
string strSecret = string("5Kg1gnAjaLfKiwhhPpGS3QfRg2m6awQvaj98JCZBZQ5SuS2F15C"); std::string strSecret = std::string("5Kg1gnAjaLfKiwhhPpGS3QfRg2m6awQvaj98JCZBZQ5SuS2F15C");
CBitcoinSecret vchSecret; CKey key = DecodeSecret(strSecret);
BOOST_CHECK(vchSecret.SetString(strSecret));
CKey key = vchSecret.GetKey();
CPubKey pubkey = key.GetPubKey(); CPubKey pubkey = key.GetPubKey();
vector<unsigned char> vchPubKey(pubkey.begin(), pubkey.end()); vector<unsigned char> vchPubKey(pubkey.begin(), pubkey.end());

View File

@@ -65,21 +65,16 @@ BOOST_FIXTURE_TEST_SUITE(key_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(key_test1) BOOST_AUTO_TEST_CASE(key_test1)
{ {
CBitcoinSecret bsecret1, bsecret2, bsecret1C, bsecret2C, baddress1; CKey key1 = DecodeSecret(strSecret1);
BOOST_CHECK( bsecret1.SetString (strSecret1)); BOOST_CHECK(key1.IsValid() && !key1.IsCompressed());
BOOST_CHECK( bsecret2.SetString (strSecret2)); CKey key2 = DecodeSecret(strSecret2);
BOOST_CHECK( bsecret1C.SetString(strSecret1C)); BOOST_CHECK(key2.IsValid() && !key2.IsCompressed());
BOOST_CHECK( bsecret2C.SetString(strSecret2C)); CKey key1C = DecodeSecret(strSecret1C);
BOOST_CHECK(!baddress1.SetString(strAddressBad)); BOOST_CHECK(key1C.IsValid() && key1C.IsCompressed());
CKey key2C = DecodeSecret(strSecret2C);
CKey key1 = bsecret1.GetKey(); BOOST_CHECK(key2C.IsValid() && key2C.IsCompressed());
BOOST_CHECK(key1.IsCompressed() == false); CKey bad_key = DecodeSecret(strAddressBad);
CKey key2 = bsecret2.GetKey(); BOOST_CHECK(!bad_key.IsValid());
BOOST_CHECK(key2.IsCompressed() == false);
CKey key1C = bsecret1C.GetKey();
BOOST_CHECK(key1C.IsCompressed() == true);
CKey key2C = bsecret2C.GetKey();
BOOST_CHECK(key2C.IsCompressed() == true);
CPubKey pubkey1 = key1. GetPubKey(); CPubKey pubkey1 = key1. GetPubKey();
CPubKey pubkey2 = key2. GetPubKey(); CPubKey pubkey2 = key2. GetPubKey();

View File

@@ -112,13 +112,8 @@ UniValue importprivkey(const UniValue& params, bool fHelp)
if (params.size() > 2) if (params.size() > 2)
fRescan = params[2].get_bool(); fRescan = params[2].get_bool();
CBitcoinSecret vchSecret; CKey key = DecodeSecret(strSecret);
bool fGood = vchSecret.SetString(strSecret); if (!key.IsValid()) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key encoding");
if (!fGood) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key encoding");
CKey key = vchSecret.GetKey();
if (!key.IsValid()) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Private key outside allowed range");
CPubKey pubkey = key.GetPubKey(); CPubKey pubkey = key.GetPubKey();
assert(key.VerifyPubKey(pubkey)); assert(key.VerifyPubKey(pubkey));
@@ -325,10 +320,9 @@ UniValue importwallet_impl(const UniValue& params, bool fHelp, bool fImportZKeys
} }
} }
CBitcoinSecret vchSecret; CKey key = DecodeSecret(vstr[0]);
if (!vchSecret.SetString(vstr[0])) if (!key.IsValid())
continue; continue;
CKey key = vchSecret.GetKey();
CPubKey pubkey = key.GetPubKey(); CPubKey pubkey = key.GetPubKey();
assert(key.VerifyPubKey(pubkey)); assert(key.VerifyPubKey(pubkey));
CKeyID keyid = pubkey.GetID(); CKeyID keyid = pubkey.GetID();
@@ -418,7 +412,7 @@ UniValue dumpprivkey(const UniValue& params, bool fHelp)
if (!pwalletMain->GetKey(*keyID, vchSecret)) { if (!pwalletMain->GetKey(*keyID, vchSecret)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Private key for address " + strAddress + " is not known"); throw JSONRPCError(RPC_WALLET_ERROR, "Private key for address " + strAddress + " is not known");
} }
return CBitcoinSecret(vchSecret).ToString(); return EncodeSecret(vchSecret);
} }
@@ -522,11 +516,11 @@ UniValue dumpwallet_impl(const UniValue& params, bool fHelp, bool fDumpZKeys)
CKey key; CKey key;
if (pwalletMain->GetKey(keyid, key)) { if (pwalletMain->GetKey(keyid, key)) {
if (pwalletMain->mapAddressBook.count(keyid)) { if (pwalletMain->mapAddressBook.count(keyid)) {
file << strprintf("%s %s label=%s # addr=%s\n", CBitcoinSecret(key).ToString(), strTime, EncodeDumpString(pwalletMain->mapAddressBook[keyid].name), strAddr); file << strprintf("%s %s label=%s # addr=%s\n", EncodeSecret(key), strTime, EncodeDumpString(pwalletMain->mapAddressBook[keyid].name), strAddr);
} else if (setKeyPool.count(keyid)) { } else if (setKeyPool.count(keyid)) {
file << strprintf("%s %s reserve=1 # addr=%s\n", CBitcoinSecret(key).ToString(), strTime, strAddr); file << strprintf("%s %s reserve=1 # addr=%s\n", EncodeSecret(key), strTime, strAddr);
} else { } else {
file << strprintf("%s %s change=1 # addr=%s\n", CBitcoinSecret(key).ToString(), strTime, strAddr); file << strprintf("%s %s change=1 # addr=%s\n", EncodeSecret(key), strTime, strAddr);
} }
} }
} }