Move Sprout and Sapling address logic into separate files

This commit is contained in:
Jack Grigg 2020-02-18 15:28:04 +00:00
parent 4964328210
commit 42b423c3a5
7 changed files with 371 additions and 314 deletions

View File

@ -92,6 +92,8 @@ LIBZCASH_H = \
zcash/IncrementalMerkleTree.hpp \
zcash/NoteEncryption.hpp \
zcash/Address.hpp \
zcash/address/sapling.hpp \
zcash/address/sprout.hpp \
zcash/JoinSplit.hpp \
zcash/Note.hpp \
zcash/prf.h \
@ -512,6 +514,8 @@ libzcash_a_SOURCES = \
zcash/IncrementalMerkleTree.cpp \
zcash/NoteEncryption.cpp \
zcash/Address.cpp \
zcash/address/sapling.cpp \
zcash/address/sprout.cpp \
zcash/JoinSplit.cpp \
zcash/Proof.cpp \
zcash/Note.cpp \

View File

@ -1,115 +1,8 @@
#include "Address.hpp"
#include "NoteEncryption.hpp"
#include "hash.h"
#include "prf.h"
#include "streams.h"
#include "zcash/zip32.h"
#include <librustzcash.h>
const unsigned char ZCASH_SAPLING_FVFP_PERSONALIZATION[crypto_generichash_blake2b_PERSONALBYTES] =
{'Z', 'c', 'a', 's', 'h', 'S', 'a', 'p', 'l', 'i', 'n', 'g', 'F', 'V', 'F', 'P'};
namespace libzcash {
uint256 SproutPaymentAddress::GetHash() const {
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << *this;
return Hash(ss.begin(), ss.end());
}
uint256 ReceivingKey::pk_enc() const {
return ZCNoteEncryption::generate_pubkey(*this);
}
SproutPaymentAddress SproutViewingKey::address() const {
return SproutPaymentAddress(a_pk, sk_enc.pk_enc());
}
ReceivingKey SproutSpendingKey::receiving_key() const {
return ReceivingKey(ZCNoteEncryption::generate_privkey(*this));
}
SproutViewingKey SproutSpendingKey::viewing_key() const {
return SproutViewingKey(PRF_addr_a_pk(*this), receiving_key());
}
SproutSpendingKey SproutSpendingKey::random() {
return SproutSpendingKey(random_uint252());
}
SproutPaymentAddress SproutSpendingKey::address() const {
return viewing_key().address();
}
//! Sapling
uint256 SaplingPaymentAddress::GetHash() const {
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << *this;
return Hash(ss.begin(), ss.end());
}
SaplingFullViewingKey SaplingExpandedSpendingKey::full_viewing_key() const {
uint256 ak;
uint256 nk;
librustzcash_ask_to_ak(ask.begin(), ak.begin());
librustzcash_nsk_to_nk(nsk.begin(), nk.begin());
return SaplingFullViewingKey(ak, nk, ovk);
}
SaplingExpandedSpendingKey SaplingSpendingKey::expanded_spending_key() const {
return SaplingExpandedSpendingKey(PRF_ask(*this), PRF_nsk(*this), PRF_ovk(*this));
}
SaplingFullViewingKey SaplingSpendingKey::full_viewing_key() const {
return expanded_spending_key().full_viewing_key();
}
SaplingIncomingViewingKey SaplingFullViewingKey::in_viewing_key() const {
uint256 ivk;
librustzcash_crh_ivk(ak.begin(), nk.begin(), ivk.begin());
return SaplingIncomingViewingKey(ivk);
}
bool SaplingFullViewingKey::is_valid() const {
uint256 ivk;
librustzcash_crh_ivk(ak.begin(), nk.begin(), ivk.begin());
return !ivk.IsNull();
}
uint256 SaplingFullViewingKey::GetFingerprint() const {
CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_SAPLING_FVFP_PERSONALIZATION);
ss << *this;
return ss.GetHash();
}
SaplingSpendingKey SaplingSpendingKey::random() {
while (true) {
auto sk = SaplingSpendingKey(random_uint256());
if (sk.full_viewing_key().is_valid()) {
return sk;
}
}
}
boost::optional<SaplingPaymentAddress> SaplingIncomingViewingKey::address(diversifier_t d) const {
uint256 pk_d;
if (librustzcash_check_diversifier(d.data())) {
librustzcash_ivk_to_pkd(this->begin(), d.data(), pk_d.begin());
return SaplingPaymentAddress(d, pk_d);
} else {
return boost::none;
}
}
SaplingPaymentAddress SaplingSpendingKey::default_address() const {
// Iterates within default_diversifier to ensure a valid address is returned
auto addrOpt = full_viewing_key().in_viewing_key().address(default_diversifier(*this));
assert(addrOpt != boost::none);
return addrOpt.value();
}
std::pair<std::string, PaymentAddress> AddressInfoFromSpendingKey::operator()(const SproutSpendingKey &sk) const {
return std::make_pair("sprout", sk.address());
}

