Browse Source

Use boost::variant to represent shielded addresses and keys

libzcash::PaymentAddress has been renamed to libzcash::SproutPaymentAddress,
and a new typedef boost::variant is now libzcash::PaymentAddress. Similarly
for ViewingKey and SpendingKey.

A new class InvalidEncoding is introduced as the default boost::variant
option for each address and key type; it is used during decoding instead
of boost::optional.

All address and key storage functions in the wallet have been modified to
refer specifically to the Sprout types, as they are used very precisely.
In most other cases, the more general type is leveraged as much as possible,
and we convert to the Sprout type when necessary. This will be subsequently
wrapped in, or replaced with, context-specific functions once Sapling
types are implemented.
metaverse
Jack Grigg 6 years ago
parent
commit
e5eab182b5
No known key found for this signature in database GPG Key ID: 665DBCD284F7DAFF
  1. 18
      src/gtest/test_joinsplit.cpp
  2. 24
      src/gtest/test_keystore.cpp
  3. 4
      src/gtest/test_paymentdisclosure.cpp
  4. 4
      src/gtest/test_transaction.cpp
  5. 2
      src/gtest/test_validation.cpp
  6. 108
      src/key_io.cpp
  7. 7
      src/key_io.h
  8. 12
      src/keystore.cpp
  9. 42
      src/keystore.h
  10. 6
      src/paymentdisclosure.h
  11. 7
      src/rpcmisc.cpp
  12. 4
      src/test/coins_tests.cpp
  13. 12
      src/test/key_tests.cpp
  14. 35
      src/test/rpc_wallet_tests.cpp
  15. 4
      src/test/transaction_tests.cpp
  16. 14
      src/utiltest.cpp
  17. 6
      src/utiltest.h
  18. 22
      src/wallet/asyncrpcoperation_mergetoaddress.cpp
  19. 2
      src/wallet/asyncrpcoperation_mergetoaddress.h
  20. 31
      src/wallet/asyncrpcoperation_sendmany.cpp
  21. 10
      src/wallet/asyncrpcoperation_shieldcoinbase.cpp
  22. 18
      src/wallet/crypter.cpp
  23. 10
      src/wallet/crypter.h
  24. 52
      src/wallet/gtest/test_wallet.cpp
  25. 42
      src/wallet/gtest/test_wallet_zkeys.cpp
  26. 2
      src/wallet/rpcdisclosure.cpp
  27. 42
      src/wallet/rpcdump.cpp
  28. 85
      src/wallet/rpcwallet.cpp
  29. 30
      src/wallet/wallet.cpp
  30. 30
      src/wallet/wallet.h
  31. 18
      src/wallet/walletdb.cpp
  32. 8
      src/wallet/walletdb.h
  33. 31
      src/zcash/Address.cpp
  34. 54
      src/zcash/Address.hpp
  35. 4
      src/zcash/JoinSplit.cpp
  36. 8
      src/zcash/JoinSplit.hpp
  37. 4
      src/zcash/Note.cpp
  38. 4
      src/zcash/Note.hpp
  39. 2
      src/zcash/circuit/note.tcc
  40. 6
      src/zcbenchmarks.cpp

18
src/gtest/test_joinsplit.cpp

