ZIP 32 Sapling structs

This commit is contained in:
Jack Grigg
2018-08-03 16:04:28 +01:00
parent f8d65e8f03
commit 7614198f9d
7 changed files with 411 additions and 2 deletions

View File

@@ -19,6 +19,9 @@ 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;

139
src/zcash/zip32.cpp Normal file
View File

@@ -0,0 +1,139 @@
// Copyright (c) 2018 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "zip32.h"
#include "hash.h"
#include "random.h"
#include "streams.h"
#include "version.h"
#include <librustzcash.h>
#include <sodium.h>
const unsigned char ZCASH_HD_SEED_FP_PERSONAL[crypto_generichash_blake2b_PERSONALBYTES] =
{'Z', 'c', 'a', 's', 'h', '_', 'H', 'D', '_', 'S', 'e', 'e', 'd', '_', 'F', 'P'};
HDSeed HDSeed::Random(size_t len)
{
assert(len >= 32);
RawHDSeed rawSeed(len, 0);
GetRandBytes(rawSeed.data(), len);
return HDSeed(rawSeed);
}
uint256 HDSeed::Fingerprint() const
{
CBLAKE2bWriter h(SER_GETHASH, 0, ZCASH_HD_SEED_FP_PERSONAL);
h << seed;
return h.GetHash();
}
namespace libzcash {
boost::optional<SaplingExtendedFullViewingKey> SaplingExtendedFullViewingKey::Derive(uint32_t i) const
{
CDataStream ss_p(SER_NETWORK, PROTOCOL_VERSION);
ss_p << *this;
CSerializeData p_bytes(ss_p.begin(), ss_p.end());
CSerializeData i_bytes(ZIP32_XFVK_SIZE);
if (librustzcash_zip32_xfvk_derive(
reinterpret_cast<unsigned char*>(p_bytes.data()),
i,
reinterpret_cast<unsigned char*>(i_bytes.data())
)) {
CDataStream ss_i(i_bytes, SER_NETWORK, PROTOCOL_VERSION);
SaplingExtendedFullViewingKey xfvk_i;
ss_i >> xfvk_i;
return xfvk_i;
} else {
return boost::none;
}
}
boost::optional<std::pair<diversifier_index_t, libzcash::SaplingPaymentAddress>>
SaplingExtendedFullViewingKey::Address(diversifier_index_t j) const
{
CDataStream ss_xfvk(SER_NETWORK, PROTOCOL_VERSION);
ss_xfvk << *this;
CSerializeData xfvk_bytes(ss_xfvk.begin(), ss_xfvk.end());
diversifier_index_t j_ret;
CSerializeData addr_bytes(libzcash::SerializedSaplingPaymentAddressSize);
if (librustzcash_zip32_xfvk_address(
reinterpret_cast<unsigned char*>(xfvk_bytes.data()),
j.begin(), j_ret.begin(),
reinterpret_cast<unsigned char*>(addr_bytes.data()))) {
CDataStream ss_addr(addr_bytes, SER_NETWORK, PROTOCOL_VERSION);
libzcash::SaplingPaymentAddress addr;
ss_addr >> addr;
return std::make_pair(j_ret, addr);
} else {
return boost::none;
}
}
libzcash::SaplingPaymentAddress SaplingExtendedFullViewingKey::DefaultAddress() const
{
diversifier_index_t j0;
auto addr = Address(j0);
// If we can't obtain a default address, we are *very* unlucky...
if (!addr) {
throw std::runtime_error("SaplingExtendedFullViewingKey::DefaultAddress(): No valid diversifiers out of 2^88!");
}
return addr.get().second;
}
SaplingExtendedSpendingKey SaplingExtendedSpendingKey::Master(const HDSeed& seed)
{
auto rawSeed = seed.RawSeed();
CSerializeData m_bytes(ZIP32_XSK_SIZE);
librustzcash_zip32_xsk_master(
rawSeed.data(),
rawSeed.size(),
reinterpret_cast<unsigned char*>(m_bytes.data()));
CDataStream ss(m_bytes, SER_NETWORK, PROTOCOL_VERSION);
SaplingExtendedSpendingKey xsk_m;
ss >> xsk_m;
return xsk_m;
}
SaplingExtendedSpendingKey SaplingExtendedSpendingKey::Derive(uint32_t i) const
{
CDataStream ss_p(SER_NETWORK, PROTOCOL_VERSION);
ss_p << *this;
CSerializeData p_bytes(ss_p.begin(), ss_p.end());
CSerializeData i_bytes(ZIP32_XSK_SIZE);
librustzcash_zip32_xsk_derive(
reinterpret_cast<unsigned char*>(p_bytes.data()),
i,
reinterpret_cast<unsigned char*>(i_bytes.data()));
CDataStream ss_i(i_bytes, SER_NETWORK, PROTOCOL_VERSION);
SaplingExtendedSpendingKey xsk_i;
ss_i >> xsk_i;
return xsk_i;
}
SaplingExtendedFullViewingKey SaplingExtendedSpendingKey::ToXFVK() const
{
SaplingExtendedFullViewingKey ret;
ret.depth = depth;
ret.parentFVKTag = parentFVKTag;
ret.childIndex = childIndex;
ret.chaincode = chaincode;
ret.fvk = expsk.full_viewing_key();
ret.dk = dk;
return ret;
}
libzcash::SaplingPaymentAddress SaplingExtendedSpendingKey::DefaultAddress() const
{
return ToXFVK().DefaultAddress();
}
}