View File

@ -1,10 +1,8 @@
#ifndef ZC_ADDRESS_H_
#define ZC_ADDRESS_H_
#include "uint256.h"
#include "uint252.h"
#include "serialize.h"
#include "Zcash.h"
#include "zcash/address/sapling.hpp"
#include "zcash/address/sprout.hpp"
#include <boost/variant.hpp>
@ -15,209 +13,6 @@ public:
friend bool operator<(const InvalidEncoding &a, const InvalidEncoding &b) { return true; }
};
const size_t SerializedSproutPaymentAddressSize = 64;
const size_t SerializedSproutViewingKeySize = 64;
const size_t SerializedSproutSpendingKeySize = 32;
const size_t SerializedSaplingPaymentAddressSize = 43;
const size_t SerializedSaplingFullViewingKeySize = 96;
const size_t SerializedSaplingExpandedSpendingKeySize = 96;
const size_t SerializedSaplingSpendingKeySize = 32;
typedef std::array<unsigned char, ZC_DIVERSIFIER_SIZE> diversifier_t;
class SproutPaymentAddress {
public:
uint256 a_pk;
uint256 pk_enc;
SproutPaymentAddress() : a_pk(), pk_enc() { }
SproutPaymentAddress(uint256 a_pk, uint256 pk_enc) : a_pk(a_pk), pk_enc(pk_enc) { }
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(a_pk);
READWRITE(pk_enc);
}
//! Get the 256-bit SHA256d hash of this payment address.
uint256 GetHash() const;
friend inline bool operator==(const SproutPaymentAddress& a, const SproutPaymentAddress& b) {
return a.a_pk == b.a_pk && a.pk_enc == b.pk_enc;
}
friend inline bool operator<(const SproutPaymentAddress& a, const SproutPaymentAddress& b) {
return (a.a_pk < b.a_pk ||
(a.a_pk == b.a_pk && a.pk_enc < b.pk_enc));
}
};
class ReceivingKey : public uint256 {
public:
ReceivingKey() { }
ReceivingKey(uint256 sk_enc) : uint256(sk_enc) { }
uint256 pk_enc() const;
};
class SproutViewingKey {
public:
uint256 a_pk;
ReceivingKey sk_enc;
SproutViewingKey() : a_pk(), sk_enc() { }
SproutViewingKey(uint256 a_pk, ReceivingKey sk_enc) : a_pk(a_pk), sk_enc(sk_enc) { }
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(a_pk);
READWRITE(sk_enc);
}
SproutPaymentAddress address() const;
friend inline bool operator==(const SproutViewingKey& a, const SproutViewingKey& b) {
return a.a_pk == b.a_pk && a.sk_enc == b.sk_enc;
}
friend inline bool operator<(const SproutViewingKey& a, const SproutViewingKey& b) {
return (a.a_pk < b.a_pk ||
(a.a_pk == b.a_pk && a.sk_enc < b.sk_enc));
}
};
class SproutSpendingKey : public uint252 {
public:
SproutSpendingKey() : uint252() { }
SproutSpendingKey(uint252 a_sk) : uint252(a_sk) { }
static SproutSpendingKey random();
ReceivingKey receiving_key() const;
SproutViewingKey viewing_key() const;
SproutPaymentAddress address() const;
};
//! Sapling functions.
class SaplingPaymentAddress {
public:
diversifier_t d;
uint256 pk_d;
SaplingPaymentAddress() : d(), pk_d() { }
SaplingPaymentAddress(diversifier_t d, uint256 pk_d) : d(d), pk_d(pk_d) { }
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(d);
READWRITE(pk_d);
}
//! Get the 256-bit SHA256d hash of this payment address.
uint256 GetHash() const;
friend inline bool operator==(const SaplingPaymentAddress& a, const SaplingPaymentAddress& b) {
return a.d == b.d && a.pk_d == b.pk_d;
}
friend inline bool operator<(const SaplingPaymentAddress& a, const SaplingPaymentAddress& b) {
return (a.d < b.d ||
(a.d == b.d && a.pk_d < b.pk_d));
}
};
class SaplingIncomingViewingKey : public uint256 {
public:
SaplingIncomingViewingKey() : uint256() { }
SaplingIncomingViewingKey(uint256 ivk) : uint256(ivk) { }
// Can pass in diversifier for Sapling addr
boost::optional<SaplingPaymentAddress> address(diversifier_t d) const;
};
class SaplingFullViewingKey {
public:
uint256 ak;
uint256 nk;
uint256 ovk;
SaplingFullViewingKey() : ak(), nk(), ovk() { }
SaplingFullViewingKey(uint256 ak, uint256 nk, uint256 ovk) : ak(ak), nk(nk), ovk(ovk) { }
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(ak);
READWRITE(nk);
READWRITE(ovk);
}
//! Get the fingerprint of this full viewing key (as defined in ZIP 32).
uint256 GetFingerprint() const;
SaplingIncomingViewingKey in_viewing_key() const;
bool is_valid() const;
friend inline bool operator==(const SaplingFullViewingKey& a, const SaplingFullViewingKey& b) {
return a.ak == b.ak && a.nk == b.nk && a.ovk == b.ovk;
}
friend inline bool operator<(const SaplingFullViewingKey& a, const SaplingFullViewingKey& b) {
return (a.ak < b.ak ||
(a.ak == b.ak && a.nk < b.nk) ||
(a.ak == b.ak && a.nk == b.nk && a.ovk < b.ovk));
}
};
class SaplingExpandedSpendingKey {
public:
uint256 ask;
uint256 nsk;
uint256 ovk;
SaplingExpandedSpendingKey() : ask(), nsk(), ovk() { }
SaplingExpandedSpendingKey(uint256 ask, uint256 nsk, uint256 ovk) : ask(ask), nsk(nsk), ovk(ovk) { }
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(ask);
READWRITE(nsk);
READWRITE(ovk);
}
SaplingFullViewingKey full_viewing_key() const;
friend inline bool operator==(const SaplingExpandedSpendingKey& a, const SaplingExpandedSpendingKey& b) {
return a.ask == b.ask && a.nsk == b.nsk && a.ovk == b.ovk;
}
friend inline bool operator<(const SaplingExpandedSpendingKey& a, const SaplingExpandedSpendingKey& b) {
return (a.ask < b.ask ||
(a.ask == b.ask && a.nsk < b.nsk) ||
(a.ask == b.ask && a.nsk == b.nsk && a.ovk < b.ovk));
}
};
class SaplingSpendingKey : public uint256 {
public:
SaplingSpendingKey() : uint256() { }
SaplingSpendingKey(uint256 sk) : uint256(sk) { }
static SaplingSpendingKey random();
SaplingExpandedSpendingKey expanded_spending_key() const;
SaplingFullViewingKey full_viewing_key() const;
// Can derive Sapling addr from default diversifier
SaplingPaymentAddress default_address() const;
};
typedef boost::variant<InvalidEncoding, SproutPaymentAddress, SaplingPaymentAddress> PaymentAddress;
typedef boost::variant<InvalidEncoding, SproutViewingKey> ViewingKey;

