From f146029b0a50864e2c111034786a36e53f6f02db Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 19 Sep 2017 16:49:52 -0700 Subject: [PATCH 1/8] Replace CBitcoinSecret with {Encode,Decode}Secret --- src/base58.cpp | 48 ++++++++++++++++++--------------------- src/base58.h | 17 ++------------ src/bitcoin-tx.cpp | 8 +++---- src/rpcrawtransaction.cpp | 8 ++----- src/test/base58_tests.cpp | 21 ++++++++--------- src/test/bloom_tests.cpp | 7 ++---- src/test/key_tests.cpp | 25 ++++++++------------ src/wallet/rpcdump.cpp | 22 +++++++----------- 8 files changed, 58 insertions(+), 98 deletions(-) diff --git a/src/base58.cpp b/src/base58.cpp index f3eb73e45..55b065cbe 100644 --- a/src/base58.cpp +++ b/src/base58.cpp @@ -257,39 +257,35 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par } } // namespace -void CBitcoinSecret::SetKey(const CKey& vchSecret) +CKey DecodeSecret(const std::string& str) { - assert(vchSecret.IsValid()); - SetData(Params().Base58Prefix(CChainParams::SECRET_KEY), vchSecret.begin(), vchSecret.size()); - if (vchSecret.IsCompressed()) - vchData.push_back(1); + CKey key; + std::vector data; + if (DecodeBase58Check(str, data)) { + const std::vector& 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(vchData.size() >= 32); - ret.Set(vchData.begin(), vchData.begin() + 32, vchData.size() > 32 && vchData[32] == 1); + assert(key.IsValid()); + std::vector data = Params().Base58Prefix(CChainParams::SECRET_KEY); + 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; } -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) { return boost::apply_visitor(DestinationEncoder(Params()), dest); diff --git a/src/base58.h b/src/base58.h index 9e90db78f..f30479214 100644 --- a/src/base58.h +++ b/src/base58.h @@ -139,21 +139,8 @@ public: CZCSpendingKey(const libzcash::SpendingKey& addr) { Set(addr); } }; -/** - * A base58-encoded secret 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() {} -}; +CKey DecodeSecret(const std::string& str); +std::string EncodeSecret(const CKey& key); template class CBitcoinExtKeyBase : public CBase58Data { diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index 1158563f2..aa2523039 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -400,12 +400,10 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& strInput) for (size_t kidx = 0; kidx < keysObj.size(); kidx++) { if (!keysObj[kidx].isStr()) throw std::runtime_error("privatekey not a std::string"); - CBitcoinSecret vchSecret; - bool fGood = vchSecret.SetString(keysObj[kidx].getValStr()); - if (!fGood) + CKey key = DecodeSecret(keysObj[kidx].getValStr()); + if (!key.IsValid()) { throw std::runtime_error("privatekey not valid"); - - CKey key = vchSecret.GetKey(); + } tempKeystore.AddKey(key); } diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index e59a9b369..75af5264d 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -777,13 +777,9 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp) UniValue keys = params[2].get_array(); for (size_t idx = 0; idx < keys.size(); idx++) { UniValue k = keys[idx]; - CBitcoinSecret vchSecret; - bool fGood = vchSecret.SetString(k.get_str()); - if (!fGood) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key"); - CKey key = vchSecret.GetKey(); + CKey key = DecodeSecret(k.get_str()); 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); } } diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp index 8e7f77496..351c722c0 100644 --- a/src/test/base58_tests.cpp +++ b/src/test/base58_tests.cpp @@ -78,7 +78,7 @@ BOOST_AUTO_TEST_CASE(base58_DecodeBase58) 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))); - CBitcoinSecret secret; + CKey privkey; CTxDestination destination; SelectParams(CBaseChainParams::MAIN); @@ -102,9 +102,8 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse) if (isPrivkey) { bool isCompressed = find_value(metadata, "isCompressed").get_bool(); // Must be valid private key - BOOST_CHECK_MESSAGE(secret.SetString(exp_base58string), "!SetString:"+ strTest); - BOOST_CHECK_MESSAGE(secret.IsValid(), "!IsValid:" + strTest); - CKey privkey = secret.GetKey(); + privkey = DecodeSecret(exp_base58string); + BOOST_CHECK_MESSAGE(privkey.IsValid(), "!IsValid:" + 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); @@ -119,8 +118,8 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse) BOOST_CHECK_EQUAL(HexStr(script), HexStr(exp_payload)); // Public key must be invalid private key - secret.SetString(exp_base58string); - BOOST_CHECK_MESSAGE(!secret.IsValid(), "IsValid pubkey as privkey:" + strTest); + privkey = DecodeSecret(exp_base58string); + BOOST_CHECK_MESSAGE(!privkey.IsValid(), "IsValid pubkey as privkey:" + strTest); } } } @@ -153,9 +152,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen) CKey key; key.Set(exp_payload.begin(), exp_payload.end(), isCompressed); assert(key.IsValid()); - CBitcoinSecret secret; - secret.SetKey(key); - BOOST_CHECK_MESSAGE(secret.ToString() == exp_base58string, "result mismatch: " + strTest); + BOOST_CHECK_MESSAGE(EncodeSecret(key) == exp_base58string, "result mismatch: " + strTest); } else { CTxDestination dest; 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) { 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; 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 destination = DecodeDestination(exp_base58string); BOOST_CHECK_MESSAGE(!IsValidDestination(destination), "IsValid pubkey:" + strTest); - secret.SetString(exp_base58string); - BOOST_CHECK_MESSAGE(!secret.IsValid(), "IsValid privkey:" + strTest); + privkey = DecodeSecret(exp_base58string); + BOOST_CHECK_MESSAGE(!privkey.IsValid(), "IsValid privkey:" + strTest); } } diff --git a/src/test/bloom_tests.cpp b/src/test/bloom_tests.cpp index a8f3c0454..554882899 100644 --- a/src/test/bloom_tests.cpp +++ b/src/test/bloom_tests.cpp @@ -86,11 +86,8 @@ BOOST_AUTO_TEST_CASE(bloom_create_insert_serialize_with_tweak) BOOST_AUTO_TEST_CASE(bloom_create_insert_key) { - string strSecret = string("5Kg1gnAjaLfKiwhhPpGS3QfRg2m6awQvaj98JCZBZQ5SuS2F15C"); - CBitcoinSecret vchSecret; - BOOST_CHECK(vchSecret.SetString(strSecret)); - - CKey key = vchSecret.GetKey(); + std::string strSecret = std::string("5Kg1gnAjaLfKiwhhPpGS3QfRg2m6awQvaj98JCZBZQ5SuS2F15C"); + CKey key = DecodeSecret(strSecret); CPubKey pubkey = key.GetPubKey(); vector vchPubKey(pubkey.begin(), pubkey.end()); diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp index ed997a95a..6caaed391 100644 --- a/src/test/key_tests.cpp +++ b/src/test/key_tests.cpp @@ -65,21 +65,16 @@ BOOST_FIXTURE_TEST_SUITE(key_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(key_test1) { - CBitcoinSecret bsecret1, bsecret2, bsecret1C, bsecret2C, baddress1; - BOOST_CHECK( bsecret1.SetString (strSecret1)); - BOOST_CHECK( bsecret2.SetString (strSecret2)); - BOOST_CHECK( bsecret1C.SetString(strSecret1C)); - BOOST_CHECK( bsecret2C.SetString(strSecret2C)); - BOOST_CHECK(!baddress1.SetString(strAddressBad)); - - CKey key1 = bsecret1.GetKey(); - BOOST_CHECK(key1.IsCompressed() == false); - CKey key2 = bsecret2.GetKey(); - BOOST_CHECK(key2.IsCompressed() == false); - CKey key1C = bsecret1C.GetKey(); - BOOST_CHECK(key1C.IsCompressed() == true); - CKey key2C = bsecret2C.GetKey(); - BOOST_CHECK(key2C.IsCompressed() == true); + CKey key1 = DecodeSecret(strSecret1); + BOOST_CHECK(key1.IsValid() && !key1.IsCompressed()); + CKey key2 = DecodeSecret(strSecret2); + BOOST_CHECK(key2.IsValid() && !key2.IsCompressed()); + CKey key1C = DecodeSecret(strSecret1C); + BOOST_CHECK(key1C.IsValid() && key1C.IsCompressed()); + CKey key2C = DecodeSecret(strSecret2C); + BOOST_CHECK(key2C.IsValid() && key2C.IsCompressed()); + CKey bad_key = DecodeSecret(strAddressBad); + BOOST_CHECK(!bad_key.IsValid()); CPubKey pubkey1 = key1. GetPubKey(); CPubKey pubkey2 = key2. GetPubKey(); diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index 6768db611..c29972fc1 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -112,13 +112,8 @@ UniValue importprivkey(const UniValue& params, bool fHelp) if (params.size() > 2) fRescan = params[2].get_bool(); - CBitcoinSecret vchSecret; - bool fGood = vchSecret.SetString(strSecret); - - 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"); + CKey key = DecodeSecret(strSecret); + if (!key.IsValid()) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key encoding"); CPubKey pubkey = key.GetPubKey(); assert(key.VerifyPubKey(pubkey)); @@ -325,10 +320,9 @@ UniValue importwallet_impl(const UniValue& params, bool fHelp, bool fImportZKeys } } - CBitcoinSecret vchSecret; - if (!vchSecret.SetString(vstr[0])) + CKey key = DecodeSecret(vstr[0]); + if (!key.IsValid()) continue; - CKey key = vchSecret.GetKey(); CPubKey pubkey = key.GetPubKey(); assert(key.VerifyPubKey(pubkey)); CKeyID keyid = pubkey.GetID(); @@ -418,7 +412,7 @@ UniValue dumpprivkey(const UniValue& params, bool fHelp) if (!pwalletMain->GetKey(*keyID, vchSecret)) { 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; if (pwalletMain->GetKey(keyid, key)) { 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)) { - 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 { - 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); } } } From 80ed13d545e79e3db886b5994b19780a9cb0dc59 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 24 Apr 2018 15:01:45 +0100 Subject: [PATCH 2/8] Introduce wrappers around CZCPaymentAddress This patch removes the need for the intermediary Base58 type CZCPaymentAddress, by providing {Encode,Decode}PaymentAddress functions that directly operate on the conversion between strings and libzcash::PaymentAddress. --- src/base58.cpp | 15 ++++ src/base58.h | 3 + src/paymentdisclosure.cpp | 4 +- src/rpcmisc.cpp | 12 +-- src/test/key_tests.cpp | 8 +- src/test/rpc_wallet_tests.cpp | 45 +++++------ .../asyncrpcoperation_mergetoaddress.cpp | 15 ++-- src/wallet/asyncrpcoperation_sendmany.cpp | 17 ++--- .../asyncrpcoperation_shieldcoinbase.cpp | 13 ++-- src/wallet/gtest/test_wallet_zkeys.cpp | 19 +++-- src/wallet/rpcdisclosure.cpp | 7 +- src/wallet/rpcdump.cpp | 20 +++-- src/wallet/rpcwallet.cpp | 76 ++++++++----------- src/wallet/wallet.cpp | 19 +++-- src/wallet/wallet.h | 2 +- 15 files changed, 135 insertions(+), 140 deletions(-) diff --git a/src/base58.cpp b/src/base58.cpp index 55b065cbe..fc57966fe 100644 --- a/src/base58.cpp +++ b/src/base58.cpp @@ -363,3 +363,18 @@ template bool CZCEncoding::Get() const; + +std::string EncodePaymentAddress(const libzcash::PaymentAddress& zaddr) +{ + return CZCPaymentAddress(zaddr).ToString(); +} + +boost::optional DecodePaymentAddress(const std::string& str) +{ + CZCPaymentAddress addr(str); + try { + return addr.Get(); + } catch (const std::runtime_error&) { + return boost::none; + } +} diff --git a/src/base58.h b/src/base58.h index f30479214..135005442 100644 --- a/src/base58.h +++ b/src/base58.h @@ -179,4 +179,7 @@ CTxDestination DecodeDestination(const std::string& str); bool IsValidDestinationString(const std::string& str); bool IsValidDestinationString(const std::string& str, const CChainParams& params); +std::string EncodePaymentAddress(const libzcash::PaymentAddress& zaddr); +boost::optional DecodePaymentAddress(const std::string& str); + #endif // BITCOIN_BASE58_H diff --git a/src/paymentdisclosure.cpp b/src/paymentdisclosure.cpp index a33b1c604..e9a193cae 100644 --- a/src/paymentdisclosure.cpp +++ b/src/paymentdisclosure.cpp @@ -7,7 +7,7 @@ std::string PaymentDisclosureInfo::ToString() const { return strprintf("PaymentDisclosureInfo(version=%d, esk=%s, joinSplitPrivKey=, address=%s)", - version, esk.ToString(), CZCPaymentAddress(zaddr).ToString()); + version, esk.ToString(), EncodePaymentAddress(zaddr)); } std::string PaymentDisclosure::ToString() const { @@ -17,7 +17,7 @@ std::string PaymentDisclosure::ToString() const { std::string PaymentDisclosurePayload::ToString() const { return strprintf("PaymentDisclosurePayload(version=%d, esk=%s, txid=%s, js=%d, n=%d, address=%s, message=%s)", - version, esk.ToString(), txid.ToString(), js, n, CZCPaymentAddress(zaddr).ToString(), message); + version, esk.ToString(), txid.ToString(), js, n, EncodePaymentAddress(zaddr), message); } PaymentDisclosure::PaymentDisclosure(const uint256 &joinSplitPubKey, const PaymentDisclosureKey &key, const PaymentDisclosureInfo &info, const std::string &message) diff --git a/src/rpcmisc.cpp b/src/rpcmisc.cpp index 1f863ae70..050e95370 100644 --- a/src/rpcmisc.cpp +++ b/src/rpcmisc.cpp @@ -235,27 +235,23 @@ UniValue z_validateaddress(const UniValue& params, bool fHelp) LOCK(cs_main); #endif - bool isValid = false; bool isMine = false; std::string payingKey, transmissionKey; string strAddress = params[0].get_str(); - try { - CZCPaymentAddress address(strAddress); - libzcash::PaymentAddress addr = address.Get(); + auto isValid = DecodePaymentAddress(strAddress); + if (isValid) { + libzcash::PaymentAddress addr = *isValid; #ifdef ENABLE_WALLET isMine = pwalletMain->HaveSpendingKey(addr); #endif payingKey = addr.a_pk.GetHex(); transmissionKey = addr.pk_enc.GetHex(); - isValid = true; - } catch (std::runtime_error e) { - // address is invalid, nop here as isValid is false. } UniValue ret(UniValue::VOBJ); - ret.push_back(Pair("isvalid", isValid)); + ret.push_back(Pair("isvalid", static_cast(isValid))); if (isValid) { ret.push_back(Pair("address", strAddress)); diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp index 6caaed391..829fd1377 100644 --- a/src/test/key_tests.cpp +++ b/src/test/key_tests.cpp @@ -203,15 +203,15 @@ BOOST_AUTO_TEST_CASE(zc_address_test) { auto addr = sk.address(); - CZCPaymentAddress paymentaddr(addr); - string addr_string = paymentaddr.ToString(); + std::string addr_string = EncodePaymentAddress(addr); BOOST_CHECK(addr_string[0] == 'z'); BOOST_CHECK(addr_string[1] == 'c'); - CZCPaymentAddress paymentaddr2(addr_string); + auto paymentaddr2 = DecodePaymentAddress(addr_string); + BOOST_ASSERT(static_cast(paymentaddr2)); - PaymentAddress addr2 = paymentaddr2.Get(); + PaymentAddress addr2 = *paymentaddr2; BOOST_CHECK(addr.a_pk == addr2.a_pk); BOOST_CHECK(addr.pk_enc == addr2.pk_enc); } diff --git a/src/test/rpc_wallet_tests.cpp b/src/test/rpc_wallet_tests.cpp index f4e892f8c..a6353c01c 100644 --- a/src/test/rpc_wallet_tests.cpp +++ b/src/test/rpc_wallet_tests.cpp @@ -386,7 +386,7 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_exportwallet) BOOST_CHECK(addrs.size()==0); // wallet should have one key - CZCPaymentAddress paymentAddress = pwalletMain->GenerateNewZKey(); + auto addr = pwalletMain->GenerateNewZKey(); pwalletMain->GetPaymentAddresses(addrs); BOOST_CHECK(addrs.size()==1); @@ -411,11 +411,10 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_exportwallet) BOOST_CHECK_NO_THROW(CallRPC(string("z_exportwallet ") + tmpfilename.string())); - auto addr = paymentAddress.Get(); libzcash::SpendingKey key; BOOST_CHECK(pwalletMain->GetSpendingKey(addr, key)); - std::string s1 = paymentAddress.ToString(); + std::string s1 = EncodePaymentAddress(addr); std::string s2 = CZCSpendingKey(key).ToString(); // There's no way to really delete a private key so we will read in the @@ -459,7 +458,7 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importwallet) // create a random key locally auto testSpendingKey = libzcash::SpendingKey::random(); auto testPaymentAddress = testSpendingKey.address(); - std::string testAddr = CZCPaymentAddress(testPaymentAddress).ToString(); + std::string testAddr = EncodePaymentAddress(testPaymentAddress); std::string testKey = CZCSpendingKey(testSpendingKey).ToString(); // create test data using the random key @@ -498,8 +497,7 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importwallet) BOOST_CHECK(addrs.size()==1); // check that we have the spending key for the address - CZCPaymentAddress address(testAddr); - auto addr = address.Get(); + auto addr = *DecodePaymentAddress(testAddr); BOOST_CHECK(pwalletMain->HaveSpendingKey(addr)); // Verify the spending key is the same as the test data @@ -546,7 +544,7 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importexport) // create a random key locally auto testSpendingKey = libzcash::SpendingKey::random(); auto testPaymentAddress = testSpendingKey.address(); - std::string testAddr = CZCPaymentAddress(testPaymentAddress).ToString(); + std::string testAddr = EncodePaymentAddress(testPaymentAddress); std::string testKey = CZCSpendingKey(testSpendingKey).ToString(); BOOST_CHECK_NO_THROW(CallRPC(string("z_importkey ") + testKey)); BOOST_CHECK_NO_THROW(retValue = CallRPC(string("z_exportkey ") + testAddr)); @@ -566,7 +564,7 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importexport) // Make new addresses for the set for (int i=0; iGenerateNewZKey()).ToString()); + myaddrs.insert(EncodePaymentAddress(pwalletMain->GenerateNewZKey())); } // Verify number of addresses stored in wallet is n1+n2 @@ -593,8 +591,7 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importexport) // Add one more address BOOST_CHECK_NO_THROW(retValue = CallRPC("z_getnewaddress")); std::string newaddress = retValue.get_str(); - CZCPaymentAddress pa(newaddress); - auto newAddr = pa.Get(); + auto newAddr = *DecodePaymentAddress(newaddress); BOOST_CHECK(pwalletMain->HaveSpendingKey(newAddr)); // Check if too many args @@ -916,8 +913,8 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_parameters) std::vector v (2 * (ZC_MEMO_SIZE+1)); // x2 for hexadecimal string format std::fill(v.begin(),v.end(), 'A'); std::string badmemo(v.begin(), v.end()); - CZCPaymentAddress pa = pwalletMain->GenerateNewZKey(); - std::string zaddr1 = pa.ToString(); + auto pa = pwalletMain->GenerateNewZKey(); + std::string zaddr1 = EncodePaymentAddress(pa); BOOST_CHECK_THROW(CallRPC(string("z_sendmany tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ ") + "[{\"address\":\"" + zaddr1 + "\", \"amount\":123.456}]"), runtime_error); @@ -952,7 +949,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_parameters) std::vector recipients = { SendManyRecipient("dummy",1.0, "") }; std::shared_ptr operation( new AsyncRPCOperation_sendmany(mtx, "INVALID", recipients, {}, 1) ); } catch (const UniValue& objError) { - BOOST_CHECK( find_error(objError, "payment address is invalid")); + BOOST_CHECK( find_error(objError, "Invalid from address")); } // Testnet payment addresses begin with 'zt'. This test detects an incorrect prefix. @@ -960,7 +957,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_parameters) std::vector recipients = { SendManyRecipient("dummy",1.0, "") }; std::shared_ptr operation( new AsyncRPCOperation_sendmany(mtx, "zcMuhvq8sEkHALuSU2i4NbNQxshSAYrpCExec45ZjtivYPbuiFPwk6WHy4SvsbeZ4siy1WheuRGjtaJmoD1J8bFqNXhsG6U", recipients, {}, 1) ); } catch (const UniValue& objError) { - BOOST_CHECK( find_error(objError, "payment address is for wrong network type")); + BOOST_CHECK( find_error(objError, "Invalid from address")); } // Note: The following will crash as a google test because AsyncRPCOperation_sendmany @@ -994,8 +991,8 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_internals) // add keys manually BOOST_CHECK_NO_THROW(retValue = CallRPC("getnewaddress")); std::string taddr1 = retValue.get_str(); - CZCPaymentAddress pa = pwalletMain->GenerateNewZKey(); - std::string zaddr1 = pa.ToString(); + auto pa = pwalletMain->GenerateNewZKey(); + std::string zaddr1 = EncodePaymentAddress(pa); // there are no utxos to spend { @@ -1392,7 +1389,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_shieldcoinbase_parameters) std::vector inputs = { ShieldCoinbaseUTXO{uint256(),0,0} }; std::shared_ptr operation( new AsyncRPCOperation_shieldcoinbase(mtx, inputs, mainnetzaddr, 1) ); } catch (const UniValue& objError) { - BOOST_CHECK( find_error(objError, "payment address is for wrong network type")); + BOOST_CHECK( find_error(objError, "Invalid to address")); } } @@ -1417,8 +1414,8 @@ BOOST_AUTO_TEST_CASE(rpc_z_shieldcoinbase_internals) mapArgs["-mempooltxinputlimit"] = "1"; // Add keys manually - CZCPaymentAddress pa = pwalletMain->GenerateNewZKey(); - std::string zaddr = pa.ToString(); + auto pa = pwalletMain->GenerateNewZKey(); + std::string zaddr = EncodePaymentAddress(pa); // Supply 2 inputs when mempool limit is 1 { @@ -1542,8 +1539,8 @@ BOOST_AUTO_TEST_CASE(rpc_z_mergetoaddress_parameters) std::vector v (2 * (ZC_MEMO_SIZE+1)); // x2 for hexadecimal string format std::fill(v.begin(),v.end(), 'A'); std::string badmemo(v.begin(), v.end()); - CZCPaymentAddress pa = pwalletMain->GenerateNewZKey(); - std::string zaddr1 = pa.ToString(); + auto pa = pwalletMain->GenerateNewZKey(); + std::string zaddr1 = EncodePaymentAddress(pa); BOOST_CHECK_THROW(CallRPC(string("z_mergetoaddress [\"tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ\"] ") + zaddr1 + " 0.0001 100 100 " + badmemo), runtime_error); @@ -1590,7 +1587,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_mergetoaddress_parameters) std::shared_ptr operation( new AsyncRPCOperation_mergetoaddress(mtx, inputs, {}, mainnetzaddr, 1) ); BOOST_FAIL("Should have caused an error"); } catch (const UniValue& objError) { - BOOST_CHECK( find_error(objError, "payment address is for wrong network type")); + BOOST_CHECK( find_error(objError, "Invalid recipient address")); } } @@ -1613,8 +1610,8 @@ BOOST_AUTO_TEST_CASE(rpc_z_mergetoaddress_internals) // Add keys manually BOOST_CHECK_NO_THROW(retValue = CallRPC("getnewaddress")); MergeToAddressRecipient taddr1(retValue.get_str(), ""); - CZCPaymentAddress pa = pwalletMain->GenerateNewZKey(); - MergeToAddressRecipient zaddr1(pa.ToString(), "DEADBEEF"); + auto pa = pwalletMain->GenerateNewZKey(); + MergeToAddressRecipient zaddr1(EncodePaymentAddress(pa), "DEADBEEF"); // Supply 2 inputs when mempool limit is 1 { diff --git a/src/wallet/asyncrpcoperation_mergetoaddress.cpp b/src/wallet/asyncrpcoperation_mergetoaddress.cpp index 916ad862b..7ac680186 100644 --- a/src/wallet/asyncrpcoperation_mergetoaddress.cpp +++ b/src/wallet/asyncrpcoperation_mergetoaddress.cpp @@ -78,14 +78,12 @@ AsyncRPCOperation_mergetoaddress::AsyncRPCOperation_mergetoaddress( isToZaddr_ = false; if (!isToTaddr_) { - CZCPaymentAddress address(std::get<0>(recipient)); - try { - PaymentAddress addr = address.Get(); - + auto address = DecodePaymentAddress(std::get<0>(recipient)); + if (address) { isToZaddr_ = true; - toPaymentAddress_ = addr; - } catch (const std::runtime_error& e) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("runtime error: ") + e.what()); + toPaymentAddress_ = *address; + } else { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid recipient address"); } } @@ -857,8 +855,7 @@ UniValue AsyncRPCOperation_mergetoaddress::perform_joinsplit( PaymentDisclosureInfo pdInfo = {PAYMENT_DISCLOSURE_VERSION_EXPERIMENTAL, esk, joinSplitPrivKey, zaddr}; paymentDisclosureData_.push_back(PaymentDisclosureKeyInfo(pdKey, pdInfo)); - CZCPaymentAddress address(zaddr); - LogPrint("paymentdisclosure", "%s: Payment Disclosure: js=%d, n=%d, zaddr=%s\n", getId(), js_index, int(mapped_index), address.ToString()); + LogPrint("paymentdisclosure", "%s: Payment Disclosure: js=%d, n=%d, zaddr=%s\n", getId(), js_index, int(mapped_index), EncodePaymentAddress(zaddr)); } // !!! Payment disclosure END diff --git a/src/wallet/asyncrpcoperation_sendmany.cpp b/src/wallet/asyncrpcoperation_sendmany.cpp index ba9f566f6..b6d30a4b1 100644 --- a/src/wallet/asyncrpcoperation_sendmany.cpp +++ b/src/wallet/asyncrpcoperation_sendmany.cpp @@ -79,9 +79,9 @@ AsyncRPCOperation_sendmany::AsyncRPCOperation_sendmany( isfromzaddr_ = false; if (!isfromtaddr_) { - CZCPaymentAddress address(fromAddress); - try { - PaymentAddress addr = address.Get(); + auto address = DecodePaymentAddress(fromAddress); + if (address) { + PaymentAddress addr = *address; // We don't need to lock on the wallet as spending key related methods are thread-safe SpendingKey key; @@ -92,8 +92,8 @@ AsyncRPCOperation_sendmany::AsyncRPCOperation_sendmany( isfromzaddr_ = true; frompaymentaddress_ = addr; spendingkey_ = key; - } catch (const std::runtime_error& e) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("runtime error: ") + e.what()); + } else { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address"); } } @@ -467,7 +467,7 @@ bool AsyncRPCOperation_sendmany::main_impl() { std::string hexMemo = std::get<2>(smr); zOutputsDeque.pop_front(); - PaymentAddress pa = CZCPaymentAddress(address).Get(); + PaymentAddress pa = *DecodePaymentAddress(address); JSOutput jso = JSOutput(pa, value); if (hexMemo.size() > 0) { jso.memo = get_memo_from_hex_string(hexMemo); @@ -726,7 +726,7 @@ bool AsyncRPCOperation_sendmany::main_impl() { assert(value==0); info.vjsout.push_back(JSOutput()); // dummy output while we accumulate funds into a change note for vpub_new } else { - PaymentAddress pa = CZCPaymentAddress(address).Get(); + PaymentAddress pa = *DecodePaymentAddress(address); JSOutput jso = JSOutput(pa, value); if (hexMemo.size() > 0) { jso.memo = get_memo_from_hex_string(hexMemo); @@ -1080,8 +1080,7 @@ UniValue AsyncRPCOperation_sendmany::perform_joinsplit( PaymentDisclosureInfo pdInfo = {PAYMENT_DISCLOSURE_VERSION_EXPERIMENTAL, esk, joinSplitPrivKey, zaddr}; paymentDisclosureData_.push_back(PaymentDisclosureKeyInfo(pdKey, pdInfo)); - CZCPaymentAddress address(zaddr); - LogPrint("paymentdisclosure", "%s: Payment Disclosure: js=%d, n=%d, zaddr=%s\n", getId(), js_index, int(mapped_index), address.ToString()); + LogPrint("paymentdisclosure", "%s: Payment Disclosure: js=%d, n=%d, zaddr=%s\n", getId(), js_index, int(mapped_index), EncodePaymentAddress(zaddr)); } // !!! Payment disclosure END diff --git a/src/wallet/asyncrpcoperation_shieldcoinbase.cpp b/src/wallet/asyncrpcoperation_shieldcoinbase.cpp index 45d9321dd..69bde8526 100644 --- a/src/wallet/asyncrpcoperation_shieldcoinbase.cpp +++ b/src/wallet/asyncrpcoperation_shieldcoinbase.cpp @@ -71,11 +71,11 @@ AsyncRPCOperation_shieldcoinbase::AsyncRPCOperation_shieldcoinbase( } // Check the destination address is valid for this network i.e. not testnet being used on mainnet - CZCPaymentAddress address(toAddress); - try { - tozaddr_ = address.Get(); - } catch (const std::runtime_error& e) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("runtime error: ") + e.what()); + auto address = DecodePaymentAddress(toAddress); + if (address) { + tozaddr_ = *address; + } else { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid to address"); } // Log the context info @@ -451,8 +451,7 @@ UniValue AsyncRPCOperation_shieldcoinbase::perform_joinsplit(ShieldCoinbaseJSInf PaymentDisclosureInfo pdInfo = {PAYMENT_DISCLOSURE_VERSION_EXPERIMENTAL, esk, joinSplitPrivKey, zaddr}; paymentDisclosureData_.push_back(PaymentDisclosureKeyInfo(pdKey, pdInfo)); - CZCPaymentAddress address(zaddr); - LogPrint("paymentdisclosure", "%s: Payment Disclosure: js=%d, n=%d, zaddr=%s\n", getId(), js_index, int(mapped_index), address.ToString()); + LogPrint("paymentdisclosure", "%s: Payment Disclosure: js=%d, n=%d, zaddr=%s\n", getId(), js_index, int(mapped_index), EncodePaymentAddress(zaddr)); } // !!! Payment disclosure END diff --git a/src/wallet/gtest/test_wallet_zkeys.cpp b/src/wallet/gtest/test_wallet_zkeys.cpp index b40479e87..474656474 100644 --- a/src/wallet/gtest/test_wallet_zkeys.cpp +++ b/src/wallet/gtest/test_wallet_zkeys.cpp @@ -25,12 +25,11 @@ TEST(wallet_zkeys_tests, store_and_load_zkeys) { ASSERT_EQ(0, addrs.size()); // wallet should have one key - CZCPaymentAddress paymentAddress = wallet.GenerateNewZKey(); + auto addr = wallet.GenerateNewZKey(); wallet.GetPaymentAddresses(addrs); ASSERT_EQ(1, addrs.size()); // verify wallet has spending key for the address - auto addr = paymentAddress.Get(); ASSERT_TRUE(wallet.HaveSpendingKey(addr)); // manually add new spending key to wallet @@ -289,22 +288,22 @@ TEST(wallet_zkeys_tests, write_cryptedzkey_direct_to_db) { ASSERT_EQ(2, addrs.size()); // check we have entries for our payment addresses - ASSERT_TRUE(addrs.count(paymentAddress.Get())); - ASSERT_TRUE(addrs.count(paymentAddress2.Get())); + ASSERT_TRUE(addrs.count(paymentAddress)); + ASSERT_TRUE(addrs.count(paymentAddress2)); // spending key is crypted, so we can't extract valid payment address libzcash::SpendingKey keyOut; - wallet2.GetSpendingKey(paymentAddress.Get(), keyOut); - ASSERT_FALSE(paymentAddress.Get() == keyOut.address()); + wallet2.GetSpendingKey(paymentAddress, keyOut); + ASSERT_FALSE(paymentAddress == keyOut.address()); // unlock wallet to get spending keys and verify payment addresses wallet2.Unlock(strWalletPass); - wallet2.GetSpendingKey(paymentAddress.Get(), keyOut); - ASSERT_EQ(paymentAddress.Get(), keyOut.address()); + wallet2.GetSpendingKey(paymentAddress, keyOut); + ASSERT_EQ(paymentAddress, keyOut.address()); - wallet2.GetSpendingKey(paymentAddress2.Get(), keyOut); - ASSERT_EQ(paymentAddress2.Get(), keyOut.address()); + wallet2.GetSpendingKey(paymentAddress2, keyOut); + ASSERT_EQ(paymentAddress2, keyOut.address()); ECC_Stop(); } diff --git a/src/wallet/rpcdisclosure.cpp b/src/wallet/rpcdisclosure.cpp index d4f87ab39..7ca6086ae 100644 --- a/src/wallet/rpcdisclosure.cpp +++ b/src/wallet/rpcdisclosure.cpp @@ -254,11 +254,8 @@ UniValue z_validatepaymentdisclosure(const UniValue& params, bool fHelp) // Check the payment address is valid PaymentAddress zaddr = pd.payload.zaddr; - CZCPaymentAddress address; - if (!address.Set(zaddr)) { - errs.push_back("Payment disclosure refers to an invalid payment address"); - } else { - o.push_back(Pair("paymentAddress", address.ToString())); + { + o.push_back(Pair("paymentAddress", EncodePaymentAddress(zaddr))); try { // Decrypt the note to get value and memo field diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index c29972fc1..9b5d35072 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -300,11 +300,11 @@ UniValue importwallet_impl(const UniValue& params, bool fHelp, bool fImportZKeys libzcash::SpendingKey key = spendingkey.Get(); libzcash::PaymentAddress addr = key.address(); if (pwalletMain->HaveSpendingKey(addr)) { - LogPrint("zrpc", "Skipping import of zaddr %s (key already present)\n", CZCPaymentAddress(addr).ToString()); + LogPrint("zrpc", "Skipping import of zaddr %s (key already present)\n", EncodePaymentAddress(addr)); continue; } int64_t nTime = DecodeDumpTime(vstr[1]); - LogPrint("zrpc", "Importing zaddr %s...\n", CZCPaymentAddress(addr).ToString()); + LogPrint("zrpc", "Importing zaddr %s...\n", EncodePaymentAddress(addr)); if (!pwalletMain->AddZKey(key)) { // Something went wrong fGood = false; @@ -536,7 +536,7 @@ UniValue dumpwallet_impl(const UniValue& params, bool fHelp, bool fDumpZKeys) libzcash::SpendingKey key; if (pwalletMain->GetSpendingKey(addr, key)) { std::string strTime = EncodeDumpTime(pwalletMain->mapZKeyMetadata[addr].nCreateTime); - file << strprintf("%s %s # zaddr=%s\n", CZCSpendingKey(key).ToString(), strTime, CZCPaymentAddress(addr).ToString()); + file << strprintf("%s %s # zaddr=%s\n", CZCSpendingKey(key).ToString(), strTime, EncodePaymentAddress(addr)); } } file << "\n"; @@ -760,8 +760,11 @@ UniValue z_exportkey(const UniValue& params, bool fHelp) string strAddress = params[0].get_str(); - CZCPaymentAddress address(strAddress); - auto addr = address.Get(); + auto address = DecodePaymentAddress(strAddress); + if (!address) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr"); + } + auto addr = *address; libzcash::SpendingKey k; if (!pwalletMain->GetSpendingKey(addr, k)) @@ -796,8 +799,11 @@ UniValue z_exportviewingkey(const UniValue& params, bool fHelp) string strAddress = params[0].get_str(); - CZCPaymentAddress address(strAddress); - auto addr = address.Get(); + auto address = DecodePaymentAddress(strAddress); + if (!address) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr"); + } + auto addr = *address; libzcash::ViewingKey vk; if (!pwalletMain->GetViewingKey(addr, vk)) { diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 5de71c2c6..ca6c216e6 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2521,14 +2521,14 @@ UniValue z_listunspent(const UniValue& params, bool fHelp) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected string"); } string address = o.get_str(); - try { - CZCPaymentAddress zaddr(address); - libzcash::PaymentAddress addr = zaddr.Get(); + auto zaddr = DecodePaymentAddress(address); + if (zaddr) { + libzcash::PaymentAddress addr = *zaddr; if (!fIncludeWatchonly && !pwalletMain->HaveSpendingKey(addr)) { throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, spending key for address does not belong to wallet: ") + address); } zaddrs.insert(addr); - } catch (const std::runtime_error&) { + } else { throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, address is not a valid zaddr: ") + address); } @@ -2555,7 +2555,7 @@ UniValue z_listunspent(const UniValue& params, bool fHelp) obj.push_back(Pair("jsoutindex", (int)entry.jsop.n)); obj.push_back(Pair("confirmations", entry.nHeight)); obj.push_back(Pair("spendable", pwalletMain->HaveSpendingKey(entry.address))); - obj.push_back(Pair("address", CZCPaymentAddress(entry.address).ToString())); + obj.push_back(Pair("address", EncodePaymentAddress(entry.address))); obj.push_back(Pair("amount", ValueFromAmount(CAmount(entry.plaintext.value())))); std::string data(entry.plaintext.memo().begin(), entry.plaintext.memo().end()); obj.push_back(Pair("memo", HexStr(data))); @@ -2945,11 +2945,13 @@ UniValue zc_raw_joinsplit(const UniValue& params, bool fHelp) } for (const string& name_ : outputs.getKeys()) { - CZCPaymentAddress pubaddr(name_); - PaymentAddress addrTo = pubaddr.Get(); + auto addrTo = DecodePaymentAddress(name_); + if (!addrTo) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid recipient address."); + } CAmount nAmount = AmountFromValue(outputs[name_]); - vjsout.push_back(JSOutput(addrTo, nAmount)); + vjsout.push_back(JSOutput(*addrTo, nAmount)); } while (vjsout.size() < ZC_NUM_JS_OUTPUTS) { @@ -3059,12 +3061,11 @@ UniValue zc_raw_keygen(const UniValue& params, bool fHelp) auto addr = k.address(); auto viewing_key = k.viewing_key(); - CZCPaymentAddress pubaddr(addr); CZCSpendingKey spendingkey(k); CZCViewingKey viewingkey(viewing_key); UniValue result(UniValue::VOBJ); - result.push_back(Pair("zcaddress", pubaddr.ToString())); + result.push_back(Pair("zcaddress", EncodePaymentAddress(addr))); result.push_back(Pair("zcsecretkey", spendingkey.ToString())); result.push_back(Pair("zcviewingkey", viewingkey.ToString())); return result; @@ -3092,9 +3093,8 @@ UniValue z_getnewaddress(const UniValue& params, bool fHelp) EnsureWalletIsUnlocked(); - CZCPaymentAddress pubaddr = pwalletMain->GenerateNewZKey(); - std::string result = pubaddr.ToString(); - return result; + auto zaddr = pwalletMain->GenerateNewZKey(); + return EncodePaymentAddress(zaddr); } @@ -3131,7 +3131,7 @@ UniValue z_listaddresses(const UniValue& params, bool fHelp) pwalletMain->GetPaymentAddresses(addresses); for (auto addr : addresses ) { if (fIncludeWatchonly || pwalletMain->HaveSpendingKey(addr)) { - ret.push_back(CZCPaymentAddress(addr).ToString()); + ret.push_back(EncodePaymentAddress(addr)); } } return ret; @@ -3228,15 +3228,12 @@ UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp) // Check that the from address is valid. auto fromaddress = params[0].get_str(); - libzcash::PaymentAddress zaddr; - CZCPaymentAddress address(fromaddress); - try { - zaddr = address.Get(); - } catch (const std::runtime_error&) { + auto zaddr = DecodePaymentAddress(fromaddress); + if (!zaddr) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr."); } - if (!(pwalletMain->HaveSpendingKey(zaddr) || pwalletMain->HaveViewingKey(zaddr))) { + if (!(pwalletMain->HaveSpendingKey(*zaddr) || pwalletMain->HaveViewingKey(*zaddr))) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key or viewing key not found."); } @@ -3301,12 +3298,11 @@ UniValue z_getbalance(const UniValue& params, bool fHelp) fromTaddr = IsValidDestination(taddr); libzcash::PaymentAddress zaddr; if (!fromTaddr) { - CZCPaymentAddress address(fromaddress); - try { - zaddr = address.Get(); - } catch (const std::runtime_error&) { + auto res = DecodePaymentAddress(fromaddress); + if (!res) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr."); } + zaddr = *res; if (!(pwalletMain->HaveSpendingKey(zaddr) || pwalletMain->HaveViewingKey(zaddr))) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key or viewing key not found."); } @@ -3537,13 +3533,12 @@ UniValue z_sendmany(const UniValue& params, bool fHelp) fromTaddr = IsValidDestination(taddr); libzcash::PaymentAddress zaddr; if (!fromTaddr) { - CZCPaymentAddress address(fromaddress); - try { - zaddr = address.Get(); - } catch (const std::runtime_error&) { + auto res = DecodePaymentAddress(fromaddress); + if (!res) { // invalid throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr."); } + zaddr = *res; } // Check that we have the spending key @@ -3581,11 +3576,9 @@ UniValue z_sendmany(const UniValue& params, bool fHelp) bool isZaddr = false; CTxDestination taddr = DecodeDestination(address); if (!IsValidDestination(taddr)) { - try { - CZCPaymentAddress zaddr(address); - zaddr.Get(); + if (DecodePaymentAddress(address)) { isZaddr = true; - } catch (const std::runtime_error&) { + } else { throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ")+address ); } } @@ -3777,10 +3770,7 @@ UniValue z_shieldcoinbase(const UniValue& params, bool fHelp) // Validate the destination address auto destaddress = params[1].get_str(); - try { - CZCPaymentAddress pa(destaddress); - libzcash::PaymentAddress zaddr = pa.Get(); - } catch (const std::runtime_error&) { + if (!DecodePaymentAddress(destaddress)) { throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ") + destaddress ); } @@ -4021,13 +4011,13 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp) taddrs.insert(taddr); } } else { - try { - CZCPaymentAddress zaddr(address); + auto zaddr = DecodePaymentAddress(address); + if (zaddr) { // Ignore listed z-addrs if we are using all of them if (!(useAny || useAnyNote)) { - zaddrs.insert(zaddr.Get()); + zaddrs.insert(*zaddr); } - } catch (const std::runtime_error&) { + } else { throw JSONRPCError( RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ") + address); @@ -4045,11 +4035,9 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp) bool isToZaddr = false; CTxDestination taddr = DecodeDestination(destaddress); if (!IsValidDestination(taddr)) { - try { - CZCPaymentAddress zaddr(destaddress); - zaddr.Get(); + if (DecodePaymentAddress(destaddress)) { isToZaddr = true; - } catch (const std::runtime_error&) { + } else { throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ") + destaddress ); } } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 9aa4c4918..044313a18 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -80,7 +80,7 @@ const CWalletTx* CWallet::GetWalletTx(const uint256& hash) const } // Generate a new spending key and return its public payment address -CZCPaymentAddress CWallet::GenerateNewZKey() +libzcash::PaymentAddress CWallet::GenerateNewZKey() { AssertLockHeld(cs_wallet); // mapZKeyMetadata auto k = SpendingKey::random(); @@ -94,10 +94,9 @@ CZCPaymentAddress CWallet::GenerateNewZKey() int64_t nCreationTime = GetTime(); mapZKeyMetadata[addr] = CKeyMetadata(nCreationTime); - CZCPaymentAddress pubaddr(addr); if (!AddZKey(k)) throw std::runtime_error("CWallet::GenerateNewZKey(): AddZKey failed"); - return pubaddr; + return addr; } // Add spending key to keystore and persist to disk @@ -3718,7 +3717,7 @@ void CWallet::GetFilteredNotes(std::vector & outEntri std::set filterAddresses; if (address.length() > 0) { - filterAddresses.insert(CZCPaymentAddress(address).Get()); + filterAddresses.insert(*DecodePaymentAddress(address)); } GetFilteredNotes(outEntries, filterAddresses, minDepth, ignoreSpent, ignoreUnspendable); @@ -3781,7 +3780,7 @@ void CWallet::GetFilteredNotes( ZCNoteDecryption decryptor; if (!GetNoteDecryptor(pa, decryptor)) { // Note decryptors are created when the wallet is loaded, so it should always exist - throw std::runtime_error(strprintf("Could not find note decryptor for payment address %s", CZCPaymentAddress(pa).ToString())); + throw std::runtime_error(strprintf("Could not find note decryptor for payment address %s", EncodePaymentAddress(pa))); } // determine amount of funds in the note @@ -3798,10 +3797,10 @@ void CWallet::GetFilteredNotes( } catch (const note_decryption_failed &err) { // Couldn't decrypt with this spending key - throw std::runtime_error(strprintf("Could not decrypt note for payment address %s", CZCPaymentAddress(pa).ToString())); + throw std::runtime_error(strprintf("Could not decrypt note for payment address %s", EncodePaymentAddress(pa))); } catch (const std::exception &exc) { // Unexpected failure - throw std::runtime_error(strprintf("Error while decrypting note for payment address %s: %s", CZCPaymentAddress(pa).ToString(), exc.what())); + throw std::runtime_error(strprintf("Error while decrypting note for payment address %s: %s", EncodePaymentAddress(pa), exc.what())); } } } @@ -3857,7 +3856,7 @@ void CWallet::GetUnspentFilteredNotes( ZCNoteDecryption decryptor; if (!GetNoteDecryptor(pa, decryptor)) { // Note decryptors are created when the wallet is loaded, so it should always exist - throw std::runtime_error(strprintf("Could not find note decryptor for payment address %s", CZCPaymentAddress(pa).ToString())); + throw std::runtime_error(strprintf("Could not find note decryptor for payment address %s", EncodePaymentAddress(pa))); } // determine amount of funds in the note @@ -3874,10 +3873,10 @@ void CWallet::GetUnspentFilteredNotes( } catch (const note_decryption_failed &err) { // Couldn't decrypt with this spending key - throw std::runtime_error(strprintf("Could not decrypt note for payment address %s", CZCPaymentAddress(pa).ToString())); + throw std::runtime_error(strprintf("Could not decrypt note for payment address %s", EncodePaymentAddress(pa))); } catch (const std::exception &exc) { // Unexpected failure - throw std::runtime_error(strprintf("Error while decrypting note for payment address %s: %s", CZCPaymentAddress(pa).ToString(), exc.what())); + throw std::runtime_error(strprintf("Error while decrypting note for payment address %s: %s", EncodePaymentAddress(pa), exc.what())); } } } diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 08f22f97e..a9b8bc7e1 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -960,7 +960,7 @@ public: * ZKeys */ //! Generates a new zaddr - CZCPaymentAddress GenerateNewZKey(); + libzcash::PaymentAddress GenerateNewZKey(); //! Adds spending key to the store, and saves it to disk bool AddZKey(const libzcash::SpendingKey &key); //! Adds spending key to the store, without saving it to disk (used by LoadWallet) From 472f75bc2dba93ce38856deb1a77eabb52e2495a Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 24 Apr 2018 15:16:27 +0100 Subject: [PATCH 3/8] Introduce wrappers around CZCSpendingKey --- src/base58.cpp | 15 +++++++++++++++ src/base58.h | 3 +++ src/test/key_tests.cpp | 8 ++++---- src/test/rpc_wallet_tests.cpp | 11 +++++------ src/wallet/rpcdump.cpp | 23 ++++++++++++----------- src/wallet/rpcwallet.cpp | 17 +++++++++++------ 6 files changed, 50 insertions(+), 27 deletions(-) diff --git a/src/base58.cpp b/src/base58.cpp index fc57966fe..90982cf95 100644 --- a/src/base58.cpp +++ b/src/base58.cpp @@ -378,3 +378,18 @@ boost::optional DecodePaymentAddress(const std::string return boost::none; } } + +std::string EncodeSpendingKey(const libzcash::SpendingKey& zkey) +{ + return CZCSpendingKey(zkey).ToString(); +} + +boost::optional DecodeSpendingKey(const std::string& str) +{ + CZCSpendingKey key(str); + try { + return key.Get(); + } catch (const std::runtime_error&) { + return boost::none; + } +} diff --git a/src/base58.h b/src/base58.h index 135005442..da9b7dd1e 100644 --- a/src/base58.h +++ b/src/base58.h @@ -182,4 +182,7 @@ bool IsValidDestinationString(const std::string& str, const CChainParams& params std::string EncodePaymentAddress(const libzcash::PaymentAddress& zaddr); boost::optional DecodePaymentAddress(const std::string& str); +std::string EncodeSpendingKey(const libzcash::SpendingKey& zkey); +boost::optional DecodeSpendingKey(const std::string& str); + #endif // BITCOIN_BASE58_H diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp index 829fd1377..6292e7eb1 100644 --- a/src/test/key_tests.cpp +++ b/src/test/key_tests.cpp @@ -190,14 +190,14 @@ BOOST_AUTO_TEST_CASE(zc_address_test) for (size_t i = 0; i < 1000; i++) { auto sk = SpendingKey::random(); { - CZCSpendingKey spendingkey(sk); - string sk_string = spendingkey.ToString(); + string sk_string = EncodeSpendingKey(sk); BOOST_CHECK(sk_string[0] == 'S'); BOOST_CHECK(sk_string[1] == 'K'); - CZCSpendingKey spendingkey2(sk_string); - SpendingKey sk2 = spendingkey2.Get(); + auto spendingkey2 = DecodeSpendingKey(sk_string); + BOOST_ASSERT(static_cast(spendingkey2)); + SpendingKey sk2 = *spendingkey2; BOOST_CHECK(sk.inner() == sk2.inner()); } { diff --git a/src/test/rpc_wallet_tests.cpp b/src/test/rpc_wallet_tests.cpp index a6353c01c..3c657a3db 100644 --- a/src/test/rpc_wallet_tests.cpp +++ b/src/test/rpc_wallet_tests.cpp @@ -415,7 +415,7 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_exportwallet) BOOST_CHECK(pwalletMain->GetSpendingKey(addr, key)); std::string s1 = EncodePaymentAddress(addr); - std::string s2 = CZCSpendingKey(key).ToString(); + std::string s2 = EncodeSpendingKey(key); // There's no way to really delete a private key so we will read in the // exported wallet file and search for the spending key and payment address. @@ -459,7 +459,7 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importwallet) auto testSpendingKey = libzcash::SpendingKey::random(); auto testPaymentAddress = testSpendingKey.address(); std::string testAddr = EncodePaymentAddress(testPaymentAddress); - std::string testKey = CZCSpendingKey(testSpendingKey).ToString(); + std::string testKey = EncodeSpendingKey(testSpendingKey); // create test data using the random key std::string format_str = "# Wallet dump created by Zcash v0.11.2.0.z8-9155cc6-dirty (2016-08-11 11:37:00 -0700)\n" @@ -503,8 +503,7 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importwallet) // Verify the spending key is the same as the test data libzcash::SpendingKey k; BOOST_CHECK(pwalletMain->GetSpendingKey(addr, k)); - CZCSpendingKey spendingkey(k); - BOOST_CHECK_EQUAL(testKey, spendingkey.ToString()); + BOOST_CHECK_EQUAL(testKey, EncodeSpendingKey(k)); } @@ -528,7 +527,7 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importexport) // error if invalid args auto sk = libzcash::SpendingKey::random(); - std::string prefix = std::string("z_importkey ") + CZCSpendingKey(sk).ToString() + " yes "; + std::string prefix = std::string("z_importkey ") + EncodeSpendingKey(sk) + " yes "; BOOST_CHECK_THROW(CallRPC(prefix + "-1"), runtime_error); BOOST_CHECK_THROW(CallRPC(prefix + "2147483647"), runtime_error); // allowed, but > height of active chain tip BOOST_CHECK_THROW(CallRPC(prefix + "2147483648"), runtime_error); // not allowed, > int32 used for nHeight @@ -545,7 +544,7 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importexport) auto testSpendingKey = libzcash::SpendingKey::random(); auto testPaymentAddress = testSpendingKey.address(); std::string testAddr = EncodePaymentAddress(testPaymentAddress); - std::string testKey = CZCSpendingKey(testSpendingKey).ToString(); + std::string testKey = EncodeSpendingKey(testSpendingKey); BOOST_CHECK_NO_THROW(CallRPC(string("z_importkey ") + testKey)); BOOST_CHECK_NO_THROW(retValue = CallRPC(string("z_exportkey ") + testAddr)); BOOST_CHECK_EQUAL(retValue.get_str(), testKey); diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index 9b5d35072..e9354d179 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -295,9 +295,9 @@ UniValue importwallet_impl(const UniValue& params, bool fHelp, bool fImportZKeys // Let's see if the address is a valid Zcash spending key if (fImportZKeys) { - try { - CZCSpendingKey spendingkey(vstr[0]); - libzcash::SpendingKey key = spendingkey.Get(); + auto spendingkey = DecodeSpendingKey(vstr[0]); + if (spendingkey) { + libzcash::SpendingKey key = *spendingkey; libzcash::PaymentAddress addr = key.address(); if (pwalletMain->HaveSpendingKey(addr)) { LogPrint("zrpc", "Skipping import of zaddr %s (key already present)\n", EncodePaymentAddress(addr)); @@ -313,9 +313,8 @@ UniValue importwallet_impl(const UniValue& params, bool fHelp, bool fImportZKeys // Successfully imported zaddr. Now import the metadata. pwalletMain->mapZKeyMetadata[addr].nCreateTime = nTime; continue; - } - catch (const std::runtime_error &e) { - LogPrint("zrpc","Importing detected an error: %s\n", e.what()); + } else { + LogPrint("zrpc", "Importing detected an error: invalid spending key. Trying as a transparent key...\n"); // Not a valid spending key, so carry on and see if it's a Zcash style address. } } @@ -536,7 +535,7 @@ UniValue dumpwallet_impl(const UniValue& params, bool fHelp, bool fDumpZKeys) libzcash::SpendingKey key; if (pwalletMain->GetSpendingKey(addr, key)) { std::string strTime = EncodeDumpTime(pwalletMain->mapZKeyMetadata[addr].nCreateTime); - file << strprintf("%s %s # zaddr=%s\n", CZCSpendingKey(key).ToString(), strTime, EncodePaymentAddress(addr)); + file << strprintf("%s %s # zaddr=%s\n", EncodeSpendingKey(key), strTime, EncodePaymentAddress(addr)); } } file << "\n"; @@ -614,8 +613,11 @@ UniValue z_importkey(const UniValue& params, bool fHelp) } string strSecret = params[0].get_str(); - CZCSpendingKey spendingkey(strSecret); - auto key = spendingkey.Get(); + auto spendingkey = DecodeSpendingKey(strSecret); + if (!spendingkey) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid spending key"); + } + auto key = *spendingkey; auto addr = key.address(); { @@ -770,8 +772,7 @@ UniValue z_exportkey(const UniValue& params, bool fHelp) if (!pwalletMain->GetSpendingKey(addr, k)) throw JSONRPCError(RPC_WALLET_ERROR, "Wallet does not hold private zkey for this zaddr"); - CZCSpendingKey spendingkey(k); - return spendingkey.ToString(); + return EncodeSpendingKey(k); } UniValue z_exportviewingkey(const UniValue& params, bool fHelp) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index ca6c216e6..7f433bb3c 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2792,8 +2792,11 @@ UniValue zc_raw_receive(const UniValue& params, bool fHelp) LOCK(cs_main); - CZCSpendingKey spendingkey(params[0].get_str()); - SpendingKey k = spendingkey.Get(); + auto spendingkey = DecodeSpendingKey(params[0].get_str()); + if (!spendingkey) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid spending key"); + } + SpendingKey k = *spendingkey; uint256 epk; unsigned char nonce; @@ -2903,8 +2906,11 @@ UniValue zc_raw_joinsplit(const UniValue& params, bool fHelp) std::vector commitments; for (const string& name_ : inputs.getKeys()) { - CZCSpendingKey spendingkey(inputs[name_].get_str()); - SpendingKey k = spendingkey.Get(); + auto spendingkey = DecodeSpendingKey(inputs[name_].get_str()); + if (!spendingkey) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid spending key"); + } + SpendingKey k = *spendingkey; keys.push_back(k); @@ -3061,12 +3067,11 @@ UniValue zc_raw_keygen(const UniValue& params, bool fHelp) auto addr = k.address(); auto viewing_key = k.viewing_key(); - CZCSpendingKey spendingkey(k); CZCViewingKey viewingkey(viewing_key); UniValue result(UniValue::VOBJ); result.push_back(Pair("zcaddress", EncodePaymentAddress(addr))); - result.push_back(Pair("zcsecretkey", spendingkey.ToString())); + result.push_back(Pair("zcsecretkey", EncodeSpendingKey(k))); result.push_back(Pair("zcviewingkey", viewingkey.ToString())); return result; } From 8bf3a3d7006425cdf52dd5d1ca1f1766a9b52db1 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 24 Apr 2018 22:53:54 +0100 Subject: [PATCH 4/8] Introduce wrappers around CZCViewingKey --- src/base58.cpp | 15 +++++++++++++++ src/base58.h | 3 +++ src/wallet/rpcdump.cpp | 10 ++++++---- src/wallet/rpcwallet.cpp | 4 +--- 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/base58.cpp b/src/base58.cpp index 90982cf95..46a03e0ab 100644 --- a/src/base58.cpp +++ b/src/base58.cpp @@ -379,6 +379,21 @@ boost::optional DecodePaymentAddress(const std::string } } +std::string EncodeViewingKey(const libzcash::ViewingKey& vk) +{ + return CZCViewingKey(vk).ToString(); +} + +boost::optional DecodeViewingKey(const std::string& str) +{ + CZCViewingKey vk(str); + try { + return vk.Get(); + } catch (const std::runtime_error&) { + return boost::none; + } +} + std::string EncodeSpendingKey(const libzcash::SpendingKey& zkey) { return CZCSpendingKey(zkey).ToString(); diff --git a/src/base58.h b/src/base58.h index da9b7dd1e..0cc62b456 100644 --- a/src/base58.h +++ b/src/base58.h @@ -182,6 +182,9 @@ bool IsValidDestinationString(const std::string& str, const CChainParams& params std::string EncodePaymentAddress(const libzcash::PaymentAddress& zaddr); boost::optional DecodePaymentAddress(const std::string& str); +std::string EncodeViewingKey(const libzcash::ViewingKey& vk); +boost::optional DecodeViewingKey(const std::string& str); + std::string EncodeSpendingKey(const libzcash::SpendingKey& zkey); boost::optional DecodeSpendingKey(const std::string& str); diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index e9354d179..8d61c6170 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -705,8 +705,11 @@ UniValue z_importviewingkey(const UniValue& params, bool fHelp) } string strVKey = params[0].get_str(); - CZCViewingKey viewingkey(strVKey); - auto vkey = viewingkey.Get(); + auto viewingkey = DecodeViewingKey(strVKey); + if (!viewingkey) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid viewing key"); + } + auto vkey = *viewingkey; auto addr = vkey.address(); { @@ -815,6 +818,5 @@ UniValue z_exportviewingkey(const UniValue& params, bool fHelp) vk = k.viewing_key(); } - CZCViewingKey viewingkey(vk); - return viewingkey.ToString(); + return EncodeViewingKey(vk); } diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 7f433bb3c..ed2a120f2 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3067,12 +3067,10 @@ UniValue zc_raw_keygen(const UniValue& params, bool fHelp) auto addr = k.address(); auto viewing_key = k.viewing_key(); - CZCViewingKey viewingkey(viewing_key); - UniValue result(UniValue::VOBJ); result.push_back(Pair("zcaddress", EncodePaymentAddress(addr))); result.push_back(Pair("zcsecretkey", EncodeSpendingKey(k))); - result.push_back(Pair("zcviewingkey", viewingkey.ToString())); + result.push_back(Pair("zcviewingkey", EncodeViewingKey(viewing_key))); return result; } From aa333ee8f2a8eb24e59a87784f83446e4b96d09f Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 24 Apr 2018 23:45:04 +0100 Subject: [PATCH 5/8] Implement {Encode,Decode}PaymentAddress etc. without CZCEncoding --- src/base58.cpp | 137 ++++++++++++++++++++++--------------------------- src/base58.h | 44 ---------------- 2 files changed, 61 insertions(+), 120 deletions(-) diff --git a/src/base58.cpp b/src/base58.cpp index 46a03e0ab..996e49e3c 100644 --- a/src/base58.cpp +++ b/src/base58.cpp @@ -306,105 +306,90 @@ bool IsValidDestinationString(const std::string& str) return IsValidDestinationString(str, Params()); } -template -bool CZCEncoding::Set(const DATA_TYPE& addr) -{ - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss << addr; - std::vector addrSerialized(ss.begin(), ss.end()); - assert(addrSerialized.size() == SER_SIZE); - SetData(Params().Base58Prefix(PREFIX), &addrSerialized[0], SER_SIZE); - return true; -} - -template -DATA_TYPE CZCEncoding::Get() const -{ - if (vchData.size() != SER_SIZE) { - throw std::runtime_error( - PrependName(" is invalid") - ); - } - - if (vchVersion != Params().Base58Prefix(PREFIX)) { - throw std::runtime_error( - PrependName(" is for wrong network type") - ); - } - - std::vector serialized(vchData.begin(), vchData.end()); - - CDataStream ss(serialized, SER_NETWORK, PROTOCOL_VERSION); - DATA_TYPE ret; - ss >> ret; - return ret; -} - -// Explicit instantiations for libzcash::PaymentAddress -template bool CZCEncoding::Set(const libzcash::PaymentAddress& addr); -template libzcash::PaymentAddress CZCEncoding::Get() const; - -// Explicit instantiations for libzcash::ViewingKey -template bool CZCEncoding::Set(const libzcash::ViewingKey& vk); -template libzcash::ViewingKey CZCEncoding::Get() const; - -// Explicit instantiations for libzcash::SpendingKey -template bool CZCEncoding::Set(const libzcash::SpendingKey& sk); -template libzcash::SpendingKey CZCEncoding::Get() const; - std::string EncodePaymentAddress(const libzcash::PaymentAddress& zaddr) { - return CZCPaymentAddress(zaddr).ToString(); + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + ss << zaddr; + std::vector data = Params().Base58Prefix(CChainParams::ZCPAYMENT_ADDRRESS); + data.insert(data.end(), ss.begin(), ss.end()); + return EncodeBase58Check(data); } boost::optional DecodePaymentAddress(const std::string& str) { - CZCPaymentAddress addr(str); - try { - return addr.Get(); - } catch (const std::runtime_error&) { - return boost::none; + std::vector data; + if (DecodeBase58Check(str, data)) { + const std::vector& zaddr_prefix = Params().Base58Prefix(CChainParams::ZCPAYMENT_ADDRRESS); + if ((data.size() == libzcash::SerializedPaymentAddressSize + zaddr_prefix.size()) && + std::equal(zaddr_prefix.begin(), zaddr_prefix.end(), data.begin())) { + CSerializeData serialized(data.begin() + zaddr_prefix.size(), data.end()); + CDataStream ss(serialized, SER_NETWORK, PROTOCOL_VERSION); + libzcash::PaymentAddress ret; + ss >> ret; + return ret; + } } + return boost::none; } std::string EncodeViewingKey(const libzcash::ViewingKey& vk) { - return CZCViewingKey(vk).ToString(); + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + ss << vk; + std::vector data = Params().Base58Prefix(CChainParams::ZCVIEWING_KEY); + data.insert(data.end(), ss.begin(), ss.end()); + std::string ret = EncodeBase58Check(data); + memory_cleanse(data.data(), data.size()); + return ret; } boost::optional DecodeViewingKey(const std::string& str) { - CZCViewingKey vk(str); - try { - return vk.Get(); - } catch (const std::runtime_error&) { - return boost::none; + std::vector data; + if (DecodeBase58Check(str, data)) { + const std::vector& vk_prefix = Params().Base58Prefix(CChainParams::ZCVIEWING_KEY); + if ((data.size() == libzcash::SerializedViewingKeySize + vk_prefix.size()) && + std::equal(vk_prefix.begin(), vk_prefix.end(), data.begin())) { + CSerializeData serialized(data.begin() + vk_prefix.size(), data.end()); + CDataStream ss(serialized, SER_NETWORK, PROTOCOL_VERSION); + libzcash::ViewingKey ret; + ss >> ret; + memory_cleanse(serialized.data(), serialized.size()); + memory_cleanse(data.data(), data.size()); + return ret; + } } + memory_cleanse(data.data(), data.size()); + return boost::none; } std::string EncodeSpendingKey(const libzcash::SpendingKey& zkey) { - return CZCSpendingKey(zkey).ToString(); + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + ss << zkey; + std::vector data = Params().Base58Prefix(CChainParams::ZCSPENDING_KEY); + data.insert(data.end(), ss.begin(), ss.end()); + std::string ret = EncodeBase58Check(data); + memory_cleanse(data.data(), data.size()); + return ret; } boost::optional DecodeSpendingKey(const std::string& str) { - CZCSpendingKey key(str); - try { - return key.Get(); - } catch (const std::runtime_error&) { - return boost::none; + std::vector data; + if (DecodeBase58Check(str, data)) { + const std::vector& zkey_prefix = Params().Base58Prefix(CChainParams::ZCSPENDING_KEY); + if ((data.size() == libzcash::SerializedSpendingKeySize + zkey_prefix.size()) && + std::equal(zkey_prefix.begin(), zkey_prefix.end(), data.begin())) { + CSerializeData serialized(data.begin() + zkey_prefix.size(), data.end()); + CDataStream ss(serialized, SER_NETWORK, PROTOCOL_VERSION); + libzcash::SpendingKey ret; + ss >> ret; + memory_cleanse(serialized.data(), serialized.size()); + memory_cleanse(data.data(), data.size()); + return ret; + } } + memory_cleanse(data.data(), data.size()); + return boost::none; } diff --git a/src/base58.h b/src/base58.h index 0cc62b456..6ad323173 100644 --- a/src/base58.h +++ b/src/base58.h @@ -95,50 +95,6 @@ public: bool operator> (const CBase58Data& b58) const { return CompareTo(b58) > 0; } }; -template -class CZCEncoding : public CBase58Data { -protected: - virtual std::string PrependName(const std::string& s) const = 0; - -public: - bool Set(const DATA_TYPE& addr); - - DATA_TYPE Get() const; -}; - -class CZCPaymentAddress : public CZCEncoding { -protected: - std::string PrependName(const std::string& s) const { return "payment address" + s; } - -public: - CZCPaymentAddress() {} - - CZCPaymentAddress(const std::string& strAddress) { SetString(strAddress.c_str(), 2); } - CZCPaymentAddress(const libzcash::PaymentAddress& addr) { Set(addr); } -}; - -class CZCViewingKey : public CZCEncoding { -protected: - std::string PrependName(const std::string& s) const { return "viewing key" + s; } - -public: - CZCViewingKey() {} - - CZCViewingKey(const std::string& strViewingKey) { SetString(strViewingKey.c_str(), 3); } - CZCViewingKey(const libzcash::ViewingKey& vk) { Set(vk); } -}; - -class CZCSpendingKey : public CZCEncoding { -protected: - std::string PrependName(const std::string& s) const { return "spending key" + s; } - -public: - CZCSpendingKey() {} - - CZCSpendingKey(const std::string& strAddress) { SetString(strAddress.c_str(), 2); } - CZCSpendingKey(const libzcash::SpendingKey& addr) { Set(addr); } -}; - CKey DecodeSecret(const std::string& str); std::string EncodeSecret(const CKey& key); From 3e60c9fabd05b677198177f75c8f020bc0f414b3 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 19 Sep 2017 17:13:46 -0700 Subject: [PATCH 6/8] Stop using CBase58Data for ext keys --- src/base58.cpp | 108 +++++++++++++++++---------------------- src/base58.h | 65 ++--------------------- src/test/bip32_tests.cpp | 16 ++---- 3 files changed, 55 insertions(+), 134 deletions(-) diff --git a/src/base58.cpp b/src/base58.cpp index 996e49e3c..a37139486 100644 --- a/src/base58.cpp +++ b/src/base58.cpp @@ -144,67 +144,6 @@ bool DecodeBase58Check(const std::string& str, std::vector& vchRe return DecodeBase58Check(str.c_str(), vchRet); } -CBase58Data::CBase58Data() -{ - vchVersion.clear(); - vchData.clear(); -} - -void CBase58Data::SetData(const std::vector& 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& 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 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, unsigned int nVersionBytes) -{ - return SetString(str.c_str(), nVersionBytes); -} - -std::string CBase58Data::ToString() const -{ - std::vector 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 @@ -286,6 +225,53 @@ std::string EncodeSecret(const CKey& key) return ret; } +CExtPubKey DecodeExtPubKey(const std::string& str) +{ + CExtPubKey key; + std::vector data; + if (DecodeBase58Check(str, data)) { + const std::vector& 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 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 data; + if (DecodeBase58Check(str, data)) { + const std::vector& 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 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); diff --git a/src/base58.h b/src/base58.h index 6ad323173..60a887dcf 100644 --- a/src/base58.h +++ b/src/base58.h @@ -65,70 +65,13 @@ inline bool DecodeBase58Check(const char* psz, std::vector& vchRe */ inline bool DecodeBase58Check(const std::string& str, std::vector& vchRet); -/** - * Base class for all base58-encoded data - */ -class CBase58Data -{ -protected: - //! the version byte(s) - std::vector vchVersion; - - //! the actually encoded data - typedef std::vector > vector_uchar; - vector_uchar vchData; - - CBase58Data(); - void SetData(const std::vector &vchVersionIn, const void* pdata, size_t nSize); - void SetData(const std::vector &vchVersionIn, const unsigned char *pbegin, const unsigned char *pend); - -public: - bool SetString(const char* psz, unsigned int nVersionBytes); - bool SetString(const std::string& str, unsigned int nVersionBytes); - 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 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 CBitcoinExtKey; -typedef CBitcoinExtKeyBase 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); diff --git a/src/test/bip32_tests.cpp b/src/test/bip32_tests.cpp index 41b541747..1c8f83d6d 100644 --- a/src/test/bip32_tests.cpp +++ b/src/test/bip32_tests.cpp @@ -90,20 +90,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; From 3d31e09cbb63984da88828b8acebba64e04f7a2d Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 19 Sep 2017 18:12:25 -0700 Subject: [PATCH 7/8] Split key_io (address/key encodings) off from base58 --- src/Makefile.am | 2 + src/base58.cpp | 249 +------------------------------------ src/base58.h | 33 +---- src/bitcoin-tx.cpp | 2 +- src/core_write.cpp | 2 +- src/httprpc.cpp | 2 +- src/key_io.cpp | 254 ++++++++++++++++++++++++++++++++++++++ src/key_io.h | 40 ++++++ src/rpcmisc.cpp | 2 +- src/rpcrawtransaction.cpp | 2 +- src/rpcserver.cpp | 2 +- src/test/base58_tests.cpp | 1 + src/test/bip32_tests.cpp | 2 +- src/test/bloom_tests.cpp | 2 +- src/test/key_tests.cpp | 2 +- src/test/rpc_tests.cpp | 2 +- src/wallet/rpcdump.cpp | 2 +- src/wallet/rpcwallet.cpp | 2 +- src/wallet/wallet.cpp | 2 +- src/wallet/walletdb.cpp | 2 +- 20 files changed, 315 insertions(+), 292 deletions(-) create mode 100644 src/key_io.cpp create mode 100644 src/key_io.h diff --git a/src/Makefile.am b/src/Makefile.am index 8cc654c37..0d2a7a7eb 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -152,6 +152,7 @@ BITCOIN_CORE_H = \ httpserver.h \ init.h \ key.h \ + key_io.h \ keystore.h \ dbwrapper.h \ limitedmap.h \ @@ -368,6 +369,7 @@ libbitcoin_common_a_SOURCES = \ core_write.cpp \ hash.cpp \ key.cpp \ + key_io.cpp \ keystore.cpp \ netbase.cpp \ primitives/block.cpp \ diff --git a/src/base58.cpp b/src/base58.cpp index a37139486..137ce2c9e 100644 --- a/src/base58.cpp +++ b/src/base58.cpp @@ -4,21 +4,12 @@ #include "base58.h" -#include "hash.h" -#include "script/script.h" -#include "uint256.h" +#include +#include -#include "version.h" -#include "streams.h" - -#include -#include - -#include #include #include - /** All alphanumeric characters except for "0", "I", "O", and "l" */ static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; @@ -143,239 +134,3 @@ bool DecodeBase58Check(const std::string& str, std::vector& vchRe { return DecodeBase58Check(str.c_str(), vchRet); } - -namespace -{ -class DestinationEncoder : public boost::static_visitor -{ -private: - const CChainParams& m_params; - -public: - DestinationEncoder(const CChainParams& params) : m_params(params) {} - - std::string operator()(const CKeyID& id) const - { - std::vector data = m_params.Base58Prefix(CChainParams::PUBKEY_ADDRESS); - data.insert(data.end(), id.begin(), id.end()); - return EncodeBase58Check(data); - } - - std::string operator()(const CScriptID& id) const - { - std::vector data = m_params.Base58Prefix(CChainParams::SCRIPT_ADDRESS); - data.insert(data.end(), id.begin(), id.end()); - return EncodeBase58Check(data); - } - - std::string operator()(const CNoDestination& no) const { return ""; } -}; - -CTxDestination DecodeDestination(const std::string& str, const CChainParams& params) -{ - std::vector data; - uint160 hash; - if (DecodeBase58Check(str, data)) { - // base58-encoded Bitcoin addresses. - // Public-key-hash-addresses have version 0 (or 111 testnet). - // The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key. - const std::vector& pubkey_prefix = params.Base58Prefix(CChainParams::PUBKEY_ADDRESS); - if (data.size() == hash.size() + pubkey_prefix.size() && std::equal(pubkey_prefix.begin(), pubkey_prefix.end(), data.begin())) { - std::copy(data.begin() + pubkey_prefix.size(), data.end(), hash.begin()); - return CKeyID(hash); - } - // Script-hash-addresses have version 5 (or 196 testnet). - // The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script. - const std::vector& script_prefix = params.Base58Prefix(CChainParams::SCRIPT_ADDRESS); - if (data.size() == hash.size() + script_prefix.size() && std::equal(script_prefix.begin(), script_prefix.end(), data.begin())) { - std::copy(data.begin() + script_prefix.size(), data.end(), hash.begin()); - return CScriptID(hash); - } - } - return CNoDestination(); -} -} // namespace - -CKey DecodeSecret(const std::string& str) -{ - CKey key; - std::vector data; - if (DecodeBase58Check(str, data)) { - const std::vector& 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; -} - -std::string EncodeSecret(const CKey& key) -{ - assert(key.IsValid()); - std::vector data = Params().Base58Prefix(CChainParams::SECRET_KEY); - 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; -} - -CExtPubKey DecodeExtPubKey(const std::string& str) -{ - CExtPubKey key; - std::vector data; - if (DecodeBase58Check(str, data)) { - const std::vector& 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 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 data; - if (DecodeBase58Check(str, data)) { - const std::vector& 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 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); -} - -CTxDestination DecodeDestination(const std::string& str) -{ - return DecodeDestination(str, Params()); -} - -bool IsValidDestinationString(const std::string& str, const CChainParams& params) -{ - return IsValidDestination(DecodeDestination(str, params)); -} - -bool IsValidDestinationString(const std::string& str) -{ - return IsValidDestinationString(str, Params()); -} - -std::string EncodePaymentAddress(const libzcash::PaymentAddress& zaddr) -{ - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss << zaddr; - std::vector data = Params().Base58Prefix(CChainParams::ZCPAYMENT_ADDRRESS); - data.insert(data.end(), ss.begin(), ss.end()); - return EncodeBase58Check(data); -} - -boost::optional DecodePaymentAddress(const std::string& str) -{ - std::vector data; - if (DecodeBase58Check(str, data)) { - const std::vector& zaddr_prefix = Params().Base58Prefix(CChainParams::ZCPAYMENT_ADDRRESS); - if ((data.size() == libzcash::SerializedPaymentAddressSize + zaddr_prefix.size()) && - std::equal(zaddr_prefix.begin(), zaddr_prefix.end(), data.begin())) { - CSerializeData serialized(data.begin() + zaddr_prefix.size(), data.end()); - CDataStream ss(serialized, SER_NETWORK, PROTOCOL_VERSION); - libzcash::PaymentAddress ret; - ss >> ret; - return ret; - } - } - return boost::none; -} - -std::string EncodeViewingKey(const libzcash::ViewingKey& vk) -{ - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss << vk; - std::vector data = Params().Base58Prefix(CChainParams::ZCVIEWING_KEY); - data.insert(data.end(), ss.begin(), ss.end()); - std::string ret = EncodeBase58Check(data); - memory_cleanse(data.data(), data.size()); - return ret; -} - -boost::optional DecodeViewingKey(const std::string& str) -{ - std::vector data; - if (DecodeBase58Check(str, data)) { - const std::vector& vk_prefix = Params().Base58Prefix(CChainParams::ZCVIEWING_KEY); - if ((data.size() == libzcash::SerializedViewingKeySize + vk_prefix.size()) && - std::equal(vk_prefix.begin(), vk_prefix.end(), data.begin())) { - CSerializeData serialized(data.begin() + vk_prefix.size(), data.end()); - CDataStream ss(serialized, SER_NETWORK, PROTOCOL_VERSION); - libzcash::ViewingKey ret; - ss >> ret; - memory_cleanse(serialized.data(), serialized.size()); - memory_cleanse(data.data(), data.size()); - return ret; - } - } - memory_cleanse(data.data(), data.size()); - return boost::none; -} - -std::string EncodeSpendingKey(const libzcash::SpendingKey& zkey) -{ - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss << zkey; - std::vector data = Params().Base58Prefix(CChainParams::ZCSPENDING_KEY); - data.insert(data.end(), ss.begin(), ss.end()); - std::string ret = EncodeBase58Check(data); - memory_cleanse(data.data(), data.size()); - return ret; -} - -boost::optional DecodeSpendingKey(const std::string& str) -{ - std::vector data; - if (DecodeBase58Check(str, data)) { - const std::vector& zkey_prefix = Params().Base58Prefix(CChainParams::ZCSPENDING_KEY); - if ((data.size() == libzcash::SerializedSpendingKeySize + zkey_prefix.size()) && - std::equal(zkey_prefix.begin(), zkey_prefix.end(), data.begin())) { - CSerializeData serialized(data.begin() + zkey_prefix.size(), data.end()); - CDataStream ss(serialized, SER_NETWORK, PROTOCOL_VERSION); - libzcash::SpendingKey ret; - ss >> ret; - memory_cleanse(serialized.data(), serialized.size()); - memory_cleanse(data.data(), data.size()); - return ret; - } - } - memory_cleanse(data.data(), data.size()); - return boost::none; -} diff --git a/src/base58.h b/src/base58.h index 60a887dcf..3c926fca0 100644 --- a/src/base58.h +++ b/src/base58.h @@ -14,13 +14,6 @@ #ifndef BITCOIN_BASE58_H #define BITCOIN_BASE58_H -#include "chainparams.h" -#include "key.h" -#include "pubkey.h" -#include "script/standard.h" -#include "support/allocators/zeroafterfree.h" -#include "zcash/Address.hpp" - #include #include @@ -57,34 +50,12 @@ std::string EncodeBase58Check(const std::vector& vchIn); * Decode a base58-encoded string (psz) that includes a checksum into a byte * vector (vchRet), return true if decoding is successful */ -inline bool DecodeBase58Check(const char* psz, std::vector& vchRet); +bool DecodeBase58Check(const char* psz, std::vector& vchRet); /** * Decode a base58-encoded string (str) that includes a checksum into a byte * vector (vchRet), return true if decoding is successful */ -inline bool DecodeBase58Check(const std::string& str, std::vector& vchRet); - -CKey DecodeSecret(const std::string& str); -std::string EncodeSecret(const CKey& key); - -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); -bool IsValidDestinationString(const std::string& str); -bool IsValidDestinationString(const std::string& str, const CChainParams& params); - -std::string EncodePaymentAddress(const libzcash::PaymentAddress& zaddr); -boost::optional DecodePaymentAddress(const std::string& str); - -std::string EncodeViewingKey(const libzcash::ViewingKey& vk); -boost::optional DecodeViewingKey(const std::string& str); - -std::string EncodeSpendingKey(const libzcash::SpendingKey& zkey); -boost::optional DecodeSpendingKey(const std::string& str); +bool DecodeBase58Check(const std::string& str, std::vector& vchRet); #endif // BITCOIN_BASE58_H diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index aa2523039..3ee3c0169 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -2,12 +2,12 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "base58.h" #include "clientversion.h" #include "coins.h" #include "consensus/consensus.h" #include "consensus/upgrades.h" #include "core_io.h" +#include "key_io.h" #include "keystore.h" #include "primitives/transaction.h" #include "script/script.h" diff --git a/src/core_write.cpp b/src/core_write.cpp index df1f83456..43344656b 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -4,7 +4,7 @@ #include "core_io.h" -#include "base58.h" +#include "key_io.h" #include "primitives/transaction.h" #include "script/script.h" #include "script/standard.h" diff --git a/src/httprpc.cpp b/src/httprpc.cpp index 6d37fdfac..ade815788 100644 --- a/src/httprpc.cpp +++ b/src/httprpc.cpp @@ -1,8 +1,8 @@ #include "httprpc.h" -#include "base58.h" #include "chainparams.h" #include "httpserver.h" +#include "key_io.h" #include "rpcprotocol.h" #include "rpcserver.h" #include "random.h" diff --git a/src/key_io.cpp b/src/key_io.cpp new file mode 100644 index 000000000..77d63cca4 --- /dev/null +++ b/src/key_io.cpp @@ -0,0 +1,254 @@ +// Copyright (c) 2014-2016 The Bitcoin Core developers +// Copyright (c) 2016-2018 The Zcash developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include +#include