@ -25,8 +25,8 @@ void test_full_api(ZCJoinSplit* js)
auto verifier = libzcash::ProofVerifier::Strict();
// The recipient's information.
SpendingKey recipient_key = SpendingKey::random();
PaymentAddress recipient_addr = recipient_key.address();
SproutSpendingKey recipient_key = SproutSpendingKey::random();
SproutPaymentAddress recipient_addr = recipient_key.address();
// Create the commitment tree
ZCIncrementalMerkleTree tree;
@ -122,8 +122,8 @@ void test_full_api(ZCJoinSplit* js)
JSInput(witness_recipient, decrypted_note, recipient_key)
};
SpendingKey second_recipient = SpendingKey::random();
PaymentAddress second_addr = second_recipient.address();
SproutSpendingKey second_recipient = SproutSpendingKey::random();
SproutPaymentAddress second_addr = second_recipient.address();
boost::array<JSOutput, 2> outputs = {
JSOutput(second_addr, 9),
@ -317,8 +317,8 @@ TEST(joinsplit, full_api_test)
std::vector<ZCIncrementalWitness> witnesses;
ZCIncrementalMerkleTree tree;
increment_note_witnesses(uint256(), witnesses, tree);
SpendingKey sk = SpendingKey::random();
PaymentAddress addr = sk.address();
SproutSpendingKey sk = SproutSpendingKey::random();
SproutPaymentAddress addr = sk.address();
SproutNote note1(addr.a_pk, 100, random_uint256(), random_uint256());
increment_note_witnesses(note1.cm(), witnesses, tree);
SproutNote note2(addr.a_pk, 100, random_uint256(), random_uint256());
@ -422,7 +422,7 @@ TEST(joinsplit, full_api_test)
// Wrong secret key
invokeAPIFailure(params,
{
JSInput(witnesses[1], note1, SpendingKey::random()),
JSInput(witnesses[1], note1, SproutSpendingKey::random()),
JSInput()
},
{
@ -519,7 +519,7 @@ TEST(joinsplit, note_plaintexts)
uint256 a_pk = PRF_addr_a_pk(a_sk);
uint256 sk_enc = ZCNoteEncryption::generate_privkey(a_sk);
uint256 pk_enc = ZCNoteEncryption::generate_pubkey(sk_enc);
PaymentAddress addr_pk(a_pk, pk_enc);
SproutPaymentAddress addr_pk(a_pk, pk_enc);
uint256 h_sig;
@ -572,7 +572,7 @@ TEST(joinsplit, note_class)
uint256 a_pk = PRF_addr_a_pk(a_sk);
uint256 sk_enc = ZCNoteEncryption::generate_privkey(a_sk);
uint256 pk_enc = ZCNoteEncryption::generate_pubkey(sk_enc);
PaymentAddress addr_pk(a_pk, pk_enc);
SproutPaymentAddress addr_pk(a_pk, pk_enc);
SproutNote note(a_pk,
1945813,

24
src/gtest/test_keystore.cpp

@ -9,13 +9,13 @@
TEST(keystore_tests, store_and_retrieve_spending_key) {
CBasicKeyStore keyStore;
libzcash::SpendingKey skOut;
libzcash::SproutSpendingKey skOut;
std::set<libzcash::PaymentAddress> addrs;
std::set<libzcash::SproutPaymentAddress> addrs;
keyStore.GetPaymentAddresses(addrs);
EXPECT_EQ(0, addrs.size());
auto sk = libzcash::SpendingKey::random();
auto sk = libzcash::SproutSpendingKey::random();
auto addr = sk.address();
// Sanity-check: we can't get a key we haven't added
@ -36,7 +36,7 @@ TEST(keystore_tests, store_and_retrieve_note_decryptor) {
CBasicKeyStore keyStore;
ZCNoteDecryption decOut;
auto sk = libzcash::SpendingKey::random();
auto sk = libzcash::SproutSpendingKey::random();
auto addr = sk.address();
EXPECT_FALSE(keyStore.GetNoteDecryptor(addr, decOut));
@ -48,11 +48,11 @@ TEST(keystore_tests, store_and_retrieve_note_decryptor) {
TEST(keystore_tests, StoreAndRetrieveViewingKey) {
CBasicKeyStore keyStore;
libzcash::ViewingKey vkOut;
libzcash::SpendingKey skOut;
libzcash::SproutViewingKey vkOut;
libzcash::SproutSpendingKey skOut;
ZCNoteDecryption decOut;
auto sk = libzcash::SpendingKey::random();
auto sk = libzcash::SproutSpendingKey::random();
auto vk = sk.viewing_key();
auto addr = sk.address();
@ -66,7 +66,7 @@ TEST(keystore_tests, StoreAndRetrieveViewingKey) {
EXPECT_FALSE(keyStore.GetNoteDecryptor(addr, decOut));
// and we can't find it in our list of addresses
std::set<libzcash::PaymentAddress> addresses;
std::set<libzcash::SproutPaymentAddress> addresses;
keyStore.GetPaymentAddresses(addresses);
EXPECT_FALSE(addresses.count(addr));
@ -115,12 +115,12 @@ TEST(keystore_tests, store_and_retrieve_spending_key_in_encrypted_store) {
TestCCryptoKeyStore keyStore;
uint256 r {GetRandHash()};
CKeyingMaterial vMasterKey (r.begin(), r.end());
libzcash::SpendingKey keyOut;
libzcash::SproutSpendingKey keyOut;
ZCNoteDecryption decOut;
std::set<libzcash::PaymentAddress> addrs;
std::set<libzcash::SproutPaymentAddress> addrs;
// 1) Test adding a key to an unencrypted key store, then encrypting it
auto sk = libzcash::SpendingKey::random();
auto sk = libzcash::SproutSpendingKey::random();
auto addr = sk.address();
EXPECT_FALSE(keyStore.GetNoteDecryptor(addr, decOut));
@ -157,7 +157,7 @@ TEST(keystore_tests, store_and_retrieve_spending_key_in_encrypted_store) {
ASSERT_EQ(1, addrs.count(addr));
// 2) Test adding a spending key to an already-encrypted key store
auto sk2 = libzcash::SpendingKey::random();
auto sk2 = libzcash::SproutSpendingKey::random();
auto addr2 = sk2.address();
EXPECT_FALSE(keyStore.GetNoteDecryptor(addr2, decOut));

4
src/gtest/test_paymentdisclosure.cpp

@ -120,7 +120,7 @@ TEST(paymentdisclosure, mainnet) {
PaymentDisclosureInfo info;
info.esk = random_uint256();
info.joinSplitPrivKey = joinSplitPrivKey;
info.zaddr = libzcash::SpendingKey::random().address();
info.zaddr = libzcash::SproutSpendingKey::random().address();
ASSERT_TRUE(mydb.Put(key, info));
// Retrieve info from test database into new local variable and test it matches
@ -131,7 +131,7 @@ TEST(paymentdisclosure, mainnet) {
// Modify this local variable and confirm it no longer matches
info2.esk = random_uint256();
info2.joinSplitPrivKey = random_uint256();
info2.zaddr = libzcash::SpendingKey::random().address();
info2.zaddr = libzcash::SproutSpendingKey::random().address();
ASSERT_NE(info, info2);
// Using the payment info object, let's create a dummy payload

4
src/gtest/test_transaction.cpp

@ -12,8 +12,8 @@ TEST(Transaction, JSDescriptionRandomized) {
// construct a merkle tree
ZCIncrementalMerkleTree merkleTree;
libzcash::SpendingKey k = libzcash::SpendingKey::random();
libzcash::PaymentAddress addr = k.address();
libzcash::SproutSpendingKey k = libzcash::SproutSpendingKey::random();
libzcash::SproutPaymentAddress addr = k.address();
libzcash::SproutNote note(addr.a_pk, 100, uint256(), uint256());

2
src/gtest/test_validation.cpp

@ -87,7 +87,7 @@ TEST(Validation, ContextualCheckInputsPassesWithCoinbase) {
}
TEST(Validation, ReceivedBlockTransactions) {
auto sk = libzcash::SpendingKey::random();
auto sk = libzcash::SproutSpendingKey::random();
// Create a fake genesis block
CBlock block1;

108
src/key_io.cpp

@ -67,6 +67,70 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par
}
return CNoDestination();
}
class PaymentAddressEncoder : public boost::static_visitor<std::string>
{
private:
const CChainParams& m_params;
public:
PaymentAddressEncoder(const CChainParams& params) : m_params(params) {}
std::string operator()(const libzcash::SproutPaymentAddress& zaddr) const
{
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << zaddr;
std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::ZCPAYMENT_ADDRRESS);
data.insert(data.end(), ss.begin(), ss.end());
return EncodeBase58Check(data);
}
std::string operator()(const libzcash::InvalidEncoding& no) const { return {}; }
};
class ViewingKeyEncoder : public boost::static_visitor<std::string>
{
private:
const CChainParams& m_params;
public:
ViewingKeyEncoder(const CChainParams& params) : m_params(params) {}
std::string operator()(const libzcash::SproutViewingKey& vk) const
{
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << vk;
std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::ZCVIEWING_KEY);
data.insert(data.end(), ss.begin(), ss.end());
std::string ret = EncodeBase58Check(data);
memory_cleanse(data.data(), data.size());
return ret;
}
std::string operator()(const libzcash::InvalidEncoding& no) const { return {}; }
};
class SpendingKeyEncoder : public boost::static_visitor<std::string>
{
private:
const CChainParams& m_params;
public:
SpendingKeyEncoder(const CChainParams& params) : m_params(params) {}
std::string operator()(const libzcash::SproutSpendingKey& zkey) const
{
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << zkey;
std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::ZCSPENDING_KEY);
data.insert(data.end(), ss.begin(), ss.end());
std::string ret = EncodeBase58Check(data);
memory_cleanse(data.data(), data.size());
return ret;
}
std::string operator()(const libzcash::InvalidEncoding& no) const { return {}; }
};
} // namespace
CKey DecodeSecret(const std::string& str)
@ -167,14 +231,10 @@ bool IsValidDestinationString(const std::string& str)
std::string EncodePaymentAddress(const libzcash::PaymentAddress& zaddr)
{
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << zaddr;
std::vector<unsigned char> data = Params().Base58Prefix(CChainParams::ZCPAYMENT_ADDRRESS);
data.insert(data.end(), ss.begin(), ss.end());
return EncodeBase58Check(data);
return boost::apply_visitor(PaymentAddressEncoder(Params()), zaddr);
}
boost::optional<libzcash::PaymentAddress> DecodePaymentAddress(const std::string& str)
libzcash::PaymentAddress DecodePaymentAddress(const std::string& str)
{
std::vector<unsigned char> data;
if (DecodeBase58Check(str, data)) {
@ -183,26 +243,24 @@ boost::optional<libzcash::PaymentAddress> DecodePaymentAddress(const std::string
std::equal(zaddr_prefix.begin(), zaddr_prefix.end(), data.begin())) {
CSerializeData serialized(data.begin() + zaddr_prefix.size(), data.end());
CDataStream ss(serialized, SER_NETWORK, PROTOCOL_VERSION);
libzcash::PaymentAddress ret;
libzcash::SproutPaymentAddress ret;
ss >> ret;
return ret;
}
}
return boost::none;
return libzcash::InvalidEncoding();
}
bool IsValidPaymentAddressString(const std::string& str) {
return IsValidPaymentAddress(DecodePaymentAddress(str));
}
std::string EncodeViewingKey(const libzcash::ViewingKey& vk)
{
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << vk;
std::vector<unsigned char> data = Params().Base58Prefix(CChainParams::ZCVIEWING_KEY);
data.insert(data.end(), ss.begin(), ss.end());
std::string ret = EncodeBase58Check(data);
memory_cleanse(data.data(), data.size());
return ret;
return boost::apply_visitor(ViewingKeyEncoder(Params()), vk);
}
boost::optional<libzcash::ViewingKey> DecodeViewingKey(const std::string& str)
libzcash::ViewingKey DecodeViewingKey(const std::string& str)
{
std::vector<unsigned char> data;
if (DecodeBase58Check(str, data)) {
@ -211,7 +269,7 @@ boost::optional<libzcash::ViewingKey> DecodeViewingKey(const std::string& str)
std::equal(vk_prefix.begin(), vk_prefix.end(), data.begin())) {
CSerializeData serialized(data.begin() + vk_prefix.size(), data.end());
CDataStream ss(serialized, SER_NETWORK, PROTOCOL_VERSION);
libzcash::ViewingKey ret;
libzcash::SproutViewingKey ret;
ss >> ret;
memory_cleanse(serialized.data(), serialized.size());
memory_cleanse(data.data(), data.size());
@ -219,21 +277,15 @@ boost::optional<libzcash::ViewingKey> DecodeViewingKey(const std::string& str)
}
}
memory_cleanse(data.data(), data.size());
return boost::none;
return libzcash::InvalidEncoding();
}
std::string EncodeSpendingKey(const libzcash::SpendingKey& zkey)
{
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << zkey;
std::vector<unsigned char> data = Params().Base58Prefix(CChainParams::ZCSPENDING_KEY);
data.insert(data.end(), ss.begin(), ss.end());
std::string ret = EncodeBase58Check(data);
memory_cleanse(data.data(), data.size());
return ret;
return boost::apply_visitor(SpendingKeyEncoder(Params()), zkey);
}
boost::optional<libzcash::SpendingKey> DecodeSpendingKey(const std::string& str)
libzcash::SpendingKey DecodeSpendingKey(const std::string& str)
{
std::vector<unsigned char> data;
if (DecodeBase58Check(str, data)) {
@ -242,7 +294,7 @@ boost::optional<libzcash::SpendingKey> DecodeSpendingKey(const std::string& str)
std::equal(zkey_prefix.begin(), zkey_prefix.end(), data.begin())) {
CSerializeData serialized(data.begin() + zkey_prefix.size(), data.end());
CDataStream ss(serialized, SER_NETWORK, PROTOCOL_VERSION);
libzcash::SpendingKey ret;
libzcash::SproutSpendingKey ret;
ss >> ret;
memory_cleanse(serialized.data(), serialized.size());
memory_cleanse(data.data(), data.size());
@ -250,5 +302,5 @@ boost::optional<libzcash::SpendingKey> DecodeSpendingKey(const std::string& str)
}
}
memory_cleanse(data.data(), data.size());
return boost::none;
return libzcash::InvalidEncoding();
}

7
src/key_io.h

@ -29,12 +29,13 @@ bool IsValidDestinationString(const std::string& str);
bool IsValidDestinationString(const std::string& str, const CChainParams& params);
std::string EncodePaymentAddress(const libzcash::PaymentAddress& zaddr);
boost::optional<libzcash::PaymentAddress> DecodePaymentAddress(const std::string& str);
libzcash::PaymentAddress DecodePaymentAddress(const std::string& str);
bool IsValidPaymentAddressString(const std::string& str);
std::string EncodeViewingKey(const libzcash::ViewingKey& vk);
boost::optional<libzcash::ViewingKey> DecodeViewingKey(const std::string& str);
libzcash::ViewingKey DecodeViewingKey(const std::string& str);
std::string EncodeSpendingKey(const libzcash::SpendingKey& zkey);
boost::optional<libzcash::SpendingKey> DecodeSpendingKey(const std::string& str);
libzcash::SpendingKey DecodeSpendingKey(const std::string& str);
#endif // BITCOIN_KEYIO_H

12
src/keystore.cpp

@ -84,7 +84,7 @@ bool CBasicKeyStore::HaveWatchOnly() const
return (!setWatchOnly.empty());
}
bool CBasicKeyStore::AddSpendingKey(const libzcash::SpendingKey &sk)
bool CBasicKeyStore::AddSpendingKey(const libzcash::SproutSpendingKey &sk)
{
LOCK(cs_SpendingKeyStore);
auto address = sk.address();
@ -93,7 +93,7 @@ bool CBasicKeyStore::AddSpendingKey(const libzcash::SpendingKey &sk)
return true;
}
bool CBasicKeyStore::AddViewingKey(const libzcash::ViewingKey &vk)
bool CBasicKeyStore::AddViewingKey(const libzcash::SproutViewingKey &vk)
{
LOCK(cs_SpendingKeyStore);
auto address = vk.address();
@ -102,21 +102,21 @@ bool CBasicKeyStore::AddViewingKey(const libzcash::ViewingKey &vk)
return true;
}
bool CBasicKeyStore::RemoveViewingKey(const libzcash::ViewingKey &vk)
bool CBasicKeyStore::RemoveViewingKey(const libzcash::SproutViewingKey &vk)
{
LOCK(cs_SpendingKeyStore);
mapViewingKeys.erase(vk.address());
return true;
}
bool CBasicKeyStore::HaveViewingKey(const libzcash::PaymentAddress &address) const
bool CBasicKeyStore::HaveViewingKey(const libzcash::SproutPaymentAddress &address) const
{
LOCK(cs_SpendingKeyStore);
return mapViewingKeys.count(address) > 0;
}
bool CBasicKeyStore::GetViewingKey(const libzcash::PaymentAddress &address,
libzcash::ViewingKey &vkOut) const
bool CBasicKeyStore::GetViewingKey(const libzcash::SproutPaymentAddress &address,
libzcash::SproutViewingKey &vkOut) const
{
LOCK(cs_SpendingKeyStore);
ViewingKeyMap::const_iterator mi = mapViewingKeys.find(address);

42
src/keystore.h

@ -49,26 +49,26 @@ public:
virtual bool HaveWatchOnly() const =0;
//! Add a spending key to the store.
virtual bool AddSpendingKey(const libzcash::SpendingKey &sk) =0;
virtual bool AddSpendingKey(const libzcash::SproutSpendingKey &sk) =0;
//! Check whether a spending key corresponding to a given payment address is present in the store.
virtual bool HaveSpendingKey(const libzcash::PaymentAddress &address) const =0;
virtual bool GetSpendingKey(const libzcash::PaymentAddress &address, libzcash::SpendingKey& skOut) const =0;
virtual void GetPaymentAddresses(std::set<libzcash::PaymentAddress> &setAddress) const =0;
virtual bool HaveSpendingKey(const libzcash::SproutPaymentAddress &address) const =0;
virtual bool GetSpendingKey(const libzcash::SproutPaymentAddress &address, libzcash::SproutSpendingKey& skOut) const =0;
virtual void GetPaymentAddresses(std::set<libzcash::SproutPaymentAddress> &setAddress) const =0;
//! Support for viewing keys
virtual bool AddViewingKey(const libzcash::ViewingKey &vk) =0;
virtual bool RemoveViewingKey(const libzcash::ViewingKey &vk) =0;
virtual bool HaveViewingKey(const libzcash::PaymentAddress &address) const =0;
virtual bool GetViewingKey(const libzcash::PaymentAddress &address, libzcash::ViewingKey& vkOut) const =0;
virtual bool AddViewingKey(const libzcash::SproutViewingKey &vk) =0;
virtual bool RemoveViewingKey(const libzcash::SproutViewingKey &vk) =0;
virtual bool HaveViewingKey(const libzcash::SproutPaymentAddress &address) const =0;
virtual bool GetViewingKey(const libzcash::SproutPaymentAddress &address, libzcash::SproutViewingKey& vkOut) const =0;
};
typedef std::map<CKeyID, CKey> KeyMap;
typedef std::map<CScriptID, CScript > ScriptMap;
typedef std::set<CScript> WatchOnlySet;
typedef std::map<libzcash::PaymentAddress, libzcash::SpendingKey> SpendingKeyMap;
typedef std::map<libzcash::PaymentAddress, libzcash::ViewingKey> ViewingKeyMap;
typedef std::map<libzcash::PaymentAddress, ZCNoteDecryption> NoteDecryptorMap;
typedef std::map<libzcash::SproutPaymentAddress, libzcash::SproutSpendingKey> SpendingKeyMap;
typedef std::map<libzcash::SproutPaymentAddress, libzcash::SproutViewingKey> ViewingKeyMap;
typedef std::map<libzcash::SproutPaymentAddress, ZCNoteDecryption> NoteDecryptorMap;
/** Basic key store, that keeps keys in an address->secret map */
class CBasicKeyStore : public CKeyStore
@ -127,8 +127,8 @@ public:
virtual bool HaveWatchOnly(const CScript &dest) const;
virtual bool HaveWatchOnly() const;
bool AddSpendingKey(const libzcash::SpendingKey &sk);
bool HaveSpendingKey(const libzcash::PaymentAddress &address) const
bool AddSpendingKey(const libzcash::SproutSpendingKey &sk);
bool HaveSpendingKey(const libzcash::SproutPaymentAddress &address) const
{
bool result;
{
@ -137,7 +137,7 @@ public:
}
return result;
}
bool GetSpendingKey(const libzcash::PaymentAddress &address, libzcash::SpendingKey &skOut) const
bool GetSpendingKey(const libzcash::SproutPaymentAddress &address, libzcash::SproutSpendingKey &skOut) const
{
{
LOCK(cs_SpendingKeyStore);
@ -150,7 +150,7 @@ public:
}
return false;
}
bool GetNoteDecryptor(const libzcash::PaymentAddress &address, ZCNoteDecryption &decOut) const
bool GetNoteDecryptor(const libzcash::SproutPaymentAddress &address, ZCNoteDecryption &decOut) const
{
{
LOCK(cs_SpendingKeyStore);
@ -163,7 +163,7 @@ public:
}
return false;
}
void GetPaymentAddresses(std::set<libzcash::PaymentAddress> &setAddress) const
void GetPaymentAddresses(std::set<libzcash::SproutPaymentAddress> &setAddress) const
{
setAddress.clear();
{
@ -183,14 +183,14 @@ public:
}
}
virtual bool AddViewingKey(const libzcash::ViewingKey &vk);
virtual bool RemoveViewingKey(const libzcash::ViewingKey &vk);
virtual bool HaveViewingKey(const libzcash::PaymentAddress &address) const;
virtual bool GetViewingKey(const libzcash::PaymentAddress &address, libzcash::ViewingKey& vkOut) const;
virtual bool AddViewingKey(const libzcash::SproutViewingKey &vk);
virtual bool RemoveViewingKey(const libzcash::SproutViewingKey &vk);
virtual bool HaveViewingKey(const libzcash::SproutPaymentAddress &address) const;
virtual bool GetViewingKey(const libzcash::SproutPaymentAddress &address, libzcash::SproutViewingKey& vkOut) const;
};
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CKeyingMaterial;
typedef std::map<CKeyID, std::pair<CPubKey, std::vector<unsigned char> > > CryptedKeyMap;
typedef std::map<libzcash::PaymentAddress, std::vector<unsigned char> > CryptedSpendingKeyMap;
typedef std::map<libzcash::SproutPaymentAddress, std::vector<unsigned char> > CryptedSpendingKeyMap;
#endif // BITCOIN_KEYSTORE_H

6
src/paymentdisclosure.h

@ -38,12 +38,12 @@ struct PaymentDisclosureInfo {
uint256 joinSplitPrivKey; // primitives/transaction.h
// ed25519 - not tied to implementation e.g. libsodium, see ed25519 rfc
libzcash::PaymentAddress zaddr;
libzcash::SproutPaymentAddress zaddr;
PaymentDisclosureInfo() : version(PAYMENT_DISCLOSURE_VERSION_EXPERIMENTAL) {
}
PaymentDisclosureInfo(uint8_t v, uint256 esk, uint256 key, libzcash::PaymentAddress zaddr) : version(v), esk(esk), joinSplitPrivKey(key), zaddr(zaddr) { }
PaymentDisclosureInfo(uint8_t v, uint256 esk, uint256 key, libzcash::SproutPaymentAddress zaddr) : version(v), esk(esk), joinSplitPrivKey(key), zaddr(zaddr) { }
ADD_SERIALIZE_METHODS;
@ -75,7 +75,7 @@ struct PaymentDisclosurePayload {
uint256 txid; // primitives/transaction.h
uint64_t js; // Index into CTransaction.vjoinsplit
uint8_t n; // Index into JSDescription fields of length ZC_NUM_JS_OUTPUTS
libzcash::PaymentAddress zaddr; // zcash/Address.hpp
libzcash::SproutPaymentAddress zaddr; // zcash/Address.hpp
std::string message; // parameter to RPC call
ADD_SERIALIZE_METHODS;

7
src/rpcmisc.cpp

@ -239,9 +239,12 @@ UniValue z_validateaddress(const UniValue& params, bool fHelp)
std::string payingKey, transmissionKey;
string strAddress = params[0].get_str();
auto isValid = DecodePaymentAddress(strAddress);
auto address = DecodePaymentAddress(strAddress);
bool isValid = IsValidPaymentAddress(address);
if (isValid) {
libzcash::PaymentAddress addr = *isValid;
// TODO: Add Sapling support
assert(boost::get<libzcash::SproutPaymentAddress>(&address) != nullptr);
libzcash::SproutPaymentAddress addr = boost::get<libzcash::SproutPaymentAddress>(address);
#ifdef ENABLE_WALLET
isMine = pwalletMain->HaveSpendingKey(addr);

4
src/test/coins_tests.cpp

@ -247,8 +247,8 @@ public:
uint256 appendRandomCommitment(ZCIncrementalMerkleTree &tree)
{
libzcash::SpendingKey k = libzcash::SpendingKey::random();
libzcash::PaymentAddress addr = k.address();
libzcash::SproutSpendingKey k = libzcash::SproutSpendingKey::random();
libzcash::SproutPaymentAddress addr = k.address();
libzcash::SproutNote note(addr.a_pk, 0, uint256(), uint256());

12
src/test/key_tests.cpp

@ -188,7 +188,7 @@ BOOST_AUTO_TEST_CASE(key_test1)
BOOST_AUTO_TEST_CASE(zc_address_test)
{
for (size_t i = 0; i < 1000; i++) {
auto sk = SpendingKey::random();
auto sk = SproutSpendingKey::random();
{
string sk_string = EncodeSpendingKey(sk);
@ -196,8 +196,9 @@ BOOST_AUTO_TEST_CASE(zc_address_test)
BOOST_CHECK(sk_string[1] == 'K');
auto spendingkey2 = DecodeSpendingKey(sk_string);
BOOST_ASSERT(static_cast<bool>(spendingkey2));
SpendingKey sk2 = *spendingkey2;
BOOST_CHECK(IsValidSpendingKey(spendingkey2));
BOOST_ASSERT(boost::get<SproutSpendingKey>(&spendingkey2) != nullptr);
auto sk2 = boost::get<SproutSpendingKey>(spendingkey2);
BOOST_CHECK(sk.inner() == sk2.inner());
}
{
@ -209,9 +210,10 @@ BOOST_AUTO_TEST_CASE(zc_address_test)
BOOST_CHECK(addr_string[1] == 'c');
auto paymentaddr2 = DecodePaymentAddress(addr_string);
BOOST_ASSERT(static_cast<bool>(paymentaddr2));
BOOST_ASSERT(IsValidPaymentAddress(paymentaddr2));
PaymentAddress addr2 = *paymentaddr2;
BOOST_ASSERT(boost::get<SproutPaymentAddress>(&paymentaddr2) != nullptr);
auto addr2 = boost::get<SproutPaymentAddress>(paymentaddr2);
BOOST_CHECK(addr.a_pk == addr2.a_pk);
BOOST_CHECK(addr.pk_enc == addr2.pk_enc);
}

35
src/test/rpc_wallet_tests.cpp

@ -343,7 +343,7 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_validateaddress)
BOOST_CHECK_THROW(CallRPC("z_validateaddress toomany args"), runtime_error);
// Wallet should be empty
std::set<libzcash::PaymentAddress> addrs;
std::set<libzcash::SproutPaymentAddress> addrs;
pwalletMain->GetPaymentAddresses(addrs);
BOOST_CHECK(addrs.size()==0);
@ -381,12 +381,15 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_exportwallet)
LOCK2(cs_main, pwalletMain->cs_wallet);
// wallet should be empty
std::set<libzcash::PaymentAddress> addrs;
std::set<libzcash::SproutPaymentAddress> addrs;
pwalletMain->GetPaymentAddresses(addrs);
BOOST_CHECK(addrs.size()==0);
// wallet should have one key
auto addr = pwalletMain->GenerateNewZKey();
auto address = pwalletMain->GenerateNewZKey();
BOOST_CHECK(IsValidPaymentAddress(address));
BOOST_ASSERT(boost::get<libzcash::SproutPaymentAddress>(&address) != nullptr);
auto addr = boost::get<libzcash::SproutPaymentAddress>(address);
pwalletMain->GetPaymentAddresses(addrs);
BOOST_CHECK(addrs.size()==1);
@ -411,7 +414,7 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_exportwallet)
BOOST_CHECK_NO_THROW(CallRPC(string("z_exportwallet ") + tmpfilename.string()));
libzcash::SpendingKey key;
libzcash::SproutSpendingKey key;
BOOST_CHECK(pwalletMain->GetSpendingKey(addr, key));
std::string s1 = EncodePaymentAddress(addr);
@ -456,7 +459,7 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importwallet)
BOOST_CHECK_THROW(CallRPC("z_importwallet toomany args"), runtime_error);
// create a random key locally
auto testSpendingKey = libzcash::SpendingKey::random();
auto testSpendingKey = libzcash::SproutSpendingKey::random();
auto testPaymentAddress = testSpendingKey.address();
std::string testAddr = EncodePaymentAddress(testPaymentAddress);
std::string testKey = EncodeSpendingKey(testSpendingKey);
@ -485,7 +488,7 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importwallet)
file << std::flush;
// wallet should currently be empty
std::set<libzcash::PaymentAddress> addrs;
std::set<libzcash::SproutPaymentAddress> addrs;
pwalletMain->GetPaymentAddresses(addrs);
BOOST_CHECK(addrs.size()==0);
@ -497,11 +500,14 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importwallet)
BOOST_CHECK(addrs.size()==1);
// check that we have the spending key for the address
auto addr = *DecodePaymentAddress(testAddr);
auto address = DecodePaymentAddress(testAddr);
BOOST_CHECK(IsValidPaymentAddress(address));
BOOST_ASSERT(boost::get<libzcash::SproutPaymentAddress>(&address) != nullptr);
auto addr = boost::get<libzcash::SproutPaymentAddress>(address);
BOOST_CHECK(pwalletMain->HaveSpendingKey(addr));
// Verify the spending key is the same as the test data
libzcash::SpendingKey k;
libzcash::SproutSpendingKey k;
BOOST_CHECK(pwalletMain->GetSpendingKey(addr, k));
BOOST_CHECK_EQUAL(testKey, EncodeSpendingKey(k));
}
@ -526,7 +532,7 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importexport)
BOOST_CHECK_THROW(CallRPC("z_exportkey toomany args"), runtime_error);
// error if invalid args
auto sk = libzcash::SpendingKey::random();
auto sk = libzcash::SproutSpendingKey::random();
std::string prefix = std::string("z_importkey ") + EncodeSpendingKey(sk) + " yes ";
BOOST_CHECK_THROW(CallRPC(prefix + "-1"), runtime_error);
BOOST_CHECK_THROW(CallRPC(prefix + "2147483647"), runtime_error); // allowed, but > height of active chain tip
@ -534,14 +540,14 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importexport)
BOOST_CHECK_THROW(CallRPC(prefix + "100badchars"), runtime_error);
// wallet should currently be empty
std::set<libzcash::PaymentAddress> addrs;
std::set<libzcash::SproutPaymentAddress> addrs;
pwalletMain->GetPaymentAddresses(addrs);
BOOST_CHECK(addrs.size()==0);
// verify import and export key
for (int i = 0; i < n1; i++) {
// create a random key locally
auto testSpendingKey = libzcash::SpendingKey::random();
auto testSpendingKey = libzcash::SproutSpendingKey::random();
auto testPaymentAddress = testSpendingKey.address();
std::string testAddr = EncodePaymentAddress(testPaymentAddress);
std::string testKey = EncodeSpendingKey(testSpendingKey);
@ -590,7 +596,10 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importexport)
// Add one more address
BOOST_CHECK_NO_THROW(retValue = CallRPC("z_getnewaddress"));
std::string newaddress = retValue.get_str();
auto newAddr = *DecodePaymentAddress(newaddress);
auto address = DecodePaymentAddress(newaddress);
BOOST_CHECK(IsValidPaymentAddress(address));
BOOST_ASSERT(boost::get<libzcash::SproutPaymentAddress>(&address) != nullptr);
auto newAddr = boost::get<libzcash::SproutPaymentAddress>(address);
BOOST_CHECK(pwalletMain->HaveSpendingKey(newAddr));
// Check if too many args
@ -1217,7 +1226,7 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_encrypted_wallet_zkeys)
int n = 100;
// wallet should currently be empty
std::set<libzcash::PaymentAddress> addrs;
std::set<libzcash::SproutPaymentAddress> addrs;
pwalletMain->GetPaymentAddresses(addrs);
BOOST_CHECK(addrs.size()==0);

4
src/test/transaction_tests.cpp

@ -342,8 +342,8 @@ BOOST_AUTO_TEST_CASE(test_basic_joinsplit_verification)
// construct a merkle tree
ZCIncrementalMerkleTree merkleTree;
libzcash::SpendingKey k = libzcash::SpendingKey::random();
libzcash::PaymentAddress addr = k.address();
auto k = libzcash::SproutSpendingKey::random();
auto addr = k.address();
libzcash::SproutNote note(addr.a_pk, 100, uint256(), uint256());

14
src/utiltest.cpp

@ -7,7 +7,7 @@
#include "consensus/upgrades.h"
CWalletTx GetValidReceive(ZCJoinSplit& params,
const libzcash::SpendingKey& sk, CAmount value,
const libzcash::SproutSpendingKey& sk, CAmount value,
bool randomInputs) {
CMutableTransaction mtx;
mtx.nVersion = 2; // Enable JoinSplits
@ -62,7 +62,7 @@ CWalletTx GetValidReceive(ZCJoinSplit& params,
}
libzcash::SproutNote GetNote(ZCJoinSplit& params,
const libzcash::SpendingKey& sk,
const libzcash::SproutSpendingKey& sk,
const CTransaction& tx, size_t js, size_t n) {
ZCNoteDecryption decryptor {sk.receiving_key()};
auto hSig = tx.vjoinsplit[js].h_sig(params, tx.joinSplitPubKey);
@ -76,7 +76,7 @@ libzcash::SproutNote GetNote(ZCJoinSplit& params,
}
CWalletTx GetValidSpend(ZCJoinSplit& params,
const libzcash::SpendingKey& sk,
const libzcash::SproutSpendingKey& sk,
const libzcash::SproutNote& note, CAmount value) {
CMutableTransaction mtx;
mtx.vout.resize(2);
@ -97,12 +97,12 @@ CWalletTx GetValidSpend(ZCJoinSplit& params,
{
if (note.value() > value) {
libzcash::SpendingKey dummykey = libzcash::SpendingKey::random();
libzcash::PaymentAddress dummyaddr = dummykey.address();
libzcash::SproutSpendingKey dummykey = libzcash::SproutSpendingKey::random();
libzcash::SproutPaymentAddress dummyaddr = dummykey.address();
dummyout = libzcash::JSOutput(dummyaddr, note.value() - value);
} else if (note.value() < value) {
libzcash::SpendingKey dummykey = libzcash::SpendingKey::random();
libzcash::PaymentAddress dummyaddr = dummykey.address();
libzcash::SproutSpendingKey dummykey = libzcash::SproutSpendingKey::random();
libzcash::SproutPaymentAddress dummyaddr = dummykey.address();
libzcash::SproutNote dummynote(dummyaddr.a_pk, (value - note.value()), uint256(), uint256());
tree.append(dummynote.cm());
dummyin = libzcash::JSInput(tree.witness(), dummynote, dummykey);

6
src/utiltest.h

@ -8,11 +8,11 @@
#include "zcash/NoteEncryption.hpp"
CWalletTx GetValidReceive(ZCJoinSplit& params,
const libzcash::SpendingKey& sk, CAmount value,
const libzcash::SproutSpendingKey& sk, CAmount value,
bool randomInputs);
libzcash::SproutNote GetNote(ZCJoinSplit& params,
const libzcash::SpendingKey& sk,
const libzcash::SproutSpendingKey& sk,
const CTransaction& tx, size_t js, size_t n);
CWalletTx GetValidSpend(ZCJoinSplit& params,
const libzcash::SpendingKey& sk,
const libzcash::SproutSpendingKey& sk,
const libzcash::SproutNote& note, CAmount value);

22
src/wallet/asyncrpcoperation_mergetoaddress.cpp

@ -80,9 +80,11 @@ AsyncRPCOperation_mergetoaddress::AsyncRPCOperation_mergetoaddress(
if (!isToTaddr_) {
auto address = DecodePaymentAddress(std::get<0>(recipient));
if (address) {
if (IsValidPaymentAddress(address)) {
isToZaddr_ = true;
toPaymentAddress_ = *address;
// TODO: Add Sapling support. For now, ensure we can later convert freely.
assert(boost::get<libzcash::SproutPaymentAddress>(&address) != nullptr);
toPaymentAddress_ = address;
} else {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid recipient address");
}
@ -307,7 +309,7 @@ bool AsyncRPCOperation_mergetoaddress::main_impl()
info.vpub_old = sendAmount;
info.vpub_new = 0;
JSOutput jso = JSOutput(toPaymentAddress_, sendAmount);
JSOutput jso = JSOutput(boost::get<libzcash::SproutPaymentAddress>(toPaymentAddress_), sendAmount);
if (hexMemo.size() > 0) {
jso.memo = get_memo_from_hex_string(hexMemo);
}
@ -326,6 +328,8 @@ bool AsyncRPCOperation_mergetoaddress::main_impl()
// Copy zinputs to more flexible containers
std::deque<MergeToAddressInputNote> zInputsDeque;
for (auto o : noteInputs_) {
// TODO: Add Sapling support. For now, ensure we can later convert freely.
assert(boost::get<libzcash::SproutSpendingKey>(&std::get<3>(o)) != nullptr);
zInputsDeque.push_back(o);
}
@ -365,8 +369,8 @@ bool AsyncRPCOperation_mergetoaddress::main_impl()
// At this point, we are guaranteed to have at least one input note.
// Use address of first input note as the temporary change address.
SpendingKey changeKey = std::get<3>(zInputsDeque.front());
PaymentAddress changeAddress = changeKey.address();
SproutSpendingKey changeKey = boost::get<libzcash::SproutSpendingKey>(std::get<3>(zInputsDeque.front()));
SproutPaymentAddress changeAddress = changeKey.address();
CAmount vpubOldTarget = 0;
CAmount vpubNewTarget = 0;
@ -481,7 +485,7 @@ bool AsyncRPCOperation_mergetoaddress::main_impl()
// Consume spendable non-change notes
//
std::vector<SproutNote> vInputNotes;
std::vector<SpendingKey> vInputZKeys;
std::vector<SproutSpendingKey> vInputZKeys;
std::vector<JSOutPoint> vOutPoints;
std::vector<boost::optional<ZCIncrementalWitness>> vInputWitnesses;
uint256 inputAnchor;
@ -491,7 +495,7 @@ bool AsyncRPCOperation_mergetoaddress::main_impl()
JSOutPoint jso = std::get<0>(t);
SproutNote note = std::get<1>(t);
CAmount noteFunds = std::get<2>(t);
SpendingKey zkey = std::get<3>(t);
SproutSpendingKey zkey = boost::get<libzcash::SproutSpendingKey>(std::get<3>(t));
zInputsDeque.pop_front();
MergeToAddressWitnessAnchorData wad = jsopWitnessAnchorMap[jso.ToString()];
@ -590,7 +594,7 @@ bool AsyncRPCOperation_mergetoaddress::main_impl()
// If this is the final output, set the target and memo
if (isToZaddr_ && vpubNewProcessed) {
outputType = "target";
jso.addr = toPaymentAddress_;
jso.addr = boost::get<libzcash::SproutPaymentAddress>(toPaymentAddress_);
if (!hexMemo.empty()) {
jso.memo = get_memo_from_hex_string(hexMemo);
}
@ -852,7 +856,7 @@ UniValue AsyncRPCOperation_mergetoaddress::perform_joinsplit(
// placeholder for txid will be filled in later when tx has been finalized and signed.
PaymentDisclosureKey pdKey = {placeholder, js_index, mapped_index};
JSOutput output = outputs[mapped_index];
libzcash::PaymentAddress zaddr = output.addr; // randomized output
libzcash::SproutPaymentAddress zaddr = output.addr; // randomized output
PaymentDisclosureInfo pdInfo = {PAYMENT_DISCLOSURE_VERSION_EXPERIMENTAL, esk, joinSplitPrivKey, zaddr};
paymentDisclosureData_.push_back(PaymentDisclosureKeyInfo(pdKey, pdInfo));

2
src/wallet/asyncrpcoperation_mergetoaddress.h

@ -37,7 +37,7 @@ struct MergeToAddressJSInfo {
std::vector<JSInput> vjsin;
std::vector<JSOutput> vjsout;
std::vector<SproutNote> notes;
std::vector<SpendingKey> zkeys;
std::vector<SproutSpendingKey> zkeys;
CAmount vpub_old = 0;
CAmount vpub_new = 0;
};

31
src/wallet/asyncrpcoperation_sendmany.cpp

@ -81,11 +81,13 @@ AsyncRPCOperation_sendmany::AsyncRPCOperation_sendmany(
if (!isfromtaddr_) {
auto address = DecodePaymentAddress(fromAddress);
if (address) {
PaymentAddress addr = *address;
if (IsValidPaymentAddress(address)) {
// TODO: Add Sapling support. For now, ensure we can freely convert.
assert(boost::get<libzcash::SproutPaymentAddress>(&address) != nullptr);
SproutPaymentAddress addr = boost::get<libzcash::SproutPaymentAddress>(address);
// We don't need to lock on the wallet as spending key related methods are thread-safe
SpendingKey key;
SproutSpendingKey key;
if (!pwalletMain->GetSpendingKey(addr, key)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, no spending key found for zaddr");
}
@ -401,6 +403,9 @@ bool AsyncRPCOperation_sendmany::main_impl() {
}
std::deque<SendManyRecipient> zOutputsDeque;
for (auto o : z_outputs_) {
// TODO: Add Sapling support. For now, ensure we can later convert freely.
auto addr = DecodePaymentAddress(std::get<0>(o));
assert(boost::get<libzcash::SproutPaymentAddress>(&addr) != nullptr);
zOutputsDeque.push_back(o);
}
@ -468,8 +473,8 @@ bool AsyncRPCOperation_sendmany::main_impl() {
std::string hexMemo = std::get<2>(smr);
zOutputsDeque.pop_front();
PaymentAddress pa = *DecodePaymentAddress(address);
JSOutput jso = JSOutput(pa, value);
PaymentAddress pa = DecodePaymentAddress(address);
JSOutput jso = JSOutput(boost::get<libzcash::SproutPaymentAddress>(pa), value);
if (hexMemo.size() > 0) {
jso.memo = get_memo_from_hex_string(hexMemo);
}
@ -569,7 +574,7 @@ bool AsyncRPCOperation_sendmany::main_impl() {
intermediates.insert(std::make_pair(tree.root(), tree)); // chained js are interstitial (found in between block boundaries)
// Decrypt the change note's ciphertext to retrieve some data we need
ZCNoteDecryption decryptor(spendingkey_.receiving_key());
ZCNoteDecryption decryptor(boost::get<libzcash::SproutSpendingKey>(spendingkey_).receiving_key());
auto hSig = prevJoinSplit.h_sig(*pzcashParams, tx_.joinSplitPubKey);
try {
SproutNotePlaintext plaintext = SproutNotePlaintext::decrypt(
@ -579,7 +584,7 @@ bool AsyncRPCOperation_sendmany::main_impl() {
hSig,
(unsigned char) changeOutputIndex);
SproutNote note = plaintext.note(frompaymentaddress_);
SproutNote note = plaintext.note(boost::get<libzcash::SproutPaymentAddress>(frompaymentaddress_));
info.notes.push_back(note);
jsInputValue += plaintext.value();
@ -727,8 +732,8 @@ bool AsyncRPCOperation_sendmany::main_impl() {
assert(value==0);
info.vjsout.push_back(JSOutput()); // dummy output while we accumulate funds into a change note for vpub_new
} else {
PaymentAddress pa = *DecodePaymentAddress(address);
JSOutput jso = JSOutput(pa, value);
PaymentAddress pa = DecodePaymentAddress(address);
JSOutput jso = JSOutput(boost::get<libzcash::SproutPaymentAddress>(pa), value);
if (hexMemo.size() > 0) {
jso.memo = get_memo_from_hex_string(hexMemo);
}
@ -737,7 +742,7 @@ bool AsyncRPCOperation_sendmany::main_impl() {
// create output for any change
if (jsChange>0) {
info.vjsout.push_back(JSOutput(frompaymentaddress_, jsChange));
info.vjsout.push_back(JSOutput(boost::get<libzcash::SproutPaymentAddress>(frompaymentaddress_), jsChange));
LogPrint("zrpcunsafe", "%s: generating note for change (amount=%s)\n",
getId(),
@ -886,7 +891,7 @@ bool AsyncRPCOperation_sendmany::find_unspent_notes() {
}
for (CSproutNotePlaintextEntry & entry : entries) {
z_inputs_.push_back(SendManyInputJSOP(entry.jsop, entry.plaintext.note(frompaymentaddress_), CAmount(entry.plaintext.value())));
z_inputs_.push_back(SendManyInputJSOP(entry.jsop, entry.plaintext.note(boost::get<libzcash::SproutPaymentAddress>(frompaymentaddress_)), CAmount(entry.plaintext.value())));
std::string data(entry.plaintext.memo().begin(), entry.plaintext.memo().end());
LogPrint("zrpcunsafe", "%s: found unspent note (txid=%s, vjoinsplit=%d, ciphertext=%d, amount=%s, memo=%s)\n",
getId(),
@ -948,7 +953,7 @@ UniValue AsyncRPCOperation_sendmany::perform_joinsplit(
if (!witnesses[i]) {
throw runtime_error("joinsplit input could not be found in tree");
}
info.vjsin.push_back(JSInput(*witnesses[i], info.notes[i], spendingkey_));
info.vjsin.push_back(JSInput(*witnesses[i], info.notes[i], boost::get<libzcash::SproutSpendingKey>(spendingkey_)));
}
// Make sure there are two inputs and two outputs
@ -1077,7 +1082,7 @@ UniValue AsyncRPCOperation_sendmany::perform_joinsplit(
// placeholder for txid will be filled in later when tx has been finalized and signed.
PaymentDisclosureKey pdKey = {placeholder, js_index, mapped_index};
JSOutput output = outputs[mapped_index];
libzcash::PaymentAddress zaddr = output.addr; // randomized output
libzcash::SproutPaymentAddress zaddr = output.addr; // randomized output
PaymentDisclosureInfo pdInfo = {PAYMENT_DISCLOSURE_VERSION_EXPERIMENTAL, esk, joinSplitPrivKey, zaddr};
paymentDisclosureData_.push_back(PaymentDisclosureKeyInfo(pdKey, pdInfo));

10
src/wallet/asyncrpcoperation_shieldcoinbase.cpp

@ -73,8 +73,10 @@ AsyncRPCOperation_shieldcoinbase::AsyncRPCOperation_shieldcoinbase(
// Check the destination address is valid for this network i.e. not testnet being used on mainnet
auto address = DecodePaymentAddress(toAddress);
if (address) {
tozaddr_ = *address;
if (IsValidPaymentAddress(address)) {
// TODO: Add Sapling support. For now, ensure we can freely convert.
assert(boost::get<libzcash::SproutPaymentAddress>(&address) != nullptr);
tozaddr_ = address;
} else {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid to address");
}
@ -233,7 +235,7 @@ bool AsyncRPCOperation_shieldcoinbase::main_impl() {
ShieldCoinbaseJSInfo info;
info.vpub_old = sendAmount;
info.vpub_new = 0;
JSOutput jso = JSOutput(tozaddr_, sendAmount);
JSOutput jso = JSOutput(boost::get<libzcash::SproutPaymentAddress>(tozaddr_), sendAmount);
info.vjsout.push_back(jso);
obj = perform_joinsplit(info);
@ -448,7 +450,7 @@ UniValue AsyncRPCOperation_shieldcoinbase::perform_joinsplit(ShieldCoinbaseJSInf
// placeholder for txid will be filled in later when tx has been finalized and signed.
PaymentDisclosureKey pdKey = {placeholder, js_index, mapped_index};
JSOutput output = outputs[mapped_index];
libzcash::PaymentAddress zaddr = output.addr; // randomized output
libzcash::SproutPaymentAddress zaddr = output.addr; // randomized output
PaymentDisclosureInfo pdInfo = {PAYMENT_DISCLOSURE_VERSION_EXPERIMENTAL, esk, joinSplitPrivKey, zaddr};
paymentDisclosureData_.push_back(PaymentDisclosureKeyInfo(pdKey, pdInfo));

18
src/wallet/crypter.cpp

@ -136,8 +136,8 @@ static bool DecryptKey(const CKeyingMaterial& vMasterKey, const std::vector<unsi
static bool DecryptSpendingKey(const CKeyingMaterial& vMasterKey,
const std::vector<unsigned char>& vchCryptedSecret,
const libzcash::PaymentAddress& address,
libzcash::SpendingKey& sk)
const libzcash::SproutPaymentAddress& address,
libzcash::SproutSpendingKey& sk)
{
CKeyingMaterial vchSecret;
if(!DecryptSecret(vMasterKey, vchCryptedSecret, address.GetHash(), vchSecret))
@ -203,9 +203,9 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
CryptedSpendingKeyMap::const_iterator skmi = mapCryptedSpendingKeys.begin();
for (; skmi != mapCryptedSpendingKeys.end(); ++skmi)
{
const libzcash::PaymentAddress &address = (*skmi).first;
const libzcash::SproutPaymentAddress &address = (*skmi).first;
const std::vector<unsigned char> &vchCryptedSecret = (*skmi).second;
libzcash::SpendingKey sk;
libzcash::SproutSpendingKey sk;
if (!DecryptSpendingKey(vMasterKeyIn, vchCryptedSecret, address, sk))
{
keyFail = true;
@ -298,7 +298,7 @@ bool CCryptoKeyStore::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) co
return false;
}
bool CCryptoKeyStore::AddSpendingKey(const libzcash::SpendingKey &sk)
bool CCryptoKeyStore::AddSpendingKey(const libzcash::SproutSpendingKey &sk)
{
{
LOCK(cs_SpendingKeyStore);
@ -322,7 +322,7 @@ bool CCryptoKeyStore::AddSpendingKey(const libzcash::SpendingKey &sk)
return true;
}
bool CCryptoKeyStore::AddCryptedSpendingKey(const libzcash::PaymentAddress &address,
bool CCryptoKeyStore::AddCryptedSpendingKey(const libzcash::SproutPaymentAddress &address,
const libzcash::ReceivingKey &rk,
const std::vector<unsigned char> &vchCryptedSecret)
{
@ -337,7 +337,7 @@ bool CCryptoKeyStore::AddCryptedSpendingKey(const libzcash::PaymentAddress &addr
return true;
}
bool CCryptoKeyStore::GetSpendingKey(const libzcash::PaymentAddress &address, libzcash::SpendingKey &skOut) const
bool CCryptoKeyStore::GetSpendingKey(const libzcash::SproutPaymentAddress &address, libzcash::SproutSpendingKey &skOut) const
{
{
LOCK(cs_SpendingKeyStore);
@ -376,11 +376,11 @@ bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn)
mapKeys.clear();
BOOST_FOREACH(SpendingKeyMap::value_type& mSpendingKey, mapSpendingKeys)
{
const libzcash::SpendingKey &sk = mSpendingKey.second;
const libzcash::SproutSpendingKey &sk = mSpendingKey.second;
CSecureDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << sk;
CKeyingMaterial vchSecret(ss.begin(), ss.end());
libzcash::PaymentAddress address = sk.address();
libzcash::SproutPaymentAddress address = sk.address();
std::vector<unsigned char> vchCryptedSecret;
if (!EncryptSecret(vMasterKeyIn, vchSecret, address.GetHash(), vchCryptedSecret))
return false;

10
src/wallet/crypter.h

@ -200,11 +200,11 @@ public:
mi++;
}
}
virtual bool AddCryptedSpendingKey(const libzcash::PaymentAddress &address,
virtual bool AddCryptedSpendingKey(const libzcash::SproutPaymentAddress &address,
const libzcash::ReceivingKey &rk,
const std::vector<unsigned char> &vchCryptedSecret);
bool AddSpendingKey(const libzcash::SpendingKey &sk);
bool HaveSpendingKey(const libzcash::PaymentAddress &address) const
bool AddSpendingKey(const libzcash::SproutSpendingKey &sk);
bool HaveSpendingKey(const libzcash::SproutPaymentAddress &address) const
{
{
LOCK(cs_SpendingKeyStore);
@ -214,8 +214,8 @@ public:
}
return false;
}
bool GetSpendingKey(const libzcash::PaymentAddress &address, libzcash::SpendingKey &skOut) const;
void GetPaymentAddresses(std::set<libzcash::PaymentAddress> &setAddress) const
bool GetSpendingKey(const libzcash::SproutPaymentAddress &address, libzcash::SproutSpendingKey &skOut) const;
void GetPaymentAddresses(std::set<libzcash::SproutPaymentAddress> &setAddress) const
{
if (!IsCrypted())
{

52
src/wallet/gtest/test_wallet.cpp

@ -68,22 +68,22 @@ public:
}
};
CWalletTx GetValidReceive(const libzcash::SpendingKey& sk, CAmount value, bool randomInputs) {
CWalletTx GetValidReceive(const libzcash::SproutSpendingKey& sk, CAmount value, bool randomInputs) {
return GetValidReceive(*params, sk, value, randomInputs);
}
libzcash::SproutNote GetNote(const libzcash::SpendingKey& sk,
libzcash::SproutNote GetNote(const libzcash::SproutSpendingKey& sk,
const CTransaction& tx, size_t js, size_t n) {
return GetNote(*params, sk, tx, js, n);
}
CWalletTx GetValidSpend(const libzcash::SpendingKey& sk,
CWalletTx GetValidSpend(const libzcash::SproutSpendingKey& sk,
const libzcash::SproutNote& note, CAmount value) {
return GetValidSpend(*params, sk, note, value);
}
JSOutPoint CreateValidBlock(TestWallet& wallet,
const libzcash::SpendingKey& sk,
const libzcash::SproutSpendingKey& sk,
const CBlockIndex& index,
CBlock& block,
ZCIncrementalMerkleTree& tree) {
@ -112,7 +112,7 @@ TEST(wallet_tests, setup_datadir_location_run_as_first_test) {
}
TEST(wallet_tests, note_data_serialisation) {
auto sk = libzcash::SpendingKey::random();
auto sk = libzcash::SproutSpendingKey::random();
auto wtx = GetValidReceive(sk, 10, true);
auto note = GetNote(sk, wtx, 0, 1);
auto nullifier = note.nullifier(sk);
@ -138,7 +138,7 @@ TEST(wallet_tests, note_data_serialisation) {
TEST(wallet_tests, find_unspent_notes) {
SelectParams(CBaseChainParams::TESTNET);
CWallet wallet;
auto sk = libzcash::SpendingKey::random();
auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSpendingKey(sk);
auto wtx = GetValidReceive(sk, 10, true);
@ -295,7 +295,7 @@ TEST(wallet_tests, find_unspent_notes) {
TEST(wallet_tests, set_note_addrs_in_cwallettx) {
auto sk = libzcash::SpendingKey::random();
auto sk = libzcash::SproutSpendingKey::random();
auto wtx = GetValidReceive(sk, 10, true);
auto note = GetNote(sk, wtx, 0, 1);
auto nullifier = note.nullifier(sk);
@ -315,7 +315,7 @@ TEST(wallet_tests, set_invalid_note_addrs_in_cwallettx) {
EXPECT_EQ(0, wtx.mapNoteData.size());
mapNoteData_t noteData;
auto sk = libzcash::SpendingKey::random();
auto sk = libzcash::SproutSpendingKey::random();
JSOutPoint jsoutpt {wtx.GetHash(), 0, 1};
CNoteData nd {sk.address(), uint256()};
noteData[jsoutpt] = nd;
@ -326,7 +326,7 @@ TEST(wallet_tests, set_invalid_note_addrs_in_cwallettx) {
TEST(wallet_tests, GetNoteNullifier) {
CWallet wallet;
auto sk = libzcash::SpendingKey::random();
auto sk = libzcash::SproutSpendingKey::random();
auto address = sk.address();
auto dec = ZCNoteDecryption(sk.receiving_key());
@ -357,8 +357,8 @@ TEST(wallet_tests, GetNoteNullifier) {
TEST(wallet_tests, FindMyNotes) {
CWallet wallet;
auto sk = libzcash::SpendingKey::random();
auto sk2 = libzcash::SpendingKey::random();
auto sk = libzcash::SproutSpendingKey::random();
auto sk2 = libzcash::SproutSpendingKey::random();
wallet.AddSpendingKey(sk2);
auto wtx = GetValidReceive(sk, 10, true);
@ -384,7 +384,7 @@ TEST(wallet_tests, FindMyNotesInEncryptedWallet) {
uint256 r {GetRandHash()};
CKeyingMaterial vMasterKey (r.begin(), r.end());
auto sk = libzcash::SpendingKey::random();
auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSpendingKey(sk);
ASSERT_TRUE(wallet.EncryptKeys(vMasterKey));
@ -412,7 +412,7 @@ TEST(wallet_tests, FindMyNotesInEncryptedWallet) {
TEST(wallet_tests, get_conflicted_notes) {
CWallet wallet;
auto sk = libzcash::SpendingKey::random();
auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSpendingKey(sk);
auto wtx = GetValidReceive(sk, 10, true);
@ -443,7 +443,7 @@ TEST(wallet_tests, get_conflicted_notes) {
TEST(wallet_tests, nullifier_is_spent) {
CWallet wallet;
auto sk = libzcash::SpendingKey::random();
auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSpendingKey(sk);
auto wtx = GetValidReceive(sk, 10, true);
@ -483,7 +483,7 @@ TEST(wallet_tests, nullifier_is_spent) {
TEST(wallet_tests, navigate_from_nullifier_to_note) {
CWallet wallet;
auto sk = libzcash::SpendingKey::random();
auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSpendingKey(sk);
auto wtx = GetValidReceive(sk, 10, true);
@ -509,7 +509,7 @@ TEST(wallet_tests, navigate_from_nullifier_to_note) {
TEST(wallet_tests, spent_note_is_from_me) {
CWallet wallet;
auto sk = libzcash::SpendingKey::random();
auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSpendingKey(sk);
auto wtx = GetValidReceive(sk, 10, true);
@ -537,7 +537,7 @@ TEST(wallet_tests, spent_note_is_from_me) {
TEST(wallet_tests, cached_witnesses_empty_chain) {
TestWallet wallet;
auto sk = libzcash::SpendingKey::random();
auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSpendingKey(sk);
auto wtx = GetValidReceive(sk, 10, true);
@ -590,7 +590,7 @@ TEST(wallet_tests, cached_witnesses_chain_tip) {
CBlock block1;
ZCIncrementalMerkleTree tree;
auto sk = libzcash::SpendingKey::random();
auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSpendingKey(sk);
{
@ -672,7 +672,7 @@ TEST(wallet_tests, CachedWitnessesDecrementFirst) {
CBlockIndex index2(block2);
ZCIncrementalMerkleTree tree;
auto sk = libzcash::SpendingKey::random();
auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSpendingKey(sk);
{
@ -744,7 +744,7 @@ TEST(wallet_tests, CachedWitnessesCleanIndex) {
ZCIncrementalMerkleTree riTree = tree;
std::vector<boost::optional<ZCIncrementalWitness>> witnesses;
auto sk = libzcash::SpendingKey::random();
auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSpendingKey(sk);
// Generate a chain
@ -813,7 +813,7 @@ TEST(wallet_tests, CachedWitnessesCleanIndex) {
TEST(wallet_tests, ClearNoteWitnessCache) {
TestWallet wallet;
auto sk = libzcash::SpendingKey::random();
auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSpendingKey(sk);
auto wtx = GetValidReceive(sk, 10, true);
@ -862,7 +862,7 @@ TEST(wallet_tests, WriteWitnessCache) {
MockWalletDB walletdb;
CBlockLocator loc;
auto sk = libzcash::SpendingKey::random();
auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSpendingKey(sk);
auto wtx = GetValidReceive(sk, 10, true);
@ -939,7 +939,7 @@ TEST(wallet_tests, UpdateNullifierNoteMap) {
uint256 r {GetRandHash()};
CKeyingMaterial vMasterKey (r.begin(), r.end());
auto sk = libzcash::SpendingKey::random();
auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSpendingKey(sk);
ASSERT_TRUE(wallet.EncryptKeys(vMasterKey));
@ -972,7 +972,7 @@ TEST(wallet_tests, UpdateNullifierNoteMap) {
TEST(wallet_tests, UpdatedNoteData) {
TestWallet wallet;
auto sk = libzcash::SpendingKey::random();
auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSpendingKey(sk);
auto wtx = GetValidReceive(sk, 10, true);
@ -1019,7 +1019,7 @@ TEST(wallet_tests, UpdatedNoteData) {
TEST(wallet_tests, MarkAffectedTransactionsDirty) {
TestWallet wallet;
auto sk = libzcash::SpendingKey::random();
auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSpendingKey(sk);
auto wtx = GetValidReceive(sk, 10, true);
@ -1050,7 +1050,7 @@ TEST(wallet_tests, MarkAffectedTransactionsDirty) {
TEST(wallet_tests, NoteLocking) {
TestWallet wallet;
auto sk = libzcash::SpendingKey::random();
auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSpendingKey(sk);
auto wtx = GetValidReceive(sk, 10, true);

42
src/wallet/gtest/test_wallet_zkeys.cpp

@ -20,12 +20,14 @@ TEST(wallet_zkeys_tests, store_and_load_zkeys) {
CWallet wallet;
// wallet should be empty
std::set<libzcash::PaymentAddress> addrs;
std::set<libzcash::SproutPaymentAddress> addrs;
wallet.GetPaymentAddresses(addrs);
ASSERT_EQ(0, addrs.size());
// wallet should have one key
auto addr = wallet.GenerateNewZKey();
auto address = wallet.GenerateNewZKey();
ASSERT_NE(boost::get<libzcash::SproutPaymentAddress>(&address), nullptr);
auto addr = boost::get<libzcash::SproutPaymentAddress>(address);
wallet.GetPaymentAddresses(addrs);
ASSERT_EQ(1, addrs.size());
@ -33,7 +35,7 @@ TEST(wallet_zkeys_tests, store_and_load_zkeys) {
ASSERT_TRUE(wallet.HaveSpendingKey(addr));
// manually add new spending key to wallet
auto sk = libzcash::SpendingKey::random();
auto sk = libzcash::SproutSpendingKey::random();
ASSERT_TRUE(wallet.AddZKey(sk));
// verify wallet did add it
@ -41,7 +43,7 @@ TEST(wallet_zkeys_tests, store_and_load_zkeys) {
ASSERT_TRUE(wallet.HaveSpendingKey(addr));
// verify spending key stored correctly
libzcash::SpendingKey keyOut;
libzcash::SproutSpendingKey keyOut;
wallet.GetSpendingKey(addr, keyOut);
ASSERT_EQ(sk, keyOut);
@ -51,7 +53,7 @@ TEST(wallet_zkeys_tests, store_and_load_zkeys) {
ASSERT_EQ(1, addrs.count(addr));
// Load a third key into the wallet
sk = libzcash::SpendingKey::random();
sk = libzcash::SproutSpendingKey::random();
ASSERT_TRUE(wallet.LoadZKey(sk));
// attach metadata to this third key
@ -77,12 +79,12 @@ TEST(wallet_zkeys_tests, StoreAndLoadViewingKeys) {
CWallet wallet;
// wallet should be empty
std::set<libzcash::PaymentAddress> addrs;
std::set<libzcash::SproutPaymentAddress> addrs;
wallet.GetPaymentAddresses(addrs);
ASSERT_EQ(0, addrs.size());
// manually add new viewing key to wallet
auto sk = libzcash::SpendingKey::random();
auto sk = libzcash::SproutSpendingKey::random();
auto vk = sk.viewing_key();
ASSERT_TRUE(wallet.AddViewingKey(vk));
@ -93,12 +95,12 @@ TEST(wallet_zkeys_tests, StoreAndLoadViewingKeys) {
ASSERT_FALSE(wallet.HaveSpendingKey(addr));
// verify viewing key stored correctly
libzcash::ViewingKey vkOut;
libzcash::SproutViewingKey vkOut;
wallet.GetViewingKey(addr, vkOut);
ASSERT_EQ(vk, vkOut);
// Load a second viewing key into the wallet
auto sk2 = libzcash::SpendingKey::random();
auto sk2 = libzcash::SproutSpendingKey::random();
ASSERT_TRUE(wallet.LoadViewingKey(sk2.viewing_key()));
// verify wallet did add it
@ -133,7 +135,7 @@ TEST(wallet_zkeys_tests, write_zkey_direct_to_db) {
ASSERT_TRUE(fFirstRun);
// wallet should be empty
std::set<libzcash::PaymentAddress> addrs;
std::set<libzcash::SproutPaymentAddress> addrs;
wallet.GetPaymentAddresses(addrs);
ASSERT_EQ(0, addrs.size());
@ -145,7 +147,7 @@ TEST(wallet_zkeys_tests, write_zkey_direct_to_db) {
ASSERT_EQ(1, addrs.size());
// create random key and add it to database directly, bypassing wallet
auto sk = libzcash::SpendingKey::random();
auto sk = libzcash::SproutSpendingKey::random();
auto addr = sk.address();
int64_t now = GetTime();
CKeyMetadata meta(now);
@ -171,7 +173,7 @@ TEST(wallet_zkeys_tests, write_zkey_direct_to_db) {
ASSERT_TRUE(wallet.HaveSpendingKey(addr));
// check key is the same
libzcash::SpendingKey keyOut;
libzcash::SproutSpendingKey keyOut;
wallet.GetSpendingKey(addr, keyOut);
ASSERT_EQ(sk, keyOut);
@ -205,7 +207,7 @@ TEST(wallet_zkeys_tests, WriteViewingKeyDirectToDB) {
ASSERT_TRUE(fFirstRun);
// create random viewing key and add it to database directly, bypassing wallet
auto sk = libzcash::SpendingKey::random();
auto sk = libzcash::SproutSpendingKey::random();
auto vk = sk.viewing_key();
auto addr = sk.address();
int64_t now = GetTime();
@ -223,7 +225,7 @@ TEST(wallet_zkeys_tests, WriteViewingKeyDirectToDB) {
ASSERT_TRUE(wallet.HaveViewingKey(addr));
// check key is the same
libzcash::ViewingKey vkOut;
libzcash::SproutViewingKey vkOut;
wallet.GetViewingKey(addr, vkOut);
ASSERT_EQ(vk, vkOut);
}
@ -252,12 +254,14 @@ TEST(wallet_zkeys_tests, write_cryptedzkey_direct_to_db) {
ASSERT_TRUE(fFirstRun);
// wallet should be empty
std::set<libzcash::PaymentAddress> addrs;
std::set<libzcash::SproutPaymentAddress> addrs;
wallet.GetPaymentAddresses(addrs);
ASSERT_EQ(0, addrs.size());
// Add random key to the wallet
auto paymentAddress = wallet.GenerateNewZKey();
auto address = wallet.GenerateNewZKey();
ASSERT_NE(boost::get<libzcash::SproutPaymentAddress>(&address), nullptr);
auto paymentAddress = boost::get<libzcash::SproutPaymentAddress>(address);
// wallet should have one key
wallet.GetPaymentAddresses(addrs);
@ -274,7 +278,9 @@ TEST(wallet_zkeys_tests, write_cryptedzkey_direct_to_db) {
// unlock wallet and then add
wallet.Unlock(strWalletPass);
auto paymentAddress2 = wallet.GenerateNewZKey();
auto address2 = wallet.GenerateNewZKey();
ASSERT_NE(boost::get<libzcash::SproutPaymentAddress>(&address2), nullptr);
auto paymentAddress2 = boost::get<libzcash::SproutPaymentAddress>(address2);
// Create a new wallet from the existing wallet path
CWallet wallet2("wallet_crypted.dat");
@ -292,7 +298,7 @@ TEST(wallet_zkeys_tests, write_cryptedzkey_direct_to_db) {
ASSERT_TRUE(addrs.count(paymentAddress2));
// spending key is crypted, so we can't extract valid payment address
libzcash::SpendingKey keyOut;
libzcash::SproutSpendingKey keyOut;
wallet2.GetSpendingKey(paymentAddress, keyOut);
ASSERT_FALSE(paymentAddress == keyOut.address());

2
src/wallet/rpcdisclosure.cpp

@ -253,7 +253,7 @@ UniValue z_validatepaymentdisclosure(const UniValue& params, bool fHelp)
}
// Check the payment address is valid
PaymentAddress zaddr = pd.payload.zaddr;
SproutPaymentAddress zaddr = pd.payload.zaddr;
{
o.push_back(Pair("paymentAddress", EncodePaymentAddress(zaddr)));

42
src/wallet/rpcdump.cpp

@ -296,9 +296,11 @@ UniValue importwallet_impl(const UniValue& params, bool fHelp, bool fImportZKeys
// Let's see if the address is a valid Zcash spending key
if (fImportZKeys) {
auto spendingkey = DecodeSpendingKey(vstr[0]);
if (spendingkey) {
libzcash::SpendingKey key = *spendingkey;
libzcash::PaymentAddress addr = key.address();
if (IsValidSpendingKey(spendingkey)) {
// TODO: Add Sapling support. For now, ensure we can freely convert.
assert(boost::get<libzcash::SproutSpendingKey>(&spendingkey) != nullptr);
auto key = boost::get<libzcash::SproutSpendingKey>(spendingkey);
auto addr = key.address();
if (pwalletMain->HaveSpendingKey(addr)) {
LogPrint("zrpc", "Skipping import of zaddr %s (key already present)\n", EncodePaymentAddress(addr));
continue;
@ -526,13 +528,13 @@ UniValue dumpwallet_impl(const UniValue& params, bool fHelp, bool fDumpZKeys)
file << "\n";
if (fDumpZKeys) {
std::set<libzcash::PaymentAddress> addresses;
std::set<libzcash::SproutPaymentAddress> addresses;
pwalletMain->GetPaymentAddresses(addresses);
file << "\n";
file << "# Zkeys\n";
file << "\n";
for (auto addr : addresses ) {
libzcash::SpendingKey key;
libzcash::SproutSpendingKey key;
if (pwalletMain->GetSpendingKey(addr, key)) {
std::string strTime = EncodeDumpTime(pwalletMain->mapZKeyMetadata[addr].nCreateTime);
file << strprintf("%s %s # zaddr=%s\n", EncodeSpendingKey(key), strTime, EncodePaymentAddress(addr));
@ -614,10 +616,12 @@ UniValue z_importkey(const UniValue& params, bool fHelp)
string strSecret = params[0].get_str();
auto spendingkey = DecodeSpendingKey(strSecret);
if (!spendingkey) {
if (!IsValidSpendingKey(spendingkey)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid spending key");
}
auto key = *spendingkey;
// TODO: Add Sapling support. For now, ensure we can freely convert.
assert(boost::get<libzcash::SproutSpendingKey>(&spendingkey) != nullptr);
auto key = boost::get<libzcash::SproutSpendingKey>(spendingkey);
auto addr = key.address();
{
@ -706,10 +710,12 @@ UniValue z_importviewingkey(const UniValue& params, bool fHelp)
string strVKey = params[0].get_str();
auto viewingkey = DecodeViewingKey(strVKey);
if (!viewingkey) {
if (!IsValidViewingKey(viewingkey)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid viewing key");
}
auto vkey = *viewingkey;
// TODO: Add Sapling support. For now, ensure we can freely convert.
assert(boost::get<libzcash::SproutViewingKey>(&viewingkey) != nullptr);
auto vkey = boost::get<libzcash::SproutViewingKey>(viewingkey);
auto addr = vkey.address();
{
@ -766,12 +772,14 @@ UniValue z_exportkey(const UniValue& params, bool fHelp)
string strAddress = params[0].get_str();
auto address = DecodePaymentAddress(strAddress);
if (!address) {
if (!IsValidPaymentAddress(address)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr");
}
auto addr = *address;
// TODO: Add Sapling support. For now, ensure we can freely convert.
assert(boost::get<libzcash::SproutPaymentAddress>(&address) != nullptr);
auto addr = boost::get<libzcash::SproutPaymentAddress>(address);
libzcash::SpendingKey k;
libzcash::SproutSpendingKey k;
if (!pwalletMain->GetSpendingKey(addr, k))
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet does not hold private zkey for this zaddr");
@ -804,14 +812,16 @@ UniValue z_exportviewingkey(const UniValue& params, bool fHelp)
string strAddress = params[0].get_str();
auto address = DecodePaymentAddress(strAddress);
if (!address) {
if (!IsValidPaymentAddress(address)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr");
}
auto addr = *address;
// TODO: Add Sapling support. For now, ensure we can freely convert.
assert(boost::get<libzcash::SproutPaymentAddress>(&address) != nullptr);
auto addr = boost::get<libzcash::SproutPaymentAddress>(address);
libzcash::ViewingKey vk;
libzcash::SproutViewingKey vk;
if (!pwalletMain->GetViewingKey(addr, vk)) {
libzcash::SpendingKey k;
libzcash::SproutSpendingKey k;
if (!pwalletMain->GetSpendingKey(addr, k)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet does not hold private key or viewing key for this zaddr");
}

85
src/wallet/rpcwallet.cpp

@ -2522,8 +2522,10 @@ UniValue z_listunspent(const UniValue& params, bool fHelp)
}
string address = o.get_str();
auto zaddr = DecodePaymentAddress(address);
if (zaddr) {
libzcash::PaymentAddress addr = *zaddr;
if (IsValidPaymentAddress(zaddr)) {
// TODO: Add Sapling support. For now, ensure we can freely convert.
assert(boost::get<libzcash::SproutPaymentAddress>(&zaddr) != nullptr);
libzcash::SproutPaymentAddress addr = boost::get<libzcash::SproutPaymentAddress>(zaddr);
if (!fIncludeWatchonly && !pwalletMain->HaveSpendingKey(addr)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, spending key for address does not belong to wallet: ") + address);
}
@ -2540,7 +2542,10 @@ UniValue z_listunspent(const UniValue& params, bool fHelp)
}
else {
// User did not provide zaddrs, so use default i.e. all addresses
pwalletMain->GetPaymentAddresses(zaddrs);
// TODO: Add Sapling support
std::set<libzcash::SproutPaymentAddress> sproutzaddrs = {};
pwalletMain->GetPaymentAddresses(sproutzaddrs);
zaddrs.insert(sproutzaddrs.begin(), sproutzaddrs.end());
}
UniValue results(UniValue::VARR);
@ -2554,7 +2559,7 @@ UniValue z_listunspent(const UniValue& params, bool fHelp)
obj.push_back(Pair("jsindex", (int)entry.jsop.js ));
obj.push_back(Pair("jsoutindex", (int)entry.jsop.n));
obj.push_back(Pair("confirmations", entry.nHeight));
obj.push_back(Pair("spendable", pwalletMain->HaveSpendingKey(entry.address)));
obj.push_back(Pair("spendable", pwalletMain->HaveSpendingKey(boost::get<libzcash::SproutPaymentAddress>(entry.address))));
obj.push_back(Pair("address", EncodePaymentAddress(entry.address)));
obj.push_back(Pair("amount", ValueFromAmount(CAmount(entry.plaintext.value()))));
std::string data(entry.plaintext.memo().begin(), entry.plaintext.memo().end());
@ -2793,10 +2798,13 @@ UniValue zc_raw_receive(const UniValue& params, bool fHelp)
LOCK(cs_main);
auto spendingkey = DecodeSpendingKey(params[0].get_str());
if (!spendingkey) {
if (!IsValidSpendingKey(spendingkey)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid spending key");
}
SpendingKey k = *spendingkey;
if (boost::get<libzcash::SproutSpendingKey>(&spendingkey) == nullptr) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Only works with Sprout spending keys");
}
SproutSpendingKey k = boost::get<libzcash::SproutSpendingKey>(spendingkey);
uint256 epk;
unsigned char nonce;
@ -2826,7 +2834,7 @@ UniValue zc_raw_receive(const UniValue& params, bool fHelp)
h_sig,
nonce
);
PaymentAddress payment_addr = k.address();
SproutPaymentAddress payment_addr = k.address();
SproutNote decrypted_note = npt.note(payment_addr);
assert(pwalletMain != NULL);
@ -2902,15 +2910,18 @@ UniValue zc_raw_joinsplit(const UniValue& params, bool fHelp)
std::vector<JSInput> vjsin;
std::vector<JSOutput> vjsout;
std::vector<SproutNote> notes;
std::vector<SpendingKey> keys;
std::vector<SproutSpendingKey> keys;
std::vector<uint256> commitments;
for (const string& name_ : inputs.getKeys()) {
auto spendingkey = DecodeSpendingKey(inputs[name_].get_str());
if (!spendingkey) {
if (!IsValidSpendingKey(spendingkey)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid spending key");
}
SpendingKey k = *spendingkey;
if (boost::get<libzcash::SproutSpendingKey>(&spendingkey) == nullptr) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Only works with Sprout spending keys");
}
SproutSpendingKey k = boost::get<libzcash::SproutSpendingKey>(spendingkey);
keys.push_back(k);
@ -2921,7 +2932,7 @@ UniValue zc_raw_joinsplit(const UniValue& params, bool fHelp)
ssData >> npt;
}
PaymentAddress addr = k.address();
SproutPaymentAddress addr = k.address();
SproutNote note = npt.note(addr);
notes.push_back(note);
commitments.push_back(note.cm());
@ -2952,12 +2963,15 @@ UniValue zc_raw_joinsplit(const UniValue& params, bool fHelp)
for (const string& name_ : outputs.getKeys()) {
auto addrTo = DecodePaymentAddress(name_);
if (!addrTo) {
if (!IsValidPaymentAddress(addrTo)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid recipient address.");
}
if (boost::get<libzcash::SproutPaymentAddress>(&addrTo) == nullptr) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Only works with Sprout payment addresses");
}
CAmount nAmount = AmountFromValue(outputs[name_]);
vjsout.push_back(JSOutput(*addrTo, nAmount));
vjsout.push_back(JSOutput(boost::get<libzcash::SproutPaymentAddress>(addrTo), nAmount));
}
while (vjsout.size() < ZC_NUM_JS_OUTPUTS) {
@ -3063,7 +3077,7 @@ UniValue zc_raw_keygen(const UniValue& params, bool fHelp)
);
}
auto k = SpendingKey::random();
auto k = SproutSpendingKey::random();
auto addr = k.address();
auto viewing_key = k.viewing_key();
@ -3130,7 +3144,8 @@ UniValue z_listaddresses(const UniValue& params, bool fHelp)
}
UniValue ret(UniValue::VARR);
std::set<libzcash::PaymentAddress> addresses;
// TODO: Add Sapling support
std::set<libzcash::SproutPaymentAddress> addresses;
pwalletMain->GetPaymentAddresses(addresses);
for (auto addr : addresses ) {
if (fIncludeWatchonly || pwalletMain->HaveSpendingKey(addr)) {
@ -3232,11 +3247,14 @@ UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp)
auto fromaddress = params[0].get_str();
auto zaddr = DecodePaymentAddress(fromaddress);
if (!zaddr) {
if (!IsValidPaymentAddress(zaddr)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr.");
}
// TODO: Add Sapling support. For now, ensure we can freely convert.
assert(boost::get<libzcash::SproutPaymentAddress>(&zaddr) != nullptr);
auto sproutzaddr = boost::get<libzcash::SproutPaymentAddress>(zaddr);
if (!(pwalletMain->HaveSpendingKey(*zaddr) || pwalletMain->HaveViewingKey(*zaddr))) {
if (!(pwalletMain->HaveSpendingKey(sproutzaddr) || pwalletMain->HaveViewingKey(sproutzaddr))) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key or viewing key not found.");
}
@ -3299,13 +3317,14 @@ UniValue z_getbalance(const UniValue& params, bool fHelp)
bool fromTaddr = false;
CTxDestination taddr = DecodeDestination(fromaddress);
fromTaddr = IsValidDestination(taddr);
libzcash::PaymentAddress zaddr;
if (!fromTaddr) {
auto res = DecodePaymentAddress(fromaddress);
if (!res) {
if (!IsValidPaymentAddress(res)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
}
zaddr = *res;
// TODO: Add Sapling support. For now, ensure we can freely convert.
assert(boost::get<libzcash::SproutPaymentAddress>(&res) != nullptr);
auto zaddr = boost::get<libzcash::SproutPaymentAddress>(res);
if (!(pwalletMain->HaveSpendingKey(zaddr) || pwalletMain->HaveViewingKey(zaddr))) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key or viewing key not found.");
}
@ -3534,14 +3553,16 @@ UniValue z_sendmany(const UniValue& params, bool fHelp)
bool fromTaddr = false;
CTxDestination taddr = DecodeDestination(fromaddress);
fromTaddr = IsValidDestination(taddr);
libzcash::PaymentAddress zaddr;
libzcash::SproutPaymentAddress zaddr;
if (!fromTaddr) {
auto res = DecodePaymentAddress(fromaddress);
if (!res) {
if (!IsValidPaymentAddress(res)) {
// invalid
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
}
zaddr = *res;
// TODO: Add Sapling support. For now, ensure we can freely convert.
assert(boost::get<libzcash::SproutPaymentAddress>(&res) != nullptr);
zaddr = boost::get<libzcash::SproutPaymentAddress>(res);
}
// Check that we have the spending key
@ -3579,7 +3600,7 @@ UniValue z_sendmany(const UniValue& params, bool fHelp)
bool isZaddr = false;
CTxDestination taddr = DecodeDestination(address);
if (!IsValidDestination(taddr)) {
if (DecodePaymentAddress(address)) {
if (IsValidPaymentAddressString(address)) {
isZaddr = true;
} else {
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ")+address );
@ -3773,7 +3794,7 @@ UniValue z_shieldcoinbase(const UniValue& params, bool fHelp)
// Validate the destination address
auto destaddress = params[1].get_str();
if (!DecodePaymentAddress(destaddress)) {
if (!IsValidPaymentAddressString(destaddress)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ") + destaddress );
}
@ -4015,10 +4036,10 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
}
} else {
auto zaddr = DecodePaymentAddress(address);
if (zaddr) {
if (IsValidPaymentAddress(zaddr)) {
// Ignore listed z-addrs if we are using all of them
if (!(useAny || useAnyNote)) {
zaddrs.insert(*zaddr);
zaddrs.insert(zaddr);
}
} else {
throw JSONRPCError(
@ -4038,7 +4059,7 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
bool isToZaddr = false;
CTxDestination taddr = DecodeDestination(destaddress);
if (!IsValidDestination(taddr)) {
if (DecodePaymentAddress(destaddress)) {
if (IsValidPaymentAddressString(destaddress)) {
isToZaddr = true;
} else {
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ") + destaddress );
@ -4174,9 +4195,11 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
maxedOutNotesFlag = true;
} else {
estimatedTxSize += increase;
SpendingKey zkey;
pwalletMain->GetSpendingKey(entry.address, zkey);
noteInputs.emplace_back(entry.jsop, entry.plaintext.note(entry.address), nValue, zkey);
// TODO: Add Sapling support
auto zaddr = boost::get<SproutPaymentAddress>(entry.address);
SproutSpendingKey zkey;
pwalletMain->GetSpendingKey(zaddr, zkey);
noteInputs.emplace_back(entry.jsop, entry.plaintext.note(zaddr), nValue, zkey);
mergedNoteValue += nValue;
}
}

30
src/wallet/wallet.cpp

@ -83,7 +83,8 @@ const CWalletTx* CWallet::GetWalletTx(const uint256& hash) const
libzcash::PaymentAddress CWallet::GenerateNewZKey()
{
AssertLockHeld(cs_wallet); // mapZKeyMetadata
auto k = SpendingKey::random();
// TODO: Add Sapling support
auto k = SproutSpendingKey::random();
auto addr = k.address();
// Check for collision, even though it is unlikely to ever occur
@ -100,7 +101,8 @@ libzcash::PaymentAddress CWallet::GenerateNewZKey()
}
// Add spending key to keystore and persist to disk
bool CWallet::AddZKey(const libzcash::SpendingKey &key)
// TODO: Add Sapling support
bool CWallet::AddZKey(const libzcash::SproutSpendingKey &key)
{
AssertLockHeld(cs_wallet); // mapZKeyMetadata
auto addr = key.address();
@ -194,7 +196,7 @@ bool CWallet::AddCryptedKey(const CPubKey &vchPubKey,
}
bool CWallet::AddCryptedSpendingKey(const libzcash::PaymentAddress &address,
bool CWallet::AddCryptedSpendingKey(const libzcash::SproutPaymentAddress &address,
const libzcash::ReceivingKey &rk,
const std::vector<unsigned char> &vchCryptedSecret)
{
@ -229,7 +231,7 @@ bool CWallet::LoadKeyMetadata(const CPubKey &pubkey, const CKeyMetadata &meta)
return true;
}
bool CWallet::LoadZKeyMetadata(const PaymentAddress &addr, const CKeyMetadata &meta)
bool CWallet::LoadZKeyMetadata(const SproutPaymentAddress &addr, const CKeyMetadata &meta)
{
AssertLockHeld(cs_wallet); // mapZKeyMetadata
mapZKeyMetadata[addr] = meta;
@ -241,17 +243,17 @@ bool CWallet::LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigne
return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret);
}
bool CWallet::LoadCryptedZKey(const libzcash::PaymentAddress &addr, const libzcash::ReceivingKey &rk, const std::vector<unsigned char> &vchCryptedSecret)
bool CWallet::LoadCryptedZKey(const libzcash::SproutPaymentAddress &addr, const libzcash::ReceivingKey &rk, const std::vector<unsigned char> &vchCryptedSecret)
{
return CCryptoKeyStore::AddCryptedSpendingKey(addr, rk, vchCryptedSecret);
}
bool CWallet::LoadZKey(const libzcash::SpendingKey &key)
bool CWallet::LoadZKey(const libzcash::SproutSpendingKey &key)
{
return CCryptoKeyStore::AddSpendingKey(key);
}
bool CWallet::AddViewingKey(const libzcash::ViewingKey &vk)
bool CWallet::AddViewingKey(const libzcash::SproutViewingKey &vk)
{
if (!CCryptoKeyStore::AddViewingKey(vk)) {
return false;
@ -263,7 +265,7 @@ bool CWallet::AddViewingKey(const libzcash::ViewingKey &vk)
return CWalletDB(strWalletFile).WriteViewingKey(vk);
}
bool CWallet::RemoveViewingKey(const libzcash::ViewingKey &vk)
bool CWallet::RemoveViewingKey(const libzcash::SproutViewingKey &vk)
{
AssertLockHeld(cs_wallet);
if (!CCryptoKeyStore::RemoveViewingKey(vk)) {
@ -278,7 +280,7 @@ bool CWallet::RemoveViewingKey(const libzcash::ViewingKey &vk)
return true;
}
bool CWallet::LoadViewingKey(const libzcash::ViewingKey &vk)
bool CWallet::LoadViewingKey(const libzcash::SproutViewingKey &vk)
{
return CCryptoKeyStore::AddViewingKey(vk);
}
@ -1257,7 +1259,7 @@ void CWallet::EraseFromWallet(const uint256 &hash)
* Throws std::runtime_error if the decryptor doesn't match this note
*/
boost::optional<uint256> CWallet::GetNoteNullifier(const JSDescription& jsdesc,
const libzcash::PaymentAddress& address,
const libzcash::SproutPaymentAddress& address,
const ZCNoteDecryption& dec,
const uint256& hSig,
uint8_t n) const
@ -1273,7 +1275,7 @@ boost::optional<uint256> CWallet::GetNoteNullifier(const JSDescription& jsdesc,
// SpendingKeys are only available if:
// - We have them (this isn't a viewing key)
// - The wallet is unlocked
libzcash::SpendingKey key;
libzcash::SproutSpendingKey key;
if (GetSpendingKey(address, key)) {
ret = note.nullifier(key);
}
@ -3715,7 +3717,7 @@ void CWallet::GetFilteredNotes(std::vector<CSproutNotePlaintextEntry> & outEntri
std::set<PaymentAddress> filterAddresses;
if (address.length() > 0) {
filterAddresses.insert(*DecodePaymentAddress(address));
filterAddresses.insert(DecodePaymentAddress(address));
}
GetFilteredNotes(outEntries, filterAddresses, minDepth, ignoreSpent, ignoreUnspendable);
@ -3749,7 +3751,7 @@ void CWallet::GetFilteredNotes(
for (auto & pair : wtx.mapNoteData) {
JSOutPoint jsop = pair.first;
CNoteData nd = pair.second;
PaymentAddress pa = nd.address;
SproutPaymentAddress pa = nd.address;
// skip notes which belong to a different payment address in the wallet
if (!(filterAddresses.empty() || filterAddresses.count(pa))) {
@ -3830,7 +3832,7 @@ void CWallet::GetUnspentFilteredNotes(
for (auto & pair : wtx.mapNoteData) {
JSOutPoint jsop = pair.first;
CNoteData nd = pair.second;
PaymentAddress pa = nd.address;
SproutPaymentAddress pa = nd.address;
// skip notes which belong to a different payment address in the wallet
if (!(filterAddresses.empty() || filterAddresses.count(pa))) {

30
src/wallet/wallet.h

@ -199,7 +199,7 @@ public:
class CNoteData
{
public:
libzcash::PaymentAddress address;
libzcash::SproutPaymentAddress address;
/**
* Cached note nullifier. May not be set if the wallet was not unlocked when
@ -233,9 +233,9 @@ public:
int witnessHeight;
CNoteData() : address(), nullifier(), witnessHeight {-1} { }
CNoteData(libzcash::PaymentAddress a) :
CNoteData(libzcash::SproutPaymentAddress a) :
address {a}, nullifier(), witnessHeight {-1} { }
CNoteData(libzcash::PaymentAddress a, uint256 n) :
CNoteData(libzcash::SproutPaymentAddress a, uint256 n) :
address {a}, nullifier {n}, witnessHeight {-1} { }
ADD_SERIALIZE_METHODS;
@ -268,14 +268,14 @@ typedef std::map<JSOutPoint, CNoteData> mapNoteData_t;
struct CSproutNotePlaintextEntry
{
JSOutPoint jsop;
libzcash::PaymentAddress address;
libzcash::SproutPaymentAddress address;
libzcash::SproutNotePlaintext plaintext;
};
/** Decrypted note, location in a transaction, and confirmation height. */
struct CUnspentSproutNotePlaintextEntry {
JSOutPoint jsop;
libzcash::PaymentAddress address;
libzcash::SproutPaymentAddress address;
libzcash::SproutNotePlaintext plaintext;
int nHeight;
};
@ -785,7 +785,7 @@ public:
std::set<int64_t> setKeyPool;
std::map<CKeyID, CKeyMetadata> mapKeyMetadata;
std::map<libzcash::PaymentAddress, CKeyMetadata> mapZKeyMetadata;
std::map<libzcash::SproutPaymentAddress, CKeyMetadata> mapZKeyMetadata;
typedef std::map<unsigned int, CMasterKey> MasterKeyMap;
MasterKeyMap mapMasterKeys;
@ -962,21 +962,21 @@ public:
//! Generates a new zaddr
libzcash::PaymentAddress GenerateNewZKey();
//! Adds spending key to the store, and saves it to disk
bool AddZKey(const libzcash::SpendingKey &key);
bool AddZKey(const libzcash::SproutSpendingKey &key);
//! Adds spending key to the store, without saving it to disk (used by LoadWallet)
bool LoadZKey(const libzcash::SpendingKey &key);
bool LoadZKey(const libzcash::SproutSpendingKey &key);
//! Load spending key metadata (used by LoadWallet)
bool LoadZKeyMetadata(const libzcash::PaymentAddress &addr, const CKeyMetadata &meta);
bool LoadZKeyMetadata(const libzcash::SproutPaymentAddress &addr, const CKeyMetadata &meta);
//! Adds an encrypted spending key to the store, without saving it to disk (used by LoadWallet)
bool LoadCryptedZKey(const libzcash::PaymentAddress &addr, const libzcash::ReceivingKey &rk, const std::vector<unsigned char> &vchCryptedSecret);
bool LoadCryptedZKey(const libzcash::SproutPaymentAddress &addr, const libzcash::ReceivingKey &rk, const std::vector<unsigned char> &vchCryptedSecret);
//! Adds an encrypted spending key to the store, and saves it to disk (virtual method, declared in crypter.h)
bool AddCryptedSpendingKey(const libzcash::PaymentAddress &address, const libzcash::ReceivingKey &rk, const std::vector<unsigned char> &vchCryptedSecret);
bool AddCryptedSpendingKey(const libzcash::SproutPaymentAddress &address, const libzcash::ReceivingKey &rk, const std::vector<unsigned char> &vchCryptedSecret);
//! Adds a viewing key to the store, and saves it to disk.
bool AddViewingKey(const libzcash::ViewingKey &vk);
bool RemoveViewingKey(const libzcash::ViewingKey &vk);
bool AddViewingKey(const libzcash::SproutViewingKey &vk);
bool RemoveViewingKey(const libzcash::SproutViewingKey &vk);
//! Adds a viewing key to the store, without saving it to disk (used by LoadWallet)
bool LoadViewingKey(const libzcash::ViewingKey &dest);
bool LoadViewingKey(const libzcash::SproutViewingKey &dest);
/**
* Increment the next transaction order id
@ -1039,7 +1039,7 @@ public:
boost::optional<uint256> GetNoteNullifier(
const JSDescription& jsdesc,
const libzcash::PaymentAddress& address,
const libzcash::SproutPaymentAddress& address,
const ZCNoteDecryption& dec,
const uint256& hSig,
uint8_t n) const;

18
src/wallet/walletdb.cpp

@ -105,7 +105,7 @@ bool CWalletDB::WriteCryptedKey(const CPubKey& vchPubKey,
return true;
}
bool CWalletDB::WriteCryptedZKey(const libzcash::PaymentAddress & addr,
bool CWalletDB::WriteCryptedZKey(const libzcash::SproutPaymentAddress & addr,
const libzcash::ReceivingKey &rk,
const std::vector<unsigned char>& vchCryptedSecret,
const CKeyMetadata &keyMeta)
@ -131,7 +131,7 @@ bool CWalletDB::WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey)
return Write(std::make_pair(std::string("mkey"), nID), kMasterKey, true);
}
bool CWalletDB::WriteZKey(const libzcash::PaymentAddress& addr, const libzcash::SpendingKey& key, const CKeyMetadata &keyMeta)
bool CWalletDB::WriteZKey(const libzcash::SproutPaymentAddress& addr, const libzcash::SproutSpendingKey& key, const CKeyMetadata &keyMeta)
{
nWalletDBUpdated++;
@ -142,13 +142,13 @@ bool CWalletDB::WriteZKey(const libzcash::PaymentAddress& addr, const libzcash::
return Write(std::make_pair(std::string("zkey"), addr), key, false);
}
bool CWalletDB::WriteViewingKey(const libzcash::ViewingKey &vk)
bool CWalletDB::WriteViewingKey(const libzcash::SproutViewingKey &vk)
{
nWalletDBUpdated++;
return Write(std::make_pair(std::string("vkey"), vk), '1');
}
bool CWalletDB::EraseViewingKey(const libzcash::ViewingKey &vk)
bool CWalletDB::EraseViewingKey(const libzcash::SproutViewingKey &vk)
{
nWalletDBUpdated++;
return Erase(std::make_pair(std::string("vkey"), vk));
@ -485,7 +485,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
}
else if (strType == "vkey")
{
libzcash::ViewingKey vk;
libzcash::SproutViewingKey vk;
ssKey >> vk;
char fYes;
ssValue >> fYes;
@ -498,9 +498,9 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
}
else if (strType == "zkey")
{
libzcash::PaymentAddress addr;
libzcash::SproutPaymentAddress addr;
ssKey >> addr;
libzcash::SpendingKey key;
libzcash::SproutSpendingKey key;
ssValue >> key;
if (!pwallet->LoadZKey(key))
@ -607,7 +607,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
}
else if (strType == "czkey")
{
libzcash::PaymentAddress addr;
libzcash::SproutPaymentAddress addr;
ssKey >> addr;
// Deserialization of a pair is just one item after another
uint256 rkValue;
@ -641,7 +641,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
}
else if (strType == "zkeymeta")
{
libzcash::PaymentAddress addr;
libzcash::SproutPaymentAddress addr;
ssKey >> addr;
CKeyMetadata keyMeta;
ssValue >> keyMeta;

8
src/wallet/walletdb.h

@ -133,14 +133,14 @@ public:
static bool Recover(CDBEnv& dbenv, const std::string& filename);
/// Write spending key to wallet database, where key is payment address and value is spending key.
bool WriteZKey(const libzcash::PaymentAddress& addr, const libzcash::SpendingKey& key, const CKeyMetadata &keyMeta);
bool WriteCryptedZKey(const libzcash::PaymentAddress & addr,
bool WriteZKey(const libzcash::SproutPaymentAddress& addr, const libzcash::SproutSpendingKey& key, const CKeyMetadata &keyMeta);
bool WriteCryptedZKey(const libzcash::SproutPaymentAddress & addr,
const libzcash::ReceivingKey & rk,
const std::vector<unsigned char>& vchCryptedSecret,
const CKeyMetadata &keyMeta);
bool WriteViewingKey(const libzcash::ViewingKey &vk);
bool EraseViewingKey(const libzcash::ViewingKey &vk);
bool WriteViewingKey(const libzcash::SproutViewingKey &vk);
bool EraseViewingKey(const libzcash::SproutViewingKey &vk);
private:
CWalletDB(const CWalletDB&);

31
src/zcash/Address.cpp

@ -6,7 +6,7 @@
namespace libzcash {
uint256 PaymentAddress::GetHash() const {
uint256 SproutPaymentAddress::GetHash() const {
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << *this;
return Hash(ss.begin(), ss.end());
@ -16,24 +16,37 @@ uint256 ReceivingKey::pk_enc() const {
return ZCNoteEncryption::generate_pubkey(*this);
}
PaymentAddress ViewingKey::address() const {
return PaymentAddress(a_pk, sk_enc.pk_enc());
SproutPaymentAddress SproutViewingKey::address() const {
return SproutPaymentAddress(a_pk, sk_enc.pk_enc());
}
ReceivingKey SpendingKey::receiving_key() const {
ReceivingKey SproutSpendingKey::receiving_key() const {
return ReceivingKey(ZCNoteEncryption::generate_privkey(*this));
}
ViewingKey SpendingKey::viewing_key() const {
return ViewingKey(PRF_addr_a_pk(*this), receiving_key());
SproutViewingKey SproutSpendingKey::viewing_key() const {
return SproutViewingKey(PRF_addr_a_pk(*this), receiving_key());
}
SpendingKey SpendingKey::random() {
return SpendingKey(random_uint252());
SproutSpendingKey SproutSpendingKey::random() {
return SproutSpendingKey(random_uint252());
}
PaymentAddress SpendingKey::address() const {
SproutPaymentAddress SproutSpendingKey::address() const {
return viewing_key().address();
}
}
bool IsValidPaymentAddress(const libzcash::PaymentAddress& zaddr) {
return zaddr.which() != 0;
}
bool IsValidViewingKey(const libzcash::ViewingKey& vk) {
return vk.which() != 0;
}
bool IsValidSpendingKey(const libzcash::SpendingKey& zkey) {
return zkey.which() != 0;
}

54
src/zcash/Address.hpp

@ -5,19 +5,26 @@
#include "uint252.h"
#include "serialize.h"
#include <boost/variant.hpp>
namespace libzcash {
class InvalidEncoding {
public:
friend bool operator==(const InvalidEncoding &a, const InvalidEncoding &b) { return true; }
friend bool operator<(const InvalidEncoding &a, const InvalidEncoding &b) { return true; }
};
const size_t SerializedPaymentAddressSize = 64;
const size_t SerializedViewingKeySize = 64;
const size_t SerializedSpendingKeySize = 32;
class PaymentAddress {
class SproutPaymentAddress {
public:
uint256 a_pk;
uint256 pk_enc;
PaymentAddress() : a_pk(), pk_enc() { }
PaymentAddress(uint256 a_pk, uint256 pk_enc) : a_pk(a_pk), pk_enc(pk_enc) { }
SproutPaymentAddress() : a_pk(), pk_enc() { }
SproutPaymentAddress(uint256 a_pk, uint256 pk_enc) : a_pk(a_pk), pk_enc(pk_enc) { }
ADD_SERIALIZE_METHODS;
@ -30,10 +37,10 @@ public:
//! Get the 256-bit SHA256d hash of this payment address.
uint256 GetHash() const;
friend inline bool operator==(const PaymentAddress& a, const PaymentAddress& b) {
friend inline bool operator==(const SproutPaymentAddress& a, const SproutPaymentAddress& b) {
return a.a_pk == b.a_pk && a.pk_enc == b.pk_enc;
}
friend inline bool operator<(const PaymentAddress& a, const PaymentAddress& b) {
friend inline bool operator<(const SproutPaymentAddress& a, const SproutPaymentAddress& b) {
return (a.a_pk < b.a_pk ||
(a.a_pk == b.a_pk && a.pk_enc < b.pk_enc));
}
@ -47,13 +54,13 @@ public:
uint256 pk_enc() const;
};
class ViewingKey {
class SproutViewingKey {
public:
uint256 a_pk;
ReceivingKey sk_enc;
ViewingKey() : a_pk(), sk_enc() { }
ViewingKey(uint256 a_pk, ReceivingKey sk_enc) : a_pk(a_pk), sk_enc(sk_enc) { }
SproutViewingKey() : a_pk(), sk_enc() { }
SproutViewingKey(uint256 a_pk, ReceivingKey sk_enc) : a_pk(a_pk), sk_enc(sk_enc) { }
ADD_SERIALIZE_METHODS;
@ -63,29 +70,42 @@ public:
READWRITE(sk_enc);
}
PaymentAddress address() const;
SproutPaymentAddress address() const;
friend inline bool operator==(const ViewingKey& a, const ViewingKey& b) {
friend inline bool operator==(const SproutViewingKey& a, const SproutViewingKey& b) {
return a.a_pk == b.a_pk && a.sk_enc == b.sk_enc;
}
friend inline bool operator<(const ViewingKey& a, const ViewingKey& b) {
friend inline bool operator<(const SproutViewingKey& a, const SproutViewingKey& b) {
return (a.a_pk < b.a_pk ||
(a.a_pk == b.a_pk && a.sk_enc < b.sk_enc));
}
};
class SpendingKey : public uint252 {
class SproutSpendingKey : public uint252 {
public:
SpendingKey() : uint252() { }
SpendingKey(uint252 a_sk) : uint252(a_sk) { }
SproutSpendingKey() : uint252() { }
SproutSpendingKey(uint252 a_sk) : uint252(a_sk) { }
static SpendingKey random();
static SproutSpendingKey random();
ReceivingKey receiving_key() const;
ViewingKey viewing_key() const;
PaymentAddress address() const;
SproutViewingKey viewing_key() const;
SproutPaymentAddress address() const;
};
typedef boost::variant<InvalidEncoding, SproutPaymentAddress> PaymentAddress;
typedef boost::variant<InvalidEncoding, SproutViewingKey> ViewingKey;
typedef boost::variant<InvalidEncoding, SproutSpendingKey> SpendingKey;
}
/** Check whether a PaymentAddress is not an InvalidEncoding. */
bool IsValidPaymentAddress(const libzcash::PaymentAddress& zaddr);
/** Check whether a ViewingKey is not an InvalidEncoding. */
bool IsValidViewingKey(const libzcash::ViewingKey& vk);
/** Check whether a SpendingKey is not an InvalidEncoding. */
bool IsValidSpendingKey(const libzcash::SpendingKey& zkey);
#endif // ZC_ADDRESS_H_

4
src/zcash/JoinSplit.cpp

@ -370,12 +370,12 @@ SproutNote JSOutput::note(const uint252& phi, const uint256& r, size_t i, const
}
JSOutput::JSOutput() : addr(uint256(), uint256()), value(0) {
SpendingKey a_sk = SpendingKey::random();
SproutSpendingKey a_sk = SproutSpendingKey::random();
addr = a_sk.address();
}
JSInput::JSInput() : witness(ZCIncrementalMerkleTree().witness()),
key(SpendingKey::random()) {
key(SproutSpendingKey::random()) {
note = SproutNote(key.address().a_pk, 0, random_uint256(), random_uint256());
ZCIncrementalMerkleTree dummy_tree;
dummy_tree.append(note.cm());

8
src/zcash/JoinSplit.hpp

@ -19,12 +19,12 @@ class JSInput {
public:
ZCIncrementalWitness witness;
SproutNote note;
SpendingKey key;
SproutSpendingKey key;
JSInput();
JSInput(ZCIncrementalWitness witness,
SproutNote note,
SpendingKey key) : witness(witness), note(note), key(key) { }
SproutSpendingKey key) : witness(witness), note(note), key(key) { }
uint256 nullifier() const {
return note.nullifier(key);
@ -33,12 +33,12 @@ public:
class JSOutput {
public:
PaymentAddress addr;
SproutPaymentAddress addr;
uint64_t value;
boost::array<unsigned char, ZC_MEMO_SIZE> memo = {{0xF6}}; // 0xF6 is invalid UTF8 as per spec, rest of array is 0x00
JSOutput();
JSOutput(PaymentAddress addr, uint64_t value) : addr(addr), value(value) { }
JSOutput(SproutPaymentAddress addr, uint64_t value) : addr(addr), value(value) { }
SproutNote note(const uint252& phi, const uint256& r, size_t i, const uint256& h_sig) const;
};

4
src/zcash/Note.cpp

@ -34,7 +34,7 @@ uint256 SproutNote::cm() const {
return result;
}
uint256 SproutNote::nullifier(const SpendingKey& a_sk) const {
uint256 SproutNote::nullifier(const SproutSpendingKey& a_sk) const {
return PRF_nf(a_sk, rho);
}
@ -46,7 +46,7 @@ SproutNotePlaintext::SproutNotePlaintext(
r = note.r;
}
SproutNote SproutNotePlaintext::note(const PaymentAddress& addr) const
SproutNote SproutNotePlaintext::note(const SproutPaymentAddress& addr) const
{
return SproutNote(addr.a_pk, value_, rho, r);
}

4
src/zcash/Note.hpp

@ -35,7 +35,7 @@ public:
virtual uint256 cm() const override;
uint256 nullifier(const SpendingKey& a_sk) const;
uint256 nullifier(const SproutSpendingKey& a_sk) const;
};
class BaseNotePlaintext {
@ -61,7 +61,7 @@ public:
SproutNotePlaintext(const SproutNote& note, boost::array<unsigned char, ZC_MEMO_SIZE> memo);
SproutNote note(const PaymentAddress& addr) const;
SproutNote note(const SproutPaymentAddress& addr) const;
virtual ~SproutNotePlaintext() {}

2
src/zcash/circuit/note.tcc

@ -118,7 +118,7 @@ public:
void generate_r1cs_witness(
const MerklePath& path,
const SpendingKey& key,
const SproutSpendingKey& key,
const SproutNote& note
) {
note_gadget<FieldT>::generate_r1cs_witness(note);

6
src/zcbenchmarks.cpp

@ -281,11 +281,11 @@ double benchmark_try_decrypt_notes(size_t nAddrs)
{
CWallet wallet;
for (int i = 0; i < nAddrs; i++) {
auto sk = libzcash::SpendingKey::random();
auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSpendingKey(sk);
}
auto sk = libzcash::SpendingKey::random();
auto sk = libzcash::SproutSpendingKey::random();
auto tx = GetValidReceive(*pzcashParams, sk, 10, true);
struct timeval tv_start;
@ -299,7 +299,7 @@ double benchmark_increment_note_witnesses(size_t nTxs)
CWallet wallet;
ZCIncrementalMerkleTree tree;
auto sk = libzcash::SpendingKey::random();
auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSpendingKey(sk);
// First block

Loading…
Cancel
Save