From 70b4ad2dcd07effd65c034d8a3351849b2d919a5 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 29 Aug 2018 00:07:07 +0100 Subject: [PATCH] wallet: Switch from SaplingSpendingKey to SaplingExtendedSpendingKey The wallet now only stores Sapling extended spending keys, and thus can only be used with keys generated from an HDSeed via ZIP 32. Note that not all Sapling keys in the wallet will correspond to the wallet's HDSeed, as a standalone Sapling xsk can be imported via z_importkey. However, it must have been generated from a seed itself, and thus is more likely to be backed up elsewhere. --- src/chainparams.cpp | 6 +- src/chainparams.h | 2 +- src/gtest/test_keys.cpp | 17 +++-- src/gtest/test_keystore.cpp | 10 ++- src/key_io.cpp | 12 +-- src/key_io.h | 1 + src/keystore.cpp | 4 +- src/keystore.h | 11 ++- src/test/key_tests.cpp | 16 ++-- src/test/rpc_wallet_tests.cpp | 10 ++- src/wallet/asyncrpcoperation_sendmany.cpp | 4 +- src/wallet/crypter.cpp | 18 ++--- src/wallet/crypter.h | 4 +- src/wallet/gtest/test_wallet.cpp | 89 ++++++++++++++--------- src/wallet/gtest/test_wallet_zkeys.cpp | 23 ++++-- src/wallet/rpcdump.cpp | 10 +-- src/wallet/rpcwallet.cpp | 1 + src/wallet/wallet.cpp | 55 +++++++++----- src/wallet/wallet.h | 2 +- src/zcash/Address.cpp | 4 - src/zcash/Address.hpp | 4 - src/zcash/zip32.cpp | 4 + src/zcash/zip32.h | 5 ++ 23 files changed, 190 insertions(+), 122 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 9813a9ce5..46777f54e 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -158,7 +158,7 @@ public: bech32HRPs[SAPLING_PAYMENT_ADDRESS] = "zs"; bech32HRPs[SAPLING_FULL_VIEWING_KEY] = "zviews"; bech32HRPs[SAPLING_INCOMING_VIEWING_KEY] = "zivks"; - bech32HRPs[SAPLING_SPENDING_KEY] = "secret-spending-key-main"; + bech32HRPs[SAPLING_EXTENDED_SPEND_KEY] = "secret-extended-key-main"; vFixedSeeds = std::vector(pnSeed6_main, pnSeed6_main + ARRAYLEN(pnSeed6_main)); @@ -329,7 +329,7 @@ public: bech32HRPs[SAPLING_PAYMENT_ADDRESS] = "ztestsapling"; bech32HRPs[SAPLING_FULL_VIEWING_KEY] = "zviewtestsapling"; bech32HRPs[SAPLING_INCOMING_VIEWING_KEY] = "zivktestsapling"; - bech32HRPs[SAPLING_SPENDING_KEY] = "secret-spending-key-test"; + bech32HRPs[SAPLING_EXTENDED_SPEND_KEY] = "secret-extended-key-test"; vFixedSeeds = std::vector(pnSeed6_test, pnSeed6_test + ARRAYLEN(pnSeed6_test)); @@ -457,7 +457,7 @@ public: bech32HRPs[SAPLING_PAYMENT_ADDRESS] = "zregtestsapling"; bech32HRPs[SAPLING_FULL_VIEWING_KEY] = "zviewregtestsapling"; bech32HRPs[SAPLING_INCOMING_VIEWING_KEY] = "zivkregtestsapling"; - bech32HRPs[SAPLING_SPENDING_KEY] = "secret-spending-key-regtest"; + bech32HRPs[SAPLING_EXTENDED_SPEND_KEY] = "secret-extended-key-regtest"; // Founders reward script expects a vector of 2-of-3 multisig addresses vFoundersRewardAddress = { "t2FwcEhFdNXuFMv1tcYwaBJtYVtMj8b1uTg" }; diff --git a/src/chainparams.h b/src/chainparams.h index f24466e9a..2649fa9be 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -60,7 +60,7 @@ public: SAPLING_PAYMENT_ADDRESS, SAPLING_FULL_VIEWING_KEY, SAPLING_INCOMING_VIEWING_KEY, - SAPLING_SPENDING_KEY, + SAPLING_EXTENDED_SPEND_KEY, MAX_BECH32_TYPES }; diff --git a/src/gtest/test_keys.cpp b/src/gtest/test_keys.cpp index 23ed00a65..450bc5708 100644 --- a/src/gtest/test_keys.cpp +++ b/src/gtest/test_keys.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include @@ -8,23 +9,27 @@ TEST(Keys, DISABLED_EncodeAndDecodeSapling) { SelectParams(CBaseChainParams::MAIN); - for (size_t i = 0; i < 1000; i++) { - auto sk = libzcash::SaplingSpendingKey::random(); + std::vector> rawSeed(32); + HDSeed seed(rawSeed); + auto m = libzcash::SaplingExtendedSpendingKey::Master(seed); + + for (uint32_t i = 0; i < 1000; i++) { + auto sk = m.Derive(i); { std::string sk_string = EncodeSpendingKey(sk); EXPECT_EQ( sk_string.substr(0, 24), - Params().Bech32HRP(CChainParams::SAPLING_SPENDING_KEY)); + Params().Bech32HRP(CChainParams::SAPLING_EXTENDED_SPEND_KEY)); auto spendingkey2 = DecodeSpendingKey(sk_string); EXPECT_TRUE(IsValidSpendingKey(spendingkey2)); - ASSERT_TRUE(boost::get(&spendingkey2) != nullptr); - auto sk2 = boost::get(spendingkey2); + ASSERT_TRUE(boost::get(&spendingkey2) != nullptr); + auto sk2 = boost::get(spendingkey2); EXPECT_EQ(sk, sk2); } { - auto addr = sk.default_address(); + auto addr = sk.DefaultAddress(); std::string addr_string = EncodePaymentAddress(addr); EXPECT_EQ( diff --git a/src/gtest/test_keystore.cpp b/src/gtest/test_keystore.cpp index 33d5f0411..7059f2fc8 100644 --- a/src/gtest/test_keystore.cpp +++ b/src/gtest/test_keystore.cpp @@ -194,14 +194,16 @@ TEST(keystore_tests, StoreAndRetrieveViewingKey) { // Sapling TEST(keystore_tests, StoreAndRetrieveSaplingSpendingKey) { CBasicKeyStore keyStore; - libzcash::SaplingSpendingKey skOut; + libzcash::SaplingExtendedSpendingKey skOut; libzcash::SaplingFullViewingKey fvkOut; libzcash::SaplingIncomingViewingKey ivkOut; - auto sk = libzcash::SaplingSpendingKey::random(); - auto fvk = sk.full_viewing_key(); + std::vector> rawSeed(32); + HDSeed seed(rawSeed); + auto sk = libzcash::SaplingExtendedSpendingKey::Master(seed); + auto fvk = sk.expsk.full_viewing_key(); auto ivk = fvk.in_viewing_key(); - auto addr = sk.default_address(); + auto addr = sk.DefaultAddress(); // Sanity-check: we can't get a key we haven't added EXPECT_FALSE(keyStore.HaveSaplingSpendingKey(fvk)); diff --git a/src/key_io.cpp b/src/key_io.cpp index b129ce37b..636163638 100644 --- a/src/key_io.cpp +++ b/src/key_io.cpp @@ -142,7 +142,7 @@ public: return ret; } - std::string operator()(const libzcash::SaplingSpendingKey& zkey) const + std::string operator()(const libzcash::SaplingExtendedSpendingKey& zkey) const { CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss << zkey; @@ -152,7 +152,7 @@ public: // See calculation comment below data.reserve((serkey.size() * 8 + 4) / 5); ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, serkey.begin(), serkey.end()); - std::string ret = bech32::Encode(m_params.Bech32HRP(CChainParams::SAPLING_SPENDING_KEY), data); + std::string ret = bech32::Encode(m_params.Bech32HRP(CChainParams::SAPLING_EXTENDED_SPEND_KEY), data); memory_cleanse(serkey.data(), serkey.size()); memory_cleanse(data.data(), data.size()); return ret; @@ -166,7 +166,7 @@ public: // regular serialized size in bytes, convert to bits, and then // perform ceiling division to get the number of 5-bit clusters. const size_t ConvertedSaplingPaymentAddressSize = ((32 + 11) * 8 + 4) / 5; -const size_t ConvertedSaplingSpendingKeySize = (32 * 8 + 4) / 5; +const size_t ConvertedSaplingExtendedSpendingKeySize = (ZIP32_XSK_SIZE * 8 + 4) / 5; } // namespace CKey DecodeSecret(const std::string& str) @@ -360,13 +360,13 @@ libzcash::SpendingKey DecodeSpendingKey(const std::string& str) Params().NetworkIDString() == "test" && GetBoolArg("-experimentalfeatures", false) && GetBoolArg("-developersapling", false)); - if (allowSapling && bech.first == Params().Bech32HRP(CChainParams::SAPLING_SPENDING_KEY) && - bech.second.size() == ConvertedSaplingSpendingKeySize) { + if (allowSapling && bech.first == Params().Bech32HRP(CChainParams::SAPLING_EXTENDED_SPEND_KEY) && + bech.second.size() == ConvertedSaplingExtendedSpendingKeySize) { // Bech32 decoding data.reserve((bech.second.size() * 5) / 8); if (ConvertBits<5, 8, false>([&](unsigned char c) { data.push_back(c); }, bech.second.begin(), bech.second.end())) { CDataStream ss(data, SER_NETWORK, PROTOCOL_VERSION); - libzcash::SaplingSpendingKey ret; + libzcash::SaplingExtendedSpendingKey ret; ss >> ret; memory_cleanse(data.data(), data.size()); return ret; diff --git a/src/key_io.h b/src/key_io.h index c01d1d836..47ca84fb8 100644 --- a/src/key_io.h +++ b/src/key_io.h @@ -12,6 +12,7 @@ #include #include