View File

@ -0,0 +1,86 @@
// Copyright (c) 2016-2020 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
#include "zcash/address/sapling.hpp"
#include "hash.h"
#include "streams.h"
#include "zcash/NoteEncryption.hpp"
#include "zcash/prf.h"
#include <librustzcash.h>
namespace libzcash {
const unsigned char ZCASH_SAPLING_FVFP_PERSONALIZATION[crypto_generichash_blake2b_PERSONALBYTES] =
{'Z', 'c', 'a', 's', 'h', 'S', 'a', 'p', 'l', 'i', 'n', 'g', 'F', 'V', 'F', 'P'};
//! Sapling
uint256 SaplingPaymentAddress::GetHash() const {
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << *this;
return Hash(ss.begin(), ss.end());
}
boost::optional<SaplingPaymentAddress> SaplingIncomingViewingKey::address(diversifier_t d) const {
uint256 pk_d;
if (librustzcash_check_diversifier(d.data())) {
librustzcash_ivk_to_pkd(this->begin(), d.data(), pk_d.begin());
return SaplingPaymentAddress(d, pk_d);
} else {
return boost::none;
}
}
uint256 SaplingFullViewingKey::GetFingerprint() const {
CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_SAPLING_FVFP_PERSONALIZATION);
ss << *this;
return ss.GetHash();
}
SaplingIncomingViewingKey SaplingFullViewingKey::in_viewing_key() const {
uint256 ivk;
librustzcash_crh_ivk(ak.begin(), nk.begin(), ivk.begin());
return SaplingIncomingViewingKey(ivk);
}
bool SaplingFullViewingKey::is_valid() const {
uint256 ivk;
librustzcash_crh_ivk(ak.begin(), nk.begin(), ivk.begin());
return !ivk.IsNull();
}
SaplingFullViewingKey SaplingExpandedSpendingKey::full_viewing_key() const {
uint256 ak;
uint256 nk;
librustzcash_ask_to_ak(ask.begin(), ak.begin());
librustzcash_nsk_to_nk(nsk.begin(), nk.begin());
return SaplingFullViewingKey(ak, nk, ovk);
}
SaplingSpendingKey SaplingSpendingKey::random() {
while (true) {
auto sk = SaplingSpendingKey(random_uint256());
if (sk.full_viewing_key().is_valid()) {
return sk;
}
}
}
SaplingExpandedSpendingKey SaplingSpendingKey::expanded_spending_key() const {
return SaplingExpandedSpendingKey(PRF_ask(*this), PRF_nsk(*this), PRF_ovk(*this));
}
SaplingFullViewingKey SaplingSpendingKey::full_viewing_key() const {
return expanded_spending_key().full_viewing_key();
}
SaplingPaymentAddress SaplingSpendingKey::default_address() const {
// Iterates within default_diversifier to ensure a valid address is returned
auto addrOpt = full_viewing_key().in_viewing_key().address(default_diversifier(*this));
assert(addrOpt != boost::none);
return addrOpt.value();
}
}

