Merge pull request #5396 from nuttycom/feature/wallet_orchard-unified_addrs_prereq
Prerequisites for adding unified addresses to the wallet.
This commit is contained in:
commit
c908a3b059
|
@ -107,9 +107,12 @@ LIBZCASH_H = \
|
|||
zcash/IncrementalMerkleTree.hpp \
|
||||
zcash/NoteEncryption.hpp \
|
||||
zcash/Address.hpp \
|
||||
zcash/address/bip44.h \
|
||||
zcash/address/mnemonic.h \
|
||||
zcash/address/orchard.h \
|
||||
zcash/address/sapling.hpp \
|
||||
zcash/address/sprout.hpp \
|
||||
zcash/address/orchard.h \
|
||||
zcash/address/unified.h \
|
||||
zcash/address/zip32.h \
|
||||
zcash/History.hpp \
|
||||
zcash/JoinSplit.hpp \
|
||||
|
@ -536,9 +539,12 @@ libzcash_a_SOURCES = \
|
|||
zcash/IncrementalMerkleTree.cpp \
|
||||
zcash/NoteEncryption.cpp \
|
||||
zcash/Address.cpp \
|
||||
zcash/address/bip44.cpp \
|
||||
zcash/address/mnemonic.cpp \
|
||||
zcash/address/orchard.cpp \
|
||||
zcash/address/sapling.cpp \
|
||||
zcash/address/sprout.cpp \
|
||||
zcash/address/orchard.cpp \
|
||||
zcash/address/unified.cpp \
|
||||
zcash/address/zip32.cpp \
|
||||
zcash/History.cpp \
|
||||
zcash/JoinSplit.cpp \
|
||||
|
|
|
@ -78,11 +78,11 @@ namespace libzcash {
|
|||
return tfm::format("Sapling(%s)", HexStr(ss.begin(), ss.end()));
|
||||
}
|
||||
|
||||
std::string operator()(const P2SHAddress &p2sh) const {
|
||||
std::string operator()(const CScriptID &p2sh) const {
|
||||
return tfm::format("P2SH(%s)", p2sh.GetHex());
|
||||
}
|
||||
|
||||
std::string operator()(const P2PKHAddress &p2pkh) const {
|
||||
std::string operator()(const CKeyID &p2pkh) const {
|
||||
return tfm::format("P2PKH(%s)", p2pkh.GetHex());
|
||||
}
|
||||
|
||||
|
@ -140,11 +140,11 @@ TEST(Keys, EncodeAndDecodeUnified)
|
|||
ua.AddReceiver(r);
|
||||
}
|
||||
if (!test[1].isNull()) {
|
||||
libzcash::P2SHAddress r(ParseHex(test[1].get_str()));
|
||||
CScriptID r(ParseHex(test[1].get_str()));
|
||||
ua.AddReceiver(r);
|
||||
}
|
||||
if (!test[0].isNull()) {
|
||||
libzcash::P2PKHAddress r(ParseHex(test[0].get_str()));
|
||||
CKeyID r(ParseHex(test[0].get_str()));
|
||||
ua.AddReceiver(r);
|
||||
}
|
||||
|
||||
|
|
|
@ -56,8 +56,8 @@ public:
|
|||
DataLenForReceiver() {}
|
||||
|
||||
size_t operator()(const libzcash::SaplingPaymentAddress &zaddr) const { return 43; }
|
||||
size_t operator()(const libzcash::P2SHAddress &p2sh) const { return 20; }
|
||||
size_t operator()(const libzcash::P2PKHAddress &p2pkh) const { return 20; }
|
||||
size_t operator()(const CScriptID &p2sh) const { return 20; }
|
||||
size_t operator()(const CKeyID &p2pkh) const { return 20; }
|
||||
size_t operator()(const libzcash::UnknownReceiver &unknown) const { return unknown.data.size(); }
|
||||
};
|
||||
|
||||
|
@ -82,11 +82,11 @@ public:
|
|||
memcpy(data, ss.data(), ss.size());
|
||||
}
|
||||
|
||||
void operator()(const libzcash::P2SHAddress &p2sh) const {
|
||||
void operator()(const CScriptID &p2sh) const {
|
||||
memcpy(data, p2sh.begin(), p2sh.size());
|
||||
}
|
||||
|
||||
void operator()(const libzcash::P2PKHAddress &p2pkh) const {
|
||||
void operator()(const CKeyID &p2pkh) const {
|
||||
memcpy(data, p2pkh.begin(), p2pkh.size());
|
||||
}
|
||||
|
||||
|
@ -421,7 +421,7 @@ static bool AddP2SHReceiver(void* ua, const unsigned char* raw)
|
|||
reinterpret_cast<const char*>(raw + 20),
|
||||
SER_NETWORK,
|
||||
PROTOCOL_VERSION);
|
||||
libzcash::P2SHAddress receiver;
|
||||
CScriptID receiver;
|
||||
ss >> receiver;
|
||||
return reinterpret_cast<libzcash::UnifiedAddress*>(ua)->AddReceiver(receiver);
|
||||
}
|
||||
|
@ -436,7 +436,7 @@ static bool AddP2PKHReceiver(void* ua, const unsigned char* raw)
|
|||
reinterpret_cast<const char*>(raw + 20),
|
||||
SER_NETWORK,
|
||||
PROTOCOL_VERSION);
|
||||
libzcash::P2PKHAddress receiver;
|
||||
CKeyID receiver;
|
||||
ss >> receiver;
|
||||
return reinterpret_cast<libzcash::UnifiedAddress*>(ua)->AddReceiver(receiver);
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "script/script.h"
|
||||
#include "script/standard.h"
|
||||
#include "sync.h"
|
||||
#include "zcash/address/mnemonic.h"
|
||||
#include "zcash/Address.hpp"
|
||||
#include "zcash/NoteEncryption.hpp"
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ class CKeyID : public uint160
|
|||
public:
|
||||
CKeyID() : uint160() {}
|
||||
CKeyID(const uint160& in) : uint160(in) {}
|
||||
explicit CKeyID(const std::vector<unsigned char>& vch) : uint160(vch) {}
|
||||
};
|
||||
|
||||
typedef uint256 ChainCode;
|
||||
|
|
|
@ -625,6 +625,16 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/** A reference to a CScript: the Hash160 of its serialization */
|
||||
class CScriptID : public uint160
|
||||
{
|
||||
public:
|
||||
CScriptID() : uint160() {}
|
||||
explicit CScriptID(const CScript& in);
|
||||
CScriptID(const uint160& in) : uint160(in) {}
|
||||
explicit CScriptID(const std::vector<unsigned char>& vch) : uint160(vch) {}
|
||||
};
|
||||
|
||||
class CReserveScript
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -18,15 +18,6 @@ static const bool DEFAULT_ACCEPT_DATACARRIER = true;
|
|||
class CKeyID;
|
||||
class CScript;
|
||||
|
||||
/** A reference to a CScript: the Hash160 of its serialization (see script.h) */
|
||||
class CScriptID : public uint160
|
||||
{
|
||||
public:
|
||||
CScriptID() : uint160() {}
|
||||
explicit CScriptID(const CScript& in);
|
||||
CScriptID(const uint160& in) : uint160(in) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* Default setting for nMaxDatacarrierBytes. 80 bytes of data, +1 for OP_RETURN,
|
||||
* +2 for the pushdata opcodes.
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "zcash/address/mnemonic.h"
|
||||
#include "zcash/address/orchard.hpp"
|
||||
|
||||
TEST(OrchardZkeysTest, IVKSerializationRoundtrip) {
|
||||
|
|
|
@ -23,6 +23,9 @@
|
|||
#include "wallet/crypter.h"
|
||||
#include "wallet/walletdb.h"
|
||||
#include "wallet/rpcwallet.h"
|
||||
#include "zcash/address/bip44.h"
|
||||
#include "zcash/address/unified.h"
|
||||
#include "zcash/address/mnemonic.h"
|
||||
#include "zcash/Address.hpp"
|
||||
#include "zcash/Note.hpp"
|
||||
#include "base58.h"
|
||||
|
|
|
@ -24,8 +24,8 @@ bool UnifiedAddress::AddReceiver(Receiver receiver) {
|
|||
auto t = std::visit(TypecodeForReceiver(), r);
|
||||
if (
|
||||
(t == typecode) ||
|
||||
(std::holds_alternative<P2PKHAddress>(r) && std::holds_alternative<P2SHAddress>(receiver)) ||
|
||||
(std::holds_alternative<P2SHAddress>(r) && std::holds_alternative<P2PKHAddress>(receiver))
|
||||
(std::holds_alternative<CKeyID>(r) && std::holds_alternative<CScriptID>(receiver)) ||
|
||||
(std::holds_alternative<CScriptID>(r) && std::holds_alternative<CKeyID>(receiver))
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
@ -76,13 +76,13 @@ uint32_t TypecodeForReceiver::operator()(
|
|||
}
|
||||
|
||||
uint32_t TypecodeForReceiver::operator()(
|
||||
const libzcash::P2SHAddress &p2sh) const
|
||||
const CScriptID &p2sh) const
|
||||
{
|
||||
return ZCASH_UA_TYPECODE_P2SH;
|
||||
}
|
||||
|
||||
uint32_t TypecodeForReceiver::operator()(
|
||||
const libzcash::P2PKHAddress &p2sh) const
|
||||
const CKeyID &p2sh) const
|
||||
{
|
||||
return ZCASH_UA_TYPECODE_P2PKH;
|
||||
}
|
||||
|
@ -100,13 +100,13 @@ std::optional<libzcash::RawAddress> ReceiverToRawAddress::operator()(
|
|||
}
|
||||
|
||||
std::optional<libzcash::RawAddress> ReceiverToRawAddress::operator()(
|
||||
const libzcash::P2SHAddress &p2sh) const
|
||||
const CScriptID &p2sh) const
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<libzcash::RawAddress> ReceiverToRawAddress::operator()(
|
||||
const libzcash::P2PKHAddress &p2sh) const
|
||||
const CKeyID &p2sh) const
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
#define ZC_ADDRESS_H_
|
||||
|
||||
#include "uint256.h"
|
||||
#include "pubkey.h"
|
||||
#include "script/script.h"
|
||||
#include "zcash/address/orchard.hpp"
|
||||
#include "zcash/address/sapling.hpp"
|
||||
#include "zcash/address/sprout.hpp"
|
||||
|
@ -10,17 +12,6 @@
|
|||
#include <variant>
|
||||
|
||||
namespace libzcash {
|
||||
// We use new classes here instead of CKeyID and CScriptID to prevent a cyclic dependency.
|
||||
class P2PKHAddress: public uint160 {
|
||||
public:
|
||||
P2PKHAddress() {}
|
||||
explicit P2PKHAddress(const std::vector<unsigned char>& vch) : uint160(vch) {}
|
||||
};
|
||||
class P2SHAddress: public uint160 {
|
||||
public:
|
||||
P2SHAddress() {}
|
||||
explicit P2SHAddress(const std::vector<unsigned char>& vch) : uint160(vch) {}
|
||||
};
|
||||
|
||||
/** Protocol addresses that can receive funds in a transaction. */
|
||||
typedef std::variant<SproutPaymentAddress, SaplingPaymentAddress> RawAddress;
|
||||
|
@ -60,8 +51,8 @@ public:
|
|||
*/
|
||||
typedef std::variant<
|
||||
SaplingPaymentAddress,
|
||||
P2SHAddress,
|
||||
P2PKHAddress,
|
||||
CScriptID,
|
||||
CKeyID,
|
||||
UnknownReceiver> Receiver;
|
||||
|
||||
struct ReceiverIterator {
|
||||
|
@ -178,8 +169,8 @@ public:
|
|||
TypecodeForReceiver() {}
|
||||
|
||||
uint32_t operator()(const libzcash::SaplingPaymentAddress &zaddr) const;
|
||||
uint32_t operator()(const libzcash::P2SHAddress &p2sh) const;
|
||||
uint32_t operator()(const libzcash::P2PKHAddress &p2pkh) const;
|
||||
uint32_t operator()(const CScriptID &p2sh) const;
|
||||
uint32_t operator()(const CKeyID &p2pkh) const;
|
||||
uint32_t operator()(const libzcash::UnknownReceiver &p2pkh) const;
|
||||
};
|
||||
|
||||
|
@ -191,8 +182,8 @@ public:
|
|||
ReceiverToRawAddress() {}
|
||||
|
||||
std::optional<libzcash::RawAddress> operator()(const libzcash::SaplingPaymentAddress &zaddr) const;
|
||||
std::optional<libzcash::RawAddress> operator()(const libzcash::P2SHAddress &p2sh) const;
|
||||
std::optional<libzcash::RawAddress> operator()(const libzcash::P2PKHAddress &p2pkh) const;
|
||||
std::optional<libzcash::RawAddress> operator()(const CScriptID &p2sh) const;
|
||||
std::optional<libzcash::RawAddress> operator()(const CKeyID &p2pkh) const;
|
||||
std::optional<libzcash::RawAddress> operator()(const libzcash::UnknownReceiver &p2pkh) const;
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
// Copyright (c) 2021 The Zcash developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
|
||||
|
||||
#include "bip44.h"
|
||||
|
||||
std::optional<std::pair<CExtKey, HDKeyPath>> libzcash::DeriveBip44TransparentAccountKey(const HDSeed& seed, uint32_t bip44CoinType, libzcash::AccountId accountId) {
|
||||
auto rawSeed = seed.RawSeed();
|
||||
auto m = CExtKey::Master(rawSeed.data(), rawSeed.size());
|
||||
|
||||
// We use a fixed keypath scheme of m/44'/coin_type'/account'
|
||||
// Derive m/44'
|
||||
auto m_44h = m.Derive(44 | HARDENED_KEY_LIMIT);
|
||||
if (!m_44h.has_value()) return std::nullopt;
|
||||
|
||||
// Derive m/44'/coin_type'
|
||||
auto m_44h_cth = m_44h.value().Derive(bip44CoinType | HARDENED_KEY_LIMIT);
|
||||
if (!m_44h_cth.has_value()) return std::nullopt;
|
||||
|
||||
// Derive m/44'/coin_type'/account_id'
|
||||
auto result = m_44h_cth.value().Derive(accountId | HARDENED_KEY_LIMIT);
|
||||
if (!result.has_value()) return std::nullopt;
|
||||
|
||||
auto hdKeypath = "m/44'/" + std::to_string(bip44CoinType) + "'/" + std::to_string(accountId) + "'";
|
||||
|
||||
return std::make_pair(result.value(), hdKeypath);
|
||||
}
|
||||
|
||||
std::optional<libzcash::Bip44AccountChains> libzcash::Bip44AccountChains::ForAccount(
|
||||
const HDSeed& seed,
|
||||
uint32_t bip44CoinType,
|
||||
libzcash::AccountId accountId) {
|
||||
auto accountKeyOpt = DeriveBip44TransparentAccountKey(seed, bip44CoinType, accountId);
|
||||
if (!accountKeyOpt.has_value()) return std::nullopt;
|
||||
|
||||
auto accountKey = accountKeyOpt.value();
|
||||
auto external = accountKey.first.Derive(0);
|
||||
auto internal = accountKey.first.Derive(1);
|
||||
|
||||
if (!(external.has_value() && internal.has_value())) return std::nullopt;
|
||||
|
||||
return Bip44AccountChains(seed.Fingerprint(), bip44CoinType, accountId, external.value(), internal.value());
|
||||
}
|
||||
|
||||
std::optional<std::pair<CExtKey, HDKeyPath>> libzcash::Bip44AccountChains::DeriveExternal(uint32_t addrIndex) {
|
||||
auto childKey = external.Derive(addrIndex);
|
||||
if (!childKey.has_value()) return std::nullopt;
|
||||
|
||||
auto hdKeypath = "m/44'/"
|
||||
+ std::to_string(bip44CoinType) + "'/"
|
||||
+ std::to_string(accountId) + "'/"
|
||||
+ "0/"
|
||||
+ std::to_string(addrIndex);
|
||||
|
||||
return std::make_pair(childKey.value(), hdKeypath);
|
||||
}
|
||||
|
||||
std::optional<std::pair<CExtKey, HDKeyPath>> libzcash::Bip44AccountChains::DeriveInternal(uint32_t addrIndex) {
|
||||
auto childKey = internal.Derive(addrIndex);
|
||||
if (!childKey.has_value()) return std::nullopt;
|
||||
|
||||
auto hdKeypath = "m/44'/"
|
||||
+ std::to_string(bip44CoinType) + "'/"
|
||||
+ std::to_string(accountId) + "'/"
|
||||
+ "1/"
|
||||
+ std::to_string(addrIndex);
|
||||
|
||||
return std::make_pair(childKey.value(), hdKeypath);
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
// Copyright (c) 2021 The Zcash developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
|
||||
|
||||
#ifndef ZCASH_ZCASH_ADDRESS_BIP44_H
|
||||
#define ZCASH_ZCASH_ADDRESS_BIP44_H
|
||||
|
||||
#include "zip32.h"
|
||||
|
||||
namespace libzcash {
|
||||
|
||||
std::optional<std::pair<CExtKey, HDKeyPath>> DeriveBip44TransparentAccountKey(const HDSeed& seed, uint32_t bip44CoinType, libzcash::AccountId accountId);
|
||||
|
||||
class Bip44AccountChains {
|
||||
private:
|
||||
uint256 seedFp;
|
||||
libzcash::AccountId accountId;
|
||||
uint32_t bip44CoinType;
|
||||
CExtKey external;
|
||||
CExtKey internal;
|
||||
|
||||
Bip44AccountChains(uint256 seedFpIn, uint32_t bip44CoinTypeIn, libzcash::AccountId accountIdIn, CExtKey externalIn, CExtKey internalIn):
|
||||
seedFp(seedFpIn), accountId(accountIdIn), bip44CoinType(bip44CoinTypeIn), external(externalIn), internal(internalIn) {}
|
||||
public:
|
||||
static std::optional<Bip44AccountChains> ForAccount(
|
||||
const HDSeed& mnemonic,
|
||||
uint32_t bip44CoinType,
|
||||
libzcash::AccountId accountId);
|
||||
|
||||
std::optional<std::pair<CExtKey, HDKeyPath>> DeriveExternal(uint32_t addrIndex);
|
||||
std::optional<std::pair<CExtKey, HDKeyPath>> DeriveInternal(uint32_t addrIndex);
|
||||
};
|
||||
|
||||
} //namespace libzcash
|
||||
|
||||
#endif // ZCASH_ZCASH_ADDRESS_BIP44_H
|
|
@ -0,0 +1,37 @@
|
|||
// Copyright (c) 2018-2021 The Zcash developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
|
||||
|
||||
#include "random.h"
|
||||
|
||||
#include "mnemonic.h"
|
||||
|
||||
#include "bip44.h"
|
||||
#include "unified.h"
|
||||
|
||||
using namespace libzcash;
|
||||
|
||||
MnemonicSeed MnemonicSeed::Random(uint32_t bip44CoinType, Language language, size_t entropyLen)
|
||||
{
|
||||
assert(entropyLen >= 32);
|
||||
while (true) { // loop until we find usable entropy
|
||||
RawHDSeed entropy(entropyLen, 0);
|
||||
GetRandBytes(entropy.data(), entropyLen);
|
||||
const char* phrase = zip339_entropy_to_phrase(language, entropy.data(), entropyLen);
|
||||
SecureString mnemonic(phrase);
|
||||
zip339_free_phrase(phrase);
|
||||
MnemonicSeed seed(language, mnemonic);
|
||||
|
||||
// Verify that the seed data is valid entropy for unified spending keys at
|
||||
// account 0 and at both the public & private chain levels for account 0x7FFFFFFF.
|
||||
// It is not necessary to check for a valid diversified Sapling address at
|
||||
// account 0x7FFFFFFF because derivation via the legacy path can simply search
|
||||
// for a valid diversifier; unlike in the unified spending key case, diversifier
|
||||
// indices don't need to line up with anything.
|
||||
if (ZcashdUnifiedSpendingKey::ForAccount(seed, bip44CoinType, 0).has_value() &&
|
||||
Bip44AccountChains::ForAccount(seed, bip44CoinType, ZCASH_LEGACY_ACCOUNT).has_value()) {
|
||||
return seed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
// Copyright (c) 2021 The Zcash developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
|
||||
|
||||
#ifndef ZCASH_ZCASH_ADDRESS_MNEMONIC_H
|
||||
#define ZCASH_ZCASH_ADDRESS_MNEMONIC_H
|
||||
|
||||
#include "zip32.h"
|
||||
|
||||
class MnemonicSeed: public HDSeed {
|
||||
private:
|
||||
Language language;
|
||||
SecureString mnemonic;
|
||||
|
||||
MnemonicSeed() {}
|
||||
|
||||
void SetSeedFromMnemonic() {
|
||||
seed.resize(64);
|
||||
zip339_phrase_to_seed(language, mnemonic.c_str(), (uint8_t (*)[64])seed.data());
|
||||
}
|
||||
|
||||
public:
|
||||
MnemonicSeed(Language languageIn, SecureString mnemonicIn): language(languageIn), mnemonic(mnemonicIn) {
|
||||
SetSeedFromMnemonic();
|
||||
}
|
||||
|
||||
/**
|
||||
* Randomly generate a new mnemonic seed. A SLIP-44 coin type is required to make it possible
|
||||
* to check that the generated seed can produce valid transparent and unified addresses at account
|
||||
* numbers 0x7FFFFFFF and 0x00 respectively.
|
||||
*/
|
||||
static MnemonicSeed Random(uint32_t bip44CoinType, Language language = English, size_t entropyLen = 32);
|
||||
|
||||
static std::string LanguageName(Language language) {
|
||||
switch (language) {
|
||||
case English:
|
||||
return "English";
|
||||
case SimplifiedChinese:
|
||||
return "Simplified Chinese";
|
||||
case TraditionalChinese:
|
||||
return "Traditional Chinese";
|
||||
case Czech:
|
||||
return "Czech";
|
||||
case French:
|
||||
return "French";
|
||||
case Italian:
|
||||
return "Italian";
|
||||
case Japanese:
|
||||
return "Japanese";
|
||||
case Korean:
|
||||
return "Korean";
|
||||
case Portuguese:
|
||||
return "Portuguese";
|
||||
case Spanish:
|
||||
return "Spanish";
|
||||
default:
|
||||
return "INVALID";
|
||||
}
|
||||
}
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action) {
|
||||
if (ser_action.ForRead()) {
|
||||
uint32_t language0;
|
||||
|
||||
READWRITE(language0);
|
||||
READWRITE(mnemonic);
|
||||
language = (Language) language0;
|
||||
SetSeedFromMnemonic();
|
||||
} else {
|
||||
uint32_t language0 = (uint32_t) language;
|
||||
|
||||
READWRITE(language0);
|
||||
READWRITE(mnemonic);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Stream>
|
||||
static MnemonicSeed Read(Stream& stream) {
|
||||
MnemonicSeed seed;
|
||||
stream >> seed;
|
||||
return seed;
|
||||
}
|
||||
|
||||
const Language GetLanguage() const {
|
||||
return language;
|
||||
}
|
||||
|
||||
const SecureString& GetMnemonic() const {
|
||||
return mnemonic;
|
||||
}
|
||||
|
||||
friend bool operator==(const MnemonicSeed& a, const MnemonicSeed& b)
|
||||
{
|
||||
return a.seed == b.seed;
|
||||
}
|
||||
|
||||
friend bool operator!=(const MnemonicSeed& a, const MnemonicSeed& b)
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // ZCASH_ZCASH_ADDRESS_MNEMONIC_H
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
// Copyright (c) 2021 The Zcash developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
|
||||
|
||||
#include "unified.h"
|
||||
#include "bip44.h"
|
||||
|
||||
using namespace libzcash;
|
||||
|
||||
//
|
||||
// Unified Keys
|
||||
//
|
||||
|
||||
std::optional<std::pair<ZcashdUnifiedSpendingKey, HDKeyPath>> ZcashdUnifiedSpendingKey::ForAccount(const HDSeed& seed, uint32_t bip44CoinType, AccountId accountId) {
|
||||
ZcashdUnifiedSpendingKey usk;
|
||||
usk.accountId = accountId;
|
||||
|
||||
auto transparentKey = DeriveBip44TransparentAccountKey(seed, bip44CoinType, accountId);
|
||||
if (!transparentKey.has_value()) return std::nullopt;
|
||||
usk.transparentKey = transparentKey.value().first;
|
||||
|
||||
auto saplingKey = SaplingExtendedSpendingKey::ForAccount(seed, bip44CoinType, accountId);
|
||||
usk.saplingKey = saplingKey.first;
|
||||
|
||||
return std::make_pair(usk, saplingKey.second);
|
||||
}
|
||||
|
||||
ZcashdUnifiedFullViewingKey ZcashdUnifiedSpendingKey::ToFullViewingKey() const {
|
||||
ZcashdUnifiedFullViewingKey ufvk;
|
||||
|
||||
if (transparentKey.has_value()) {
|
||||
ufvk.transparentKey = transparentKey.value().Neuter();
|
||||
}
|
||||
|
||||
if (saplingKey.has_value()) {
|
||||
ufvk.saplingKey = saplingKey.value().ToXFVK();
|
||||
}
|
||||
|
||||
return ufvk;
|
||||
}
|
||||
|
||||
std::optional<UnifiedAddress> ZcashdUnifiedFullViewingKey::Address(diversifier_index_t j) const {
|
||||
UnifiedAddress ua;
|
||||
|
||||
if (saplingKey.has_value()) {
|
||||
auto saplingAddress = saplingKey.value().Address(j);
|
||||
if (saplingAddress.has_value()) {
|
||||
ua.AddReceiver(saplingAddress.value());
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
if (transparentKey.has_value()) {
|
||||
auto childIndex = j.ToTransparentChildIndex();
|
||||
if (!childIndex.has_value()) return std::nullopt;
|
||||
|
||||
CExtPubKey externalKey;
|
||||
if (!transparentKey.value().Derive(externalKey, 0)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
CExtPubKey childKey;
|
||||
if (externalKey.Derive(childKey, childIndex.value())) {
|
||||
ua.AddReceiver(childKey.pubkey.GetID());
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
return ua;
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
// Copyright (c) 2021 The Zcash developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
|
||||
|
||||
#ifndef ZCASH_ZCASH_ADDRESS_UNIFIED_H
|
||||
#define ZCASH_ZCASH_ADDRESS_UNIFIED_H
|
||||
|
||||
#include "zip32.h"
|
||||
#include "bip44.h"
|
||||
#include "zcash/Address.hpp"
|
||||
|
||||
namespace libzcash {
|
||||
|
||||
class ZcashdUnifiedSpendingKey;
|
||||
class ZcashdUnifiedFullViewingKey;
|
||||
|
||||
class ZcashdUnifiedFullViewingKey {
|
||||
private:
|
||||
std::optional<CExtPubKey> transparentKey;
|
||||
std::optional<SaplingExtendedFullViewingKey> saplingKey;
|
||||
|
||||
ZcashdUnifiedFullViewingKey() {}
|
||||
|
||||
friend class ZcashdUnifiedSpendingKey;
|
||||
public:
|
||||
const std::optional<CExtPubKey>& GetTransparentKey() const {
|
||||
return transparentKey;
|
||||
}
|
||||
|
||||
const std::optional<SaplingExtendedFullViewingKey>& GetSaplingExtendedFullViewingKey() const {
|
||||
return saplingKey;
|
||||
}
|
||||
|
||||
std::optional<UnifiedAddress> Address(diversifier_index_t j) const;
|
||||
|
||||
std::pair<UnifiedAddress, diversifier_index_t> FindAddress(diversifier_index_t j) const {
|
||||
auto addr = Address(j);
|
||||
while (!addr.has_value()) {
|
||||
if (!j.increment())
|
||||
throw std::runtime_error(std::string(__func__) + ": diversifier index overflow.");;
|
||||
addr = Address(j);
|
||||
}
|
||||
return std::make_pair(addr.value(), j);
|
||||
}
|
||||
};
|
||||
|
||||
class ZcashdUnifiedSpendingKey {
|
||||
private:
|
||||
libzcash::AccountId accountId;
|
||||
std::optional<CExtKey> transparentKey;
|
||||
std::optional<SaplingExtendedSpendingKey> saplingKey;
|
||||
|
||||
ZcashdUnifiedSpendingKey() {}
|
||||
public:
|
||||
static std::optional<std::pair<ZcashdUnifiedSpendingKey, HDKeyPath>> ForAccount(
|
||||
const HDSeed& seed,
|
||||
uint32_t bip44CoinType,
|
||||
libzcash::AccountId accountId);
|
||||
|
||||
const std::optional<CExtKey>& GetTransparentKey() const {
|
||||
return transparentKey;
|
||||
}
|
||||
|
||||
const std::optional<SaplingExtendedSpendingKey>& GetSaplingExtendedSpendingKey() const {
|
||||
return saplingKey;
|
||||
}
|
||||
|
||||
ZcashdUnifiedFullViewingKey ToFullViewingKey() const;
|
||||
};
|
||||
|
||||
} //namespace libzcash
|
||||
|
||||
#endif // ZCASH_ZCASH_ADDRESS_UNIFIED_H
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2018 The Zcash developers
|
||||
// Copyright (c) 2018-2021 The Zcash developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
|
||||
|
||||
|
@ -21,30 +21,6 @@ const unsigned char ZCASH_TADDR_OVK_PERSONAL[BLAKE2bPersonalBytes] =
|
|||
|
||||
const libzcash::diversifier_index_t MAX_TRANSPARENT_CHILD_IDX(0x7FFFFFFF);
|
||||
|
||||
MnemonicSeed MnemonicSeed::Random(uint32_t bip44CoinType, Language language, size_t entropyLen)
|
||||
{
|
||||
assert(entropyLen >= 32);
|
||||
while (true) { // loop until we find usable entropy
|
||||
RawHDSeed entropy(entropyLen, 0);
|
||||
GetRandBytes(entropy.data(), entropyLen);
|
||||
const char* phrase = zip339_entropy_to_phrase(language, entropy.data(), entropyLen);
|
||||
SecureString mnemonic(phrase);
|
||||
zip339_free_phrase(phrase);
|
||||
MnemonicSeed seed(language, mnemonic);
|
||||
|
||||
// Verify that the seed data is valid entropy for unified spending keys at
|
||||
// account 0 and at both the public & private chain levels for account 0x7FFFFFFF.
|
||||
// It is not necessary to check for a valid diversified Sapling address at
|
||||
// account 0x7FFFFFFF because derivation via the legacy path can simply search
|
||||
// for a valid diversifier; unlike in the unified spending key case, diversifier
|
||||
// indices don't need to line up with anything.
|
||||
if (libzcash::ZcashdUnifiedSpendingKey::ForAccount(seed, bip44CoinType, 0).has_value() &&
|
||||
libzcash::Bip44AccountChains::ForAccount(seed, bip44CoinType, ZCASH_LEGACY_ACCOUNT).has_value()) {
|
||||
return seed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint256 HDSeed::Fingerprint() const
|
||||
{
|
||||
CBLAKE2bWriter h(SER_GETHASH, 0, ZCASH_HD_SEED_FP_PERSONAL);
|
||||
|
@ -81,74 +57,6 @@ std::optional<unsigned int> diversifier_index_t::ToTransparentChildIndex() const
|
|||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Transparent
|
||||
//
|
||||
|
||||
std::optional<std::pair<CExtKey, HDKeyPath>> DeriveBip44TransparentAccountKey(const MnemonicSeed& seed, uint32_t bip44CoinType, libzcash::AccountId accountId) {
|
||||
auto rawSeed = seed.RawSeed();
|
||||
auto m = CExtKey::Master(rawSeed.data(), rawSeed.size());
|
||||
|
||||
// We use a fixed keypath scheme of m/44'/coin_type'/account'
|
||||
// Derive m/44'
|
||||
auto m_44h = m.Derive(44 | HARDENED_KEY_LIMIT);
|
||||
if (!m_44h.has_value()) return std::nullopt;
|
||||
|
||||
// Derive m/44'/coin_type'
|
||||
auto m_44h_cth = m_44h.value().Derive(bip44CoinType | HARDENED_KEY_LIMIT);
|
||||
if (!m_44h_cth.has_value()) return std::nullopt;
|
||||
|
||||
// Derive m/44'/coin_type'/account_id'
|
||||
auto result = m_44h_cth.value().Derive(accountId | HARDENED_KEY_LIMIT);
|
||||
if (!result.has_value()) return std::nullopt;
|
||||
|
||||
auto hdKeypath = "m/44'/" + std::to_string(bip44CoinType) + "'/" + std::to_string(accountId) + "'";
|
||||
|
||||
return std::make_pair(result.value(), hdKeypath);
|
||||
}
|
||||
|
||||
std::optional<Bip44AccountChains> Bip44AccountChains::ForAccount(
|
||||
const MnemonicSeed& seed,
|
||||
uint32_t bip44CoinType,
|
||||
libzcash::AccountId accountId) {
|
||||
auto accountKeyOpt = DeriveBip44TransparentAccountKey(seed, bip44CoinType, accountId);
|
||||
if (!accountKeyOpt.has_value()) return std::nullopt;
|
||||
|
||||
auto accountKey = accountKeyOpt.value();
|
||||
auto external = accountKey.first.Derive(0);
|
||||
auto internal = accountKey.first.Derive(1);
|
||||
|
||||
if (!(external.has_value() && internal.has_value())) return std::nullopt;
|
||||
|
||||
return Bip44AccountChains(seed.Fingerprint(), bip44CoinType, accountId, external.value(), internal.value());
|
||||
}
|
||||
|
||||
std::optional<std::pair<CExtKey, HDKeyPath>> Bip44AccountChains::DeriveExternal(uint32_t addrIndex) {
|
||||
auto childKey = external.Derive(addrIndex);
|
||||
if (!childKey.has_value()) return std::nullopt;
|
||||
|
||||
auto hdKeypath = "m/44'/"
|
||||
+ std::to_string(bip44CoinType) + "'/"
|
||||
+ std::to_string(accountId) + "'/"
|
||||
+ "0/"
|
||||
+ std::to_string(addrIndex);
|
||||
|
||||
return std::make_pair(childKey.value(), hdKeypath);
|
||||
}
|
||||
|
||||
std::optional<std::pair<CExtKey, HDKeyPath>> Bip44AccountChains::DeriveInternal(uint32_t addrIndex) {
|
||||
auto childKey = internal.Derive(addrIndex);
|
||||
if (!childKey.has_value()) return std::nullopt;
|
||||
|
||||
auto hdKeypath = "m/44'/"
|
||||
+ std::to_string(bip44CoinType) + "'/"
|
||||
+ std::to_string(accountId) + "'/"
|
||||
+ "1/"
|
||||
+ std::to_string(addrIndex);
|
||||
|
||||
return std::make_pair(childKey.value(), hdKeypath);
|
||||
}
|
||||
|
||||
//
|
||||
// Sapling
|
||||
//
|
||||
|
@ -251,7 +159,7 @@ SaplingExtendedSpendingKey SaplingExtendedSpendingKey::Derive(uint32_t i) const
|
|||
return xsk_i;
|
||||
}
|
||||
|
||||
std::pair<SaplingExtendedSpendingKey, HDKeyPath> SaplingExtendedSpendingKey::ForAccount(const MnemonicSeed& seed, uint32_t bip44CoinType, libzcash::AccountId accountId) {
|
||||
std::pair<SaplingExtendedSpendingKey, HDKeyPath> SaplingExtendedSpendingKey::ForAccount(const HDSeed& seed, uint32_t bip44CoinType, libzcash::AccountId accountId) {
|
||||
auto m = Master(seed);
|
||||
|
||||
// We use a fixed keypath scheme of m/32'/coin_type'/account'
|
||||
|
@ -269,7 +177,7 @@ std::pair<SaplingExtendedSpendingKey, HDKeyPath> SaplingExtendedSpendingKey::For
|
|||
return std::make_pair(xsk, hdKeypath);
|
||||
}
|
||||
|
||||
std::pair<SaplingExtendedSpendingKey, HDKeyPath> SaplingExtendedSpendingKey::Legacy(const MnemonicSeed& seed, uint32_t bip44CoinType, uint32_t addressIndex) {
|
||||
std::pair<SaplingExtendedSpendingKey, HDKeyPath> SaplingExtendedSpendingKey::Legacy(const HDSeed& seed, uint32_t bip44CoinType, uint32_t addressIndex) {
|
||||
auto m = Master(seed);
|
||||
|
||||
// We use a fixed keypath scheme of m/32'/coin_type'/0x7FFFFFFF'/addressIndex'
|
||||
|
@ -309,70 +217,6 @@ SaplingExtendedFullViewingKey SaplingExtendedSpendingKey::ToXFVK() const
|
|||
return ret;
|
||||
}
|
||||
|
||||
//
|
||||
// Unified
|
||||
//
|
||||
|
||||
std::optional<std::pair<ZcashdUnifiedSpendingKey, HDKeyPath>> ZcashdUnifiedSpendingKey::ForAccount(const MnemonicSeed& seed, uint32_t bip44CoinType, libzcash::AccountId accountId) {
|
||||
ZcashdUnifiedSpendingKey usk;
|
||||
usk.accountId = accountId;
|
||||
|
||||
auto transparentKey = DeriveBip44TransparentAccountKey(seed, bip44CoinType, accountId);
|
||||
if (!transparentKey.has_value()) return std::nullopt;
|
||||
usk.transparentKey = transparentKey.value().first;
|
||||
|
||||
auto saplingKey = SaplingExtendedSpendingKey::ForAccount(seed, bip44CoinType, accountId);
|
||||
usk.saplingKey = saplingKey.first;
|
||||
|
||||
return std::make_pair(usk, saplingKey.second);
|
||||
}
|
||||
|
||||
ZcashdUnifiedFullViewingKey ZcashdUnifiedSpendingKey::ToFullViewingKey() const {
|
||||
ZcashdUnifiedFullViewingKey ufvk;
|
||||
|
||||
if (transparentKey.has_value()) {
|
||||
ufvk.transparentKey = transparentKey.value().Neuter();
|
||||
}
|
||||
|
||||
if (saplingKey.has_value()) {
|
||||
ufvk.saplingKey = saplingKey.value().ToXFVK();
|
||||
}
|
||||
|
||||
return ufvk;
|
||||
}
|
||||
|
||||
std::optional<ZcashdUnifiedAddress> ZcashdUnifiedFullViewingKey::Address(diversifier_index_t j) const {
|
||||
ZcashdUnifiedAddress ua;
|
||||
|
||||
if (transparentKey.has_value()) {
|
||||
auto childIndex = j.ToTransparentChildIndex();
|
||||
if (!childIndex.has_value()) return std::nullopt;
|
||||
|
||||
CExtPubKey externalKey;
|
||||
if (!transparentKey.value().Derive(externalKey, 0)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
CExtPubKey childKey;
|
||||
if (externalKey.Derive(childKey, childIndex.value())) {
|
||||
ua.transparentAddress = childKey.pubkey.GetID();
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
if (saplingKey.has_value()) {
|
||||
auto saplingAddress = saplingKey.value().Address(j);
|
||||
if (saplingAddress.has_value()) {
|
||||
ua.saplingAddress = saplingAddress.value();
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
return ua;
|
||||
}
|
||||
|
||||
std::optional<unsigned long> ParseHDKeypathAccount(uint32_t purpose, uint32_t coinType, const std::string& keyPath) {
|
||||
std::regex pattern("m/" + std::to_string(purpose) + "'/" + std::to_string(coinType) + "'/([0-9]+)'.*");
|
||||
std::smatch matches;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2018 The Zcash developers
|
||||
// Copyright (c) 2018-2021 The Zcash developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
|
||||
|
||||
|
@ -22,13 +22,6 @@ const uint32_t HARDENED_KEY_LIMIT = 0x80000000;
|
|||
const size_t ZIP32_XFVK_SIZE = 169;
|
||||
const size_t ZIP32_XSK_SIZE = 169;
|
||||
|
||||
/**
|
||||
* The account identifier used for HD derivation of
|
||||
* transparent and Sapling addresses via the legacy
|
||||
* `getnewaddress` and `z_getnewaddress` code paths,
|
||||
*/
|
||||
const uint32_t ZCASH_LEGACY_ACCOUNT = HARDENED_KEY_LIMIT - 1;
|
||||
|
||||
typedef std::vector<unsigned char, secure_allocator<unsigned char>> RawHDSeed;
|
||||
|
||||
typedef std::string HDKeyPath;
|
||||
|
@ -64,102 +57,6 @@ public:
|
|||
};
|
||||
|
||||
|
||||
class MnemonicSeed: public HDSeed {
|
||||
private:
|
||||
Language language;
|
||||
SecureString mnemonic;
|
||||
|
||||
MnemonicSeed() {}
|
||||
|
||||
void SetSeedFromMnemonic() {
|
||||
seed.resize(64);
|
||||
zip339_phrase_to_seed(language, mnemonic.c_str(), (uint8_t (*)[64])seed.data());
|
||||
}
|
||||
|
||||
public:
|
||||
MnemonicSeed(Language languageIn, SecureString mnemonicIn): language(languageIn), mnemonic(mnemonicIn) {
|
||||
SetSeedFromMnemonic();
|
||||
}
|
||||
|
||||
/**
|
||||
* Randomly generate a new mnemonic seed. A SLIP-44 coin type is required to make it possible
|
||||
* to check that the generated seed can produce valid transparent and unified addresses at account
|
||||
* numbers 0x7FFFFFFF and 0x00 respectively.
|
||||
*/
|
||||
static MnemonicSeed Random(uint32_t bip44CoinType, Language language = English, size_t entropyLen = 32);
|
||||
|
||||
static std::string LanguageName(Language language) {
|
||||
switch (language) {
|
||||
case English:
|
||||
return "English";
|
||||
case SimplifiedChinese:
|
||||
return "Simplified Chinese";
|
||||
case TraditionalChinese:
|
||||
return "Traditional Chinese";
|
||||
case Czech:
|
||||
return "Czech";
|
||||
case French:
|
||||
return "French";
|
||||
case Italian:
|
||||
return "Italian";
|
||||
case Japanese:
|
||||
return "Japanese";
|
||||
case Korean:
|
||||
return "Korean";
|
||||
case Portuguese:
|
||||
return "Portuguese";
|
||||
case Spanish:
|
||||
return "Spanish";
|
||||
default:
|
||||
return "INVALID";
|
||||
}
|
||||
}
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action) {
|
||||
if (ser_action.ForRead()) {
|
||||
uint32_t language0;
|
||||
|
||||
READWRITE(language0);
|
||||
READWRITE(mnemonic);
|
||||
language = (Language) language0;
|
||||
SetSeedFromMnemonic();
|
||||
} else {
|
||||
uint32_t language0 = (uint32_t) language;
|
||||
|
||||
READWRITE(language0);
|
||||
READWRITE(mnemonic);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Stream>
|
||||
static MnemonicSeed Read(Stream& stream) {
|
||||
MnemonicSeed seed;
|
||||
stream >> seed;
|
||||
return seed;
|
||||
}
|
||||
|
||||
const Language GetLanguage() const {
|
||||
return language;
|
||||
}
|
||||
|
||||
const SecureString& GetMnemonic() const {
|
||||
return mnemonic;
|
||||
}
|
||||
|
||||
friend bool operator==(const MnemonicSeed& a, const MnemonicSeed& b)
|
||||
{
|
||||
return a.seed == b.seed;
|
||||
}
|
||||
|
||||
friend bool operator!=(const MnemonicSeed& a, const MnemonicSeed& b)
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
||||
};
|
||||
|
||||
// This is not part of ZIP 32, but is here because it's linked to the HD seed.
|
||||
uint256 ovkForShieldingFromTaddr(HDSeed& seed);
|
||||
|
||||
|
@ -167,6 +64,13 @@ namespace libzcash {
|
|||
|
||||
typedef uint32_t AccountId;
|
||||
|
||||
/**
|
||||
* The account identifier used for HD derivation of
|
||||
* transparent and Sapling addresses via the legacy
|
||||
* `getnewaddress` and `z_getnewaddress` code paths,
|
||||
*/
|
||||
const AccountId ZCASH_LEGACY_ACCOUNT = HARDENED_KEY_LIMIT - 1;
|
||||
|
||||
/**
|
||||
* 88-bit diversifier index. This would ideally derive from base_uint
|
||||
* but those values must have bit widths that are multiples of 32.
|
||||
|
@ -292,8 +196,8 @@ struct SaplingExtendedSpendingKey {
|
|||
}
|
||||
|
||||
static SaplingExtendedSpendingKey Master(const HDSeed& seed);
|
||||
static std::pair<SaplingExtendedSpendingKey, HDKeyPath> ForAccount(const MnemonicSeed& seed, uint32_t bip44CoinType, libzcash::AccountId accountId);
|
||||
static std::pair<SaplingExtendedSpendingKey, HDKeyPath> Legacy(const MnemonicSeed& seed, uint32_t bip44CoinType, uint32_t addressIndex);
|
||||
static std::pair<SaplingExtendedSpendingKey, HDKeyPath> ForAccount(const HDSeed& seed, uint32_t bip44CoinType, libzcash::AccountId accountId);
|
||||
static std::pair<SaplingExtendedSpendingKey, HDKeyPath> Legacy(const HDSeed& seed, uint32_t bip44CoinType, uint32_t addressIndex);
|
||||
|
||||
|
||||
SaplingExtendedSpendingKey Derive(uint32_t i) const;
|
||||
|
@ -311,104 +215,8 @@ struct SaplingExtendedSpendingKey {
|
|||
}
|
||||
};
|
||||
|
||||
class ZcashdUnifiedSpendingKey;
|
||||
class ZcashdUnifiedFullViewingKey;
|
||||
|
||||
class ZcashdUnifiedAddress {
|
||||
private:
|
||||
diversifier_index_t diversifier_index;
|
||||
std::optional<CKeyID> transparentAddress;
|
||||
std::optional<SaplingPaymentAddress> saplingAddress;
|
||||
|
||||
friend class ZcashdUnifiedFullViewingKey;
|
||||
|
||||
ZcashdUnifiedAddress() {}
|
||||
public:
|
||||
const std::optional<CKeyID>& GetTransparentAddress() const {
|
||||
return transparentAddress;
|
||||
}
|
||||
|
||||
const std::optional<SaplingPaymentAddress>& GetSaplingPaymentAddress() const {
|
||||
return saplingAddress;
|
||||
}
|
||||
};
|
||||
|
||||
class ZcashdUnifiedFullViewingKey {
|
||||
private:
|
||||
std::optional<CExtPubKey> transparentKey;
|
||||
std::optional<SaplingExtendedFullViewingKey> saplingKey;
|
||||
|
||||
ZcashdUnifiedFullViewingKey() {}
|
||||
|
||||
friend class ZcashdUnifiedSpendingKey;
|
||||
public:
|
||||
const std::optional<CExtPubKey>& GetTransparentKey() const {
|
||||
return transparentKey;
|
||||
}
|
||||
|
||||
const std::optional<SaplingExtendedFullViewingKey>& GetSaplingExtendedFullViewingKey() const {
|
||||
return saplingKey;
|
||||
}
|
||||
|
||||
std::optional<ZcashdUnifiedAddress> Address(diversifier_index_t j) const;
|
||||
|
||||
std::pair<ZcashdUnifiedAddress, diversifier_index_t> FindAddress(diversifier_index_t j) const {
|
||||
auto addr = Address(j);
|
||||
while (!addr.has_value()) {
|
||||
if (!j.increment())
|
||||
throw std::runtime_error(std::string(__func__) + ": diversifier index overflow.");;
|
||||
addr = Address(j);
|
||||
}
|
||||
return std::make_pair(addr.value(), j);
|
||||
}
|
||||
};
|
||||
|
||||
class ZcashdUnifiedSpendingKey {
|
||||
private:
|
||||
libzcash::AccountId accountId;
|
||||
std::optional<CExtKey> transparentKey;
|
||||
std::optional<SaplingExtendedSpendingKey> saplingKey;
|
||||
|
||||
ZcashdUnifiedSpendingKey() {}
|
||||
public:
|
||||
static std::optional<std::pair<ZcashdUnifiedSpendingKey, HDKeyPath>> ForAccount(
|
||||
const MnemonicSeed& mnemonic,
|
||||
uint32_t bip44CoinType,
|
||||
libzcash::AccountId accountId);
|
||||
|
||||
const std::optional<CExtKey>& GetTransparentKey() const {
|
||||
return transparentKey;
|
||||
}
|
||||
|
||||
const std::optional<SaplingExtendedSpendingKey>& GetSaplingExtendedSpendingKey() const {
|
||||
return saplingKey;
|
||||
}
|
||||
|
||||
ZcashdUnifiedFullViewingKey ToFullViewingKey() const;
|
||||
};
|
||||
|
||||
std::optional<unsigned long> ParseHDKeypathAccount(uint32_t purpose, uint32_t coinType, const std::string& keyPath);
|
||||
|
||||
class Bip44AccountChains {
|
||||
private:
|
||||
uint256 seedFp;
|
||||
libzcash::AccountId accountId;
|
||||
uint32_t bip44CoinType;
|
||||
CExtKey external;
|
||||
CExtKey internal;
|
||||
|
||||
Bip44AccountChains(uint256 seedFpIn, uint32_t bip44CoinTypeIn, libzcash::AccountId accountIdIn, CExtKey externalIn, CExtKey internalIn):
|
||||
seedFp(seedFpIn), accountId(accountIdIn), bip44CoinType(bip44CoinTypeIn), external(externalIn), internal(internalIn) {}
|
||||
public:
|
||||
static std::optional<Bip44AccountChains> ForAccount(
|
||||
const MnemonicSeed& mnemonic,
|
||||
uint32_t bip44CoinType,
|
||||
libzcash::AccountId accountId);
|
||||
|
||||
std::optional<std::pair<CExtKey, HDKeyPath>> DeriveExternal(uint32_t addrIndex);
|
||||
std::optional<std::pair<CExtKey, HDKeyPath>> DeriveInternal(uint32_t addrIndex);
|
||||
};
|
||||
|
||||
}
|
||||
} //namespace libzcash
|
||||
|
||||
#endif // ZCASH_ZCASH_ADDRESS_ZIP32_H
|
||||
|
|
Loading…
Reference in New Issue