From 1b79de781c800611b1b9c15b53d1bbe8fff2efdd Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 5 Oct 2018 23:13:32 +0100 Subject: [PATCH] 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. --- src/keystore.h | 2 +- src/wallet/crypter.cpp | 38 +++++++++++++++++++------------------- src/wallet/crypter.h | 8 ++++++-- src/wallet/wallet.cpp | 4 ++-- src/wallet/wallet.h | 2 +- src/zcash/zip32.h | 15 +++++++++++++++ 6 files changed, 44 insertions(+), 25 deletions(-) diff --git a/src/keystore.h b/src/keystore.h index b369dec78..6ff34b20d 100644 --- a/src/keystore.h +++ b/src/keystore.h @@ -311,6 +311,6 @@ typedef std::map > > Crypt typedef std::map > CryptedSproutSpendingKeyMap; //! Sapling -typedef std::map > CryptedSaplingSpendingKeyMap; +typedef std::map > CryptedSaplingSpendingKeyMap; #endif // BITCOIN_KEYSTORE_H diff --git a/src/wallet/crypter.cpp b/src/wallet/crypter.cpp index 25d69cc3d..cf87c01d4 100644 --- a/src/wallet/crypter.cpp +++ b/src/wallet/crypter.cpp @@ -170,11 +170,11 @@ static bool DecryptSproutSpendingKey(const CKeyingMaterial& vMasterKey, static bool DecryptSaplingSpendingKey(const CKeyingMaterial& vMasterKey, const std::vector& vchCryptedSecret, - const libzcash::SaplingFullViewingKey& fvk, + const libzcash::SaplingExtendedFullViewingKey& extfvk, libzcash::SaplingExtendedSpendingKey& sk) { CKeyingMaterial vchSecret; - if (!DecryptSecret(vMasterKey, vchCryptedSecret, fvk.GetFingerprint(), vchSecret)) + if (!DecryptSecret(vMasterKey, vchCryptedSecret, extfvk.fvk.GetFingerprint(), vchSecret)) return false; if (vchSecret.size() != ZIP32_XSK_SIZE) @@ -182,7 +182,7 @@ static bool DecryptSaplingSpendingKey(const CKeyingMaterial& vMasterKey, CSecureDataStream ss(vchSecret, SER_NETWORK, PROTOCOL_VERSION); ss >> sk; - return sk.expsk.full_viewing_key() == fvk; + return sk.expsk.full_viewing_key() == extfvk.fvk; } bool CCryptoKeyStore::SetCrypted() @@ -261,10 +261,10 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn) CryptedSaplingSpendingKeyMap::const_iterator miSapling = mapCryptedSaplingSpendingKeys.begin(); for (; miSapling != mapCryptedSaplingSpendingKeys.end(); ++miSapling) { - const libzcash::SaplingFullViewingKey &fvk = (*miSapling).first; + const libzcash::SaplingExtendedFullViewingKey &extfvk = (*miSapling).first; const std::vector &vchCryptedSecret = (*miSapling).second; libzcash::SaplingExtendedSpendingKey sk; - if (!DecryptSaplingSpendingKey(vMasterKeyIn, vchCryptedSecret, fvk, sk)) + if (!DecryptSaplingSpendingKey(vMasterKeyIn, vchCryptedSecret, extfvk, sk)) { keyFail = true; break; @@ -465,12 +465,12 @@ bool CCryptoKeyStore::AddSaplingSpendingKey( CSecureDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss << sk; CKeyingMaterial vchSecret(ss.begin(), ss.end()); - auto fvk = sk.expsk.full_viewing_key(); - if (!EncryptSecret(vMasterKey, vchSecret, fvk.GetFingerprint(), vchCryptedSecret)) { + auto extfvk = sk.ToXFVK(); + if (!EncryptSecret(vMasterKey, vchSecret, extfvk.fvk.GetFingerprint(), vchCryptedSecret)) { return false; } - if (!AddCryptedSaplingSpendingKey(fvk, vchCryptedSecret, defaultAddr)) { + if (!AddCryptedSaplingSpendingKey(extfvk, vchCryptedSecret, defaultAddr)) { return false; } } @@ -494,7 +494,7 @@ bool CCryptoKeyStore::AddCryptedSproutSpendingKey( } bool CCryptoKeyStore::AddCryptedSaplingSpendingKey( - const libzcash::SaplingFullViewingKey &fvk, + const libzcash::SaplingExtendedFullViewingKey &extfvk, const std::vector &vchCryptedSecret, const libzcash::SaplingPaymentAddress &defaultAddr) { @@ -505,11 +505,11 @@ bool CCryptoKeyStore::AddCryptedSaplingSpendingKey( } // if SaplingFullViewingKey is not in SaplingFullViewingKeyMap, add it - if (!AddSaplingFullViewingKey(fvk, defaultAddr)) { + if (!AddSaplingFullViewingKey(extfvk.fvk, defaultAddr)) { return false; } - mapCryptedSaplingSpendingKeys[fvk] = vchCryptedSecret; + mapCryptedSaplingSpendingKeys[extfvk] = vchCryptedSecret; } return true; } @@ -538,11 +538,11 @@ bool CCryptoKeyStore::GetSaplingSpendingKey(const libzcash::SaplingFullViewingKe if (!IsCrypted()) return CBasicKeyStore::GetSaplingSpendingKey(fvk, skOut); - CryptedSaplingSpendingKeyMap::const_iterator mi = mapCryptedSaplingSpendingKeys.find(fvk); - if (mi != mapCryptedSaplingSpendingKeys.end()) - { - const std::vector &vchCryptedSecret = (*mi).second; - return DecryptSaplingSpendingKey(vMasterKey, vchCryptedSecret, fvk, skOut); + for (auto entry : mapCryptedSaplingSpendingKeys) { + if (entry.first.fvk == fvk) { + const std::vector &vchCryptedSecret = entry.second; + return DecryptSaplingSpendingKey(vMasterKey, vchCryptedSecret, entry.first, skOut); + } } } return false; @@ -609,12 +609,12 @@ bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn) CSecureDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss << sk; CKeyingMaterial vchSecret(ss.begin(), ss.end()); - libzcash::SaplingFullViewingKey fvk = sk.expsk.full_viewing_key(); + auto extfvk = sk.ToXFVK(); std::vector vchCryptedSecret; - if (!EncryptSecret(vMasterKeyIn, vchSecret, fvk.GetFingerprint(), vchCryptedSecret)) { + if (!EncryptSecret(vMasterKeyIn, vchSecret, extfvk.fvk.GetFingerprint(), vchCryptedSecret)) { return false; } - if (!AddCryptedSaplingSpendingKey(fvk, vchCryptedSecret, sk.DefaultAddress())) { + if (!AddCryptedSaplingSpendingKey(extfvk, vchCryptedSecret, sk.DefaultAddress())) { return false; } } diff --git a/src/wallet/crypter.h b/src/wallet/crypter.h index b751ce300..1cfefe886 100644 --- a/src/wallet/crypter.h +++ b/src/wallet/crypter.h @@ -241,7 +241,7 @@ public: } //! Sapling virtual bool AddCryptedSaplingSpendingKey( - const libzcash::SaplingFullViewingKey &fvk, + const libzcash::SaplingExtendedFullViewingKey &extfvk, const std::vector &vchCryptedSecret, const libzcash::SaplingPaymentAddress &defaultAddr); bool AddSaplingSpendingKey( @@ -253,7 +253,11 @@ public: LOCK(cs_SpendingKeyStore); if (!IsCrypted()) return CBasicKeyStore::HaveSaplingSpendingKey(fvk); - return mapCryptedSaplingSpendingKeys.count(fvk) > 0; + for (auto entry : mapCryptedSaplingSpendingKeys) { + if (entry.first.fvk == fvk) { + return true; + } + } } return false; } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index b53691fbb..09a9d15d5 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -293,11 +293,11 @@ bool CWallet::AddCryptedSproutSpendingKey( return false; } -bool CWallet::AddCryptedSaplingSpendingKey(const libzcash::SaplingFullViewingKey &fvk, +bool CWallet::AddCryptedSaplingSpendingKey(const libzcash::SaplingExtendedFullViewingKey &extfvk, const std::vector &vchCryptedSecret, const libzcash::SaplingPaymentAddress &defaultAddr) { - if (!CCryptoKeyStore::AddCryptedSaplingSpendingKey(fvk, vchCryptedSecret, defaultAddr)) + if (!CCryptoKeyStore::AddCryptedSaplingSpendingKey(extfvk, vchCryptedSecret, defaultAddr)) return false; if (!fFileBacked) return true; diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index a08a8c782..95cd7b63e 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -1060,7 +1060,7 @@ public: const libzcash::SaplingExtendedSpendingKey &key, const libzcash::SaplingPaymentAddress &defaultAddr); bool AddCryptedSaplingSpendingKey( - const libzcash::SaplingFullViewingKey &fvk, + const libzcash::SaplingExtendedFullViewingKey &extfvk, const std::vector &vchCryptedSecret, const libzcash::SaplingPaymentAddress &defaultAddr); diff --git a/src/zcash/zip32.h b/src/zcash/zip32.h index 0fc5785bd..44bc58598 100644 --- a/src/zcash/zip32.h +++ b/src/zcash/zip32.h @@ -78,6 +78,21 @@ struct SaplingExtendedFullViewingKey { Address(diversifier_index_t j) 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 {