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.
This commit is contained in:
@@ -158,7 +158,7 @@ public:
|
|||||||
bech32HRPs[SAPLING_PAYMENT_ADDRESS] = "zs";
|
bech32HRPs[SAPLING_PAYMENT_ADDRESS] = "zs";
|
||||||
bech32HRPs[SAPLING_FULL_VIEWING_KEY] = "zviews";
|
bech32HRPs[SAPLING_FULL_VIEWING_KEY] = "zviews";
|
||||||
bech32HRPs[SAPLING_INCOMING_VIEWING_KEY] = "zivks";
|
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<SeedSpec6>(pnSeed6_main, pnSeed6_main + ARRAYLEN(pnSeed6_main));
|
vFixedSeeds = std::vector<SeedSpec6>(pnSeed6_main, pnSeed6_main + ARRAYLEN(pnSeed6_main));
|
||||||
|
|
||||||
@@ -329,7 +329,7 @@ public:
|
|||||||
bech32HRPs[SAPLING_PAYMENT_ADDRESS] = "ztestsapling";
|
bech32HRPs[SAPLING_PAYMENT_ADDRESS] = "ztestsapling";
|
||||||
bech32HRPs[SAPLING_FULL_VIEWING_KEY] = "zviewtestsapling";
|
bech32HRPs[SAPLING_FULL_VIEWING_KEY] = "zviewtestsapling";
|
||||||
bech32HRPs[SAPLING_INCOMING_VIEWING_KEY] = "zivktestsapling";
|
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<SeedSpec6>(pnSeed6_test, pnSeed6_test + ARRAYLEN(pnSeed6_test));
|
vFixedSeeds = std::vector<SeedSpec6>(pnSeed6_test, pnSeed6_test + ARRAYLEN(pnSeed6_test));
|
||||||
|
|
||||||
@@ -457,7 +457,7 @@ public:
|
|||||||
bech32HRPs[SAPLING_PAYMENT_ADDRESS] = "zregtestsapling";
|
bech32HRPs[SAPLING_PAYMENT_ADDRESS] = "zregtestsapling";
|
||||||
bech32HRPs[SAPLING_FULL_VIEWING_KEY] = "zviewregtestsapling";
|
bech32HRPs[SAPLING_FULL_VIEWING_KEY] = "zviewregtestsapling";
|
||||||
bech32HRPs[SAPLING_INCOMING_VIEWING_KEY] = "zivkregtestsapling";
|
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
|
// Founders reward script expects a vector of 2-of-3 multisig addresses
|
||||||
vFoundersRewardAddress = { "t2FwcEhFdNXuFMv1tcYwaBJtYVtMj8b1uTg" };
|
vFoundersRewardAddress = { "t2FwcEhFdNXuFMv1tcYwaBJtYVtMj8b1uTg" };
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ public:
|
|||||||
SAPLING_PAYMENT_ADDRESS,
|
SAPLING_PAYMENT_ADDRESS,
|
||||||
SAPLING_FULL_VIEWING_KEY,
|
SAPLING_FULL_VIEWING_KEY,
|
||||||
SAPLING_INCOMING_VIEWING_KEY,
|
SAPLING_INCOMING_VIEWING_KEY,
|
||||||
SAPLING_SPENDING_KEY,
|
SAPLING_EXTENDED_SPEND_KEY,
|
||||||
|
|
||||||
MAX_BECH32_TYPES
|
MAX_BECH32_TYPES
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include <chainparams.h>
|
#include <chainparams.h>
|
||||||
#include <key_io.h>
|
#include <key_io.h>
|
||||||
#include <zcash/Address.hpp>
|
#include <zcash/Address.hpp>
|
||||||
|
#include <zcash/zip32.h>
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
@@ -8,23 +9,27 @@ TEST(Keys, DISABLED_EncodeAndDecodeSapling)
|
|||||||
{
|
{
|
||||||
SelectParams(CBaseChainParams::MAIN);
|
SelectParams(CBaseChainParams::MAIN);
|
||||||
|
|
||||||
for (size_t i = 0; i < 1000; i++) {
|
std::vector<unsigned char, secure_allocator<unsigned char>> rawSeed(32);
|
||||||
auto sk = libzcash::SaplingSpendingKey::random();
|
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);
|
std::string sk_string = EncodeSpendingKey(sk);
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
sk_string.substr(0, 24),
|
sk_string.substr(0, 24),
|
||||||
Params().Bech32HRP(CChainParams::SAPLING_SPENDING_KEY));
|
Params().Bech32HRP(CChainParams::SAPLING_EXTENDED_SPEND_KEY));
|
||||||
|
|
||||||
auto spendingkey2 = DecodeSpendingKey(sk_string);
|
auto spendingkey2 = DecodeSpendingKey(sk_string);
|
||||||
EXPECT_TRUE(IsValidSpendingKey(spendingkey2));
|
EXPECT_TRUE(IsValidSpendingKey(spendingkey2));
|
||||||
|
|
||||||
ASSERT_TRUE(boost::get<libzcash::SaplingSpendingKey>(&spendingkey2) != nullptr);
|
ASSERT_TRUE(boost::get<libzcash::SaplingExtendedSpendingKey>(&spendingkey2) != nullptr);
|
||||||
auto sk2 = boost::get<libzcash::SaplingSpendingKey>(spendingkey2);
|
auto sk2 = boost::get<libzcash::SaplingExtendedSpendingKey>(spendingkey2);
|
||||||
EXPECT_EQ(sk, sk2);
|
EXPECT_EQ(sk, sk2);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto addr = sk.default_address();
|
auto addr = sk.DefaultAddress();
|
||||||
|
|
||||||
std::string addr_string = EncodePaymentAddress(addr);
|
std::string addr_string = EncodePaymentAddress(addr);
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
|
|||||||
@@ -194,14 +194,16 @@ TEST(keystore_tests, StoreAndRetrieveViewingKey) {
|
|||||||
// Sapling
|
// Sapling
|
||||||
TEST(keystore_tests, StoreAndRetrieveSaplingSpendingKey) {
|
TEST(keystore_tests, StoreAndRetrieveSaplingSpendingKey) {
|
||||||
CBasicKeyStore keyStore;
|
CBasicKeyStore keyStore;
|
||||||
libzcash::SaplingSpendingKey skOut;
|
libzcash::SaplingExtendedSpendingKey skOut;
|
||||||
libzcash::SaplingFullViewingKey fvkOut;
|
libzcash::SaplingFullViewingKey fvkOut;
|
||||||
libzcash::SaplingIncomingViewingKey ivkOut;
|
libzcash::SaplingIncomingViewingKey ivkOut;
|
||||||
|
|
||||||
auto sk = libzcash::SaplingSpendingKey::random();
|
std::vector<unsigned char, secure_allocator<unsigned char>> rawSeed(32);
|
||||||
auto fvk = sk.full_viewing_key();
|
HDSeed seed(rawSeed);
|
||||||
|
auto sk = libzcash::SaplingExtendedSpendingKey::Master(seed);
|
||||||
|
auto fvk = sk.expsk.full_viewing_key();
|
||||||
auto ivk = fvk.in_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
|
// Sanity-check: we can't get a key we haven't added
|
||||||
EXPECT_FALSE(keyStore.HaveSaplingSpendingKey(fvk));
|
EXPECT_FALSE(keyStore.HaveSaplingSpendingKey(fvk));
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ public:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string operator()(const libzcash::SaplingSpendingKey& zkey) const
|
std::string operator()(const libzcash::SaplingExtendedSpendingKey& zkey) const
|
||||||
{
|
{
|
||||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||||
ss << zkey;
|
ss << zkey;
|
||||||
@@ -152,7 +152,7 @@ public:
|
|||||||
// See calculation comment below
|
// See calculation comment below
|
||||||
data.reserve((serkey.size() * 8 + 4) / 5);
|
data.reserve((serkey.size() * 8 + 4) / 5);
|
||||||
ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, serkey.begin(), serkey.end());
|
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(serkey.data(), serkey.size());
|
||||||
memory_cleanse(data.data(), data.size());
|
memory_cleanse(data.data(), data.size());
|
||||||
return ret;
|
return ret;
|
||||||
@@ -166,7 +166,7 @@ public:
|
|||||||
// regular serialized size in bytes, convert to bits, and then
|
// regular serialized size in bytes, convert to bits, and then
|
||||||
// perform ceiling division to get the number of 5-bit clusters.
|
// perform ceiling division to get the number of 5-bit clusters.
|
||||||
const size_t ConvertedSaplingPaymentAddressSize = ((32 + 11) * 8 + 4) / 5;
|
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
|
} // namespace
|
||||||
|
|
||||||
CKey DecodeSecret(const std::string& str)
|
CKey DecodeSecret(const std::string& str)
|
||||||
@@ -360,13 +360,13 @@ libzcash::SpendingKey DecodeSpendingKey(const std::string& str)
|
|||||||
Params().NetworkIDString() == "test" &&
|
Params().NetworkIDString() == "test" &&
|
||||||
GetBoolArg("-experimentalfeatures", false) &&
|
GetBoolArg("-experimentalfeatures", false) &&
|
||||||
GetBoolArg("-developersapling", false));
|
GetBoolArg("-developersapling", false));
|
||||||
if (allowSapling && bech.first == Params().Bech32HRP(CChainParams::SAPLING_SPENDING_KEY) &&
|
if (allowSapling && bech.first == Params().Bech32HRP(CChainParams::SAPLING_EXTENDED_SPEND_KEY) &&
|
||||||
bech.second.size() == ConvertedSaplingSpendingKeySize) {
|
bech.second.size() == ConvertedSaplingExtendedSpendingKeySize) {
|
||||||
// Bech32 decoding
|
// Bech32 decoding
|
||||||
data.reserve((bech.second.size() * 5) / 8);
|
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())) {
|
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);
|
CDataStream ss(data, SER_NETWORK, PROTOCOL_VERSION);
|
||||||
libzcash::SaplingSpendingKey ret;
|
libzcash::SaplingExtendedSpendingKey ret;
|
||||||
ss >> ret;
|
ss >> ret;
|
||||||
memory_cleanse(data.data(), data.size());
|
memory_cleanse(data.data(), data.size());
|
||||||
return ret;
|
return ret;
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include <pubkey.h>
|
#include <pubkey.h>
|
||||||
#include <script/standard.h>
|
#include <script/standard.h>
|
||||||
#include <zcash/Address.hpp>
|
#include <zcash/Address.hpp>
|
||||||
|
#include <zcash/zip32.h>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
|||||||
@@ -119,11 +119,11 @@ bool CBasicKeyStore::AddSproutSpendingKey(const libzcash::SproutSpendingKey &sk)
|
|||||||
|
|
||||||
//! Sapling
|
//! Sapling
|
||||||
bool CBasicKeyStore::AddSaplingSpendingKey(
|
bool CBasicKeyStore::AddSaplingSpendingKey(
|
||||||
const libzcash::SaplingSpendingKey &sk,
|
const libzcash::SaplingExtendedSpendingKey &sk,
|
||||||
const boost::optional<libzcash::SaplingPaymentAddress> &defaultAddr)
|
const boost::optional<libzcash::SaplingPaymentAddress> &defaultAddr)
|
||||||
{
|
{
|
||||||
LOCK(cs_SpendingKeyStore);
|
LOCK(cs_SpendingKeyStore);
|
||||||
auto fvk = sk.full_viewing_key();
|
auto fvk = sk.expsk.full_viewing_key();
|
||||||
|
|
||||||
// if SaplingFullViewingKey is not in SaplingFullViewingKeyMap, add it
|
// if SaplingFullViewingKey is not in SaplingFullViewingKeyMap, add it
|
||||||
if (!AddSaplingFullViewingKey(fvk, defaultAddr)){
|
if (!AddSaplingFullViewingKey(fvk, defaultAddr)){
|
||||||
|
|||||||
@@ -65,12 +65,12 @@ public:
|
|||||||
|
|
||||||
//! Add a Sapling spending key to the store.
|
//! Add a Sapling spending key to the store.
|
||||||
virtual bool AddSaplingSpendingKey(
|
virtual bool AddSaplingSpendingKey(
|
||||||
const libzcash::SaplingSpendingKey &sk,
|
const libzcash::SaplingExtendedSpendingKey &sk,
|
||||||
const boost::optional<libzcash::SaplingPaymentAddress> &defaultAddr = boost::none) =0;
|
const boost::optional<libzcash::SaplingPaymentAddress> &defaultAddr = boost::none) =0;
|
||||||
|
|
||||||
//! Check whether a Sapling spending key corresponding to a given Sapling viewing key is present in the store.
|
//! Check whether a Sapling spending key corresponding to a given Sapling viewing key is present in the store.
|
||||||
virtual bool HaveSaplingSpendingKey(const libzcash::SaplingFullViewingKey &fvk) const =0;
|
virtual bool HaveSaplingSpendingKey(const libzcash::SaplingFullViewingKey &fvk) const =0;
|
||||||
virtual bool GetSaplingSpendingKey(const libzcash::SaplingFullViewingKey &fvk, libzcash::SaplingSpendingKey& skOut) const =0;
|
virtual bool GetSaplingSpendingKey(const libzcash::SaplingFullViewingKey &fvk, libzcash::SaplingExtendedSpendingKey& skOut) const =0;
|
||||||
|
|
||||||
//! Support for Sapling full viewing keys
|
//! Support for Sapling full viewing keys
|
||||||
virtual bool AddSaplingFullViewingKey(
|
virtual bool AddSaplingFullViewingKey(
|
||||||
@@ -106,8 +106,7 @@ typedef std::map<libzcash::SproutPaymentAddress, ZCNoteDecryption> NoteDecryptor
|
|||||||
|
|
||||||
// Full viewing key has equivalent functionality to a transparent address
|
// Full viewing key has equivalent functionality to a transparent address
|
||||||
// When encrypting wallet, encrypt SaplingSpendingKeyMap, while leaving SaplingFullViewingKeyMap unencrypted
|
// When encrypting wallet, encrypt SaplingSpendingKeyMap, while leaving SaplingFullViewingKeyMap unencrypted
|
||||||
// When implementing ZIP 32, add another map from SaplingFullViewingKey -> SaplingExpandedSpendingKey
|
typedef std::map<libzcash::SaplingFullViewingKey, libzcash::SaplingExtendedSpendingKey> SaplingSpendingKeyMap;
|
||||||
typedef std::map<libzcash::SaplingFullViewingKey, libzcash::SaplingSpendingKey> SaplingSpendingKeyMap;
|
|
||||||
typedef std::map<libzcash::SaplingIncomingViewingKey, libzcash::SaplingFullViewingKey> SaplingFullViewingKeyMap;
|
typedef std::map<libzcash::SaplingIncomingViewingKey, libzcash::SaplingFullViewingKey> SaplingFullViewingKeyMap;
|
||||||
// Only maps from default addresses to ivk, may need to be reworked when adding diversified addresses.
|
// Only maps from default addresses to ivk, may need to be reworked when adding diversified addresses.
|
||||||
typedef std::map<libzcash::SaplingPaymentAddress, libzcash::SaplingIncomingViewingKey> SaplingIncomingViewingKeyMap;
|
typedef std::map<libzcash::SaplingPaymentAddress, libzcash::SaplingIncomingViewingKey> SaplingIncomingViewingKeyMap;
|
||||||
@@ -236,7 +235,7 @@ public:
|
|||||||
|
|
||||||
//! Sapling
|
//! Sapling
|
||||||
bool AddSaplingSpendingKey(
|
bool AddSaplingSpendingKey(
|
||||||
const libzcash::SaplingSpendingKey &sk,
|
const libzcash::SaplingExtendedSpendingKey &sk,
|
||||||
const boost::optional<libzcash::SaplingPaymentAddress> &defaultAddr = boost::none);
|
const boost::optional<libzcash::SaplingPaymentAddress> &defaultAddr = boost::none);
|
||||||
bool HaveSaplingSpendingKey(const libzcash::SaplingFullViewingKey &fvk) const
|
bool HaveSaplingSpendingKey(const libzcash::SaplingFullViewingKey &fvk) const
|
||||||
{
|
{
|
||||||
@@ -247,7 +246,7 @@ public:
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
bool GetSaplingSpendingKey(const libzcash::SaplingFullViewingKey &fvk, libzcash::SaplingSpendingKey &skOut) const
|
bool GetSaplingSpendingKey(const libzcash::SaplingFullViewingKey &fvk, libzcash::SaplingExtendedSpendingKey &skOut) const
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
LOCK(cs_SpendingKeyStore);
|
LOCK(cs_SpendingKeyStore);
|
||||||
|
|||||||
@@ -225,21 +225,25 @@ BOOST_AUTO_TEST_CASE(zs_address_test)
|
|||||||
{
|
{
|
||||||
SelectParams(CBaseChainParams::REGTEST);
|
SelectParams(CBaseChainParams::REGTEST);
|
||||||
|
|
||||||
for (size_t i = 0; i < 1000; i++) {
|
std::vector<unsigned char, secure_allocator<unsigned char>> rawSeed(32);
|
||||||
auto sk = SaplingSpendingKey::random();
|
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);
|
std::string sk_string = EncodeSpendingKey(sk);
|
||||||
BOOST_CHECK(sk_string.compare(0, 27, Params().Bech32HRP(CChainParams::SAPLING_SPENDING_KEY)) == 0);
|
BOOST_CHECK(sk_string.compare(0, 27, Params().Bech32HRP(CChainParams::SAPLING_EXTENDED_SPEND_KEY)) == 0);
|
||||||
|
|
||||||
auto spendingkey2 = DecodeSpendingKey(sk_string);
|
auto spendingkey2 = DecodeSpendingKey(sk_string);
|
||||||
BOOST_CHECK(IsValidSpendingKey(spendingkey2));
|
BOOST_CHECK(IsValidSpendingKey(spendingkey2));
|
||||||
|
|
||||||
BOOST_ASSERT(boost::get<SaplingSpendingKey>(&spendingkey2) != nullptr);
|
BOOST_ASSERT(boost::get<SaplingExtendedSpendingKey>(&spendingkey2) != nullptr);
|
||||||
auto sk2 = boost::get<SaplingSpendingKey>(spendingkey2);
|
auto sk2 = boost::get<SaplingExtendedSpendingKey>(spendingkey2);
|
||||||
BOOST_CHECK(sk == sk2);
|
BOOST_CHECK(sk == sk2);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto addr = sk.default_address();
|
auto addr = sk.DefaultAddress();
|
||||||
|
|
||||||
std::string addr_string = EncodePaymentAddress(addr);
|
std::string addr_string = EncodePaymentAddress(addr);
|
||||||
BOOST_CHECK(addr_string.compare(0, 15, Params().Bech32HRP(CChainParams::SAPLING_PAYMENT_ADDRESS)) == 0);
|
BOOST_CHECK(addr_string.compare(0, 15, Params().Bech32HRP(CChainParams::SAPLING_PAYMENT_ADDRESS)) == 0);
|
||||||
|
|||||||
@@ -568,6 +568,10 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importexport)
|
|||||||
pwalletMain->GetSaplingPaymentAddresses(saplingAddrs);
|
pwalletMain->GetSaplingPaymentAddresses(saplingAddrs);
|
||||||
BOOST_CHECK(saplingAddrs.empty());
|
BOOST_CHECK(saplingAddrs.empty());
|
||||||
|
|
||||||
|
std::vector<unsigned char, secure_allocator<unsigned char>> rawSeed(32);
|
||||||
|
HDSeed seed(rawSeed);
|
||||||
|
auto m = libzcash::SaplingExtendedSpendingKey::Master(seed);
|
||||||
|
|
||||||
// verify import and export key
|
// verify import and export key
|
||||||
for (int i = 0; i < n1; i++) {
|
for (int i = 0; i < n1; i++) {
|
||||||
// create a random Sprout key locally
|
// create a random Sprout key locally
|
||||||
@@ -578,10 +582,10 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importexport)
|
|||||||
BOOST_CHECK_NO_THROW(CallRPC(string("z_importkey ") + testKey));
|
BOOST_CHECK_NO_THROW(CallRPC(string("z_importkey ") + testKey));
|
||||||
BOOST_CHECK_NO_THROW(retValue = CallRPC(string("z_exportkey ") + testAddr));
|
BOOST_CHECK_NO_THROW(retValue = CallRPC(string("z_exportkey ") + testAddr));
|
||||||
BOOST_CHECK_EQUAL(retValue.get_str(), testKey);
|
BOOST_CHECK_EQUAL(retValue.get_str(), testKey);
|
||||||
|
|
||||||
// create a random Sapling key locally
|
// create a random Sapling key locally
|
||||||
auto testSaplingSpendingKey = libzcash::SaplingSpendingKey::random();
|
auto testSaplingSpendingKey = m.Derive(i);
|
||||||
auto testSaplingPaymentAddress = testSaplingSpendingKey.default_address();
|
auto testSaplingPaymentAddress = testSaplingSpendingKey.DefaultAddress();
|
||||||
std::string testSaplingAddr = EncodePaymentAddress(testSaplingPaymentAddress);
|
std::string testSaplingAddr = EncodePaymentAddress(testSaplingPaymentAddress);
|
||||||
std::string testSaplingKey = EncodeSpendingKey(testSaplingSpendingKey);
|
std::string testSaplingKey = EncodeSpendingKey(testSaplingSpendingKey);
|
||||||
BOOST_CHECK_NO_THROW(CallRPC(string("z_importkey ") + testSaplingKey));
|
BOOST_CHECK_NO_THROW(CallRPC(string("z_importkey ") + testSaplingKey));
|
||||||
|
|||||||
@@ -382,8 +382,8 @@ bool AsyncRPCOperation_sendmany::main_impl() {
|
|||||||
SaplingExpandedSpendingKey expsk;
|
SaplingExpandedSpendingKey expsk;
|
||||||
SaplingFullViewingKey from;
|
SaplingFullViewingKey from;
|
||||||
if (isfromzaddr_) {
|
if (isfromzaddr_) {
|
||||||
auto sk = boost::get<libzcash::SaplingSpendingKey>(spendingkey_);
|
auto sk = boost::get<libzcash::SaplingExtendedSpendingKey>(spendingkey_);
|
||||||
expsk = sk.expanded_spending_key();
|
expsk = sk.expsk;
|
||||||
from = expsk.full_viewing_key();
|
from = expsk.full_viewing_key();
|
||||||
} else {
|
} else {
|
||||||
// TODO: Set "from" to something!
|
// TODO: Set "from" to something!
|
||||||
|
|||||||
@@ -171,18 +171,18 @@ static bool DecryptSproutSpendingKey(const CKeyingMaterial& vMasterKey,
|
|||||||
static bool DecryptSaplingSpendingKey(const CKeyingMaterial& vMasterKey,
|
static bool DecryptSaplingSpendingKey(const CKeyingMaterial& vMasterKey,
|
||||||
const std::vector<unsigned char>& vchCryptedSecret,
|
const std::vector<unsigned char>& vchCryptedSecret,
|
||||||
const libzcash::SaplingFullViewingKey& fvk,
|
const libzcash::SaplingFullViewingKey& fvk,
|
||||||
libzcash::SaplingSpendingKey& sk)
|
libzcash::SaplingExtendedSpendingKey& sk)
|
||||||
{
|
{
|
||||||
CKeyingMaterial vchSecret;
|
CKeyingMaterial vchSecret;
|
||||||
if (!DecryptSecret(vMasterKey, vchCryptedSecret, fvk.GetFingerprint(), vchSecret))
|
if (!DecryptSecret(vMasterKey, vchCryptedSecret, fvk.GetFingerprint(), vchSecret))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (vchSecret.size() != libzcash::SerializedSaplingSpendingKeySize)
|
if (vchSecret.size() != ZIP32_XSK_SIZE)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
CSecureDataStream ss(vchSecret, SER_NETWORK, PROTOCOL_VERSION);
|
CSecureDataStream ss(vchSecret, SER_NETWORK, PROTOCOL_VERSION);
|
||||||
ss >> sk;
|
ss >> sk;
|
||||||
return sk.full_viewing_key() == fvk;
|
return sk.expsk.full_viewing_key() == fvk;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CCryptoKeyStore::SetCrypted()
|
bool CCryptoKeyStore::SetCrypted()
|
||||||
@@ -263,7 +263,7 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
|
|||||||
{
|
{
|
||||||
const libzcash::SaplingFullViewingKey &fvk = (*miSapling).first;
|
const libzcash::SaplingFullViewingKey &fvk = (*miSapling).first;
|
||||||
const std::vector<unsigned char> &vchCryptedSecret = (*miSapling).second;
|
const std::vector<unsigned char> &vchCryptedSecret = (*miSapling).second;
|
||||||
libzcash::SaplingSpendingKey sk;
|
libzcash::SaplingExtendedSpendingKey sk;
|
||||||
if (!DecryptSaplingSpendingKey(vMasterKeyIn, vchCryptedSecret, fvk, sk))
|
if (!DecryptSaplingSpendingKey(vMasterKeyIn, vchCryptedSecret, fvk, sk))
|
||||||
{
|
{
|
||||||
keyFail = true;
|
keyFail = true;
|
||||||
@@ -442,7 +442,7 @@ bool CCryptoKeyStore::AddSproutSpendingKey(const libzcash::SproutSpendingKey &sk
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool CCryptoKeyStore::AddSaplingSpendingKey(
|
bool CCryptoKeyStore::AddSaplingSpendingKey(
|
||||||
const libzcash::SaplingSpendingKey &sk,
|
const libzcash::SaplingExtendedSpendingKey &sk,
|
||||||
const boost::optional<libzcash::SaplingPaymentAddress> &defaultAddr)
|
const boost::optional<libzcash::SaplingPaymentAddress> &defaultAddr)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
@@ -459,7 +459,7 @@ bool CCryptoKeyStore::AddSaplingSpendingKey(
|
|||||||
CSecureDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
CSecureDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||||
ss << sk;
|
ss << sk;
|
||||||
CKeyingMaterial vchSecret(ss.begin(), ss.end());
|
CKeyingMaterial vchSecret(ss.begin(), ss.end());
|
||||||
auto fvk = sk.full_viewing_key();
|
auto fvk = sk.expsk.full_viewing_key();
|
||||||
if (!EncryptSecret(vMasterKey, vchSecret, fvk.GetFingerprint(), vchCryptedSecret)) {
|
if (!EncryptSecret(vMasterKey, vchSecret, fvk.GetFingerprint(), vchCryptedSecret)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -525,7 +525,7 @@ bool CCryptoKeyStore::GetSproutSpendingKey(const libzcash::SproutPaymentAddress
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CCryptoKeyStore::GetSaplingSpendingKey(const libzcash::SaplingFullViewingKey &fvk, libzcash::SaplingSpendingKey &skOut) const
|
bool CCryptoKeyStore::GetSaplingSpendingKey(const libzcash::SaplingFullViewingKey &fvk, libzcash::SaplingExtendedSpendingKey &skOut) const
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
LOCK(cs_SpendingKeyStore);
|
LOCK(cs_SpendingKeyStore);
|
||||||
@@ -597,11 +597,11 @@ bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn)
|
|||||||
//! Sapling key support
|
//! Sapling key support
|
||||||
BOOST_FOREACH(SaplingSpendingKeyMap::value_type& mSaplingSpendingKey, mapSaplingSpendingKeys)
|
BOOST_FOREACH(SaplingSpendingKeyMap::value_type& mSaplingSpendingKey, mapSaplingSpendingKeys)
|
||||||
{
|
{
|
||||||
const libzcash::SaplingSpendingKey &sk = mSaplingSpendingKey.second;
|
const auto &sk = mSaplingSpendingKey.second;
|
||||||
CSecureDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
CSecureDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||||
ss << sk;
|
ss << sk;
|
||||||
CKeyingMaterial vchSecret(ss.begin(), ss.end());
|
CKeyingMaterial vchSecret(ss.begin(), ss.end());
|
||||||
libzcash::SaplingFullViewingKey fvk = sk.full_viewing_key();
|
libzcash::SaplingFullViewingKey fvk = sk.expsk.full_viewing_key();
|
||||||
std::vector<unsigned char> vchCryptedSecret;
|
std::vector<unsigned char> vchCryptedSecret;
|
||||||
if (!EncryptSecret(vMasterKeyIn, vchSecret, fvk.GetFingerprint(), vchCryptedSecret)) {
|
if (!EncryptSecret(vMasterKeyIn, vchSecret, fvk.GetFingerprint(), vchCryptedSecret)) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -245,7 +245,7 @@ public:
|
|||||||
const std::vector<unsigned char> &vchCryptedSecret,
|
const std::vector<unsigned char> &vchCryptedSecret,
|
||||||
const boost::optional<libzcash::SaplingPaymentAddress> &defaultAddr = boost::none);
|
const boost::optional<libzcash::SaplingPaymentAddress> &defaultAddr = boost::none);
|
||||||
bool AddSaplingSpendingKey(
|
bool AddSaplingSpendingKey(
|
||||||
const libzcash::SaplingSpendingKey &sk,
|
const libzcash::SaplingExtendedSpendingKey &sk,
|
||||||
const boost::optional<libzcash::SaplingPaymentAddress> &defaultAddr = boost::none);
|
const boost::optional<libzcash::SaplingPaymentAddress> &defaultAddr = boost::none);
|
||||||
bool HaveSaplingSpendingKey(const libzcash::SaplingFullViewingKey &fvk) const
|
bool HaveSaplingSpendingKey(const libzcash::SaplingFullViewingKey &fvk) const
|
||||||
{
|
{
|
||||||
@@ -257,7 +257,7 @@ public:
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool GetSaplingSpendingKey(const libzcash::SaplingFullViewingKey &fvk, libzcash::SaplingSpendingKey &skOut) const;
|
bool GetSaplingSpendingKey(const libzcash::SaplingFullViewingKey &fvk, libzcash::SaplingExtendedSpendingKey &skOut) const;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -363,11 +363,13 @@ TEST(WalletTests, SetSaplingNoteAddrsInCWalletTx) {
|
|||||||
|
|
||||||
TestWallet wallet;
|
TestWallet wallet;
|
||||||
|
|
||||||
auto sk = libzcash::SaplingSpendingKey::random();
|
std::vector<unsigned char, secure_allocator<unsigned char>> rawSeed(32);
|
||||||
auto expsk = sk.expanded_spending_key();
|
HDSeed seed(rawSeed);
|
||||||
auto fvk = sk.full_viewing_key();
|
auto sk = libzcash::SaplingExtendedSpendingKey::Master(seed);
|
||||||
auto pk = sk.default_address();
|
auto expsk = sk.expsk;
|
||||||
|
auto fvk = expsk.full_viewing_key();
|
||||||
auto ivk = fvk.in_viewing_key();
|
auto ivk = fvk.in_viewing_key();
|
||||||
|
auto pk = sk.DefaultAddress();
|
||||||
|
|
||||||
libzcash::SaplingNote note(pk, 50000);
|
libzcash::SaplingNote note(pk, 50000);
|
||||||
auto cm = note.cm().get();
|
auto cm = note.cm().get();
|
||||||
@@ -484,10 +486,12 @@ TEST(WalletTests, FindMySaplingNotes) {
|
|||||||
TestWallet wallet;
|
TestWallet wallet;
|
||||||
|
|
||||||
// Generate dummy Sapling address
|
// Generate dummy Sapling address
|
||||||
auto sk = libzcash::SaplingSpendingKey::random();
|
std::vector<unsigned char, secure_allocator<unsigned char>> rawSeed(32);
|
||||||
auto expsk = sk.expanded_spending_key();
|
HDSeed seed(rawSeed);
|
||||||
auto fvk = sk.full_viewing_key();
|
auto sk = libzcash::SaplingExtendedSpendingKey::Master(seed);
|
||||||
auto pk = sk.default_address();
|
auto expsk = sk.expsk;
|
||||||
|
auto fvk = expsk.full_viewing_key();
|
||||||
|
auto pk = sk.DefaultAddress();
|
||||||
|
|
||||||
// Generate dummy Sapling note
|
// Generate dummy Sapling note
|
||||||
libzcash::SaplingNote note(pk, 50000);
|
libzcash::SaplingNote note(pk, 50000);
|
||||||
@@ -618,11 +622,13 @@ TEST(WalletTests, GetConflictedSaplingNotes) {
|
|||||||
TestWallet wallet;
|
TestWallet wallet;
|
||||||
|
|
||||||
// Generate Sapling address
|
// Generate Sapling address
|
||||||
auto sk = libzcash::SaplingSpendingKey::random();
|
std::vector<unsigned char, secure_allocator<unsigned char>> rawSeed(32);
|
||||||
auto expsk = sk.expanded_spending_key();
|
HDSeed seed(rawSeed);
|
||||||
auto fvk = sk.full_viewing_key();
|
auto sk = libzcash::SaplingExtendedSpendingKey::Master(seed);
|
||||||
|
auto expsk = sk.expsk;
|
||||||
|
auto fvk = expsk.full_viewing_key();
|
||||||
auto ivk = fvk.in_viewing_key();
|
auto ivk = fvk.in_viewing_key();
|
||||||
auto pk = sk.default_address();
|
auto pk = sk.DefaultAddress();
|
||||||
|
|
||||||
ASSERT_TRUE(wallet.AddSaplingZKey(sk));
|
ASSERT_TRUE(wallet.AddSaplingZKey(sk));
|
||||||
ASSERT_TRUE(wallet.HaveSaplingSpendingKey(fvk));
|
ASSERT_TRUE(wallet.HaveSaplingSpendingKey(fvk));
|
||||||
@@ -785,10 +791,12 @@ TEST(WalletTests, SaplingNullifierIsSpent) {
|
|||||||
TestWallet wallet;
|
TestWallet wallet;
|
||||||
|
|
||||||
// Generate dummy Sapling address
|
// Generate dummy Sapling address
|
||||||
auto sk = libzcash::SaplingSpendingKey::random();
|
std::vector<unsigned char, secure_allocator<unsigned char>> rawSeed(32);
|
||||||
auto expsk = sk.expanded_spending_key();
|
HDSeed seed(rawSeed);
|
||||||
auto fvk = sk.full_viewing_key();
|
auto sk = libzcash::SaplingExtendedSpendingKey::Master(seed);
|
||||||
auto pk = sk.default_address();
|
auto expsk = sk.expsk;
|
||||||
|
auto fvk = expsk.full_viewing_key();
|
||||||
|
auto pk = sk.DefaultAddress();
|
||||||
|
|
||||||
// Generate dummy Sapling note
|
// Generate dummy Sapling note
|
||||||
libzcash::SaplingNote note(pk, 50000);
|
libzcash::SaplingNote note(pk, 50000);
|
||||||
@@ -880,10 +888,12 @@ TEST(WalletTests, NavigateFromSaplingNullifierToNote) {
|
|||||||
TestWallet wallet;
|
TestWallet wallet;
|
||||||
|
|
||||||
// Generate dummy Sapling address
|
// Generate dummy Sapling address
|
||||||
auto sk = libzcash::SaplingSpendingKey::random();
|
std::vector<unsigned char, secure_allocator<unsigned char>> rawSeed(32);
|
||||||
auto expsk = sk.expanded_spending_key();
|
HDSeed seed(rawSeed);
|
||||||
auto fvk = sk.full_viewing_key();
|
auto sk = libzcash::SaplingExtendedSpendingKey::Master(seed);
|
||||||
auto pk = sk.default_address();
|
auto expsk = sk.expsk;
|
||||||
|
auto fvk = expsk.full_viewing_key();
|
||||||
|
auto pk = sk.DefaultAddress();
|
||||||
|
|
||||||
// Generate dummy Sapling note
|
// Generate dummy Sapling note
|
||||||
libzcash::SaplingNote note(pk, 50000);
|
libzcash::SaplingNote note(pk, 50000);
|
||||||
@@ -1013,11 +1023,13 @@ TEST(WalletTests, SpentSaplingNoteIsFromMe) {
|
|||||||
TestWallet wallet;
|
TestWallet wallet;
|
||||||
|
|
||||||
// Generate Sapling address
|
// Generate Sapling address
|
||||||
auto sk = libzcash::SaplingSpendingKey::random();
|
std::vector<unsigned char, secure_allocator<unsigned char>> rawSeed(32);
|
||||||
auto expsk = sk.expanded_spending_key();
|
HDSeed seed(rawSeed);
|
||||||
auto fvk = sk.full_viewing_key();
|
auto sk = libzcash::SaplingExtendedSpendingKey::Master(seed);
|
||||||
|
auto expsk = sk.expsk;
|
||||||
|
auto fvk = expsk.full_viewing_key();
|
||||||
auto ivk = fvk.in_viewing_key();
|
auto ivk = fvk.in_viewing_key();
|
||||||
auto pk = sk.default_address();
|
auto pk = sk.DefaultAddress();
|
||||||
|
|
||||||
// Generate Sapling note A
|
// Generate Sapling note A
|
||||||
libzcash::SaplingNote note(pk, 50000);
|
libzcash::SaplingNote note(pk, 50000);
|
||||||
@@ -1705,16 +1717,21 @@ TEST(WalletTests, UpdatedSaplingNoteData) {
|
|||||||
|
|
||||||
TestWallet wallet;
|
TestWallet wallet;
|
||||||
|
|
||||||
|
std::vector<unsigned char, secure_allocator<unsigned char>> rawSeed(32);
|
||||||
|
HDSeed seed(rawSeed);
|
||||||
|
auto m = libzcash::SaplingExtendedSpendingKey::Master(seed);
|
||||||
|
|
||||||
// Generate dummy Sapling address
|
// Generate dummy Sapling address
|
||||||
auto sk = libzcash::SaplingSpendingKey::random();
|
auto sk = m.Derive(0);
|
||||||
auto expsk = sk.expanded_spending_key();
|
auto expsk = sk.expsk;
|
||||||
auto fvk = sk.full_viewing_key();
|
auto fvk = expsk.full_viewing_key();
|
||||||
auto pk = sk.default_address();
|
auto pk = sk.DefaultAddress();
|
||||||
|
|
||||||
// Generate dummy recipient Sapling address
|
// Generate dummy recipient Sapling address
|
||||||
auto sk2 = libzcash::SaplingSpendingKey::random();
|
auto sk2 = m.Derive(1);
|
||||||
auto fvk2 = sk2.full_viewing_key();
|
auto expsk2 = sk2.expsk;
|
||||||
auto pk2 = sk2.default_address();
|
auto fvk2 = expsk2.full_viewing_key();
|
||||||
|
auto pk2 = sk2.DefaultAddress();
|
||||||
|
|
||||||
// Generate dummy Sapling note
|
// Generate dummy Sapling note
|
||||||
libzcash::SaplingNote note(pk, 50000);
|
libzcash::SaplingNote note(pk, 50000);
|
||||||
@@ -1856,11 +1873,13 @@ TEST(WalletTests, MarkAffectedSaplingTransactionsDirty) {
|
|||||||
TestWallet wallet;
|
TestWallet wallet;
|
||||||
|
|
||||||
// Generate Sapling address
|
// Generate Sapling address
|
||||||
auto sk = libzcash::SaplingSpendingKey::random();
|
std::vector<unsigned char, secure_allocator<unsigned char>> rawSeed(32);
|
||||||
auto expsk = sk.expanded_spending_key();
|
HDSeed seed(rawSeed);
|
||||||
auto fvk = sk.full_viewing_key();
|
auto sk = libzcash::SaplingExtendedSpendingKey::Master(seed);
|
||||||
|
auto expsk = sk.expsk;
|
||||||
|
auto fvk = expsk.full_viewing_key();
|
||||||
auto ivk = fvk.in_viewing_key();
|
auto ivk = fvk.in_viewing_key();
|
||||||
auto pk = sk.default_address();
|
auto pk = sk.DefaultAddress();
|
||||||
|
|
||||||
ASSERT_TRUE(wallet.AddSaplingZKey(sk));
|
ASSERT_TRUE(wallet.AddSaplingZKey(sk));
|
||||||
ASSERT_TRUE(wallet.HaveSaplingSpendingKey(fvk));
|
ASSERT_TRUE(wallet.HaveSaplingSpendingKey(fvk));
|
||||||
|
|||||||
@@ -21,8 +21,18 @@ TEST(wallet_zkeys_tests, store_and_load_sapling_zkeys) {
|
|||||||
wallet.GetSaplingPaymentAddresses(addrs);
|
wallet.GetSaplingPaymentAddresses(addrs);
|
||||||
ASSERT_EQ(0, addrs.size());
|
ASSERT_EQ(0, addrs.size());
|
||||||
|
|
||||||
// wallet should have one key
|
// No HD seed in the wallet
|
||||||
|
EXPECT_ANY_THROW(wallet.GenerateNewSaplingZKey());
|
||||||
|
|
||||||
|
// Load the all-zeroes seed
|
||||||
|
CKeyingMaterial rawSeed(32, 0);
|
||||||
|
HDSeed seed(rawSeed);
|
||||||
|
wallet.LoadHDSeed(seed);
|
||||||
|
|
||||||
|
// Now this call succeeds
|
||||||
auto address = wallet.GenerateNewSaplingZKey();
|
auto address = wallet.GenerateNewSaplingZKey();
|
||||||
|
|
||||||
|
// wallet should have one key
|
||||||
wallet.GetSaplingPaymentAddresses(addrs);
|
wallet.GetSaplingPaymentAddresses(addrs);
|
||||||
ASSERT_EQ(1, addrs.size());
|
ASSERT_EQ(1, addrs.size());
|
||||||
|
|
||||||
@@ -30,15 +40,16 @@ TEST(wallet_zkeys_tests, store_and_load_sapling_zkeys) {
|
|||||||
ASSERT_TRUE(wallet.HaveSaplingIncomingViewingKey(address));
|
ASSERT_TRUE(wallet.HaveSaplingIncomingViewingKey(address));
|
||||||
|
|
||||||
// manually add new spending key to wallet
|
// manually add new spending key to wallet
|
||||||
auto sk = libzcash::SaplingSpendingKey::random();
|
auto m = libzcash::SaplingExtendedSpendingKey::Master(seed);
|
||||||
ASSERT_TRUE(wallet.AddSaplingZKey(sk, sk.default_address()));
|
auto sk = m.Derive(0);
|
||||||
|
ASSERT_TRUE(wallet.AddSaplingZKey(sk, sk.DefaultAddress()));
|
||||||
|
|
||||||
// verify wallet did add it
|
// verify wallet did add it
|
||||||
auto fvk = sk.full_viewing_key();
|
auto fvk = sk.expsk.full_viewing_key();
|
||||||
ASSERT_TRUE(wallet.HaveSaplingSpendingKey(fvk));
|
ASSERT_TRUE(wallet.HaveSaplingSpendingKey(fvk));
|
||||||
|
|
||||||
// verify spending key stored correctly
|
// verify spending key stored correctly
|
||||||
libzcash::SaplingSpendingKey keyOut;
|
libzcash::SaplingExtendedSpendingKey keyOut;
|
||||||
wallet.GetSaplingSpendingKey(fvk, keyOut);
|
wallet.GetSaplingSpendingKey(fvk, keyOut);
|
||||||
ASSERT_EQ(sk, keyOut);
|
ASSERT_EQ(sk, keyOut);
|
||||||
|
|
||||||
@@ -46,7 +57,7 @@ TEST(wallet_zkeys_tests, store_and_load_sapling_zkeys) {
|
|||||||
wallet.GetSaplingPaymentAddresses(addrs);
|
wallet.GetSaplingPaymentAddresses(addrs);
|
||||||
EXPECT_EQ(2, addrs.size());
|
EXPECT_EQ(2, addrs.size());
|
||||||
EXPECT_EQ(1, addrs.count(address));
|
EXPECT_EQ(1, addrs.count(address));
|
||||||
EXPECT_EQ(1, addrs.count(sk.default_address()));
|
EXPECT_EQ(1, addrs.count(sk.DefaultAddress()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -576,18 +576,18 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator()(const libzcash::SaplingSpendingKey &sk) const {
|
bool operator()(const libzcash::SaplingExtendedSpendingKey &sk) const {
|
||||||
auto fvk = sk.full_viewing_key();
|
auto fvk = sk.expsk.full_viewing_key();
|
||||||
auto ivk = fvk.in_viewing_key();
|
auto ivk = fvk.in_viewing_key();
|
||||||
auto addr = sk.default_address();
|
auto addr = sk.DefaultAddress();
|
||||||
{
|
{
|
||||||
// Don't throw error in case a key is already there
|
// Don't throw error in case a key is already there
|
||||||
if (m_wallet->HaveSaplingSpendingKey(fvk)) {
|
if (m_wallet->HaveSaplingSpendingKey(fvk)) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
m_wallet->MarkDirty();
|
m_wallet->MarkDirty();
|
||||||
|
|
||||||
if (!m_wallet-> AddSaplingZKey(sk, addr)) {
|
if (!m_wallet-> AddSaplingZKey(sk, addr)) {
|
||||||
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding spending key to wallet");
|
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding spending key to wallet");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
#include "primitives/transaction.h"
|
#include "primitives/transaction.h"
|
||||||
#include "zcbenchmarks.h"
|
#include "zcbenchmarks.h"
|
||||||
#include "script/interpreter.h"
|
#include "script/interpreter.h"
|
||||||
|
#include "zcash/zip32.h"
|
||||||
|
|
||||||
#include "utiltime.h"
|
#include "utiltime.h"
|
||||||
#include "asyncrpcoperation.h"
|
#include "asyncrpcoperation.h"
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include "utilmoneystr.h"
|
#include "utilmoneystr.h"
|
||||||
#include "zcash/Note.hpp"
|
#include "zcash/Note.hpp"
|
||||||
#include "crypter.h"
|
#include "crypter.h"
|
||||||
|
#include "zcash/zip32.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
@@ -104,22 +105,42 @@ libzcash::PaymentAddress CWallet::GenerateNewZKey()
|
|||||||
SaplingPaymentAddress CWallet::GenerateNewSaplingZKey()
|
SaplingPaymentAddress CWallet::GenerateNewSaplingZKey()
|
||||||
{
|
{
|
||||||
AssertLockHeld(cs_wallet); // mapSaplingZKeyMetadata
|
AssertLockHeld(cs_wallet); // mapSaplingZKeyMetadata
|
||||||
|
|
||||||
auto sk = SaplingSpendingKey::random();
|
|
||||||
auto fvk = sk.full_viewing_key();
|
|
||||||
auto ivk = fvk.in_viewing_key();
|
|
||||||
auto addr = sk.default_address();
|
|
||||||
|
|
||||||
// Check for collision, even though it is unlikely to ever occur
|
|
||||||
if (CCryptoKeyStore::HaveSaplingSpendingKey(fvk)) {
|
|
||||||
throw std::runtime_error("CWallet::GenerateNewSaplingZKey(): Collision detected");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create new metadata
|
// Create new metadata
|
||||||
int64_t nCreationTime = GetTime();
|
int64_t nCreationTime = GetTime();
|
||||||
mapSaplingZKeyMetadata[ivk] = CKeyMetadata(nCreationTime);
|
CKeyMetadata metadata(nCreationTime);
|
||||||
|
|
||||||
if (!AddSaplingZKey(sk, addr)) {
|
// Try to get the seed
|
||||||
|
HDSeed seed;
|
||||||
|
if (!GetHDSeed(seed))
|
||||||
|
throw std::runtime_error("CWallet::GenerateNewSaplingZKey(): HD seed not found");
|
||||||
|
|
||||||
|
auto m = libzcash::SaplingExtendedSpendingKey::Master(seed);
|
||||||
|
|
||||||
|
// We use a fixed keypath scheme of m/32'/coin_type'/account'
|
||||||
|
// Derive m/32'
|
||||||
|
auto m_32h = m.Derive(32 | ZIP32_HARDENED_KEY_LIMIT);
|
||||||
|
// Derive m/32'/coin_type'
|
||||||
|
auto m_32h_cth = m_32h.Derive(Params().BIP44CoinType() | ZIP32_HARDENED_KEY_LIMIT);
|
||||||
|
|
||||||
|
// Derive account key at next index, skip keys already known to the wallet
|
||||||
|
libzcash::SaplingExtendedSpendingKey xsk;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
xsk = m_32h_cth.Derive(hdChain.saplingAccountCounter | ZIP32_HARDENED_KEY_LIMIT);
|
||||||
|
// Increment childkey index
|
||||||
|
hdChain.saplingAccountCounter++;
|
||||||
|
} while (HaveSaplingSpendingKey(xsk.expsk.full_viewing_key()));
|
||||||
|
|
||||||
|
// Update the chain model in the database
|
||||||
|
if (fFileBacked && !CWalletDB(strWalletFile).WriteHDChain(hdChain))
|
||||||
|
throw std::runtime_error("CWallet::GenerateNewSaplingZKey(): Writing HD chain model failed");
|
||||||
|
|
||||||
|
auto ivk = xsk.expsk.full_viewing_key().in_viewing_key();
|
||||||
|
mapSaplingZKeyMetadata[ivk] = metadata;
|
||||||
|
|
||||||
|
auto addr = xsk.DefaultAddress();
|
||||||
|
if (!AddSaplingZKey(xsk, addr)) {
|
||||||
throw std::runtime_error("CWallet::GenerateNewSaplingZKey(): AddSaplingZKey failed");
|
throw std::runtime_error("CWallet::GenerateNewSaplingZKey(): AddSaplingZKey failed");
|
||||||
}
|
}
|
||||||
// return default sapling payment address.
|
// return default sapling payment address.
|
||||||
@@ -128,7 +149,7 @@ SaplingPaymentAddress CWallet::GenerateNewSaplingZKey()
|
|||||||
|
|
||||||
// Add spending key to keystore
|
// Add spending key to keystore
|
||||||
bool CWallet::AddSaplingZKey(
|
bool CWallet::AddSaplingZKey(
|
||||||
const libzcash::SaplingSpendingKey &sk,
|
const libzcash::SaplingExtendedSpendingKey &sk,
|
||||||
const boost::optional<libzcash::SaplingPaymentAddress> &defaultAddr)
|
const boost::optional<libzcash::SaplingPaymentAddress> &defaultAddr)
|
||||||
{
|
{
|
||||||
AssertLockHeld(cs_wallet); // mapSaplingZKeyMetadata
|
AssertLockHeld(cs_wallet); // mapSaplingZKeyMetadata
|
||||||
@@ -4450,8 +4471,8 @@ bool PaymentAddressBelongsToWallet::operator()(const libzcash::SaplingPaymentAdd
|
|||||||
{
|
{
|
||||||
libzcash::SaplingIncomingViewingKey ivk;
|
libzcash::SaplingIncomingViewingKey ivk;
|
||||||
|
|
||||||
// If we have a SaplingSpendingKey or SaplingExpandedSpendingKey in the
|
// If we have a SaplingExtendedSpendingKey in the wallet, then we will
|
||||||
// wallet, then we will also have the corresponding SaplingFullViewingKey.
|
// also have the corresponding SaplingFullViewingKey.
|
||||||
return m_wallet->GetSaplingIncomingViewingKey(zaddr, ivk) &&
|
return m_wallet->GetSaplingIncomingViewingKey(zaddr, ivk) &&
|
||||||
m_wallet->HaveSaplingFullViewingKey(ivk);
|
m_wallet->HaveSaplingFullViewingKey(ivk);
|
||||||
}
|
}
|
||||||
@@ -4497,7 +4518,7 @@ boost::optional<libzcash::SpendingKey> GetSpendingKeyForPaymentAddress::operator
|
|||||||
{
|
{
|
||||||
libzcash::SaplingIncomingViewingKey ivk;
|
libzcash::SaplingIncomingViewingKey ivk;
|
||||||
libzcash::SaplingFullViewingKey fvk;
|
libzcash::SaplingFullViewingKey fvk;
|
||||||
libzcash::SaplingSpendingKey sk;
|
libzcash::SaplingExtendedSpendingKey sk;
|
||||||
|
|
||||||
if (m_wallet->GetSaplingIncomingViewingKey(zaddr, ivk) &&
|
if (m_wallet->GetSaplingIncomingViewingKey(zaddr, ivk) &&
|
||||||
m_wallet->GetSaplingFullViewingKey(ivk, fvk) &&
|
m_wallet->GetSaplingFullViewingKey(ivk, fvk) &&
|
||||||
|
|||||||
@@ -1052,7 +1052,7 @@ public:
|
|||||||
libzcash::SaplingPaymentAddress GenerateNewSaplingZKey();
|
libzcash::SaplingPaymentAddress GenerateNewSaplingZKey();
|
||||||
//! Adds Sapling spending key to the store, and saves it to disk
|
//! Adds Sapling spending key to the store, and saves it to disk
|
||||||
bool AddSaplingZKey(
|
bool AddSaplingZKey(
|
||||||
const libzcash::SaplingSpendingKey &key,
|
const libzcash::SaplingExtendedSpendingKey &key,
|
||||||
const boost::optional<libzcash::SaplingPaymentAddress> &defaultAddr = boost::none);
|
const boost::optional<libzcash::SaplingPaymentAddress> &defaultAddr = boost::none);
|
||||||
bool AddCryptedSaplingSpendingKey(
|
bool AddCryptedSaplingSpendingKey(
|
||||||
const libzcash::SaplingFullViewingKey &fvk,
|
const libzcash::SaplingFullViewingKey &fvk,
|
||||||
|
|||||||
@@ -118,7 +118,3 @@ bool IsValidPaymentAddress(const libzcash::PaymentAddress& zaddr) {
|
|||||||
bool IsValidViewingKey(const libzcash::ViewingKey& vk) {
|
bool IsValidViewingKey(const libzcash::ViewingKey& vk) {
|
||||||
return vk.which() != 0;
|
return vk.which() != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsValidSpendingKey(const libzcash::SpendingKey& zkey) {
|
|
||||||
return zkey.which() != 0;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -220,7 +220,6 @@ public:
|
|||||||
|
|
||||||
typedef boost::variant<InvalidEncoding, SproutPaymentAddress, SaplingPaymentAddress> PaymentAddress;
|
typedef boost::variant<InvalidEncoding, SproutPaymentAddress, SaplingPaymentAddress> PaymentAddress;
|
||||||
typedef boost::variant<InvalidEncoding, SproutViewingKey> ViewingKey;
|
typedef boost::variant<InvalidEncoding, SproutViewingKey> ViewingKey;
|
||||||
typedef boost::variant<InvalidEncoding, SproutSpendingKey, SaplingSpendingKey> SpendingKey;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -230,7 +229,4 @@ bool IsValidPaymentAddress(const libzcash::PaymentAddress& zaddr);
|
|||||||
/** Check whether a ViewingKey is not an InvalidEncoding. */
|
/** Check whether a ViewingKey is not an InvalidEncoding. */
|
||||||
bool IsValidViewingKey(const libzcash::ViewingKey& vk);
|
bool IsValidViewingKey(const libzcash::ViewingKey& vk);
|
||||||
|
|
||||||
/** Check whether a SpendingKey is not an InvalidEncoding. */
|
|
||||||
bool IsValidSpendingKey(const libzcash::SpendingKey& zkey);
|
|
||||||
|
|
||||||
#endif // ZC_ADDRESS_H_
|
#endif // ZC_ADDRESS_H_
|
||||||
|
|||||||
@@ -137,3 +137,7 @@ libzcash::SaplingPaymentAddress SaplingExtendedSpendingKey::DefaultAddress() con
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsValidSpendingKey(const libzcash::SpendingKey& zkey) {
|
||||||
|
return zkey.which() != 0;
|
||||||
|
}
|
||||||
|
|||||||
@@ -116,6 +116,11 @@ struct SaplingExtendedSpendingKey {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef boost::variant<InvalidEncoding, SproutSpendingKey, SaplingExtendedSpendingKey> SpendingKey;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Check whether a SpendingKey is not an InvalidEncoding. */
|
||||||
|
bool IsValidSpendingKey(const libzcash::SpendingKey& zkey);
|
||||||
|
|
||||||
#endif // ZCASH_ZIP32_H
|
#endif // ZCASH_ZIP32_H
|
||||||
|
|||||||
Reference in New Issue
Block a user