121
src/zcash/zip32.h Normal file
View File

@@ -0,0 +1,121 @@
// Copyright (c) 2018 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef ZCASH_ZIP32_H
#define ZCASH_ZIP32_H
#include "serialize.h"
#include "support/allocators/secure.h"
#include "uint256.h"
#include "zcash/Address.hpp"
#include <boost/optional.hpp>
const uint32_t ZIP32_HARDENED_KEY_LIMIT = 0x80000000;
const size_t ZIP32_XFVK_SIZE = 169;
const size_t ZIP32_XSK_SIZE = 169;
typedef std::vector<unsigned char, secure_allocator<unsigned char>> RawHDSeed;
class HDSeed {
private:
RawHDSeed seed;
public:
HDSeed() {}
HDSeed(RawHDSeed& seedIn) : seed(seedIn) {}
static HDSeed Random(size_t len = 32);
bool IsNull() const { return seed.empty(); };
uint256 Fingerprint() const;
RawHDSeed RawSeed() const { return seed; }
friend bool operator==(const HDSeed& a, const HDSeed& b)
{
return a.seed == b.seed;
}
friend bool operator!=(const HDSeed& a, const HDSeed& b)
{
return !(a == b);
}
};
namespace libzcash {
typedef blob88 diversifier_index_t;
struct SaplingExtendedFullViewingKey {
uint8_t depth;
uint32_t parentFVKTag;
uint32_t childIndex;
uint256 chaincode;
libzcash::SaplingFullViewingKey fvk;
uint256 dk;
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(depth);
READWRITE(parentFVKTag);
READWRITE(childIndex);
READWRITE(chaincode);
READWRITE(fvk);
READWRITE(dk);
}
boost::optional<SaplingExtendedFullViewingKey> Derive(uint32_t i) const;
// Returns the first index starting from j that generates a valid
// payment address, along with the corresponding address. Returns
// an error if the diversifier space is exhausted.
boost::optional<std::pair<diversifier_index_t, libzcash::SaplingPaymentAddress>>
Address(diversifier_index_t j) const;
libzcash::SaplingPaymentAddress DefaultAddress() const;
};
struct SaplingExtendedSpendingKey {
uint8_t depth;
uint32_t parentFVKTag;
uint32_t childIndex;
uint256 chaincode;
libzcash::SaplingExpandedSpendingKey expsk;
uint256 dk;
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(depth);
READWRITE(parentFVKTag);
READWRITE(childIndex);
READWRITE(chaincode);
READWRITE(expsk);
READWRITE(dk);
}
static SaplingExtendedSpendingKey Master(const HDSeed& seed);
SaplingExtendedSpendingKey Derive(uint32_t i) const;
SaplingExtendedFullViewingKey ToXFVK() const;
libzcash::SaplingPaymentAddress DefaultAddress() const;
friend bool operator==(const SaplingExtendedSpendingKey& a, const SaplingExtendedSpendingKey& b)
{
return a.depth == b.depth &&
a.parentFVKTag == b.parentFVKTag &&
a.childIndex == b.childIndex &&
a.chaincode == b.chaincode &&
a.expsk == b.expsk &&
a.dk == b.dk;
}
};
}
#endif // ZCASH_ZIP32_H