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

24
src/gtest/test_keystore.cpp

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

4
src/gtest/test_paymentdisclosure.cpp

@ -120,7 +120,7 @@ TEST(paymentdisclosure, mainnet) {
PaymentDisclosureInfo info; PaymentDisclosureInfo info;
info.esk = random_uint256(); info.esk = random_uint256();
info.joinSplitPrivKey = joinSplitPrivKey; info.joinSplitPrivKey = joinSplitPrivKey;
info.zaddr = libzcash::SpendingKey::random().address(); info.zaddr = libzcash::SproutSpendingKey::random().address();
ASSERT_TRUE(mydb.Put(key, info)); ASSERT_TRUE(mydb.Put(key, info));
// Retrieve info from test database into new local variable and test it matches // 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 // Modify this local variable and confirm it no longer matches
info2.esk = random_uint256(); info2.esk = random_uint256();
info2.joinSplitPrivKey = random_uint256(); info2.joinSplitPrivKey = random_uint256();
info2.zaddr = libzcash::SpendingKey::random().address(); info2.zaddr = libzcash::SproutSpendingKey::random().address();
ASSERT_NE(info, info2); ASSERT_NE(info, info2);
// Using the payment info object, let's create a dummy payload // 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 // construct a merkle tree
ZCIncrementalMerkleTree merkleTree; ZCIncrementalMerkleTree merkleTree;
libzcash::SpendingKey k = libzcash::SpendingKey::random(); libzcash::SproutSpendingKey k = libzcash::SproutSpendingKey::random();
libzcash::PaymentAddress addr = k.address(); libzcash::SproutPaymentAddress addr = k.address();
libzcash::SproutNote note(addr.a_pk, 100, uint256(), uint256()); 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) { TEST(Validation, ReceivedBlockTransactions) {
auto sk = libzcash::SpendingKey::random(); auto sk = libzcash::SproutSpendingKey::random();
// Create a fake genesis block // Create a fake genesis block
CBlock block1; CBlock block1;

108
src/key_io.cpp

@ -67,6 +67,70 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par
} }
return CNoDestination(); 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 } // namespace
CKey DecodeSecret(const std::string& str) CKey DecodeSecret(const std::string& str)
@ -167,14 +231,10 @@ bool IsValidDestinationString(const std::string& str)
std::string EncodePaymentAddress(const libzcash::PaymentAddress& zaddr) std::string EncodePaymentAddress(const libzcash::PaymentAddress& zaddr)
{ {
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); return boost::apply_visitor(PaymentAddressEncoder(Params()), zaddr);
ss << zaddr;
std::vector<unsigned char> data = Params().Base58Prefix(CChainParams::ZCPAYMENT_ADDRRESS);
data.insert(data.end(), ss.begin(), ss.end());
return EncodeBase58Check(data);
} }
boost::optional<libzcash::PaymentAddress> DecodePaymentAddress(const std::string& str) libzcash::PaymentAddress DecodePaymentAddress(const std::string& str)
{ {
std::vector<unsigned char> data; std::vector<unsigned char> data;
if (DecodeBase58Check(str, 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())) { std::equal(zaddr_prefix.begin(), zaddr_prefix.end(), data.begin())) {
CSerializeData serialized(data.begin() + zaddr_prefix.size(), data.end()); CSerializeData serialized(data.begin() + zaddr_prefix.size(), data.end());
CDataStream ss(serialized, SER_NETWORK, PROTOCOL_VERSION); CDataStream ss(serialized, SER_NETWORK, PROTOCOL_VERSION);
libzcash::PaymentAddress ret; libzcash::SproutPaymentAddress ret;
ss >> ret; ss >> ret;
return 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) std::string EncodeViewingKey(const libzcash::ViewingKey& vk)
{ {
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); return boost::apply_visitor(ViewingKeyEncoder(Params()), vk);
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;
} }
boost::optional<libzcash::ViewingKey> DecodeViewingKey(const std::string& str) libzcash::ViewingKey DecodeViewingKey(const std::string& str)
{ {
std::vector<unsigned char> data; std::vector<unsigned char> data;
if (DecodeBase58Check(str, 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())) { std::equal(vk_prefix.begin(), vk_prefix.end(), data.begin())) {
CSerializeData serialized(data.begin() + vk_prefix.size(), data.end()); CSerializeData serialized(data.begin() + vk_prefix.size(), data.end());
CDataStream ss(serialized, SER_NETWORK, PROTOCOL_VERSION); CDataStream ss(serialized, SER_NETWORK, PROTOCOL_VERSION);
libzcash::ViewingKey ret; libzcash::SproutViewingKey ret;
ss >> ret; ss >> ret;
memory_cleanse(serialized.data(), serialized.size()); memory_cleanse(serialized.data(), serialized.size());
memory_cleanse(data.data(), data.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()); memory_cleanse(data.data(), data.size());
return boost::none; return libzcash::InvalidEncoding();
} }
std::string EncodeSpendingKey(const libzcash::SpendingKey& zkey) std::string EncodeSpendingKey(const libzcash::SpendingKey& zkey)
{ {
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); return boost::apply_visitor(SpendingKeyEncoder(Params()), zkey);
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;
} }
boost::optional<libzcash::SpendingKey> DecodeSpendingKey(const std::string& str) libzcash::SpendingKey DecodeSpendingKey(const std::string& str)
{ {
std::vector<unsigned char> data; std::vector<unsigned char> data;
if (DecodeBase58Check(str, 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())) { std::equal(zkey_prefix.begin(), zkey_prefix.end(), data.begin())) {
CSerializeData serialized(data.begin() + zkey_prefix.size(), data.end()); CSerializeData serialized(data.begin() + zkey_prefix.size(), data.end());
CDataStream ss(serialized, SER_NETWORK, PROTOCOL_VERSION); CDataStream ss(serialized, SER_NETWORK, PROTOCOL_VERSION);
libzcash::SpendingKey ret; libzcash::SproutSpendingKey ret;
ss >> ret; ss >> ret;
memory_cleanse(serialized.data(), serialized.size()); memory_cleanse(serialized.data(), serialized.size());
memory_cleanse(data.data(), data.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()); 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); bool IsValidDestinationString(const std::string& str, const CChainParams& params);
std::string EncodePaymentAddress(const libzcash::PaymentAddress& zaddr); 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); 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); 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 #endif // BITCOIN_KEYIO_H

12
src/keystore.cpp

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

42
src/keystore.h

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

6
src/paymentdisclosure.h

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

7
src/rpcmisc.cpp

@ -239,9 +239,12 @@ UniValue z_validateaddress(const UniValue& params, bool fHelp)
std::string payingKey, transmissionKey; std::string payingKey, transmissionKey;
string strAddress = params[0].get_str(); string strAddress = params[0].get_str();
auto isValid = DecodePaymentAddress(strAddress); auto address = DecodePaymentAddress(strAddress);
bool isValid = IsValidPaymentAddress(address);
if (isValid) { 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 #ifdef ENABLE_WALLET
isMine = pwalletMain->HaveSpendingKey(addr); isMine = pwalletMain->HaveSpendingKey(addr);

4
src/test/coins_tests.cpp

@ -247,8 +247,8 @@ public:
uint256 appendRandomCommitment(ZCIncrementalMerkleTree &tree) uint256 appendRandomCommitment(ZCIncrementalMerkleTree &tree)
{ {
libzcash::SpendingKey k = libzcash::SpendingKey::random(); libzcash::SproutSpendingKey k = libzcash::SproutSpendingKey::random();
libzcash::PaymentAddress addr = k.address(); libzcash::SproutPaymentAddress addr = k.address();
libzcash::SproutNote note(addr.a_pk, 0, uint256(), uint256()); 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) BOOST_AUTO_TEST_CASE(zc_address_test)
{ {
for (size_t i = 0; i < 1000; i++) { for (size_t i = 0; i < 1000; i++) {
auto sk = SpendingKey::random(); auto sk = SproutSpendingKey::random();
{ {
string sk_string = EncodeSpendingKey(sk); string sk_string = EncodeSpendingKey(sk);
@ -196,8 +196,9 @@ BOOST_AUTO_TEST_CASE(zc_address_test)
BOOST_CHECK(sk_string[1] == 'K'); BOOST_CHECK(sk_string[1] == 'K');
auto spendingkey2 = DecodeSpendingKey(sk_string); auto spendingkey2 = DecodeSpendingKey(sk_string);
BOOST_ASSERT(static_cast<bool>(spendingkey2)); BOOST_CHECK(IsValidSpendingKey(spendingkey2));
SpendingKey sk2 = *spendingkey2; BOOST_ASSERT(boost::get<SproutSpendingKey>(&spendingkey2) != nullptr);
auto sk2 = boost::get<SproutSpendingKey>(spendingkey2);
BOOST_CHECK(sk.inner() == sk2.inner()); BOOST_CHECK(sk.inner() == sk2.inner());
} }
{ {
@ -209,9 +210,10 @@ BOOST_AUTO_TEST_CASE(zc_address_test)
BOOST_CHECK(addr_string[1] == 'c'); BOOST_CHECK(addr_string[1] == 'c');
auto paymentaddr2 = DecodePaymentAddress(addr_string); 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.a_pk == addr2.a_pk);
BOOST_CHECK(addr.pk_enc == addr2.pk_enc); 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); BOOST_CHECK_THROW(CallRPC("z_validateaddress toomany args"), runtime_error);
// Wallet should be empty // Wallet should be empty
std::set<libzcash::PaymentAddress> addrs; std::set<libzcash::SproutPaymentAddress> addrs;
pwalletMain->GetPaymentAddresses(addrs); pwalletMain->GetPaymentAddresses(addrs);
BOOST_CHECK(addrs.size()==0); BOOST_CHECK(addrs.size()==0);
@ -381,12 +381,15 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_exportwallet)
LOCK2(cs_main, pwalletMain->cs_wallet); LOCK2(cs_main, pwalletMain->cs_wallet);
// wallet should be empty // wallet should be empty
std::set<libzcash::PaymentAddress> addrs; std::set<libzcash::SproutPaymentAddress> addrs;
pwalletMain->GetPaymentAddresses(addrs); pwalletMain->GetPaymentAddresses(addrs);
BOOST_CHECK(addrs.size()==0); BOOST_CHECK(addrs.size()==0);
// wallet should have one key // 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); pwalletMain->GetPaymentAddresses(addrs);
BOOST_CHECK(addrs.size()==1); 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())); BOOST_CHECK_NO_THROW(CallRPC(string("z_exportwallet ") + tmpfilename.string()));
libzcash::SpendingKey key; libzcash::SproutSpendingKey key;
BOOST_CHECK(pwalletMain->GetSpendingKey(addr, key)); BOOST_CHECK(pwalletMain->GetSpendingKey(addr, key));
std::string s1 = EncodePaymentAddress(addr); 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); BOOST_CHECK_THROW(CallRPC("z_importwallet toomany args"), runtime_error);
// create a random key locally // create a random key locally
auto testSpendingKey = libzcash::SpendingKey::random(); auto testSpendingKey = libzcash::SproutSpendingKey::random();
auto testPaymentAddress = testSpendingKey.address(); auto testPaymentAddress = testSpendingKey.address();
std::string testAddr = EncodePaymentAddress(testPaymentAddress); std::string testAddr = EncodePaymentAddress(testPaymentAddress);
std::string testKey = EncodeSpendingKey(testSpendingKey); std::string testKey = EncodeSpendingKey(testSpendingKey);
@ -485,7 +488,7 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importwallet)
file << std::flush; file << std::flush;
// wallet should currently be empty // wallet should currently be empty
std::set<libzcash::PaymentAddress> addrs; std::set<libzcash::SproutPaymentAddress> addrs;
pwalletMain->GetPaymentAddresses(addrs); pwalletMain->GetPaymentAddresses(addrs);
BOOST_CHECK(addrs.size()==0); BOOST_CHECK(addrs.size()==0);
@ -497,11 +500,14 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importwallet)
BOOST_CHECK(addrs.size()==1); BOOST_CHECK(addrs.size()==1);
// check that we have the spending key for the address // 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)); BOOST_CHECK(pwalletMain->HaveSpendingKey(addr));
// Verify the spending key is the same as the test data // 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(pwalletMain->GetSpendingKey(addr, k));
BOOST_CHECK_EQUAL(testKey, EncodeSpendingKey(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); BOOST_CHECK_THROW(CallRPC("z_exportkey toomany args"), runtime_error);
// error if invalid args // error if invalid args
auto sk = libzcash::SpendingKey::random(); auto sk = libzcash::SproutSpendingKey::random();
std::string prefix = std::string("z_importkey ") + EncodeSpendingKey(sk) + " yes "; std::string prefix = std::string("z_importkey ") + EncodeSpendingKey(sk) + " yes ";
BOOST_CHECK_THROW(CallRPC(prefix + "-1"), runtime_error); BOOST_CHECK_THROW(CallRPC(prefix + "-1"), runtime_error);
BOOST_CHECK_THROW(CallRPC(prefix + "2147483647"), runtime_error); // allowed, but > height of active chain tip 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); BOOST_CHECK_THROW(CallRPC(prefix + "100badchars"), runtime_error);
// wallet should currently be empty // wallet should currently be empty
std::set<libzcash::PaymentAddress> addrs; std::set<libzcash::SproutPaymentAddress> addrs;
pwalletMain->GetPaymentAddresses(addrs); pwalletMain->GetPaymentAddresses(addrs);
BOOST_CHECK(addrs.size()==0); BOOST_CHECK(addrs.size()==0);
// verify import and export key // verify import and export key
for (int i = 0; i < n1; i++) { for (int i = 0; i < n1; i++) {
// create a random key locally // create a random key locally
auto testSpendingKey = libzcash::SpendingKey::random(); auto testSpendingKey = libzcash::SproutSpendingKey::random();
auto testPaymentAddress = testSpendingKey.address(); auto testPaymentAddress = testSpendingKey.address();
std::string testAddr = EncodePaymentAddress(testPaymentAddress); std::string testAddr = EncodePaymentAddress(testPaymentAddress);
std::string testKey = EncodeSpendingKey(testSpendingKey); std::string testKey = EncodeSpendingKey(testSpendingKey);
@ -590,7 +596,10 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importexport)
// Add one more address // Add one more address
BOOST_CHECK_NO_THROW(retValue = CallRPC("z_getnewaddress")); BOOST_CHECK_NO_THROW(retValue = CallRPC("z_getnewaddress"));
std::string newaddress = retValue.get_str(); 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)); BOOST_CHECK(pwalletMain->HaveSpendingKey(newAddr));
// Check if too many args // Check if too many args
@ -1217,7 +1226,7 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_encrypted_wallet_zkeys)
int n = 100; int n = 100;
// wallet should currently be empty // wallet should currently be empty
std::set<libzcash::PaymentAddress> addrs; std::set<libzcash::SproutPaymentAddress> addrs;
pwalletMain->GetPaymentAddresses(addrs); pwalletMain->GetPaymentAddresses(addrs);
BOOST_CHECK(addrs.size()==0); 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 // construct a merkle tree
ZCIncrementalMerkleTree merkleTree; ZCIncrementalMerkleTree merkleTree;
libzcash::SpendingKey k = libzcash::SpendingKey::random(); auto k = libzcash::SproutSpendingKey::random();
libzcash::PaymentAddress addr = k.address(); auto addr = k.address();
libzcash::SproutNote note(addr.a_pk, 100, uint256(), uint256()); libzcash::SproutNote note(addr.a_pk, 100, uint256(), uint256());

