Auto merge of #3273 - arcalinea:sapling_keys, r=str4d
Sapling keys in keystore, wallet - Add/Have/Get SaplingSpendingKey - Add/Remove/Have/Get SaplingFullViewingKey - Have/Get SaplingIncomingViewingKey - SaplingSpendingKeyMap, SaplingFullViewingKeyMap, SaplingIncomingViewingKeyMap - GenerateNewSaplingZKey() Not included: note decryptors, crypted keystore
This commit is contained in:
@@ -56,7 +56,9 @@ TEST(keystore_tests, sapling_keys) {
|
|||||||
|
|
||||||
// Check that the default address from primitives and from sk method are the same
|
// Check that the default address from primitives and from sk method are the same
|
||||||
auto default_addr = sk.default_address();
|
auto default_addr = sk.default_address();
|
||||||
auto default_addr_2 = in_viewing_key.address(default_d);
|
auto addrOpt2 = in_viewing_key.address(default_d);
|
||||||
|
EXPECT_TRUE(addrOpt2);
|
||||||
|
auto default_addr_2 = addrOpt2.value();
|
||||||
EXPECT_EQ(default_addr, default_addr_2);
|
EXPECT_EQ(default_addr, default_addr_2);
|
||||||
|
|
||||||
auto default_addr_3 = libzcash::SaplingPaymentAddress(default_d, default_pk_d);
|
auto default_addr_3 = libzcash::SaplingPaymentAddress(default_d, default_pk_d);
|
||||||
@@ -161,6 +163,40 @@ TEST(keystore_tests, StoreAndRetrieveViewingKey) {
|
|||||||
EXPECT_EQ(ZCNoteDecryption(sk.receiving_key()), decOut);
|
EXPECT_EQ(ZCNoteDecryption(sk.receiving_key()), decOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sapling
|
||||||
|
TEST(keystore_tests, StoreAndRetrieveSaplingSpendingKey) {
|
||||||
|
CBasicKeyStore keyStore;
|
||||||
|
libzcash::SaplingSpendingKey skOut;
|
||||||
|
libzcash::SaplingFullViewingKey fvkOut;
|
||||||
|
libzcash::SaplingIncomingViewingKey ivkOut;
|
||||||
|
|
||||||
|
auto sk = libzcash::SaplingSpendingKey::random();
|
||||||
|
auto fvk = sk.full_viewing_key();
|
||||||
|
auto ivk = fvk.in_viewing_key();
|
||||||
|
auto addr = sk.default_address();
|
||||||
|
|
||||||
|
// Sanity-check: we can't get a key we haven't added
|
||||||
|
EXPECT_FALSE(keyStore.HaveSaplingSpendingKey(fvk));
|
||||||
|
EXPECT_FALSE(keyStore.GetSaplingSpendingKey(fvk, skOut));
|
||||||
|
// Sanity-check: we can't get a full viewing key we haven't added
|
||||||
|
EXPECT_FALSE(keyStore.HaveSaplingFullViewingKey(ivk));
|
||||||
|
EXPECT_FALSE(keyStore.GetSaplingFullViewingKey(ivk, fvkOut));
|
||||||
|
// Sanity-check: we can't get an incoming viewing key we haven't added
|
||||||
|
EXPECT_FALSE(keyStore.HaveSaplingIncomingViewingKey(addr));
|
||||||
|
EXPECT_FALSE(keyStore.GetSaplingIncomingViewingKey(addr, ivkOut));
|
||||||
|
|
||||||
|
keyStore.AddSaplingSpendingKey(sk);
|
||||||
|
EXPECT_TRUE(keyStore.HaveSaplingSpendingKey(fvk));
|
||||||
|
EXPECT_TRUE(keyStore.GetSaplingSpendingKey(fvk, skOut));
|
||||||
|
EXPECT_TRUE(keyStore.HaveSaplingFullViewingKey(ivk));
|
||||||
|
EXPECT_TRUE(keyStore.GetSaplingFullViewingKey(ivk, fvkOut));
|
||||||
|
EXPECT_TRUE(keyStore.HaveSaplingIncomingViewingKey(addr));
|
||||||
|
EXPECT_TRUE(keyStore.GetSaplingIncomingViewingKey(addr, ivkOut));
|
||||||
|
EXPECT_EQ(sk, skOut);
|
||||||
|
EXPECT_EQ(fvk, fvkOut);
|
||||||
|
EXPECT_EQ(ivk, ivkOut);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_WALLET
|
#ifdef ENABLE_WALLET
|
||||||
class TestCCryptoKeyStore : public CCryptoKeyStore
|
class TestCCryptoKeyStore : public CCryptoKeyStore
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ TEST(SaplingNote, TestVectors)
|
|||||||
TEST(SaplingNote, Random)
|
TEST(SaplingNote, Random)
|
||||||
{
|
{
|
||||||
// Test creating random notes using the same spending key
|
// Test creating random notes using the same spending key
|
||||||
auto address = SaplingSpendingKey::random().default_address().get();
|
auto address = SaplingSpendingKey::random().default_address();
|
||||||
SaplingNote note1(address, GetRand(MAX_MONEY));
|
SaplingNote note1(address, GetRand(MAX_MONEY));
|
||||||
SaplingNote note2(address, GetRand(MAX_MONEY));
|
SaplingNote note2(address, GetRand(MAX_MONEY));
|
||||||
|
|
||||||
@@ -66,7 +66,7 @@ TEST(SaplingNote, Random)
|
|||||||
ASSERT_NE(note1.r, note2.r);
|
ASSERT_NE(note1.r, note2.r);
|
||||||
|
|
||||||
// Test diversifier and pk_d are not the same for different spending keys
|
// Test diversifier and pk_d are not the same for different spending keys
|
||||||
SaplingNote note3(SaplingSpendingKey::random().default_address().get(), GetRand(MAX_MONEY));
|
SaplingNote note3(SaplingSpendingKey::random().default_address(), GetRand(MAX_MONEY));
|
||||||
ASSERT_NE(note1.d, note3.d);
|
ASSERT_NE(note1.d, note3.d);
|
||||||
ASSERT_NE(note1.pk_d, note3.pk_d);
|
ASSERT_NE(note1.pk_d, note3.pk_d);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,6 +93,27 @@ bool CBasicKeyStore::AddSpendingKey(const libzcash::SproutSpendingKey &sk)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! Sapling
|
||||||
|
bool CBasicKeyStore::AddSaplingSpendingKey(const libzcash::SaplingSpendingKey &sk)
|
||||||
|
{
|
||||||
|
LOCK(cs_SpendingKeyStore);
|
||||||
|
auto fvk = sk.full_viewing_key();
|
||||||
|
|
||||||
|
// if SaplingFullViewingKey is not in SaplingFullViewingKeyMap, add it
|
||||||
|
if (!AddSaplingFullViewingKey(fvk)){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mapSaplingSpendingKeys[fvk] = sk;
|
||||||
|
|
||||||
|
// Add addr -> SaplingIncomingViewing to SaplingIncomingViewingKeyMap
|
||||||
|
auto ivk = fvk.in_viewing_key();
|
||||||
|
auto addr = sk.default_address();
|
||||||
|
mapSaplingIncomingViewingKeys[addr] = ivk;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool CBasicKeyStore::AddViewingKey(const libzcash::SproutViewingKey &vk)
|
bool CBasicKeyStore::AddViewingKey(const libzcash::SproutViewingKey &vk)
|
||||||
{
|
{
|
||||||
LOCK(cs_SpendingKeyStore);
|
LOCK(cs_SpendingKeyStore);
|
||||||
@@ -102,6 +123,17 @@ bool CBasicKeyStore::AddViewingKey(const libzcash::SproutViewingKey &vk)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CBasicKeyStore::AddSaplingFullViewingKey(const libzcash::SaplingFullViewingKey &fvk)
|
||||||
|
{
|
||||||
|
LOCK(cs_SpendingKeyStore);
|
||||||
|
auto ivk = fvk.in_viewing_key();
|
||||||
|
mapSaplingFullViewingKeys[ivk] = fvk;
|
||||||
|
|
||||||
|
//! TODO: Note decryptors for Sapling
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool CBasicKeyStore::RemoveViewingKey(const libzcash::SproutViewingKey &vk)
|
bool CBasicKeyStore::RemoveViewingKey(const libzcash::SproutViewingKey &vk)
|
||||||
{
|
{
|
||||||
LOCK(cs_SpendingKeyStore);
|
LOCK(cs_SpendingKeyStore);
|
||||||
@@ -115,6 +147,18 @@ bool CBasicKeyStore::HaveViewingKey(const libzcash::SproutPaymentAddress &addres
|
|||||||
return mapViewingKeys.count(address) > 0;
|
return mapViewingKeys.count(address) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CBasicKeyStore::HaveSaplingFullViewingKey(const libzcash::SaplingIncomingViewingKey &ivk) const
|
||||||
|
{
|
||||||
|
LOCK(cs_SpendingKeyStore);
|
||||||
|
return mapSaplingFullViewingKeys.count(ivk) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CBasicKeyStore::HaveSaplingIncomingViewingKey(const libzcash::SaplingPaymentAddress &addr) const
|
||||||
|
{
|
||||||
|
LOCK(cs_SpendingKeyStore);
|
||||||
|
return mapSaplingIncomingViewingKeys.count(addr) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool CBasicKeyStore::GetViewingKey(const libzcash::SproutPaymentAddress &address,
|
bool CBasicKeyStore::GetViewingKey(const libzcash::SproutPaymentAddress &address,
|
||||||
libzcash::SproutViewingKey &vkOut) const
|
libzcash::SproutViewingKey &vkOut) const
|
||||||
{
|
{
|
||||||
@@ -126,3 +170,27 @@ bool CBasicKeyStore::GetViewingKey(const libzcash::SproutPaymentAddress &address
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CBasicKeyStore::GetSaplingFullViewingKey(const libzcash::SaplingIncomingViewingKey &ivk,
|
||||||
|
libzcash::SaplingFullViewingKey &fvkOut) const
|
||||||
|
{
|
||||||
|
LOCK(cs_SpendingKeyStore);
|
||||||
|
SaplingFullViewingKeyMap::const_iterator mi = mapSaplingFullViewingKeys.find(ivk);
|
||||||
|
if (mi != mapSaplingFullViewingKeys.end()) {
|
||||||
|
fvkOut = mi->second;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CBasicKeyStore::GetSaplingIncomingViewingKey(const libzcash::SaplingPaymentAddress &addr,
|
||||||
|
libzcash::SaplingIncomingViewingKey &ivkOut) const
|
||||||
|
{
|
||||||
|
LOCK(cs_SpendingKeyStore);
|
||||||
|
SaplingIncomingViewingKeyMap::const_iterator mi = mapSaplingIncomingViewingKeys.find(addr);
|
||||||
|
if (mi != mapSaplingIncomingViewingKeys.end()) {
|
||||||
|
ivkOut = mi->second;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|||||||
@@ -56,6 +56,26 @@ public:
|
|||||||
virtual bool GetSpendingKey(const libzcash::SproutPaymentAddress &address, libzcash::SproutSpendingKey& skOut) const =0;
|
virtual bool GetSpendingKey(const libzcash::SproutPaymentAddress &address, libzcash::SproutSpendingKey& skOut) const =0;
|
||||||
virtual void GetPaymentAddresses(std::set<libzcash::SproutPaymentAddress> &setAddress) const =0;
|
virtual void GetPaymentAddresses(std::set<libzcash::SproutPaymentAddress> &setAddress) const =0;
|
||||||
|
|
||||||
|
//! Add a Sapling spending key to the store.
|
||||||
|
virtual bool AddSaplingSpendingKey(const libzcash::SaplingSpendingKey &sk) =0;
|
||||||
|
|
||||||
|
//! 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 GetSaplingSpendingKey(const libzcash::SaplingFullViewingKey &fvk, libzcash::SaplingSpendingKey& skOut) const =0;
|
||||||
|
|
||||||
|
//! Support for Sapling full viewing keys
|
||||||
|
virtual bool AddSaplingFullViewingKey(const libzcash::SaplingFullViewingKey &fvk) =0;
|
||||||
|
virtual bool HaveSaplingFullViewingKey(const libzcash::SaplingIncomingViewingKey &ivk) const =0;
|
||||||
|
virtual bool GetSaplingFullViewingKey(
|
||||||
|
const libzcash::SaplingIncomingViewingKey &ivk,
|
||||||
|
libzcash::SaplingFullViewingKey& fvkOut) const =0;
|
||||||
|
|
||||||
|
//! Sapling incoming viewing keys
|
||||||
|
virtual bool HaveSaplingIncomingViewingKey(const libzcash::SaplingPaymentAddress &addr) const =0;
|
||||||
|
virtual bool GetSaplingIncomingViewingKey(
|
||||||
|
const libzcash::SaplingPaymentAddress &addr,
|
||||||
|
libzcash::SaplingIncomingViewingKey& ivkOut) const =0;
|
||||||
|
|
||||||
//! Support for viewing keys
|
//! Support for viewing keys
|
||||||
virtual bool AddViewingKey(const libzcash::SproutViewingKey &vk) =0;
|
virtual bool AddViewingKey(const libzcash::SproutViewingKey &vk) =0;
|
||||||
virtual bool RemoveViewingKey(const libzcash::SproutViewingKey &vk) =0;
|
virtual bool RemoveViewingKey(const libzcash::SproutViewingKey &vk) =0;
|
||||||
@@ -70,6 +90,14 @@ typedef std::map<libzcash::SproutPaymentAddress, libzcash::SproutSpendingKey> Sp
|
|||||||
typedef std::map<libzcash::SproutPaymentAddress, libzcash::SproutViewingKey> ViewingKeyMap;
|
typedef std::map<libzcash::SproutPaymentAddress, libzcash::SproutViewingKey> ViewingKeyMap;
|
||||||
typedef std::map<libzcash::SproutPaymentAddress, ZCNoteDecryption> NoteDecryptorMap;
|
typedef std::map<libzcash::SproutPaymentAddress, ZCNoteDecryption> NoteDecryptorMap;
|
||||||
|
|
||||||
|
// Full viewing key has equivalent functionality to a transparent address
|
||||||
|
// 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::SaplingSpendingKey> SaplingSpendingKeyMap;
|
||||||
|
typedef std::map<libzcash::SaplingIncomingViewingKey, libzcash::SaplingFullViewingKey> SaplingFullViewingKeyMap;
|
||||||
|
// Only maps from default addresses to ivk, may need to be reworked when adding diversified addresses.
|
||||||
|
typedef std::map<libzcash::SaplingPaymentAddress, libzcash::SaplingIncomingViewingKey> SaplingIncomingViewingKeyMap;
|
||||||
|
|
||||||
/** Basic key store, that keeps keys in an address->secret map */
|
/** Basic key store, that keeps keys in an address->secret map */
|
||||||
class CBasicKeyStore : public CKeyStore
|
class CBasicKeyStore : public CKeyStore
|
||||||
{
|
{
|
||||||
@@ -81,6 +109,10 @@ protected:
|
|||||||
ViewingKeyMap mapViewingKeys;
|
ViewingKeyMap mapViewingKeys;
|
||||||
NoteDecryptorMap mapNoteDecryptors;
|
NoteDecryptorMap mapNoteDecryptors;
|
||||||
|
|
||||||
|
SaplingSpendingKeyMap mapSaplingSpendingKeys;
|
||||||
|
SaplingFullViewingKeyMap mapSaplingFullViewingKeys;
|
||||||
|
SaplingIncomingViewingKeyMap mapSaplingIncomingViewingKeys;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey);
|
bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey);
|
||||||
bool HaveKey(const CKeyID &address) const
|
bool HaveKey(const CKeyID &address) const
|
||||||
@@ -183,6 +215,43 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! Sapling
|
||||||
|
bool AddSaplingSpendingKey(const libzcash::SaplingSpendingKey &sk);
|
||||||
|
bool HaveSaplingSpendingKey(const libzcash::SaplingFullViewingKey &fvk) const
|
||||||
|
{
|
||||||
|
bool result;
|
||||||
|
{
|
||||||
|
LOCK(cs_SpendingKeyStore);
|
||||||
|
result = (mapSaplingSpendingKeys.count(fvk) > 0);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
bool GetSaplingSpendingKey(const libzcash::SaplingFullViewingKey &fvk, libzcash::SaplingSpendingKey &skOut) const
|
||||||
|
{
|
||||||
|
{
|
||||||
|
LOCK(cs_SpendingKeyStore);
|
||||||
|
|
||||||
|
SaplingSpendingKeyMap::const_iterator mi = mapSaplingSpendingKeys.find(fvk);
|
||||||
|
if (mi != mapSaplingSpendingKeys.end())
|
||||||
|
{
|
||||||
|
skOut = mi->second;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool AddSaplingFullViewingKey(const libzcash::SaplingFullViewingKey &fvk);
|
||||||
|
virtual bool HaveSaplingFullViewingKey(const libzcash::SaplingIncomingViewingKey &ivk) const;
|
||||||
|
virtual bool GetSaplingFullViewingKey(
|
||||||
|
const libzcash::SaplingIncomingViewingKey &ivk,
|
||||||
|
libzcash::SaplingFullViewingKey& fvkOut) const;
|
||||||
|
|
||||||
|
virtual bool HaveSaplingIncomingViewingKey(const libzcash::SaplingPaymentAddress &addr) const;
|
||||||
|
virtual bool GetSaplingIncomingViewingKey(
|
||||||
|
const libzcash::SaplingPaymentAddress &addr,
|
||||||
|
libzcash::SaplingIncomingViewingKey& ivkOut) const;
|
||||||
|
|
||||||
virtual bool AddViewingKey(const libzcash::SproutViewingKey &vk);
|
virtual bool AddViewingKey(const libzcash::SproutViewingKey &vk);
|
||||||
virtual bool RemoveViewingKey(const libzcash::SproutViewingKey &vk);
|
virtual bool RemoveViewingKey(const libzcash::SproutViewingKey &vk);
|
||||||
virtual bool HaveViewingKey(const libzcash::SproutPaymentAddress &address) const;
|
virtual bool HaveViewingKey(const libzcash::SproutPaymentAddress &address) const;
|
||||||
@@ -193,4 +262,7 @@ typedef std::vector<unsigned char, secure_allocator<unsigned char> > CKeyingMate
|
|||||||
typedef std::map<CKeyID, std::pair<CPubKey, std::vector<unsigned char> > > CryptedKeyMap;
|
typedef std::map<CKeyID, std::pair<CPubKey, std::vector<unsigned char> > > CryptedKeyMap;
|
||||||
typedef std::map<libzcash::SproutPaymentAddress, std::vector<unsigned char> > CryptedSpendingKeyMap;
|
typedef std::map<libzcash::SproutPaymentAddress, std::vector<unsigned char> > CryptedSpendingKeyMap;
|
||||||
|
|
||||||
|
//! Sapling
|
||||||
|
typedef std::map<libzcash::SaplingFullViewingKey, std::vector<unsigned char> > CryptedSaplingSpendingKeyMap;
|
||||||
|
|
||||||
#endif // BITCOIN_KEYSTORE_H
|
#endif // BITCOIN_KEYSTORE_H
|
||||||
|
|||||||
@@ -239,7 +239,7 @@ BOOST_AUTO_TEST_CASE(zs_address_test)
|
|||||||
{
|
{
|
||||||
auto addr = sk.default_address();
|
auto addr = sk.default_address();
|
||||||
|
|
||||||
std::string addr_string = EncodePaymentAddress(*addr);
|
std::string addr_string = EncodePaymentAddress(addr);
|
||||||
BOOST_CHECK(addr_string.compare(0, 2, Params().Bech32HRP(CChainParams::SAPLING_PAYMENT_ADDRESS)) == 0);
|
BOOST_CHECK(addr_string.compare(0, 2, Params().Bech32HRP(CChainParams::SAPLING_PAYMENT_ADDRESS)) == 0);
|
||||||
|
|
||||||
auto paymentaddr2 = DecodePaymentAddress(addr_string);
|
auto paymentaddr2 = DecodePaymentAddress(addr_string);
|
||||||
|
|||||||
@@ -322,6 +322,35 @@ bool CCryptoKeyStore::AddSpendingKey(const libzcash::SproutSpendingKey &sk)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CCryptoKeyStore::AddSaplingSpendingKey(const libzcash::SaplingSpendingKey &sk)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
LOCK(cs_SpendingKeyStore);
|
||||||
|
if (!IsCrypted()) {
|
||||||
|
return CBasicKeyStore::AddSaplingSpendingKey(sk);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsLocked()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<unsigned char> vchCryptedSecret;
|
||||||
|
CSecureDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||||
|
ss << sk;
|
||||||
|
CKeyingMaterial vchSecret(ss.begin(), ss.end());
|
||||||
|
auto address = sk.default_address();
|
||||||
|
auto fvk = sk.full_viewing_key();
|
||||||
|
if (!EncryptSecret(vMasterKey, vchSecret, address.GetHash(), vchCryptedSecret)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!AddCryptedSaplingSpendingKey(fvk, vchCryptedSecret)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool CCryptoKeyStore::AddCryptedSpendingKey(const libzcash::SproutPaymentAddress &address,
|
bool CCryptoKeyStore::AddCryptedSpendingKey(const libzcash::SproutPaymentAddress &address,
|
||||||
const libzcash::ReceivingKey &rk,
|
const libzcash::ReceivingKey &rk,
|
||||||
const std::vector<unsigned char> &vchCryptedSecret)
|
const std::vector<unsigned char> &vchCryptedSecret)
|
||||||
@@ -337,6 +366,21 @@ bool CCryptoKeyStore::AddCryptedSpendingKey(const libzcash::SproutPaymentAddress
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Handle note decryptors
|
||||||
|
bool CCryptoKeyStore::AddCryptedSaplingSpendingKey(const libzcash::SaplingFullViewingKey &fvk,
|
||||||
|
const std::vector<unsigned char> &vchCryptedSecret)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
LOCK(cs_SpendingKeyStore);
|
||||||
|
if (!SetCrypted()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mapCryptedSaplingSpendingKeys[fvk] = vchCryptedSecret;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool CCryptoKeyStore::GetSpendingKey(const libzcash::SproutPaymentAddress &address, libzcash::SproutSpendingKey &skOut) const
|
bool CCryptoKeyStore::GetSpendingKey(const libzcash::SproutPaymentAddress &address, libzcash::SproutSpendingKey &skOut) const
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -130,6 +130,8 @@ private:
|
|||||||
CryptedKeyMap mapCryptedKeys;
|
CryptedKeyMap mapCryptedKeys;
|
||||||
CryptedSpendingKeyMap mapCryptedSpendingKeys;
|
CryptedSpendingKeyMap mapCryptedSpendingKeys;
|
||||||
|
|
||||||
|
CryptedSaplingSpendingKeyMap mapCryptedSaplingSpendingKeys;
|
||||||
|
|
||||||
CKeyingMaterial vMasterKey;
|
CKeyingMaterial vMasterKey;
|
||||||
|
|
||||||
//! if fUseCrypto is true, mapKeys and mapSpendingKeys must be empty
|
//! if fUseCrypto is true, mapKeys and mapSpendingKeys must be empty
|
||||||
@@ -230,6 +232,10 @@ public:
|
|||||||
mi++;
|
mi++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//! Sapling
|
||||||
|
virtual bool AddCryptedSaplingSpendingKey(const libzcash::SaplingFullViewingKey &fvk,
|
||||||
|
const std::vector<unsigned char> &vchCryptedSecret);
|
||||||
|
bool AddSaplingSpendingKey(const libzcash::SaplingSpendingKey &sk);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wallet status (encrypted, locked) changed.
|
* Wallet status (encrypted, locked) changed.
|
||||||
|
|||||||
@@ -7,6 +7,29 @@
|
|||||||
|
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This test covers Sapling methods on CWallet
|
||||||
|
* GenerateNewSaplingZKey()
|
||||||
|
*/
|
||||||
|
TEST(wallet_zkeys_tests, store_and_load_sapling_zkeys) {
|
||||||
|
SelectParams(CBaseChainParams::MAIN);
|
||||||
|
|
||||||
|
CWallet wallet;
|
||||||
|
|
||||||
|
auto address = wallet.GenerateNewSaplingZKey();
|
||||||
|
|
||||||
|
// verify wallet has incoming viewing key for the address
|
||||||
|
ASSERT_TRUE(wallet.HaveSaplingIncomingViewingKey(address));
|
||||||
|
|
||||||
|
// manually add new spending key to wallet
|
||||||
|
auto sk = libzcash::SaplingSpendingKey::random();
|
||||||
|
ASSERT_TRUE(wallet.AddSaplingZKey(sk));
|
||||||
|
|
||||||
|
// verify wallet did add it
|
||||||
|
auto fvk = sk.full_viewing_key();
|
||||||
|
ASSERT_TRUE(wallet.HaveSaplingSpendingKey(fvk));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This test covers methods on CWallet
|
* This test covers methods on CWallet
|
||||||
* GenerateNewZKey()
|
* GenerateNewZKey()
|
||||||
|
|||||||
@@ -100,8 +100,51 @@ libzcash::PaymentAddress CWallet::GenerateNewZKey()
|
|||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Generate a new Sapling spending key and return its public payment address
|
||||||
|
SaplingPaymentAddress CWallet::GenerateNewSaplingZKey()
|
||||||
|
{
|
||||||
|
AssertLockHeld(cs_wallet); // mapSaplingZKeyMetadata
|
||||||
|
|
||||||
|
auto sk = SaplingSpendingKey::random();
|
||||||
|
auto fvk = sk.full_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
|
||||||
|
int64_t nCreationTime = GetTime();
|
||||||
|
mapSaplingZKeyMetadata[addr] = CKeyMetadata(nCreationTime);
|
||||||
|
|
||||||
|
if (!AddSaplingZKey(sk)) {
|
||||||
|
throw std::runtime_error("CWallet::GenerateNewSaplingZKey(): AddSaplingZKey failed");
|
||||||
|
}
|
||||||
|
// return default sapling payment address.
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add spending key to keystore
|
||||||
|
bool CWallet::AddSaplingZKey(const libzcash::SaplingSpendingKey &sk)
|
||||||
|
{
|
||||||
|
AssertLockHeld(cs_wallet); // mapSaplingZKeyMetadata
|
||||||
|
|
||||||
|
if (!CCryptoKeyStore::AddSaplingSpendingKey(sk)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fFileBacked) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Persist to disk
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Add spending key to keystore and persist to disk
|
// Add spending key to keystore and persist to disk
|
||||||
// TODO: Add Sapling support
|
|
||||||
bool CWallet::AddZKey(const libzcash::SproutSpendingKey &key)
|
bool CWallet::AddZKey(const libzcash::SproutSpendingKey &key)
|
||||||
{
|
{
|
||||||
AssertLockHeld(cs_wallet); // mapZKeyMetadata
|
AssertLockHeld(cs_wallet); // mapZKeyMetadata
|
||||||
|
|||||||
@@ -786,6 +786,7 @@ public:
|
|||||||
std::set<int64_t> setKeyPool;
|
std::set<int64_t> setKeyPool;
|
||||||
std::map<CKeyID, CKeyMetadata> mapKeyMetadata;
|
std::map<CKeyID, CKeyMetadata> mapKeyMetadata;
|
||||||
std::map<libzcash::SproutPaymentAddress, CKeyMetadata> mapZKeyMetadata;
|
std::map<libzcash::SproutPaymentAddress, CKeyMetadata> mapZKeyMetadata;
|
||||||
|
std::map<libzcash::SaplingPaymentAddress, CKeyMetadata> mapSaplingZKeyMetadata;
|
||||||
|
|
||||||
typedef std::map<unsigned int, CMasterKey> MasterKeyMap;
|
typedef std::map<unsigned int, CMasterKey> MasterKeyMap;
|
||||||
MasterKeyMap mapMasterKeys;
|
MasterKeyMap mapMasterKeys;
|
||||||
@@ -978,6 +979,14 @@ public:
|
|||||||
//! Adds a viewing key to the store, without saving it to disk (used by LoadWallet)
|
//! Adds a viewing key to the store, without saving it to disk (used by LoadWallet)
|
||||||
bool LoadViewingKey(const libzcash::SproutViewingKey &dest);
|
bool LoadViewingKey(const libzcash::SproutViewingKey &dest);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sapling ZKeys
|
||||||
|
*/
|
||||||
|
//! Generates new Sapling key
|
||||||
|
libzcash::SaplingPaymentAddress GenerateNewSaplingZKey();
|
||||||
|
//! Adds Sapling spending key to the store, and saves it to disk
|
||||||
|
bool AddSaplingZKey(const libzcash::SaplingSpendingKey &key);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Increment the next transaction order id
|
* Increment the next transaction order id
|
||||||
* @return next transaction order id
|
* @return next transaction order id
|
||||||
|
|||||||
@@ -39,6 +39,12 @@ SproutPaymentAddress SproutSpendingKey::address() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//! Sapling
|
//! Sapling
|
||||||
|
uint256 SaplingPaymentAddress::GetHash() const {
|
||||||
|
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||||
|
ss << *this;
|
||||||
|
return Hash(ss.begin(), ss.end());
|
||||||
|
}
|
||||||
|
|
||||||
SaplingFullViewingKey SaplingExpandedSpendingKey::full_viewing_key() const {
|
SaplingFullViewingKey SaplingExpandedSpendingKey::full_viewing_key() const {
|
||||||
uint256 ak;
|
uint256 ak;
|
||||||
uint256 nk;
|
uint256 nk;
|
||||||
@@ -75,8 +81,11 @@ boost::optional<SaplingPaymentAddress> SaplingIncomingViewingKey::address(divers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::optional<SaplingPaymentAddress> SaplingSpendingKey::default_address() const {
|
SaplingPaymentAddress SaplingSpendingKey::default_address() const {
|
||||||
return full_viewing_key().in_viewing_key().address(default_diversifier(*this));
|
// Iterates within default_diversifier to ensure a valid address is returned
|
||||||
|
auto addrOpt = full_viewing_key().in_viewing_key().address(default_diversifier(*this));
|
||||||
|
assert(addrOpt != boost::none);
|
||||||
|
return addrOpt.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -112,6 +112,9 @@ public:
|
|||||||
READWRITE(pk_d);
|
READWRITE(pk_d);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! Get the 256-bit SHA256d hash of this payment address.
|
||||||
|
uint256 GetHash() const;
|
||||||
|
|
||||||
friend inline bool operator==(const SaplingPaymentAddress& a, const SaplingPaymentAddress& b) {
|
friend inline bool operator==(const SaplingPaymentAddress& a, const SaplingPaymentAddress& b) {
|
||||||
return a.d == b.d && a.pk_d == b.pk_d;
|
return a.d == b.d && a.pk_d == b.pk_d;
|
||||||
}
|
}
|
||||||
@@ -202,7 +205,7 @@ public:
|
|||||||
SaplingFullViewingKey full_viewing_key() const;
|
SaplingFullViewingKey full_viewing_key() const;
|
||||||
|
|
||||||
// Can derive Sapling addr from default diversifier
|
// Can derive Sapling addr from default diversifier
|
||||||
boost::optional<SaplingPaymentAddress> default_address() const;
|
SaplingPaymentAddress default_address() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef boost::variant<InvalidEncoding, SproutPaymentAddress, SaplingPaymentAddress> PaymentAddress;
|
typedef boost::variant<InvalidEncoding, SproutPaymentAddress, SaplingPaymentAddress> PaymentAddress;
|
||||||
|
|||||||
Reference in New Issue
Block a user