View File

@ -0,0 +1,140 @@
// Copyright (c) 2016-2020 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
#ifndef ZC_ADDRESS_SAPLING_H_
#define ZC_ADDRESS_SAPLING_H_
#include "serialize.h"
#include "uint256.h"
#include "zcash/Zcash.h"
namespace libzcash {
const size_t SerializedSaplingPaymentAddressSize = 43;
const size_t SerializedSaplingFullViewingKeySize = 96;
const size_t SerializedSaplingExpandedSpendingKeySize = 96;
const size_t SerializedSaplingSpendingKeySize = 32;
typedef std::array<unsigned char, ZC_DIVERSIFIER_SIZE> diversifier_t;
//! Sapling functions.
class SaplingPaymentAddress {
public:
diversifier_t d;
uint256 pk_d;
SaplingPaymentAddress() : d(), pk_d() { }
SaplingPaymentAddress(diversifier_t d, uint256 pk_d) : d(d), pk_d(pk_d) { }
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(d);
READWRITE(pk_d);
}
//! Get the 256-bit SHA256d hash of this payment address.
uint256 GetHash() const;
friend inline bool operator==(const SaplingPaymentAddress& a, const SaplingPaymentAddress& b) {
return a.d == b.d && a.pk_d == b.pk_d;
}
friend inline bool operator<(const SaplingPaymentAddress& a, const SaplingPaymentAddress& b) {
return (a.d < b.d ||
(a.d == b.d && a.pk_d < b.pk_d));
}
};
class SaplingIncomingViewingKey : public uint256 {
public:
SaplingIncomingViewingKey() : uint256() { }
SaplingIncomingViewingKey(uint256 ivk) : uint256(ivk) { }
// Can pass in diversifier for Sapling addr
boost::optional<SaplingPaymentAddress> address(diversifier_t d) const;
};
class SaplingFullViewingKey {
public:
uint256 ak;
uint256 nk;
uint256 ovk;
SaplingFullViewingKey() : ak(), nk(), ovk() { }
SaplingFullViewingKey(uint256 ak, uint256 nk, uint256 ovk) : ak(ak), nk(nk), ovk(ovk) { }
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(ak);
READWRITE(nk);
READWRITE(ovk);
}
//! Get the fingerprint of this full viewing key (as defined in ZIP 32).
uint256 GetFingerprint() const;
SaplingIncomingViewingKey in_viewing_key() const;
bool is_valid() const;
friend inline bool operator==(const SaplingFullViewingKey& a, const SaplingFullViewingKey& b) {
return a.ak == b.ak && a.nk == b.nk && a.ovk == b.ovk;
}
friend inline bool operator<(const SaplingFullViewingKey& a, const SaplingFullViewingKey& b) {
return (a.ak < b.ak ||
(a.ak == b.ak && a.nk < b.nk) ||
(a.ak == b.ak && a.nk == b.nk && a.ovk < b.ovk));
}
};
class SaplingExpandedSpendingKey {
public:
uint256 ask;
uint256 nsk;
uint256 ovk;
SaplingExpandedSpendingKey() : ask(), nsk(), ovk() { }
SaplingExpandedSpendingKey(uint256 ask, uint256 nsk, uint256 ovk) : ask(ask), nsk(nsk), ovk(ovk) { }
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(ask);
READWRITE(nsk);
READWRITE(ovk);
}
SaplingFullViewingKey full_viewing_key() const;
friend inline bool operator==(const SaplingExpandedSpendingKey& a, const SaplingExpandedSpendingKey& b) {
return a.ask == b.ask && a.nsk == b.nsk && a.ovk == b.ovk;
}
friend inline bool operator<(const SaplingExpandedSpendingKey& a, const SaplingExpandedSpendingKey& b) {
return (a.ask < b.ask ||
(a.ask == b.ask && a.nsk < b.nsk) ||
(a.ask == b.ask && a.nsk == b.nsk && a.ovk < b.ovk));
}
};
class SaplingSpendingKey : public uint256 {
public:
SaplingSpendingKey() : uint256() { }
SaplingSpendingKey(uint256 sk) : uint256(sk) { }
static SaplingSpendingKey random();
SaplingExpandedSpendingKey expanded_spending_key() const;
SaplingFullViewingKey full_viewing_key() const;
// Can derive Sapling addr from default diversifier
SaplingPaymentAddress default_address() const;
};
} // namespace libzcash
#endif // ZC_ADDRESS_SAPLING_H_

