Store ExtFVK with encrypted Sapling spending key instead of FVK
This ensures that even when the wallet is encrypted, we can derive the default Sapling payment address for our spending keys.
This commit is contained in:
@@ -311,6 +311,6 @@ typedef std::map<CKeyID, std::pair<CPubKey, std::vector<unsigned char> > > Crypt
|
|||||||
typedef std::map<libzcash::SproutPaymentAddress, std::vector<unsigned char> > CryptedSproutSpendingKeyMap;
|
typedef std::map<libzcash::SproutPaymentAddress, std::vector<unsigned char> > CryptedSproutSpendingKeyMap;
|
||||||
|
|
||||||
//! Sapling
|
//! Sapling
|
||||||
typedef std::map<libzcash::SaplingFullViewingKey, std::vector<unsigned char> > CryptedSaplingSpendingKeyMap;
|
typedef std::map<libzcash::SaplingExtendedFullViewingKey, std::vector<unsigned char> > CryptedSaplingSpendingKeyMap;
|
||||||
|
|
||||||
#endif // BITCOIN_KEYSTORE_H
|
#endif // BITCOIN_KEYSTORE_H
|
||||||
|
|||||||
@@ -170,11 +170,11 @@ 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::SaplingExtendedFullViewingKey& extfvk,
|
||||||
libzcash::SaplingExtendedSpendingKey& sk)
|
libzcash::SaplingExtendedSpendingKey& sk)
|
||||||
{
|
{
|
||||||
CKeyingMaterial vchSecret;
|
CKeyingMaterial vchSecret;
|
||||||
if (!DecryptSecret(vMasterKey, vchCryptedSecret, fvk.GetFingerprint(), vchSecret))
|
if (!DecryptSecret(vMasterKey, vchCryptedSecret, extfvk.fvk.GetFingerprint(), vchSecret))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (vchSecret.size() != ZIP32_XSK_SIZE)
|
if (vchSecret.size() != ZIP32_XSK_SIZE)
|
||||||
@@ -182,7 +182,7 @@ static bool DecryptSaplingSpendingKey(const CKeyingMaterial& vMasterKey,
|
|||||||
|
|
||||||
CSecureDataStream ss(vchSecret, SER_NETWORK, PROTOCOL_VERSION);
|
CSecureDataStream ss(vchSecret, SER_NETWORK, PROTOCOL_VERSION);
|
||||||
ss >> sk;
|
ss >> sk;
|
||||||
return sk.expsk.full_viewing_key() == fvk;
|
return sk.expsk.full_viewing_key() == extfvk.fvk;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CCryptoKeyStore::SetCrypted()
|
bool CCryptoKeyStore::SetCrypted()
|
||||||
@@ -261,10 +261,10 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
|
|||||||
CryptedSaplingSpendingKeyMap::const_iterator miSapling = mapCryptedSaplingSpendingKeys.begin();
|
CryptedSaplingSpendingKeyMap::const_iterator miSapling = mapCryptedSaplingSpendingKeys.begin();
|
||||||
for (; miSapling != mapCryptedSaplingSpendingKeys.end(); ++miSapling)
|
for (; miSapling != mapCryptedSaplingSpendingKeys.end(); ++miSapling)
|
||||||
{
|
{
|
||||||
const libzcash::SaplingFullViewingKey &fvk = (*miSapling).first;
|
const libzcash::SaplingExtendedFullViewingKey &extfvk = (*miSapling).first;
|
||||||
const std::vector<unsigned char> &vchCryptedSecret = (*miSapling).second;
|
const std::vector<unsigned char> &vchCryptedSecret = (*miSapling).second;
|
||||||
libzcash::SaplingExtendedSpendingKey sk;
|
libzcash::SaplingExtendedSpendingKey sk;
|
||||||
if (!DecryptSaplingSpendingKey(vMasterKeyIn, vchCryptedSecret, fvk, sk))
|
if (!DecryptSaplingSpendingKey(vMasterKeyIn, vchCryptedSecret, extfvk, sk))
|
||||||
{
|
{
|
||||||
keyFail = true;
|
keyFail = true;
|
||||||
break;
|
break;
|
||||||
@@ -465,12 +465,12 @@ 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.expsk.full_viewing_key();
|
auto extfvk = sk.ToXFVK();
|
||||||
if (!EncryptSecret(vMasterKey, vchSecret, fvk.GetFingerprint(), vchCryptedSecret)) {
|
if (!EncryptSecret(vMasterKey, vchSecret, extfvk.fvk.GetFingerprint(), vchCryptedSecret)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!AddCryptedSaplingSpendingKey(fvk, vchCryptedSecret, defaultAddr)) {
|
if (!AddCryptedSaplingSpendingKey(extfvk, vchCryptedSecret, defaultAddr)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -494,7 +494,7 @@ bool CCryptoKeyStore::AddCryptedSproutSpendingKey(
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool CCryptoKeyStore::AddCryptedSaplingSpendingKey(
|
bool CCryptoKeyStore::AddCryptedSaplingSpendingKey(
|
||||||
const libzcash::SaplingFullViewingKey &fvk,
|
const libzcash::SaplingExtendedFullViewingKey &extfvk,
|
||||||
const std::vector<unsigned char> &vchCryptedSecret,
|
const std::vector<unsigned char> &vchCryptedSecret,
|
||||||
const libzcash::SaplingPaymentAddress &defaultAddr)
|
const libzcash::SaplingPaymentAddress &defaultAddr)
|
||||||
{
|
{
|
||||||
@@ -505,11 +505,11 @@ bool CCryptoKeyStore::AddCryptedSaplingSpendingKey(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// if SaplingFullViewingKey is not in SaplingFullViewingKeyMap, add it
|
// if SaplingFullViewingKey is not in SaplingFullViewingKeyMap, add it
|
||||||
if (!AddSaplingFullViewingKey(fvk, defaultAddr)) {
|
if (!AddSaplingFullViewingKey(extfvk.fvk, defaultAddr)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
mapCryptedSaplingSpendingKeys[fvk] = vchCryptedSecret;
|
mapCryptedSaplingSpendingKeys[extfvk] = vchCryptedSecret;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -538,11 +538,11 @@ bool CCryptoKeyStore::GetSaplingSpendingKey(const libzcash::SaplingFullViewingKe
|
|||||||
if (!IsCrypted())
|
if (!IsCrypted())
|
||||||
return CBasicKeyStore::GetSaplingSpendingKey(fvk, skOut);
|
return CBasicKeyStore::GetSaplingSpendingKey(fvk, skOut);
|
||||||
|
|
||||||
CryptedSaplingSpendingKeyMap::const_iterator mi = mapCryptedSaplingSpendingKeys.find(fvk);
|
for (auto entry : mapCryptedSaplingSpendingKeys) {
|
||||||
if (mi != mapCryptedSaplingSpendingKeys.end())
|
if (entry.first.fvk == fvk) {
|
||||||
{
|
const std::vector<unsigned char> &vchCryptedSecret = entry.second;
|
||||||
const std::vector<unsigned char> &vchCryptedSecret = (*mi).second;
|
return DecryptSaplingSpendingKey(vMasterKey, vchCryptedSecret, entry.first, skOut);
|
||||||
return DecryptSaplingSpendingKey(vMasterKey, vchCryptedSecret, fvk, skOut);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -609,12 +609,12 @@ bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn)
|
|||||||
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.expsk.full_viewing_key();
|
auto extfvk = sk.ToXFVK();
|
||||||
std::vector<unsigned char> vchCryptedSecret;
|
std::vector<unsigned char> vchCryptedSecret;
|
||||||
if (!EncryptSecret(vMasterKeyIn, vchSecret, fvk.GetFingerprint(), vchCryptedSecret)) {
|
if (!EncryptSecret(vMasterKeyIn, vchSecret, extfvk.fvk.GetFingerprint(), vchCryptedSecret)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!AddCryptedSaplingSpendingKey(fvk, vchCryptedSecret, sk.DefaultAddress())) {
|
if (!AddCryptedSaplingSpendingKey(extfvk, vchCryptedSecret, sk.DefaultAddress())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -241,7 +241,7 @@ public:
|
|||||||
}
|
}
|
||||||
//! Sapling
|
//! Sapling
|
||||||
virtual bool AddCryptedSaplingSpendingKey(
|
virtual bool AddCryptedSaplingSpendingKey(
|
||||||
const libzcash::SaplingFullViewingKey &fvk,
|
const libzcash::SaplingExtendedFullViewingKey &extfvk,
|
||||||
const std::vector<unsigned char> &vchCryptedSecret,
|
const std::vector<unsigned char> &vchCryptedSecret,
|
||||||
const libzcash::SaplingPaymentAddress &defaultAddr);
|
const libzcash::SaplingPaymentAddress &defaultAddr);
|
||||||
bool AddSaplingSpendingKey(
|
bool AddSaplingSpendingKey(
|
||||||
@@ -253,7 +253,11 @@ public:
|
|||||||
LOCK(cs_SpendingKeyStore);
|
LOCK(cs_SpendingKeyStore);
|
||||||
if (!IsCrypted())
|
if (!IsCrypted())
|
||||||
return CBasicKeyStore::HaveSaplingSpendingKey(fvk);
|
return CBasicKeyStore::HaveSaplingSpendingKey(fvk);
|
||||||
return mapCryptedSaplingSpendingKeys.count(fvk) > 0;
|
for (auto entry : mapCryptedSaplingSpendingKeys) {
|
||||||
|
if (entry.first.fvk == fvk) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -293,11 +293,11 @@ bool CWallet::AddCryptedSproutSpendingKey(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CWallet::AddCryptedSaplingSpendingKey(const libzcash::SaplingFullViewingKey &fvk,
|
bool CWallet::AddCryptedSaplingSpendingKey(const libzcash::SaplingExtendedFullViewingKey &extfvk,
|
||||||
const std::vector<unsigned char> &vchCryptedSecret,
|
const std::vector<unsigned char> &vchCryptedSecret,
|
||||||
const libzcash::SaplingPaymentAddress &defaultAddr)
|
const libzcash::SaplingPaymentAddress &defaultAddr)
|
||||||
{
|
{
|
||||||
if (!CCryptoKeyStore::AddCryptedSaplingSpendingKey(fvk, vchCryptedSecret, defaultAddr))
|
if (!CCryptoKeyStore::AddCryptedSaplingSpendingKey(extfvk, vchCryptedSecret, defaultAddr))
|
||||||
return false;
|
return false;
|
||||||
if (!fFileBacked)
|
if (!fFileBacked)
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -1060,7 +1060,7 @@ public:
|
|||||||
const libzcash::SaplingExtendedSpendingKey &key,
|
const libzcash::SaplingExtendedSpendingKey &key,
|
||||||
const libzcash::SaplingPaymentAddress &defaultAddr);
|
const libzcash::SaplingPaymentAddress &defaultAddr);
|
||||||
bool AddCryptedSaplingSpendingKey(
|
bool AddCryptedSaplingSpendingKey(
|
||||||
const libzcash::SaplingFullViewingKey &fvk,
|
const libzcash::SaplingExtendedFullViewingKey &extfvk,
|
||||||
const std::vector<unsigned char> &vchCryptedSecret,
|
const std::vector<unsigned char> &vchCryptedSecret,
|
||||||
const libzcash::SaplingPaymentAddress &defaultAddr);
|
const libzcash::SaplingPaymentAddress &defaultAddr);
|
||||||
|
|
||||||
|
|||||||
@@ -78,6 +78,21 @@ struct SaplingExtendedFullViewingKey {
|
|||||||
Address(diversifier_index_t j) const;
|
Address(diversifier_index_t j) const;
|
||||||
|
|
||||||
libzcash::SaplingPaymentAddress DefaultAddress() const;
|
libzcash::SaplingPaymentAddress DefaultAddress() const;
|
||||||
|
|
||||||
|
friend inline bool operator==(const SaplingExtendedFullViewingKey& a, const SaplingExtendedFullViewingKey& b) {
|
||||||
|
return (
|
||||||
|
a.depth == b.depth &&
|
||||||
|
a.parentFVKTag == b.parentFVKTag &&
|
||||||
|
a.childIndex == b.childIndex &&
|
||||||
|
a.chaincode == b.chaincode &&
|
||||||
|
a.fvk == b.fvk &&
|
||||||
|
a.dk == b.dk);
|
||||||
|
}
|
||||||
|
friend inline bool operator<(const SaplingExtendedFullViewingKey& a, const SaplingExtendedFullViewingKey& b) {
|
||||||
|
return (a.depth < b.depth ||
|
||||||
|
(a.depth == b.depth && a.childIndex < b.childIndex) ||
|
||||||
|
(a.depth == b.depth && a.childIndex == b.childIndex && a.fvk < b.fvk));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SaplingExtendedSpendingKey {
|
struct SaplingExtendedSpendingKey {
|
||||||
|
|||||||
Reference in New Issue
Block a user