Auto merge of #3242 - str4d:3058-key-encoding-refactor, r=str4d

Key encoding refactor

Includes code cherry-picked from the following upstream PRs:

- bitcoin/bitcoin#11372
  - Only the first three commits (the fourth commit depends on #2390)

Part of #3058.
This commit is contained in:
Homu
2018-05-11 12:21:29 -07:00
34 changed files with 520 additions and 638 deletions

View File

@@ -9,6 +9,7 @@
#include "data/base58_keys_valid.json.h"
#include "key.h"
#include "key_io.h"
#include "script/script.h"
#include "test/test_bitcoin.h"
#include "uint256.h"
@@ -78,7 +79,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 +103,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 +119,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 +153,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 +170,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 +186,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);
}
}

View File

@@ -4,8 +4,8 @@
#include <boost/test/unit_test.hpp>
#include "base58.h"
#include "key.h"
#include "key_io.h"
#include "uint256.h"
#include "util.h"
#include "utilstrencodings.h"
@@ -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;

View File

@@ -4,9 +4,9 @@
#include "bloom.h"
#include "base58.h"
#include "clientversion.h"
#include "key.h"
#include "key_io.h"
#include "merkleblock.h"
#include "random.h"
#include "serialize.h"
@@ -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<unsigned char> vchPubKey(pubkey.begin(), pubkey.end());

View File

@@ -4,7 +4,7 @@
#include "key.h"
#include "base58.h"
#include "key_io.h"
#include "script/script.h"
#include "uint256.h"
#include "util.h"
@@ -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();
@@ -195,28 +190,28 @@ 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<bool>(spendingkey2));
SpendingKey sk2 = *spendingkey2;
BOOST_CHECK(sk.inner() == sk2.inner());
}
{
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<bool>(paymentaddr2));
PaymentAddress addr2 = paymentaddr2.Get();
PaymentAddress addr2 = *paymentaddr2;
BOOST_CHECK(addr.a_pk == addr2.a_pk);
BOOST_CHECK(addr.pk_enc == addr2.pk_enc);
}

View File

@@ -5,7 +5,7 @@
#include "rpcserver.h"
#include "rpcclient.h"
#include "base58.h"
#include "key_io.h"
#include "netbase.h"
#include "utilstrencodings.h"

View File

@@ -5,7 +5,7 @@
#include "rpcserver.h"
#include "rpcclient.h"
#include "base58.h"
#include "key_io.h"
#include "main.h"
#include "wallet/wallet.h"
@@ -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,12 +411,11 @@ 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 s2 = CZCSpendingKey(key).ToString();
std::string s1 = EncodePaymentAddress(addr);
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,8 +458,8 @@ 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 testKey = CZCSpendingKey(testSpendingKey).ToString();
std::string testAddr = EncodePaymentAddress(testPaymentAddress);
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"
@@ -498,15 +497,13 @@ 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
libzcash::SpendingKey k;
BOOST_CHECK(pwalletMain->GetSpendingKey(addr, k));
CZCSpendingKey spendingkey(k);
BOOST_CHECK_EQUAL(testKey, spendingkey.ToString());
BOOST_CHECK_EQUAL(testKey, EncodeSpendingKey(k));
}
@@ -530,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
@@ -546,8 +543,8 @@ 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 testKey = CZCSpendingKey(testSpendingKey).ToString();
std::string testAddr = EncodePaymentAddress(testPaymentAddress);
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);
@@ -566,7 +563,7 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importexport)
// Make new addresses for the set
for (int i=0; i<n2; i++) {
myaddrs.insert((pwalletMain->GenerateNewZKey()).ToString());
myaddrs.insert(EncodePaymentAddress(pwalletMain->GenerateNewZKey()));
}
// Verify number of addresses stored in wallet is n1+n2
@@ -593,8 +590,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 +912,8 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_parameters)
std::vector<char> 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 +948,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_parameters)
std::vector<SendManyRecipient> recipients = { SendManyRecipient("dummy",1.0, "") };
std::shared_ptr<AsyncRPCOperation> 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 +956,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_parameters)
std::vector<SendManyRecipient> recipients = { SendManyRecipient("dummy",1.0, "") };
std::shared_ptr<AsyncRPCOperation> 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 +990,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 +1388,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_shieldcoinbase_parameters)
std::vector<ShieldCoinbaseUTXO> inputs = { ShieldCoinbaseUTXO{uint256(),0,0} };
std::shared_ptr<AsyncRPCOperation> 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 +1413,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 +1538,8 @@ BOOST_AUTO_TEST_CASE(rpc_z_mergetoaddress_parameters)
std::vector<char> 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 +1586,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_mergetoaddress_parameters)
std::shared_ptr<AsyncRPCOperation> 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 +1609,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
{