#ifndef ZC_ADDRESS_H_ #define ZC_ADDRESS_H_ #include "consensus/params.h" #include "key_constants.h" #include "pubkey.h" #include "key_constants.h" #include "script/script.h" #include "uint256.h" #include "pubkey.h" #include "script/script.h" #include "util/match.h" #include "zcash/address/orchard.hpp" #include "zcash/address/sapling.hpp" #include "zcash/address/sprout.hpp" #include "zcash/address/unified.h" #include "zcash/address/zip32.h" #include #include #include const unsigned char ZCASH_UFVK_ID_PERSONAL[blake2b::PERSONALBYTES] = {'Z', 'c', 'a', 's', 'h', '_', 'U', 'F', 'V', 'K', '_', 'I', 'd', '_', 'F', 'P'}; namespace libzcash { bool HasKnownReceiverType(const Receiver& receiver); struct ReceiverIterator { using iterator_category = std::random_access_iterator_tag; using difference_type = std::ptrdiff_t; using value_type = const Receiver; using pointer = const Receiver*; using reference = const Receiver&; ReceiverIterator(std::vector sorted, size_t cur) : sortedReceivers(sorted), cur(cur) {} reference operator*() const { return *sortedReceivers[cur]; } pointer operator->() { return sortedReceivers[cur]; } ReceiverIterator& operator++() { cur++; return *this; } ReceiverIterator operator++(int) { ReceiverIterator tmp = *this; ++(*this); return tmp; } friend bool operator==(const ReceiverIterator& a, const ReceiverIterator& b) { return a.sortedReceivers == b.sortedReceivers && a.cur == b.cur; } friend bool operator!=(const ReceiverIterator& a, const ReceiverIterator& b) { return !(a == b); } private: std::vector sortedReceivers; size_t cur; }; class UnifiedAddress { std::vector receivers; std::vector GetSorted() const; public: UnifiedAddress() {} static UnifiedAddress ForSingleReceiver(Receiver receiver) { UnifiedAddress ua; ua.AddReceiver(receiver); return ua; } static std::optional Parse(const KeyConstants& keyConstants, const std::string& str); ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(receivers); } /** * Adds the given receiver to this unified address. * * Receivers are stored in the unified address (and its encoding) in the order they * are added. When generating a new UA, call this method in preference order. * * Returns false if adding this receiver would result in an invalid unified address: * - The UA already contains this receiver type. * - The UA would contain both P2PKH and P2SH receivers. */ bool AddReceiver(Receiver receiver); bool ContainsReceiver(const Receiver& receiver) const; const std::vector& GetReceiversAsParsed() const { return receivers; } std::set GetKnownReceiverTypes() const { std::set result; for (const auto& receiver : receivers) { examine(receiver, match { [&](const libzcash::OrchardRawAddress &zaddr) { result.insert(ReceiverType::Orchard); }, [&](const libzcash::SaplingPaymentAddress &zaddr) { result.insert(ReceiverType::Sapling); }, [&](const CScriptID &zaddr) { result.insert(ReceiverType::P2SH); }, [&](const CKeyID &zaddr) { result.insert(ReceiverType::P2PKH); }, [&](const libzcash::UnknownReceiver &uaddr) { } }); } return result; } ReceiverIterator begin() const { return ReceiverIterator(GetSorted(), 0); } ReceiverIterator end() const { return ReceiverIterator(GetSorted(), receivers.size()); } size_t size() const { return receivers.size(); } std::optional GetP2PKHReceiver() const; std::optional GetP2SHReceiver() const; std::optional GetSaplingReceiver() const; std::optional GetOrchardReceiver() const; /** * Return the most-preferred receiver from among the receiver types * that we recognize and can use at the given block height. */ std::optional GetPreferredRecipientAddress( const Consensus::Params& consensus, int height) const; friend inline bool operator==(const UnifiedAddress& a, const UnifiedAddress& b) { return a.receivers == b.receivers; } friend inline bool operator!=(const UnifiedAddress& a, const UnifiedAddress& b) { return a.receivers != b.receivers; } friend inline bool operator<(const UnifiedAddress& a, const UnifiedAddress& b) { return a.receivers < b.receivers; } }; class UnifiedFullViewingKeyBuilder; /** * Wrapper for a zcash_address::unified::Ufvk. */ class UnifiedFullViewingKey { private: std::unique_ptr inner; UnifiedFullViewingKey() : inner(nullptr, unified_full_viewing_key_free) {} UnifiedFullViewingKey(UnifiedFullViewingKeyPtr* ptr) : inner(ptr, unified_full_viewing_key_free) {} friend class UnifiedFullViewingKeyBuilder; public: UnifiedFullViewingKey(UnifiedFullViewingKey&& key) : inner(std::move(key.inner)) {} UnifiedFullViewingKey(const UnifiedFullViewingKey& key) : inner(unified_full_viewing_key_clone(key.inner.get()), unified_full_viewing_key_free) {} /** * This method should only be used for serialization of unified full * viewing keys that have been generated internally from unified spending * keys by Zcashd. It is not suitable for use in any case where the * ZcashdUnifiedFullViewingKey value may have been produced by a * potentially-lossy conversion from a UnifiedFullViewingKey value that * originated outside of zcashd. */ static UnifiedFullViewingKey FromZcashdUFVK(const ZcashdUnifiedFullViewingKey&); static std::optional Decode( const std::string& str, const KeyConstants& keyConstants); std::string Encode(const KeyConstants& keyConstants) const; std::optional GetOrchardKey() const; std::optional GetSaplingKey() const; std::optional GetTransparentKey() const; UFVKId GetKeyID(const KeyConstants& keyConstants) const; std::set GetKnownReceiverTypes() const { std::set result; if (GetTransparentKey().has_value()) { result.insert(ReceiverType::P2PKH); } if (GetSaplingKey().has_value()) { result.insert(ReceiverType::Sapling); } if (GetOrchardKey().has_value()) { result.insert(ReceiverType::Orchard); } return result; } UnifiedFullViewingKey& operator=(UnifiedFullViewingKey&& key) { if (this != &key) { inner = std::move(key.inner); } return *this; } UnifiedFullViewingKey& operator=(const UnifiedFullViewingKey& key) { if (this != &key) { inner.reset(unified_full_viewing_key_clone(key.inner.get())); } return *this; } }; class UnifiedFullViewingKeyBuilder { private: std::optional> t_bytes; std::optional> sapling_bytes; std::optional> orchard_bytes; public: UnifiedFullViewingKeyBuilder(): t_bytes(std::nullopt), sapling_bytes(std::nullopt), orchard_bytes(std::nullopt) {} bool AddTransparentKey(const transparent::AccountPubKey&); bool AddSaplingKey(const SaplingDiversifiableFullViewingKey&); bool AddOrchardKey(const OrchardFullViewingKey&); std::optional build() const; }; /** Addresses that can appear in a string encoding. */ typedef std::variant< CKeyID, CScriptID, SproutPaymentAddress, SaplingPaymentAddress, UnifiedAddress> PaymentAddress; /** Viewing keys that can have a string encoding. */ typedef std::variant< SproutViewingKey, SaplingExtendedFullViewingKey, UnifiedFullViewingKey> ViewingKey; /** Spending keys that can have a string encoding. */ typedef std::variant< SproutSpendingKey, SaplingExtendedSpendingKey> SpendingKey; class HasShieldedRecipient { public: bool operator()(const CKeyID& p2pkh) { return false; } bool operator()(const CScriptID& p2sh) { return false; } bool operator()(const SproutPaymentAddress& addr) { return true; } bool operator()(const SaplingPaymentAddress& addr) { return true; } bool operator()(const UnifiedAddress& addr) { return true; } }; class SelectRecipientAddress { const Consensus::Params& consensus; int height; public: SelectRecipientAddress(const Consensus::Params& consensus, int height) : consensus(consensus), height(height) {} std::optional operator()(const CKeyID& p2pkh) { return p2pkh; } std::optional operator()(const CScriptID& p2sh) { return p2sh; } std::optional operator()(const SproutPaymentAddress& addr) { return std::nullopt; } std::optional operator()(const SaplingPaymentAddress& addr) { return addr; } std::optional operator()(const UnifiedAddress& addr) { return addr.GetPreferredRecipientAddress(consensus, height); } }; class AddressInfoFromSpendingKey { public: std::pair operator()(const SproutSpendingKey&) const; std::pair operator()(const struct SaplingExtendedSpendingKey&) const; }; class AddressInfoFromViewingKey { private: const KeyConstants& keyConstants; public: AddressInfoFromViewingKey(const KeyConstants& keyConstants): keyConstants(keyConstants) {} std::pair operator()(const SproutViewingKey&) const; std::pair operator()(const struct SaplingExtendedFullViewingKey&) const; std::pair operator()(const UnifiedFullViewingKey&) const; }; } //namespace libzcash /** * Gets the typecode for the given UA receiver. */ class TypecodeForReceiver { public: TypecodeForReceiver() {} uint32_t operator()(const libzcash::OrchardRawAddress &zaddr) const; uint32_t operator()(const libzcash::SaplingPaymentAddress &zaddr) const; uint32_t operator()(const CScriptID &p2sh) const; uint32_t operator()(const CKeyID &p2pkh) const; uint32_t operator()(const libzcash::UnknownReceiver &p2pkh) const; }; #endif // ZC_ADDRESS_H_