View File

@ -0,0 +1,44 @@
// Copyright (c) 2016-2020 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
#include "zcash/address/sprout.hpp"
#include "hash.h"
#include "streams.h"
#include "zcash/NoteEncryption.hpp"
#include "zcash/prf.h"
namespace libzcash {
uint256 SproutPaymentAddress::GetHash() const {
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << *this;
return Hash(ss.begin(), ss.end());
}
uint256 ReceivingKey::pk_enc() const {
return ZCNoteEncryption::generate_pubkey(*this);
}
SproutPaymentAddress SproutViewingKey::address() const {
return SproutPaymentAddress(a_pk, sk_enc.pk_enc());
}
ReceivingKey SproutSpendingKey::receiving_key() const {
return ReceivingKey(ZCNoteEncryption::generate_privkey(*this));
}
SproutViewingKey SproutSpendingKey::viewing_key() const {
return SproutViewingKey(PRF_addr_a_pk(*this), receiving_key());
}
SproutSpendingKey SproutSpendingKey::random() {
return SproutSpendingKey(random_uint252());
}
SproutPaymentAddress SproutSpendingKey::address() const {
return viewing_key().address();
}
} // namespace libzcash

View File

@ -0,0 +1,95 @@
// Copyright (c) 2016-2020 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
#ifndef ZC_ADDRESS_SPROUT_H_
#define ZC_ADDRESS_SPROUT_H_
#include "serialize.h"
#include "uint252.h"
#include "uint256.h"
namespace libzcash {
const size_t SerializedSproutPaymentAddressSize = 64;
const size_t SerializedSproutViewingKeySize = 64;
const size_t SerializedSproutSpendingKeySize = 32;
class SproutPaymentAddress {
public:
uint256 a_pk;
uint256 pk_enc;
SproutPaymentAddress() : a_pk(), pk_enc() { }
SproutPaymentAddress(uint256 a_pk, uint256 pk_enc) : a_pk(a_pk), pk_enc(pk_enc) { }
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(a_pk);
READWRITE(pk_enc);
}
//! Get the 256-bit SHA256d hash of this payment address.
uint256 GetHash() const;
friend inline bool operator==(const SproutPaymentAddress& a, const SproutPaymentAddress& b) {
return a.a_pk == b.a_pk && a.pk_enc == b.pk_enc;
}
friend inline bool operator<(const SproutPaymentAddress& a, const SproutPaymentAddress& b) {
return (a.a_pk < b.a_pk ||
(a.a_pk == b.a_pk && a.pk_enc < b.pk_enc));
}
};
class ReceivingKey : public uint256 {
public:
ReceivingKey() { }
ReceivingKey(uint256 sk_enc) : uint256(sk_enc) { }
uint256 pk_enc() const;
};
class SproutViewingKey {
public:
uint256 a_pk;
ReceivingKey sk_enc;
SproutViewingKey() : a_pk(), sk_enc() { }
SproutViewingKey(uint256 a_pk, ReceivingKey sk_enc) : a_pk(a_pk), sk_enc(sk_enc) { }
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(a_pk);
READWRITE(sk_enc);
}
SproutPaymentAddress address() const;
friend inline bool operator==(const SproutViewingKey& a, const SproutViewingKey& b) {
return a.a_pk == b.a_pk && a.sk_enc == b.sk_enc;
}
friend inline bool operator<(const SproutViewingKey& a, const SproutViewingKey& b) {
return (a.a_pk < b.a_pk ||
(a.a_pk == b.a_pk && a.sk_enc < b.sk_enc));
}
};
class SproutSpendingKey : public uint252 {
public:
SproutSpendingKey() : uint252() { }
SproutSpendingKey(uint252 a_sk) : uint252(a_sk) { }
static SproutSpendingKey random();
ReceivingKey receiving_key() const;
SproutViewingKey viewing_key() const;
SproutPaymentAddress address() const;
};
} // namespace libzcash
#endif // ZC_ADDRESS_SPROUT_H_