14
src/utiltest.cpp

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

6
src/utiltest.h

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

22
src/wallet/asyncrpcoperation_mergetoaddress.cpp

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

2
src/wallet/asyncrpcoperation_mergetoaddress.h

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

31
src/wallet/asyncrpcoperation_sendmany.cpp

@ -81,11 +81,13 @@ AsyncRPCOperation_sendmany::AsyncRPCOperation_sendmany(
if (!isfromtaddr_) { if (!isfromtaddr_) {
auto address = DecodePaymentAddress(fromAddress); auto address = DecodePaymentAddress(fromAddress);
if (address) { if (IsValidPaymentAddress(address)) {
PaymentAddress addr = *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 // 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)) { if (!pwalletMain->GetSpendingKey(addr, key)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, no spending key found for zaddr"); 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; std::deque<SendManyRecipient> zOutputsDeque;
for (auto o : z_outputs_) { 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); zOutputsDeque.push_back(o);
} }
@ -468,8 +473,8 @@ bool AsyncRPCOperation_sendmany::main_impl() {
std::string hexMemo = std::get<2>(smr); std::string hexMemo = std::get<2>(smr);
zOutputsDeque.pop_front(); zOutputsDeque.pop_front();
PaymentAddress pa = *DecodePaymentAddress(address); PaymentAddress pa = DecodePaymentAddress(address);
JSOutput jso = JSOutput(pa, value); JSOutput jso = JSOutput(boost::get<libzcash::SproutPaymentAddress>(pa), value);
if (hexMemo.size() > 0) { if (hexMemo.size() > 0) {
jso.memo = get_memo_from_hex_string(hexMemo); 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) 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 // 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); auto hSig = prevJoinSplit.h_sig(*pzcashParams, tx_.joinSplitPubKey);
try { try {
SproutNotePlaintext plaintext = SproutNotePlaintext::decrypt( SproutNotePlaintext plaintext = SproutNotePlaintext::decrypt(
@ -579,7 +584,7 @@ bool AsyncRPCOperation_sendmany::main_impl() {
hSig, hSig,
(unsigned char) changeOutputIndex); (unsigned char) changeOutputIndex);
SproutNote note = plaintext.note(frompaymentaddress_); SproutNote note = plaintext.note(boost::get<libzcash::SproutPaymentAddress>(frompaymentaddress_));
info.notes.push_back(note); info.notes.push_back(note);
jsInputValue += plaintext.value(); jsInputValue += plaintext.value();
@ -727,8 +732,8 @@ bool AsyncRPCOperation_sendmany::main_impl() {
assert(value==0); assert(value==0);
info.vjsout.push_back(JSOutput()); // dummy output while we accumulate funds into a change note for vpub_new info.vjsout.push_back(JSOutput()); // dummy output while we accumulate funds into a change note for vpub_new
} else { } else {
PaymentAddress pa = *DecodePaymentAddress(address); PaymentAddress pa = DecodePaymentAddress(address);
JSOutput jso = JSOutput(pa, value); JSOutput jso = JSOutput(boost::get<libzcash::SproutPaymentAddress>(pa), value);
if (hexMemo.size() > 0) { if (hexMemo.size() > 0) {
jso.memo = get_memo_from_hex_string(hexMemo); jso.memo = get_memo_from_hex_string(hexMemo);
} }
@ -737,7 +742,7 @@ bool AsyncRPCOperation_sendmany::main_impl() {
// create output for any change // create output for any change
if (jsChange>0) { 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", LogPrint("zrpcunsafe", "%s: generating note for change (amount=%s)\n",
getId(), getId(),
@ -886,7 +891,7 @@ bool AsyncRPCOperation_sendmany::find_unspent_notes() {
} }
for (CSproutNotePlaintextEntry & entry : entries) { 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()); 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", LogPrint("zrpcunsafe", "%s: found unspent note (txid=%s, vjoinsplit=%d, ciphertext=%d, amount=%s, memo=%s)\n",
getId(), getId(),
@ -948,7 +953,7 @@ UniValue AsyncRPCOperation_sendmany::perform_joinsplit(
if (!witnesses[i]) { if (!witnesses[i]) {
throw runtime_error("joinsplit input could not be found in tree"); 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 // 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. // placeholder for txid will be filled in later when tx has been finalized and signed.
PaymentDisclosureKey pdKey = {placeholder, js_index, mapped_index}; PaymentDisclosureKey pdKey = {placeholder, js_index, mapped_index};
JSOutput output = outputs[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}; PaymentDisclosureInfo pdInfo = {PAYMENT_DISCLOSURE_VERSION_EXPERIMENTAL, esk, joinSplitPrivKey, zaddr};
paymentDisclosureData_.push_back(PaymentDisclosureKeyInfo(pdKey, pdInfo)); 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 // Check the destination address is valid for this network i.e. not testnet being used on mainnet
auto address = DecodePaymentAddress(toAddress); auto address = DecodePaymentAddress(toAddress);
if (address) { if (IsValidPaymentAddress(address)) {
tozaddr_ = *address; // TODO: Add Sapling support. For now, ensure we can freely convert.
assert(boost::get<libzcash::SproutPaymentAddress>(&address) != nullptr);
tozaddr_ = address;
} else { } else {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid to address"); throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid to address");
} }
@ -233,7 +235,7 @@ bool AsyncRPCOperation_shieldcoinbase::main_impl() {
ShieldCoinbaseJSInfo info; ShieldCoinbaseJSInfo info;
info.vpub_old = sendAmount; info.vpub_old = sendAmount;
info.vpub_new = 0; info.vpub_new = 0;
JSOutput jso = JSOutput(tozaddr_, sendAmount); JSOutput jso = JSOutput(boost::get<libzcash::SproutPaymentAddress>(tozaddr_), sendAmount);
info.vjsout.push_back(jso); info.vjsout.push_back(jso);
obj = perform_joinsplit(info); 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. // placeholder for txid will be filled in later when tx has been finalized and signed.
PaymentDisclosureKey pdKey = {placeholder, js_index, mapped_index}; PaymentDisclosureKey pdKey = {placeholder, js_index, mapped_index};
JSOutput output = outputs[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}; PaymentDisclosureInfo pdInfo = {PAYMENT_DISCLOSURE_VERSION_EXPERIMENTAL, esk, joinSplitPrivKey, zaddr};
paymentDisclosureData_.push_back(PaymentDisclosureKeyInfo(pdKey, pdInfo)); 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, static bool DecryptSpendingKey(const CKeyingMaterial& vMasterKey,
const std::vector<unsigned char>& vchCryptedSecret, const std::vector<unsigned char>& vchCryptedSecret,
const libzcash::PaymentAddress& address, const libzcash::SproutPaymentAddress& address,
libzcash::SpendingKey& sk) libzcash::SproutSpendingKey& sk)
{ {
CKeyingMaterial vchSecret; CKeyingMaterial vchSecret;
if(!DecryptSecret(vMasterKey, vchCryptedSecret, address.GetHash(), vchSecret)) if(!DecryptSecret(vMasterKey, vchCryptedSecret, address.GetHash(), vchSecret))
@ -203,9 +203,9 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
CryptedSpendingKeyMap::const_iterator skmi = mapCryptedSpendingKeys.begin(); CryptedSpendingKeyMap::const_iterator skmi = mapCryptedSpendingKeys.begin();
for (; skmi != mapCryptedSpendingKeys.end(); ++skmi) 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; const std::vector<unsigned char> &vchCryptedSecret = (*skmi).second;
libzcash::SpendingKey sk; libzcash::SproutSpendingKey sk;
if (!DecryptSpendingKey(vMasterKeyIn, vchCryptedSecret, address, sk)) if (!DecryptSpendingKey(vMasterKeyIn, vchCryptedSecret, address, sk))
{ {
keyFail = true; keyFail = true;
@ -298,7 +298,7 @@ bool CCryptoKeyStore::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) co
return false; return false;
} }
bool CCryptoKeyStore::AddSpendingKey(const libzcash::SpendingKey &sk) bool CCryptoKeyStore::AddSpendingKey(const libzcash::SproutSpendingKey &sk)
{ {
{ {
LOCK(cs_SpendingKeyStore); LOCK(cs_SpendingKeyStore);
@ -322,7 +322,7 @@ bool CCryptoKeyStore::AddSpendingKey(const libzcash::SpendingKey &sk)
return true; return true;
} }
bool CCryptoKeyStore::AddCryptedSpendingKey(const libzcash::PaymentAddress &address, bool CCryptoKeyStore::AddCryptedSpendingKey(const libzcash::SproutPaymentAddress &address,
const libzcash::ReceivingKey &rk, const libzcash::ReceivingKey &rk,
const std::vector<unsigned char> &vchCryptedSecret) const std::vector<unsigned char> &vchCryptedSecret)
{ {
@ -337,7 +337,7 @@ bool CCryptoKeyStore::AddCryptedSpendingKey(const libzcash::PaymentAddress &addr
return true; 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); LOCK(cs_SpendingKeyStore);
@ -376,11 +376,11 @@ bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn)
mapKeys.clear(); mapKeys.clear();
BOOST_FOREACH(SpendingKeyMap::value_type& mSpendingKey, mapSpendingKeys) 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); CSecureDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << sk; ss << sk;
CKeyingMaterial vchSecret(ss.begin(), ss.end()); CKeyingMaterial vchSecret(ss.begin(), ss.end());
libzcash::PaymentAddress address = sk.address(); libzcash::SproutPaymentAddress address = sk.address();
std::vector<unsigned char> vchCryptedSecret; std::vector<unsigned char> vchCryptedSecret;
if (!EncryptSecret(vMasterKeyIn, vchSecret, address.GetHash(), vchCryptedSecret)) if (!EncryptSecret(vMasterKeyIn, vchSecret, address.GetHash(), vchCryptedSecret))
return false; return false;

10
src/wallet/crypter.h

@ -200,11 +200,11 @@ public:
mi++; mi++;
} }
} }
virtual bool AddCryptedSpendingKey(const libzcash::PaymentAddress &address, virtual bool AddCryptedSpendingKey(const libzcash::SproutPaymentAddress &address,
const libzcash::ReceivingKey &rk, const libzcash::ReceivingKey &rk,
const std::vector<unsigned char> &vchCryptedSecret); const std::vector<unsigned char> &vchCryptedSecret);
bool AddSpendingKey(const libzcash::SpendingKey &sk); bool AddSpendingKey(const libzcash::SproutSpendingKey &sk);
bool HaveSpendingKey(const libzcash::PaymentAddress &address) const bool HaveSpendingKey(const libzcash::SproutPaymentAddress &address) const
{ {
{ {
LOCK(cs_SpendingKeyStore); LOCK(cs_SpendingKeyStore);
@ -214,8 +214,8 @@ public:
} }
return false; return false;
} }
bool GetSpendingKey(const libzcash::PaymentAddress &address, libzcash::SpendingKey &skOut) const; bool GetSpendingKey(const libzcash::SproutPaymentAddress &address, libzcash::SproutSpendingKey &skOut) const;
void GetPaymentAddresses(std::set<libzcash::PaymentAddress> &setAddress) const void GetPaymentAddresses(std::set<libzcash::SproutPaymentAddress> &setAddress) const
{ {
if (!IsCrypted()) 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); 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) { const CTransaction& tx, size_t js, size_t n) {
return GetNote(*params, sk, tx, js, 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) { const libzcash::SproutNote& note, CAmount value) {
return GetValidSpend(*params, sk, note, value); return GetValidSpend(*params, sk, note, value);
} }
JSOutPoint CreateValidBlock(TestWallet& wallet, JSOutPoint CreateValidBlock(TestWallet& wallet,
const libzcash::SpendingKey& sk, const libzcash::SproutSpendingKey& sk,
const CBlockIndex& index, const CBlockIndex& index,
CBlock& block, CBlock& block,
ZCIncrementalMerkleTree& tree) { ZCIncrementalMerkleTree& tree) {
@ -112,7 +112,7 @@ TEST(wallet_tests, setup_datadir_location_run_as_first_test) {
} }
TEST(wallet_tests, note_data_serialisation) { TEST(wallet_tests, note_data_serialisation) {
auto sk = libzcash::SpendingKey::random(); auto sk = libzcash::SproutSpendingKey::random();
auto wtx = GetValidReceive(sk, 10, true); auto wtx = GetValidReceive(sk, 10, true);
auto note = GetNote(sk, wtx, 0, 1); auto note = GetNote(sk, wtx, 0, 1);
auto nullifier = note.nullifier(sk); auto nullifier = note.nullifier(sk);
@ -138,7 +138,7 @@ TEST(wallet_tests, note_data_serialisation) {
TEST(wallet_tests, find_unspent_notes) { TEST(wallet_tests, find_unspent_notes) {
SelectParams(CBaseChainParams::TESTNET); SelectParams(CBaseChainParams::TESTNET);
CWallet wallet; CWallet wallet;
auto sk = libzcash::SpendingKey::random(); auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSpendingKey(sk); wallet.AddSpendingKey(sk);
auto wtx = GetValidReceive(sk, 10, true); auto wtx = GetValidReceive(sk, 10, true);
@ -295,7 +295,7 @@ TEST(wallet_tests, find_unspent_notes) {
TEST(wallet_tests, set_note_addrs_in_cwallettx) { 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 wtx = GetValidReceive(sk, 10, true);
auto note = GetNote(sk, wtx, 0, 1); auto note = GetNote(sk, wtx, 0, 1);
auto nullifier = note.nullifier(sk); auto nullifier = note.nullifier(sk);
@ -315,7 +315,7 @@ TEST(wallet_tests, set_invalid_note_addrs_in_cwallettx) {
EXPECT_EQ(0, wtx.mapNoteData.size()); EXPECT_EQ(0, wtx.mapNoteData.size());
mapNoteData_t noteData; mapNoteData_t noteData;
auto sk = libzcash::SpendingKey::random(); auto sk = libzcash::SproutSpendingKey::random();
JSOutPoint jsoutpt {wtx.GetHash(), 0, 1}; JSOutPoint jsoutpt {wtx.GetHash(), 0, 1};
CNoteData nd {sk.address(), uint256()}; CNoteData nd {sk.address(), uint256()};
noteData[jsoutpt] = nd; noteData[jsoutpt] = nd;
@ -326,7 +326,7 @@ TEST(wallet_tests, set_invalid_note_addrs_in_cwallettx) {
TEST(wallet_tests, GetNoteNullifier) { TEST(wallet_tests, GetNoteNullifier) {
CWallet wallet; CWallet wallet;
auto sk = libzcash::SpendingKey::random(); auto sk = libzcash::SproutSpendingKey::random();
auto address = sk.address(); auto address = sk.address();
auto dec = ZCNoteDecryption(sk.receiving_key()); auto dec = ZCNoteDecryption(sk.receiving_key());
@ -357,8 +357,8 @@ TEST(wallet_tests, GetNoteNullifier) {
TEST(wallet_tests, FindMyNotes) { TEST(wallet_tests, FindMyNotes) {
CWallet wallet; CWallet wallet;
auto sk = libzcash::SpendingKey::random(); auto sk = libzcash::SproutSpendingKey::random();
auto sk2 = libzcash::SpendingKey::random(); auto sk2 = libzcash::SproutSpendingKey::random();
wallet.AddSpendingKey(sk2); wallet.AddSpendingKey(sk2);
auto wtx = GetValidReceive(sk, 10, true); auto wtx = GetValidReceive(sk, 10, true);
@ -384,7 +384,7 @@ TEST(wallet_tests, FindMyNotesInEncryptedWallet) {
uint256 r {GetRandHash()}; uint256 r {GetRandHash()};
CKeyingMaterial vMasterKey (r.begin(), r.end()); CKeyingMaterial vMasterKey (r.begin(), r.end());
auto sk = libzcash::SpendingKey::random(); auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSpendingKey(sk); wallet.AddSpendingKey(sk);
ASSERT_TRUE(wallet.EncryptKeys(vMasterKey)); ASSERT_TRUE(wallet.EncryptKeys(vMasterKey));
@ -412,7 +412,7 @@ TEST(wallet_tests, FindMyNotesInEncryptedWallet) {
TEST(wallet_tests, get_conflicted_notes) { TEST(wallet_tests, get_conflicted_notes) {
CWallet wallet; CWallet wallet;
auto sk = libzcash::SpendingKey::random(); auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSpendingKey(sk); wallet.AddSpendingKey(sk);
auto wtx = GetValidReceive(sk, 10, true); auto wtx = GetValidReceive(sk, 10, true);
@ -443,7 +443,7 @@ TEST(wallet_tests, get_conflicted_notes) {
TEST(wallet_tests, nullifier_is_spent) { TEST(wallet_tests, nullifier_is_spent) {
CWallet wallet; CWallet wallet;
auto sk = libzcash::SpendingKey::random(); auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSpendingKey(sk); wallet.AddSpendingKey(sk);
auto wtx = GetValidReceive(sk, 10, true); auto wtx = GetValidReceive(sk, 10, true);
@ -483,7 +483,7 @@ TEST(wallet_tests, nullifier_is_spent) {
TEST(wallet_tests, navigate_from_nullifier_to_note) { TEST(wallet_tests, navigate_from_nullifier_to_note) {
CWallet wallet; CWallet wallet;
auto sk = libzcash::SpendingKey::random(); auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSpendingKey(sk); wallet.AddSpendingKey(sk);
auto wtx = GetValidReceive(sk, 10, true); 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) { TEST(wallet_tests, spent_note_is_from_me) {
CWallet wallet; CWallet wallet;
auto sk = libzcash::SpendingKey::random(); auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSpendingKey(sk); wallet.AddSpendingKey(sk);
auto wtx = GetValidReceive(sk, 10, true); 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) { TEST(wallet_tests, cached_witnesses_empty_chain) {
TestWallet wallet; TestWallet wallet;
auto sk = libzcash::SpendingKey::random(); auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSpendingKey(sk); wallet.AddSpendingKey(sk);
auto wtx = GetValidReceive(sk, 10, true); auto wtx = GetValidReceive(sk, 10, true);
@ -590,7 +590,7 @@ TEST(wallet_tests, cached_witnesses_chain_tip) {
CBlock block1; CBlock block1;
ZCIncrementalMerkleTree tree; ZCIncrementalMerkleTree tree;
auto sk = libzcash::SpendingKey::random(); auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSpendingKey(sk); wallet.AddSpendingKey(sk);
{ {
@ -672,7 +672,7 @@ TEST(wallet_tests, CachedWitnessesDecrementFirst) {
CBlockIndex index2(block2); CBlockIndex index2(block2);
ZCIncrementalMerkleTree tree; ZCIncrementalMerkleTree tree;
auto sk = libzcash::SpendingKey::random(); auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSpendingKey(sk); wallet.AddSpendingKey(sk);
{ {
@ -744,7 +744,7 @@ TEST(wallet_tests, CachedWitnessesCleanIndex) {
ZCIncrementalMerkleTree riTree = tree; ZCIncrementalMerkleTree riTree = tree;
std::vector<boost::optional<ZCIncrementalWitness>> witnesses; std::vector<boost::optional<ZCIncrementalWitness>> witnesses;
auto sk = libzcash::SpendingKey::random(); auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSpendingKey(sk); wallet.AddSpendingKey(sk);
// Generate a chain // Generate a chain
@ -813,7 +813,7 @@ TEST(wallet_tests, CachedWitnessesCleanIndex) {
TEST(wallet_tests, ClearNoteWitnessCache) { TEST(wallet_tests, ClearNoteWitnessCache) {
TestWallet wallet; TestWallet wallet;
auto sk = libzcash::SpendingKey::random(); auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSpendingKey(sk); wallet.AddSpendingKey(sk);
auto wtx = GetValidReceive(sk, 10, true); auto wtx = GetValidReceive(sk, 10, true);
@ -862,7 +862,7 @@ TEST(wallet_tests, WriteWitnessCache) {
MockWalletDB walletdb; MockWalletDB walletdb;
CBlockLocator loc; CBlockLocator loc;
auto sk = libzcash::SpendingKey::random(); auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSpendingKey(sk); wallet.AddSpendingKey(sk);
auto wtx = GetValidReceive(sk, 10, true); auto wtx = GetValidReceive(sk, 10, true);
@ -939,7 +939,7 @@ TEST(wallet_tests, UpdateNullifierNoteMap) {
uint256 r {GetRandHash()}; uint256 r {GetRandHash()};
CKeyingMaterial vMasterKey (r.begin(), r.end()); CKeyingMaterial vMasterKey (r.begin(), r.end());
auto sk = libzcash::SpendingKey::random(); auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSpendingKey(sk); wallet.AddSpendingKey(sk);
ASSERT_TRUE(wallet.EncryptKeys(vMasterKey)); ASSERT_TRUE(wallet.EncryptKeys(vMasterKey));
@ -972,7 +972,7 @@ TEST(wallet_tests, UpdateNullifierNoteMap) {
TEST(wallet_tests, UpdatedNoteData) { TEST(wallet_tests, UpdatedNoteData) {
TestWallet wallet; TestWallet wallet;
auto sk = libzcash::SpendingKey::random(); auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSpendingKey(sk); wallet.AddSpendingKey(sk);
auto wtx = GetValidReceive(sk, 10, true); auto wtx = GetValidReceive(sk, 10, true);
@ -1019,7 +1019,7 @@ TEST(wallet_tests, UpdatedNoteData) {
TEST(wallet_tests, MarkAffectedTransactionsDirty) { TEST(wallet_tests, MarkAffectedTransactionsDirty) {
TestWallet wallet; TestWallet wallet;
auto sk = libzcash::SpendingKey::random(); auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSpendingKey(sk); wallet.AddSpendingKey(sk);
auto wtx = GetValidReceive(sk, 10, true); auto wtx = GetValidReceive(sk, 10, true);
@ -1050,7 +1050,7 @@ TEST(wallet_tests, MarkAffectedTransactionsDirty) {
TEST(wallet_tests, NoteLocking) { TEST(wallet_tests, NoteLocking) {
TestWallet wallet; TestWallet wallet;
auto sk = libzcash::SpendingKey::random(); auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSpendingKey(sk); wallet.AddSpendingKey(sk);
auto wtx = GetValidReceive(sk, 10, true); 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; CWallet wallet;
// wallet should be empty // wallet should be empty
std::set<libzcash::PaymentAddress> addrs; std::set<libzcash::SproutPaymentAddress> addrs;
wallet.GetPaymentAddresses(addrs); wallet.GetPaymentAddresses(addrs);
ASSERT_EQ(0, addrs.size()); ASSERT_EQ(0, addrs.size());
// wallet should have one key // 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); wallet.GetPaymentAddresses(addrs);
ASSERT_EQ(1, addrs.size()); ASSERT_EQ(1, addrs.size());
@ -33,7 +35,7 @@ TEST(wallet_zkeys_tests, store_and_load_zkeys) {
ASSERT_TRUE(wallet.HaveSpendingKey(addr)); ASSERT_TRUE(wallet.HaveSpendingKey(addr));
// manually add new spending key to wallet // manually add new spending key to wallet
auto sk = libzcash::SpendingKey::random(); auto sk = libzcash::SproutSpendingKey::random();
ASSERT_TRUE(wallet.AddZKey(sk)); ASSERT_TRUE(wallet.AddZKey(sk));
// verify wallet did add it // verify wallet did add it
@ -41,7 +43,7 @@ TEST(wallet_zkeys_tests, store_and_load_zkeys) {
ASSERT_TRUE(wallet.HaveSpendingKey(addr)); ASSERT_TRUE(wallet.HaveSpendingKey(addr));
// verify spending key stored correctly // verify spending key stored correctly
libzcash::SpendingKey keyOut; libzcash::SproutSpendingKey keyOut;
wallet.GetSpendingKey(addr, keyOut); wallet.GetSpendingKey(addr, keyOut);
ASSERT_EQ(sk, keyOut); ASSERT_EQ(sk, keyOut);
@ -51,7 +53,7 @@ TEST(wallet_zkeys_tests, store_and_load_zkeys) {
ASSERT_EQ(1, addrs.count(addr)); ASSERT_EQ(1, addrs.count(addr));
// Load a third key into the wallet // Load a third key into the wallet
sk = libzcash::SpendingKey::random(); sk = libzcash::SproutSpendingKey::random();
ASSERT_TRUE(wallet.LoadZKey(sk)); ASSERT_TRUE(wallet.LoadZKey(sk));
// attach metadata to this third key // attach metadata to this third key
@ -77,12 +79,12 @@ TEST(wallet_zkeys_tests, StoreAndLoadViewingKeys) {
CWallet wallet; CWallet wallet;
// wallet should be empty // wallet should be empty
std::set<libzcash::PaymentAddress> addrs; std::set<libzcash::SproutPaymentAddress> addrs;
wallet.GetPaymentAddresses(addrs); wallet.GetPaymentAddresses(addrs);
ASSERT_EQ(0, addrs.size()); ASSERT_EQ(0, addrs.size());
// manually add new viewing key to wallet // manually add new viewing key to wallet
auto sk = libzcash::SpendingKey::random(); auto sk = libzcash::SproutSpendingKey::random();
auto vk = sk.viewing_key(); auto vk = sk.viewing_key();
ASSERT_TRUE(wallet.AddViewingKey(vk)); ASSERT_TRUE(wallet.AddViewingKey(vk));
@ -93,12 +95,12 @@ TEST(wallet_zkeys_tests, StoreAndLoadViewingKeys) {
ASSERT_FALSE(wallet.HaveSpendingKey(addr)); ASSERT_FALSE(wallet.HaveSpendingKey(addr));
// verify viewing key stored correctly // verify viewing key stored correctly
libzcash::ViewingKey vkOut; libzcash::SproutViewingKey vkOut;
wallet.GetViewingKey(addr, vkOut); wallet.GetViewingKey(addr, vkOut);
ASSERT_EQ(vk, vkOut); ASSERT_EQ(vk, vkOut);
// Load a second viewing key into the wallet // 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())); ASSERT_TRUE(wallet.LoadViewingKey(sk2.viewing_key()));
// verify wallet did add it // verify wallet did add it
@ -133,7 +135,7 @@ TEST(wallet_zkeys_tests, write_zkey_direct_to_db) {
ASSERT_TRUE(fFirstRun); ASSERT_TRUE(fFirstRun);
// wallet should be empty // wallet should be empty
std::set<libzcash::PaymentAddress> addrs; std::set<libzcash::SproutPaymentAddress> addrs;
wallet.GetPaymentAddresses(addrs); wallet.GetPaymentAddresses(addrs);
ASSERT_EQ(0, addrs.size()); ASSERT_EQ(0, addrs.size());
@ -145,7 +147,7 @@ TEST(wallet_zkeys_tests, write_zkey_direct_to_db) {
ASSERT_EQ(1, addrs.size()); ASSERT_EQ(1, addrs.size());
// create random key and add it to database directly, bypassing wallet // 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(); auto addr = sk.address();
int64_t now = GetTime(); int64_t now = GetTime();
CKeyMetadata meta(now); CKeyMetadata meta(now);
@ -171,7 +173,7 @@ TEST(wallet_zkeys_tests, write_zkey_direct_to_db) {
ASSERT_TRUE(wallet.HaveSpendingKey(addr)); ASSERT_TRUE(wallet.HaveSpendingKey(addr));
// check key is the same // check key is the same
libzcash::SpendingKey keyOut; libzcash::SproutSpendingKey keyOut;
wallet.GetSpendingKey(addr, keyOut); wallet.GetSpendingKey(addr, keyOut);
ASSERT_EQ(sk, keyOut); ASSERT_EQ(sk, keyOut);
@ -205,7 +207,7 @@ TEST(wallet_zkeys_tests, WriteViewingKeyDirectToDB) {
ASSERT_TRUE(fFirstRun); ASSERT_TRUE(fFirstRun);
// create random viewing key and add it to database directly, bypassing wallet // 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 vk = sk.viewing_key();
auto addr = sk.address(); auto addr = sk.address();
int64_t now = GetTime(); int64_t now = GetTime();
@ -223,7 +225,7 @@ TEST(wallet_zkeys_tests, WriteViewingKeyDirectToDB) {
ASSERT_TRUE(wallet.HaveViewingKey(addr)); ASSERT_TRUE(wallet.HaveViewingKey(addr));
// check key is the same // check key is the same
libzcash::ViewingKey vkOut; libzcash::SproutViewingKey vkOut;
wallet.GetViewingKey(addr, vkOut); wallet.GetViewingKey(addr, vkOut);
ASSERT_EQ(vk, vkOut); ASSERT_EQ(vk, vkOut);
} }
@ -252,12 +254,14 @@ TEST(wallet_zkeys_tests, write_cryptedzkey_direct_to_db) {
ASSERT_TRUE(fFirstRun); ASSERT_TRUE(fFirstRun);
// wallet should be empty // wallet should be empty
std::set<libzcash::PaymentAddress> addrs; std::set<libzcash::SproutPaymentAddress> addrs;
wallet.GetPaymentAddresses(addrs); wallet.GetPaymentAddresses(addrs);
ASSERT_EQ(0, addrs.size()); ASSERT_EQ(0, addrs.size());
// Add random key to the wallet // 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 should have one key
wallet.GetPaymentAddresses(addrs); wallet.GetPaymentAddresses(addrs);
@ -274,7 +278,9 @@ TEST(wallet_zkeys_tests, write_cryptedzkey_direct_to_db) {
// unlock wallet and then add // unlock wallet and then add
wallet.Unlock(strWalletPass); 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 // Create a new wallet from the existing wallet path
CWallet wallet2("wallet_crypted.dat"); CWallet wallet2("wallet_crypted.dat");
@ -292,7 +298,7 @@ TEST(wallet_zkeys_tests, write_cryptedzkey_direct_to_db) {
ASSERT_TRUE(addrs.count(paymentAddress2)); ASSERT_TRUE(addrs.count(paymentAddress2));
// spending key is crypted, so we can't extract valid payment address // spending key is crypted, so we can't extract valid payment address
libzcash::SpendingKey keyOut; libzcash::SproutSpendingKey keyOut;
wallet2.GetSpendingKey(paymentAddress, keyOut); wallet2.GetSpendingKey(paymentAddress, keyOut);
ASSERT_FALSE(paymentAddress == keyOut.address()); 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 // Check the payment address is valid
PaymentAddress zaddr = pd.payload.zaddr; SproutPaymentAddress zaddr = pd.payload.zaddr;
{ {
o.push_back(Pair("paymentAddress", EncodePaymentAddress(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 // Let's see if the address is a valid Zcash spending key
if (fImportZKeys) { if (fImportZKeys) {
auto spendingkey = DecodeSpendingKey(vstr[0]); auto spendingkey = DecodeSpendingKey(vstr[0]);
if (spendingkey) { if (IsValidSpendingKey(spendingkey)) {
libzcash::SpendingKey key = *spendingkey; // TODO: Add Sapling support. For now, ensure we can freely convert.
libzcash::PaymentAddress addr = key.address(); assert(boost::get<libzcash::SproutSpendingKey>(&spendingkey) != nullptr);
auto key = boost::get<libzcash::SproutSpendingKey>(spendingkey);
auto addr = key.address();
if (pwalletMain->HaveSpendingKey(addr)) { if (pwalletMain->HaveSpendingKey(addr)) {
LogPrint("zrpc", "Skipping import of zaddr %s (key already present)\n", EncodePaymentAddress(addr)); LogPrint("zrpc", "Skipping import of zaddr %s (key already present)\n", EncodePaymentAddress(addr));
continue; continue;
@ -526,13 +528,13 @@ UniValue dumpwallet_impl(const UniValue& params, bool fHelp, bool fDumpZKeys)
file << "\n"; file << "\n";
if (fDumpZKeys) { if (fDumpZKeys) {
std::set<libzcash::PaymentAddress> addresses; std::set<libzcash::SproutPaymentAddress> addresses;
pwalletMain->GetPaymentAddresses(addresses); pwalletMain->GetPaymentAddresses(addresses);
file << "\n"; file << "\n";
file << "# Zkeys\n"; file << "# Zkeys\n";
file << "\n"; file << "\n";
for (auto addr : addresses ) { for (auto addr : addresses ) {
libzcash::SpendingKey key; libzcash::SproutSpendingKey key;
if (pwalletMain->GetSpendingKey(addr, key)) { if (pwalletMain->GetSpendingKey(addr, key)) {
std::string strTime = EncodeDumpTime(pwalletMain->mapZKeyMetadata[addr].nCreateTime); std::string strTime = EncodeDumpTime(pwalletMain->mapZKeyMetadata[addr].nCreateTime);
file << strprintf("%s %s # zaddr=%s\n", EncodeSpendingKey(key), strTime, EncodePaymentAddress(addr)); 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(); string strSecret = params[0].get_str();
auto spendingkey = DecodeSpendingKey(strSecret); auto spendingkey = DecodeSpendingKey(strSecret);
if (!spendingkey) { if (!IsValidSpendingKey(spendingkey)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid spending key"); 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(); auto addr = key.address();
{ {
@ -706,10 +710,12 @@ UniValue z_importviewingkey(const UniValue& params, bool fHelp)
string strVKey = params[0].get_str(); string strVKey = params[0].get_str();
auto viewingkey = DecodeViewingKey(strVKey); auto viewingkey = DecodeViewingKey(strVKey);
if (!viewingkey) { if (!IsValidViewingKey(viewingkey)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid viewing key"); 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(); auto addr = vkey.address();
{ {
@ -766,12 +772,14 @@ UniValue z_exportkey(const UniValue& params, bool fHelp)
string strAddress = params[0].get_str(); string strAddress = params[0].get_str();
auto address = DecodePaymentAddress(strAddress); auto address = DecodePaymentAddress(strAddress);
if (!address) { if (!IsValidPaymentAddress(address)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr"); 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)) if (!pwalletMain->GetSpendingKey(addr, k))
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet does not hold private zkey for this zaddr"); 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(); string strAddress = params[0].get_str();
auto address = DecodePaymentAddress(strAddress); auto address = DecodePaymentAddress(strAddress);
if (!address) { if (!IsValidPaymentAddress(address)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr"); 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)) { if (!pwalletMain->GetViewingKey(addr, vk)) {
libzcash::SpendingKey k; libzcash::SproutSpendingKey k;
if (!pwalletMain->GetSpendingKey(addr, k)) { if (!pwalletMain->GetSpendingKey(addr, k)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet does not hold private key or viewing key for this zaddr"); 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(); string address = o.get_str();
auto zaddr = DecodePaymentAddress(address); auto zaddr = DecodePaymentAddress(address);
if (zaddr) { if (IsValidPaymentAddress(zaddr)) {
libzcash::PaymentAddress addr = *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)) { if (!fIncludeWatchonly && !pwalletMain->HaveSpendingKey(addr)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, spending key for address does not belong to wallet: ") + address); 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 { else {
// User did not provide zaddrs, so use default i.e. all addresses // 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); 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("jsindex", (int)entry.jsop.js ));
obj.push_back(Pair("jsoutindex", (int)entry.jsop.n)); obj.push_back(Pair("jsoutindex", (int)entry.jsop.n));
obj.push_back(Pair("confirmations", entry.nHeight)); 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("address", EncodePaymentAddress(entry.address)));
obj.push_back(Pair("amount", ValueFromAmount(CAmount(entry.plaintext.value())))); obj.push_back(Pair("amount", ValueFromAmount(CAmount(entry.plaintext.value()))));
std::string data(entry.plaintext.memo().begin(), entry.plaintext.memo().end()); 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); LOCK(cs_main);
auto spendingkey = DecodeSpendingKey(params[0].get_str()); auto spendingkey = DecodeSpendingKey(params[0].get_str());
if (!spendingkey) { if (!IsValidSpendingKey(spendingkey)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid spending key"); 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; uint256 epk;
unsigned char nonce; unsigned char nonce;
@ -2826,7 +2834,7 @@ UniValue zc_raw_receive(const UniValue& params, bool fHelp)
h_sig, h_sig,
nonce nonce
); );
PaymentAddress payment_addr = k.address(); SproutPaymentAddress payment_addr = k.address();
SproutNote decrypted_note = npt.note(payment_addr); SproutNote decrypted_note = npt.note(payment_addr);
assert(pwalletMain != NULL); assert(pwalletMain != NULL);
@ -2902,15 +2910,18 @@ UniValue zc_raw_joinsplit(const UniValue& params, bool fHelp)
std::vector<JSInput> vjsin; std::vector<JSInput> vjsin;
std::vector<JSOutput> vjsout; std::vector<JSOutput> vjsout;
std::vector<SproutNote> notes; std::vector<SproutNote> notes;
std::vector<SpendingKey> keys; std::vector<SproutSpendingKey> keys;
std::vector<uint256> commitments; std::vector<uint256> commitments;
for (const string& name_ : inputs.getKeys()) { for (const string& name_ : inputs.getKeys()) {
auto spendingkey = DecodeSpendingKey(inputs[name_].get_str()); auto spendingkey = DecodeSpendingKey(inputs[name_].get_str());
if (!spendingkey) { if (!IsValidSpendingKey(spendingkey)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid spending key"); 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); keys.push_back(k);
@ -2921,7 +2932,7 @@ UniValue zc_raw_joinsplit(const UniValue& params, bool fHelp)
ssData >> npt; ssData >> npt;
} }
PaymentAddress addr = k.address(); SproutPaymentAddress addr = k.address();
SproutNote note = npt.note(addr); SproutNote note = npt.note(addr);
notes.push_back(note); notes.push_back(note);
commitments.push_back(note.cm()); commitments.push_back(note.cm());
@ -2952,12 +2963,15 @@ UniValue zc_raw_joinsplit(const UniValue& params, bool fHelp)
for (const string& name_ : outputs.getKeys()) { for (const string& name_ : outputs.getKeys()) {
auto addrTo = DecodePaymentAddress(name_); auto addrTo = DecodePaymentAddress(name_);
if (!addrTo) { if (!IsValidPaymentAddress(addrTo)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid recipient address."); 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_]); 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) { 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 addr = k.address();
auto viewing_key = k.viewing_key(); auto viewing_key = k.viewing_key();
@ -3130,7 +3144,8 @@ UniValue z_listaddresses(const UniValue& params, bool fHelp)
} }
UniValue ret(UniValue::VARR); UniValue ret(UniValue::VARR);
std::set<libzcash::PaymentAddress> addresses; // TODO: Add Sapling support
std::set<libzcash::SproutPaymentAddress> addresses;
pwalletMain->GetPaymentAddresses(addresses); pwalletMain->GetPaymentAddresses(addresses);
for (auto addr : addresses ) { for (auto addr : addresses ) {
if (fIncludeWatchonly || pwalletMain->HaveSpendingKey(addr)) { if (fIncludeWatchonly || pwalletMain->HaveSpendingKey(addr)) {
@ -3232,11 +3247,14 @@ UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp)
auto fromaddress = params[0].get_str(); auto fromaddress = params[0].get_str();
auto zaddr = DecodePaymentAddress(fromaddress); auto zaddr = DecodePaymentAddress(fromaddress);
if (!zaddr) { if (!IsValidPaymentAddress(zaddr)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid 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."); 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; bool fromTaddr = false;
CTxDestination taddr = DecodeDestination(fromaddress); CTxDestination taddr = DecodeDestination(fromaddress);
fromTaddr = IsValidDestination(taddr); fromTaddr = IsValidDestination(taddr);
libzcash::PaymentAddress zaddr;
if (!fromTaddr) { if (!fromTaddr) {
auto res = DecodePaymentAddress(fromaddress); 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."); 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))) { 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."); 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; bool fromTaddr = false;
CTxDestination taddr = DecodeDestination(fromaddress); CTxDestination taddr = DecodeDestination(fromaddress);
fromTaddr = IsValidDestination(taddr); fromTaddr = IsValidDestination(taddr);
libzcash::PaymentAddress zaddr; libzcash::SproutPaymentAddress zaddr;
if (!fromTaddr) { if (!fromTaddr) {
auto res = DecodePaymentAddress(fromaddress); auto res = DecodePaymentAddress(fromaddress);
if (!res) { if (!IsValidPaymentAddress(res)) {
// invalid // invalid
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr."); 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 // Check that we have the spending key
@ -3579,7 +3600,7 @@ UniValue z_sendmany(const UniValue& params, bool fHelp)
bool isZaddr = false; bool isZaddr = false;
CTxDestination taddr = DecodeDestination(address); CTxDestination taddr = DecodeDestination(address);
if (!IsValidDestination(taddr)) { if (!IsValidDestination(taddr)) {
if (DecodePaymentAddress(address)) { if (IsValidPaymentAddressString(address)) {
isZaddr = true; isZaddr = true;
} else { } else {
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ")+address ); 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 // Validate the destination address
auto destaddress = params[1].get_str(); auto destaddress = params[1].get_str();
if (!DecodePaymentAddress(destaddress)) { if (!IsValidPaymentAddressString(destaddress)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ") + 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 { } else {
auto zaddr = DecodePaymentAddress(address); auto zaddr = DecodePaymentAddress(address);
if (zaddr) { if (IsValidPaymentAddress(zaddr)) {
// Ignore listed z-addrs if we are using all of them // Ignore listed z-addrs if we are using all of them
if (!(useAny || useAnyNote)) { if (!(useAny || useAnyNote)) {
zaddrs.insert(*zaddr); zaddrs.insert(zaddr);
} }
} else { } else {
throw JSONRPCError( throw JSONRPCError(
@ -4038,7 +4059,7 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
bool isToZaddr = false; bool isToZaddr = false;
CTxDestination taddr = DecodeDestination(destaddress); CTxDestination taddr = DecodeDestination(destaddress);
if (!IsValidDestination(taddr)) { if (!IsValidDestination(taddr)) {
if (DecodePaymentAddress(destaddress)) { if (IsValidPaymentAddressString(destaddress)) {
isToZaddr = true; isToZaddr = true;
} else { } else {
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ") + destaddress ); 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; maxedOutNotesFlag = true;
} else { } else {
estimatedTxSize += increase; estimatedTxSize += increase;
SpendingKey zkey; // TODO: Add Sapling support
pwalletMain->GetSpendingKey(entry.address, zkey); auto zaddr = boost::get<SproutPaymentAddress>(entry.address);
noteInputs.emplace_back(entry.jsop, entry.plaintext.note(entry.address), nValue, zkey); SproutSpendingKey zkey;
pwalletMain->GetSpendingKey(zaddr, zkey);
noteInputs.emplace_back(entry.jsop, entry.plaintext.note(zaddr), nValue, zkey);
mergedNoteValue += nValue; mergedNoteValue += nValue;
} }
} }

30
src/wallet/wallet.cpp

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

30
src/wallet/wallet.h

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

18
src/wallet/walletdb.cpp

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

8
src/wallet/walletdb.h

@ -133,14 +133,14 @@ public:
static bool Recover(CDBEnv& dbenv, const std::string& filename); 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. /// 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 WriteZKey(const libzcash::SproutPaymentAddress& addr, const libzcash::SproutSpendingKey& key, const CKeyMetadata &keyMeta);
bool WriteCryptedZKey(const libzcash::PaymentAddress & addr, bool WriteCryptedZKey(const libzcash::SproutPaymentAddress & addr,
const libzcash::ReceivingKey & rk, const libzcash::ReceivingKey & rk,
const std::vector<unsigned char>& vchCryptedSecret, const std::vector<unsigned char>& vchCryptedSecret,
const CKeyMetadata &keyMeta); const CKeyMetadata &keyMeta);
bool WriteViewingKey(const libzcash::ViewingKey &vk); bool WriteViewingKey(const libzcash::SproutViewingKey &vk);
bool EraseViewingKey(const libzcash::ViewingKey &vk); bool EraseViewingKey(const libzcash::SproutViewingKey &vk);
private: private:
CWalletDB(const CWalletDB&); CWalletDB(const CWalletDB&);

31
src/zcash/Address.cpp

@ -6,7 +6,7 @@
namespace libzcash { namespace libzcash {
uint256 PaymentAddress::GetHash() const { uint256 SproutPaymentAddress::GetHash() const {
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << *this; ss << *this;
return Hash(ss.begin(), ss.end()); return Hash(ss.begin(), ss.end());
@ -16,24 +16,37 @@ uint256 ReceivingKey::pk_enc() const {
return ZCNoteEncryption::generate_pubkey(*this); return ZCNoteEncryption::generate_pubkey(*this);
} }
PaymentAddress ViewingKey::address() const { SproutPaymentAddress SproutViewingKey::address() const {
return PaymentAddress(a_pk, sk_enc.pk_enc()); return SproutPaymentAddress(a_pk, sk_enc.pk_enc());
} }
ReceivingKey SpendingKey::receiving_key() const { ReceivingKey SproutSpendingKey::receiving_key() const {
return ReceivingKey(ZCNoteEncryption::generate_privkey(*this)); return ReceivingKey(ZCNoteEncryption::generate_privkey(*this));
} }
ViewingKey SpendingKey::viewing_key() const { SproutViewingKey SproutSpendingKey::viewing_key() const {
return ViewingKey(PRF_addr_a_pk(*this), receiving_key()); return SproutViewingKey(PRF_addr_a_pk(*this), receiving_key());
} }
SpendingKey SpendingKey::random() { SproutSpendingKey SproutSpendingKey::random() {
return SpendingKey(random_uint252()); return SproutSpendingKey(random_uint252());
} }
PaymentAddress SpendingKey::address() const { SproutPaymentAddress SproutSpendingKey::address() const {
return viewing_key().address(); 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 "uint252.h"
#include "serialize.h" #include "serialize.h"
#include <boost/variant.hpp>
namespace libzcash { 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 SerializedPaymentAddressSize = 64;
const size_t SerializedViewingKeySize = 64; const size_t SerializedViewingKeySize = 64;
const size_t SerializedSpendingKeySize = 32; const size_t SerializedSpendingKeySize = 32;
class PaymentAddress { class SproutPaymentAddress {
public: public:
uint256 a_pk; uint256 a_pk;
uint256 pk_enc; uint256 pk_enc;
PaymentAddress() : a_pk(), pk_enc() { } SproutPaymentAddress() : a_pk(), pk_enc() { }
PaymentAddress(uint256 a_pk, uint256 pk_enc) : a_pk(a_pk), pk_enc(pk_enc) { } SproutPaymentAddress(uint256 a_pk, uint256 pk_enc) : a_pk(a_pk), pk_enc(pk_enc) { }
ADD_SERIALIZE_METHODS; ADD_SERIALIZE_METHODS;
@ -30,10 +37,10 @@ public:
//! Get the 256-bit SHA256d hash of this payment address. //! Get the 256-bit SHA256d hash of this payment address.
uint256 GetHash() const; 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; 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 || return (a.a_pk < b.a_pk ||
(a.a_pk == b.a_pk && a.pk_enc < b.pk_enc)); (a.a_pk == b.a_pk && a.pk_enc < b.pk_enc));
} }
@ -47,13 +54,13 @@ public:
uint256 pk_enc() const; uint256 pk_enc() const;
}; };
class ViewingKey { class SproutViewingKey {
public: public:
uint256 a_pk; uint256 a_pk;
ReceivingKey sk_enc; ReceivingKey sk_enc;
ViewingKey() : a_pk(), sk_enc() { } SproutViewingKey() : a_pk(), sk_enc() { }
ViewingKey(uint256 a_pk, ReceivingKey sk_enc) : a_pk(a_pk), sk_enc(sk_enc) { } SproutViewingKey(uint256 a_pk, ReceivingKey sk_enc) : a_pk(a_pk), sk_enc(sk_enc) { }
ADD_SERIALIZE_METHODS; ADD_SERIALIZE_METHODS;
@ -63,29 +70,42 @@ public:
READWRITE(sk_enc); 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; 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 || return (a.a_pk < b.a_pk ||
(a.a_pk == b.a_pk && a.sk_enc < b.sk_enc)); (a.a_pk == b.a_pk && a.sk_enc < b.sk_enc));
} }
}; };
class SpendingKey : public uint252 { class SproutSpendingKey : public uint252 {
public: public:
SpendingKey() : uint252() { } SproutSpendingKey() : uint252() { }
SpendingKey(uint252 a_sk) : uint252(a_sk) { } SproutSpendingKey(uint252 a_sk) : uint252(a_sk) { }
static SpendingKey random(); static SproutSpendingKey random();
ReceivingKey receiving_key() const; ReceivingKey receiving_key() const;
ViewingKey viewing_key() const; SproutViewingKey viewing_key() const;
PaymentAddress address() 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_ #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) { JSOutput::JSOutput() : addr(uint256(), uint256()), value(0) {
SpendingKey a_sk = SpendingKey::random(); SproutSpendingKey a_sk = SproutSpendingKey::random();
addr = a_sk.address(); addr = a_sk.address();
} }
JSInput::JSInput() : witness(ZCIncrementalMerkleTree().witness()), JSInput::JSInput() : witness(ZCIncrementalMerkleTree().witness()),
key(SpendingKey::random()) { key(SproutSpendingKey::random()) {
note = SproutNote(key.address().a_pk, 0, random_uint256(), random_uint256()); note = SproutNote(key.address().a_pk, 0, random_uint256(), random_uint256());
ZCIncrementalMerkleTree dummy_tree; ZCIncrementalMerkleTree dummy_tree;
dummy_tree.append(note.cm()); dummy_tree.append(note.cm());

8
src/zcash/JoinSplit.hpp

@ -19,12 +19,12 @@ class JSInput {
public: public:
ZCIncrementalWitness witness; ZCIncrementalWitness witness;
SproutNote note; SproutNote note;
SpendingKey key; SproutSpendingKey key;
JSInput(); JSInput();
JSInput(ZCIncrementalWitness witness, JSInput(ZCIncrementalWitness witness,
SproutNote note, SproutNote note,
SpendingKey key) : witness(witness), note(note), key(key) { } SproutSpendingKey key) : witness(witness), note(note), key(key) { }
uint256 nullifier() const { uint256 nullifier() const {
return note.nullifier(key); return note.nullifier(key);
@ -33,12 +33,12 @@ public:
class JSOutput { class JSOutput {
public: public:
PaymentAddress addr; SproutPaymentAddress addr;
uint64_t value; uint64_t value;
boost::array<unsigned char, ZC_MEMO_SIZE> memo = {{0xF6}}; // 0xF6 is invalid UTF8 as per spec, rest of array is 0x00 boost::array<unsigned char, ZC_MEMO_SIZE> memo = {{0xF6}}; // 0xF6 is invalid UTF8 as per spec, rest of array is 0x00
JSOutput(); 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; 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; return result;
} }
uint256 SproutNote::nullifier(const SpendingKey& a_sk) const { uint256 SproutNote::nullifier(const SproutSpendingKey& a_sk) const {
return PRF_nf(a_sk, rho); return PRF_nf(a_sk, rho);
} }
@ -46,7 +46,7 @@ SproutNotePlaintext::SproutNotePlaintext(
r = note.r; 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); return SproutNote(addr.a_pk, value_, rho, r);
} }

4
src/zcash/Note.hpp

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

2
src/zcash/circuit/note.tcc

@ -118,7 +118,7 @@ public:
void generate_r1cs_witness( void generate_r1cs_witness(
const MerklePath& path, const MerklePath& path,
const SpendingKey& key, const SproutSpendingKey& key,
const SproutNote& note const SproutNote& note
) { ) {
note_gadget<FieldT>::generate_r1cs_witness(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; CWallet wallet;
for (int i = 0; i < nAddrs; i++) { for (int i = 0; i < nAddrs; i++) {
auto sk = libzcash::SpendingKey::random(); auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSpendingKey(sk); wallet.AddSpendingKey(sk);
} }
auto sk = libzcash::SpendingKey::random(); auto sk = libzcash::SproutSpendingKey::random();
auto tx = GetValidReceive(*pzcashParams, sk, 10, true); auto tx = GetValidReceive(*pzcashParams, sk, 10, true);
struct timeval tv_start; struct timeval tv_start;
@ -299,7 +299,7 @@ double benchmark_increment_note_witnesses(size_t nTxs)
CWallet wallet; CWallet wallet;
ZCIncrementalMerkleTree tree; ZCIncrementalMerkleTree tree;
auto sk = libzcash::SpendingKey::random(); auto sk = libzcash::SproutSpendingKey::random();
wallet.AddSpendingKey(sk); wallet.AddSpendingKey(sk);
// First block // First block

Loading…
Cancel
Save