Adds Orchard Address, IncomingViewingKey, FullViewingKey, and SpendingKey types.

This commit is contained in:
Kris Nuttycombe 2021-07-19 16:06:52 -06:00
parent 8f5591a9c1
commit 59a4c84112
11 changed files with 876 additions and 3 deletions

2
Cargo.lock generated
View File

@ -1112,7 +1112,7 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
[[package]]
name = "orchard"
version = "0.0.0"
source = "git+https://github.com/zcash/orchard.git?rev=2c8241f25b943aa05203eacf9905db117c69bd29#2c8241f25b943aa05203eacf9905db117c69bd29"
source = "git+https://github.com/nuttycom/orchard.git?rev=14c4b40dfc2368b904ee157bc2aeaa7a2c90cb86#14c4b40dfc2368b904ee157bc2aeaa7a2c90cb86"
dependencies = [
"aes",
"arrayvec 0.7.2",

View File

@ -72,7 +72,7 @@ codegen-units = 1
[patch.crates-io]
ed25519-zebra = { git = "https://github.com/ZcashFoundation/ed25519-zebra.git", rev = "d3512400227a362d08367088ffaa9bd4142a69c7" }
incrementalmerkletree = { git = "https://github.com/zcash/incrementalmerkletree", rev = "b7bd6246122a6e9ace8edb51553fbf5228906cbb" }
orchard = { git = "https://github.com/zcash/orchard.git", rev = "2c8241f25b943aa05203eacf9905db117c69bd29" }
orchard = { git = "https://github.com/nuttycom/orchard.git", rev = "14c4b40dfc2368b904ee157bc2aeaa7a2c90cb86" }
zcash_address = { git = "https://github.com/zcash/librustzcash.git", rev = "3d7b9dc9aa14ecc8f95ed338b2d7876fac12fd12" }
zcash_history = { git = "https://github.com/zcash/librustzcash.git", rev = "3d7b9dc9aa14ecc8f95ed338b2d7876fac12fd12" }
zcash_note_encryption = { git = "https://github.com/zcash/librustzcash.git", rev = "3d7b9dc9aa14ecc8f95ed338b2d7876fac12fd12" }

View File

@ -109,6 +109,7 @@ LIBZCASH_H = \
zcash/Address.hpp \
zcash/address/sapling.hpp \
zcash/address/sprout.hpp \
zcash/address/orchard.h \
zcash/address/zip32.h \
zcash/History.hpp \
zcash/JoinSplit.hpp \
@ -537,6 +538,7 @@ libzcash_a_SOURCES = \
zcash/Address.cpp \
zcash/address/sapling.cpp \
zcash/address/sprout.cpp \
zcash/address/orchard.cpp \
zcash/address/zip32.cpp \
zcash/History.cpp \
zcash/JoinSplit.cpp \

View File

@ -21,7 +21,8 @@ zcash_gtest_SOURCES = \
# depend on global state (see #1539)
if ENABLE_WALLET
zcash_gtest_SOURCES += \
wallet/gtest/test_wallet_zkeys.cpp
wallet/gtest/test_wallet_zkeys.cpp \
wallet/gtest/test_orchard_zkeys.cpp
endif
zcash_gtest_SOURCES += \
test/data/merkle_roots_orchard.h \

View File

@ -0,0 +1,216 @@
// 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_RUST_INCLUDE_RUST_ORCHARD_KEYS_H
#define ZCASH_RUST_INCLUDE_RUST_ORCHARD_KEYS_H
#include "rust/streams.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* A pointer to an Orchard shielded payment address, as defined in
* https://zips.z.cash/protocol/nu5.pdf#orchardpaymentaddrencoding
*/
struct OrchardRawAddressPtr;
typedef struct OrchardRawAddressPtr OrchardRawAddressPtr;
/**
* Clones the given Orchard payment address and returns
* a pointer to the newly created value. Both the original
* one's memory and the newly allocated one need to be freed
* independently.
*/
OrchardRawAddressPtr* orchard_address_clone(
const OrchardRawAddressPtr* ptr);
/**
* Frees the memory allocated for the given Orchard payment address
*/
void orchard_address_free(OrchardRawAddressPtr* ptr);
//
// Incoming Viewing Keys
//
struct OrchardIncomingViewingKeyPtr;
typedef struct OrchardIncomingViewingKeyPtr OrchardIncomingViewingKeyPtr;
/**
* Clones the given Orchard incoming viewing key and returns
* a pointer to the newly created value. Both the original
* one's memory and the newly allocated one need to be freed
* independently.
*/
OrchardIncomingViewingKeyPtr* orchard_incoming_viewing_key_clone(
const OrchardIncomingViewingKeyPtr* ptr);
/**
* Frees the memory allocated for the given Orchard incoming viewing key
*/
void orchard_incoming_viewing_key_free(OrchardIncomingViewingKeyPtr* ptr);
/**
* Returns the address at the specified diversifier index.
*/
OrchardRawAddressPtr* orchard_incoming_viewing_key_to_address(
const OrchardIncomingViewingKeyPtr* incoming_viewing_key,
const unsigned char* j);
/**
* Parses an Orchard incoming viewing key from the given stream.
*
* - If the key does not parse correctly, the returned pointer will be null.
*/
OrchardIncomingViewingKeyPtr* orchard_incoming_viewing_key_parse(
void* stream,
read_callback_t read_cb);
/**
* Serializes an Orchard incoming viewing key to the given stream
*
* If `incoming_viewing_key == nullptr`, this serializes `nActionsOrchard = 0`.
*/
bool orchard_incoming_viewing_key_serialize(
const OrchardIncomingViewingKeyPtr* incoming_viewing_key,
void* stream,
write_callback_t write_cb);
/**
* Implements the "less than" operation for comparing two keys.
*/
bool orchard_incoming_viewing_key_lt(
const OrchardIncomingViewingKeyPtr* k0,
const OrchardIncomingViewingKeyPtr* k1);
/**
* Implements equality testing between incoming viewing keys.
*/
bool orchard_incoming_viewing_key_eq(
const OrchardIncomingViewingKeyPtr* k0,
const OrchardIncomingViewingKeyPtr* k1);
//
// Full Viewing Keys
//
struct OrchardFullViewingKeyPtr;
typedef struct OrchardFullViewingKeyPtr OrchardFullViewingKeyPtr;
/**
* Clones the given Orchard full viewing key and returns
* a pointer to the newly created value. Both the original
* one's memory and the newly allocated one need to be freed
* independently.
*/
OrchardFullViewingKeyPtr* orchard_full_viewing_key_clone(
const OrchardFullViewingKeyPtr* ptr);
/**
* Free the memory allocated for the given Orchard full viewing key
*/
void orchard_full_viewing_key_free(OrchardFullViewingKeyPtr* ptr);
/**
* Parses an Orchard full viewing key from the given stream.
*
* - If the key does not parse correctly, the returned pointer will be null.
*/
OrchardFullViewingKeyPtr* orchard_full_viewing_key_parse(
void* stream,
read_callback_t read_cb);
/**
* Serializes an Orchard full viewing key to the given stream
*
* If `full_viewing_key == nullptr`, this serializes `nActionsOrchard = 0`.
*/
bool orchard_full_viewing_key_serialize(
const OrchardFullViewingKeyPtr* full_viewing_key,
void* stream,
write_callback_t write_cb);
/**
* Returns the incoming viewing key for the specified full viewing key.
*/
OrchardIncomingViewingKeyPtr* orchard_full_viewing_key_to_incoming_viewing_key(
const OrchardFullViewingKeyPtr* key);
/**
* Implements equality testing between full viewing keys.
*/
bool orchard_full_viewing_key_eq(
const OrchardFullViewingKeyPtr* k0,
const OrchardFullViewingKeyPtr* k1);
//
// Spending Keys
//
struct OrchardSpendingKeyPtr;
typedef struct OrchardSpendingKeyPtr OrchardSpendingKeyPtr;
/**
* Constructs a spending key by ZIP-32 derivation to the account
* level from the provided seed.
*/
OrchardSpendingKeyPtr* orchard_spending_key_for_account(
const unsigned char* seed,
size_t seed_len,
uint32_t bip44_coin_type,
uint32_t account_id);
/**
* Clones the given Orchard spending key and returns
* a pointer to the newly created value. Both the original
* one's memory and the newly allocated one need to be freed
* independently.
*/
OrchardSpendingKeyPtr* orchard_spending_key_clone(
const OrchardSpendingKeyPtr* ptr);
/**
* Free the memory allocated for the given Orchard spending key
*/
void orchard_spending_key_free(OrchardSpendingKeyPtr* ptr);
/**
* Parses an Orchard spending key from the given stream.
*
* - If the key does not parse correctly, the returned pointer will be null.
*/
OrchardSpendingKeyPtr* orchard_spending_key_parse(
void* stream,
read_callback_t read_cb);
/**
* Serializes an Orchard spending key to the given stream
*
* If `spending_key == nullptr`, this will return `false`
*/
bool orchard_spending_key_serialize(
const OrchardSpendingKeyPtr* spending_key,
void* stream,
write_callback_t write_cb);
/**
* Returns the full viewing key for the specified spending key.
*/
OrchardFullViewingKeyPtr* orchard_spending_key_to_full_viewing_key(
const OrchardSpendingKeyPtr* key);
/**
* Implements equality testing between spending keys.
*/
bool orchard_spending_key_eq(
const OrchardSpendingKeyPtr* k0,
const OrchardSpendingKeyPtr* k1);
#ifdef __cplusplus
}
#endif
#endif // ZCASH_RUST_INCLUDE_RUST_ORCHARD_KEYS_H

View File

@ -0,0 +1,304 @@
use std::io::{Read, Write};
use std::slice;
use tracing::error;
use orchard::keys::{DiversifierIndex, FullViewingKey, IncomingViewingKey, SpendingKey};
use orchard::Address;
use crate::streams_ffi::{CppStreamReader, CppStreamWriter, ReadCb, StreamObj, WriteCb};
//
// Addresses
//
#[no_mangle]
pub extern "C" fn orchard_address_clone(addr: *const Address) -> *mut Address {
unsafe { addr.as_ref() }
.map(|addr| Box::into_raw(Box::new(*addr)))
.unwrap_or(std::ptr::null_mut())
}
#[no_mangle]
pub extern "C" fn orchard_address_free(addr: *mut Address) {
if !addr.is_null() {
drop(unsafe { Box::from_raw(addr) });
}
}
//
// Incoming viewing keys
//
#[no_mangle]
pub extern "C" fn orchard_incoming_viewing_key_clone(
key: *const IncomingViewingKey,
) -> *mut IncomingViewingKey {
unsafe { key.as_ref() }
.map(|key| Box::into_raw(Box::new(key.clone())))
.unwrap_or(std::ptr::null_mut())
}
#[no_mangle]
pub extern "C" fn orchard_incoming_viewing_key_free(key: *mut IncomingViewingKey) {
if !key.is_null() {
drop(unsafe { Box::from_raw(key) });
}
}
#[no_mangle]
pub extern "C" fn orchard_incoming_viewing_key_parse(
stream: Option<StreamObj>,
read_cb: Option<ReadCb>,
) -> *mut IncomingViewingKey {
let mut reader = CppStreamReader::from_raw_parts(stream, read_cb.unwrap());
let mut buf = [0u8; 64];
match reader.read_exact(&mut buf) {
Err(e) => {
error!(
"Stream failure reading bytes of Orchard incoming viewing key: {}",
e
);
std::ptr::null_mut()
}
Ok(()) => {
let read = IncomingViewingKey::from_bytes(&buf);
if read.is_some().into() {
Box::into_raw(Box::new(read.unwrap()))
} else {
error!("Failed to parse Orchard incoming viewing key.");
std::ptr::null_mut()
}
}
}
}
#[no_mangle]
pub extern "C" fn orchard_incoming_viewing_key_to_address(
key: *const IncomingViewingKey,
diversifier_index: *const [u8; 11],
) -> *mut Address {
let key = unsafe {
key.as_ref()
.expect("Orchard incoming viewing key pointer may not be null.")
};
let diversifier_index = unsafe { DiversifierIndex::from(*diversifier_index) };
Box::into_raw(Box::new(key.address_at(diversifier_index)))
}
#[no_mangle]
pub extern "C" fn orchard_incoming_viewing_key_serialize(
key: *const IncomingViewingKey,
stream: Option<StreamObj>,
write_cb: Option<WriteCb>,
) -> bool {
let key = unsafe {
key.as_ref()
.expect("Orchard incoming viewing key pointer may not be null.")
};
let mut writer = CppStreamWriter::from_raw_parts(stream, write_cb.unwrap());
match writer.write_all(&key.to_bytes()) {
Ok(()) => true,
Err(e) => {
error!("Stream failure writing Orchard incoming viewing key: {}", e);
false
}
}
}
#[no_mangle]
pub extern "C" fn orchard_incoming_viewing_key_lt(
k0: *const IncomingViewingKey,
k1: *const IncomingViewingKey,
) -> bool {
let k0 = unsafe { k0.as_ref() };
let k1 = unsafe { k1.as_ref() };
k0 < k1
}
#[no_mangle]
pub extern "C" fn orchard_incoming_viewing_key_eq(
k0: *const IncomingViewingKey,
k1: *const IncomingViewingKey,
) -> bool {
let k0 = unsafe { k0.as_ref() };
let k1 = unsafe { k1.as_ref() };
k0 == k1
}
//
// Full viewing keys
//
#[no_mangle]
pub extern "C" fn orchard_full_viewing_key_clone(
key: *const FullViewingKey,
) -> *mut FullViewingKey {
unsafe { key.as_ref() }
.map(|key| Box::into_raw(Box::new(key.clone())))
.unwrap_or(std::ptr::null_mut())
}
#[no_mangle]
pub extern "C" fn orchard_full_viewing_key_free(key: *mut FullViewingKey) {
if !key.is_null() {
drop(unsafe { Box::from_raw(key) });
}
}
#[no_mangle]
pub extern "C" fn orchard_full_viewing_key_parse(
stream: Option<StreamObj>,
read_cb: Option<ReadCb>,
) -> *mut FullViewingKey {
let reader = CppStreamReader::from_raw_parts(stream, read_cb.unwrap());
match FullViewingKey::read(reader) {
Err(e) => {
error!(
"Stream failure reading bytes of Orchard full viewing key: {}",
e
);
std::ptr::null_mut()
}
Ok(fvk) => Box::into_raw(Box::new(fvk)),
}
}
#[no_mangle]
pub extern "C" fn orchard_full_viewing_key_serialize(
key: *const FullViewingKey,
stream: Option<StreamObj>,
write_cb: Option<WriteCb>,
) -> bool {
let key = unsafe {
key.as_ref()
.expect("Orchard full viewing key pointer may not be null.")
};
let mut writer = CppStreamWriter::from_raw_parts(stream, write_cb.unwrap());
match key.write(&mut writer) {
Ok(()) => true,
Err(e) => {
error!("Stream failure writing Orchard full viewing key: {}", e);
false
}
}
}
#[no_mangle]
pub extern "C" fn orchard_full_viewing_key_to_incoming_viewing_key(
key: *const FullViewingKey,
) -> *mut IncomingViewingKey {
unsafe { key.as_ref() }
.map(|key| Box::into_raw(Box::new(IncomingViewingKey::from(key))))
.unwrap_or(std::ptr::null_mut())
}
#[no_mangle]
pub extern "C" fn orchard_full_viewing_key_eq(
k0: *const FullViewingKey,
k1: *const FullViewingKey,
) -> bool {
let k0 = unsafe { k0.as_ref() };
let k1 = unsafe { k1.as_ref() };
k0 == k1
}
//
// Spending keys
//
#[no_mangle]
pub extern "C" fn orchard_spending_key_for_account(
seed: *const u8,
seed_len: usize,
bip44_coin_type: u32,
account_id: u32,
) -> *mut SpendingKey {
let seed = unsafe { slice::from_raw_parts(seed, seed_len) };
SpendingKey::from_zip32_seed(seed, bip44_coin_type, account_id)
.map(|key| Box::into_raw(Box::new(key)))
.unwrap_or(std::ptr::null_mut())
}
#[no_mangle]
pub extern "C" fn orchard_spending_key_clone(key: *const SpendingKey) -> *mut SpendingKey {
unsafe { key.as_ref() }
.map(|key| Box::into_raw(Box::new(*key)))
.unwrap_or(std::ptr::null_mut())
}
#[no_mangle]
pub extern "C" fn orchard_spending_key_free(key: *mut SpendingKey) {
if !key.is_null() {
drop(unsafe { Box::from_raw(key) });
}
}
#[no_mangle]
pub extern "C" fn orchard_spending_key_parse(
stream: Option<StreamObj>,
read_cb: Option<ReadCb>,
) -> *mut SpendingKey {
let mut reader = CppStreamReader::from_raw_parts(stream, read_cb.unwrap());
let mut buf = [0u8; 32];
match reader.read_exact(&mut buf) {
Err(e) => {
error!(
"Stream failure reading bytes of Orchard spending key: {}",
e
);
std::ptr::null_mut()
}
Ok(()) => {
let sk_opt = SpendingKey::from_bytes(buf);
if sk_opt.is_some().into() {
Box::into_raw(Box::new(sk_opt.unwrap()))
} else {
error!("Failed to parse Orchard spending key.");
std::ptr::null_mut()
}
}
}
}
#[no_mangle]
pub extern "C" fn orchard_spending_key_serialize(
key: *const SpendingKey,
stream: Option<StreamObj>,
write_cb: Option<WriteCb>,
) -> bool {
let key = unsafe {
key.as_ref()
.expect("Orchard spending key pointer may not be null.")
};
let mut writer = CppStreamWriter::from_raw_parts(stream, write_cb.unwrap());
match writer.write_all(key.to_bytes()) {
Ok(()) => true,
Err(e) => {
error!("Stream failure writing Orchard spending key: {}", e);
false
}
}
}
#[no_mangle]
pub extern "C" fn orchard_spending_key_to_full_viewing_key(
key: *const SpendingKey,
) -> *mut FullViewingKey {
unsafe { key.as_ref() }
.map(|key| Box::into_raw(Box::new(FullViewingKey::from(key))))
.unwrap_or(std::ptr::null_mut())
}
#[no_mangle]
pub extern "C" fn orchard_spending_key_eq(k0: *const SpendingKey, k1: *const SpendingKey) -> bool {
let k0 = unsafe { k0.as_ref() };
let k1 = unsafe { k1.as_ref() };
k0 == k1
}

View File

@ -72,6 +72,7 @@ mod address_ffi;
mod history_ffi;
mod incremental_merkle_tree_ffi;
mod orchard_ffi;
mod orchard_keys_ffi;
mod transaction_ffi;
mod zip339_ffi;

View File

@ -0,0 +1,46 @@
// 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 <gtest/gtest.h>
#include "zcash/address/orchard.hpp"
TEST(OrchardZkeysTest, IVKSerializationRoundtrip) {
auto seed = MnemonicSeed::Random(1); //testnet coin type
auto sk = libzcash::OrchardSpendingKey::ForAccount(seed, 1, 0);
auto fvk = sk.ToFullViewingKey();
auto ivk = fvk.ToIncomingViewingKey();
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << ivk;
auto ivk0 = libzcash::OrchardIncomingViewingKey::Read(ss);
ASSERT_EQ(ivk, ivk0);
}
TEST(OrchardZkeysTest, FVKSerializationRoundtrip) {
auto seed = MnemonicSeed::Random(1); //testnet coin type
auto sk = libzcash::OrchardSpendingKey::ForAccount(seed, 1, 0);
auto fvk = sk.ToFullViewingKey();
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << fvk;
auto fvk0 = libzcash::OrchardFullViewingKey::Read(ss);
ASSERT_EQ(fvk, fvk0);
}
TEST(OrchardZkeysTest, SKSerializationRoundtrip) {
auto seed = MnemonicSeed::Random(1); //testnet coin type
auto sk = libzcash::OrchardSpendingKey::ForAccount(seed, 1, 0);
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << sk;
auto sk0 = libzcash::OrchardSpendingKey::Read(ss);
ASSERT_EQ(sk, sk0);
}

View File

@ -2,6 +2,7 @@
#define ZC_ADDRESS_H_
#include "uint256.h"
#include "zcash/address/orchard.hpp"
#include "zcash/address/sapling.hpp"
#include "zcash/address/sprout.hpp"
#include "zcash/address/zip32.h"

View File

@ -0,0 +1,40 @@
// 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 "zcash/address/orchard.hpp"
namespace libzcash {
OrchardRawAddress OrchardIncomingViewingKey::Address(const diversifier_index_t& j) const {
return OrchardRawAddress(orchard_incoming_viewing_key_to_address(inner.get(), j.begin()));
}
OrchardIncomingViewingKey OrchardFullViewingKey::ToIncomingViewingKey() const {
return OrchardIncomingViewingKey(orchard_full_viewing_key_to_incoming_viewing_key(inner.get()));
}
OrchardSpendingKey OrchardSpendingKey::ForAccount(
const HDSeed& seed,
uint32_t bip44CoinType,
libzcash::AccountId accountId) {
auto ptr = orchard_spending_key_for_account(
seed.RawSeed().data(),
seed.RawSeed().size(),
bip44CoinType,
accountId);
if (ptr == nullptr) {
throw std::ios_base::failure("Unable to generate Orchard extended spending key.");
}
return OrchardSpendingKey(ptr);
}
OrchardFullViewingKey OrchardSpendingKey::ToFullViewingKey() const {
return OrchardFullViewingKey(orchard_spending_key_to_full_viewing_key(inner.get()));
}
} //namespace libzcash

View File

@ -0,0 +1,262 @@
// 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_ADDRESS_ORCHARD_H
#define ZCASH_ADDRESS_ORCHARD_H
#include "streams.h"
#include "zcash/address/zip32.h"
#include <rust/orchard/keys.h>
namespace libzcash {
class OrchardIncomingViewingKey;
class OrchardRawAddress
{
private:
std::unique_ptr<OrchardRawAddressPtr, decltype(&orchard_address_free)> inner;
OrchardRawAddress() : inner(nullptr, orchard_address_free) {}
OrchardRawAddress(OrchardRawAddressPtr* ptr) : inner(ptr, orchard_address_free) {}
friend class OrchardIncomingViewingKey;
public:
OrchardRawAddress(OrchardRawAddress&& key) : inner(std::move(key.inner)) {}
OrchardRawAddress(const OrchardRawAddress& key) :
inner(orchard_address_clone(key.inner.get()), orchard_address_free) {}
OrchardRawAddress& operator=(OrchardRawAddress&& key)
{
if (this != &key) {
inner = std::move(key.inner);
}
return *this;
}
OrchardRawAddress& operator=(const OrchardRawAddress& key)
{
if (this != &key) {
inner.reset(orchard_address_clone(key.inner.get()));
}
return *this;
}
};
class OrchardFullViewingKey;
class OrchardIncomingViewingKey
{
private:
std::unique_ptr<OrchardIncomingViewingKeyPtr, decltype(&orchard_incoming_viewing_key_free)> inner;
OrchardIncomingViewingKey() : inner(nullptr, orchard_incoming_viewing_key_free) {}
OrchardIncomingViewingKey(OrchardIncomingViewingKeyPtr* key) :
inner(key, orchard_incoming_viewing_key_free) {}
friend class OrchardFullViewingKey;
public:
OrchardIncomingViewingKey(OrchardIncomingViewingKey&& key) : inner(std::move(key.inner)) {}
OrchardIncomingViewingKey(const OrchardIncomingViewingKey& key) :
inner(orchard_incoming_viewing_key_clone(key.inner.get()), orchard_incoming_viewing_key_free) {}
OrchardRawAddress Address(const diversifier_index_t& j) const;
OrchardIncomingViewingKey& operator=(OrchardIncomingViewingKey&& key)
{
if (this != &key) {
inner = std::move(key.inner);
}
return *this;
}
OrchardIncomingViewingKey& operator=(const OrchardIncomingViewingKey& key)
{
if (this != &key) {
inner.reset(orchard_incoming_viewing_key_clone(key.inner.get()));
}
return *this;
}
friend bool operator==(const OrchardIncomingViewingKey& a, const OrchardIncomingViewingKey& b)
{
return orchard_incoming_viewing_key_eq(a.inner.get(), b.inner.get());
}
friend bool operator<(const OrchardIncomingViewingKey& c1, const OrchardIncomingViewingKey& c2) {
return orchard_incoming_viewing_key_lt(c1.inner.get(), c2.inner.get());
}
template<typename Stream>
void Serialize(Stream& s) const {
RustStream rs(s);
if (!orchard_incoming_viewing_key_serialize(inner.get(), &rs, RustStream<Stream>::write_callback)) {
throw std::ios_base::failure("Failed to serialize Orchard incoming viewing key");
}
}
template<typename Stream>
void Unserialize(Stream& s) {
RustStream rs(s);
OrchardIncomingViewingKeyPtr* key = orchard_incoming_viewing_key_parse(&rs, RustStream<Stream>::read_callback);
if (key == nullptr) {
throw std::ios_base::failure("Failed to parse Orchard incoming viewing key");
}
inner.reset(key);
}
template<typename Stream>
static OrchardIncomingViewingKey Read(Stream& stream) {
OrchardIncomingViewingKey key;
stream >> key;
return key;
}
};
class OrchardSpendingKey;
class OrchardFullViewingKey
{
private:
std::unique_ptr<OrchardFullViewingKeyPtr, decltype(&orchard_full_viewing_key_free)> inner;
OrchardFullViewingKey() : inner(nullptr, orchard_full_viewing_key_free) {}
OrchardFullViewingKey(OrchardFullViewingKeyPtr* ptr) :
inner(ptr, orchard_full_viewing_key_free) {}
friend class OrchardSpendingKey;
public:
OrchardFullViewingKey(OrchardFullViewingKey&& key) : inner(std::move(key.inner)) {}
OrchardFullViewingKey(const OrchardFullViewingKey& key) :
inner(orchard_full_viewing_key_clone(key.inner.get()), orchard_full_viewing_key_free) {}
OrchardFullViewingKey& operator=(OrchardFullViewingKey&& key)
{
if (this != &key) {
inner = std::move(key.inner);
}
return *this;
}
OrchardFullViewingKey& operator=(const OrchardFullViewingKey& key)
{
if (this != &key) {
inner.reset(orchard_full_viewing_key_clone(key.inner.get()));
}
return *this;
}
friend bool operator==(const OrchardFullViewingKey& a, const OrchardFullViewingKey& b)
{
return orchard_full_viewing_key_eq(a.inner.get(), b.inner.get());
}
template<typename Stream>
void Serialize(Stream& s) const {
RustStream rs(s);
if (!orchard_full_viewing_key_serialize(inner.get(), &rs, RustStream<Stream>::write_callback)) {
throw std::ios_base::failure("Failed to serialize Orchard full viewing key");
}
}
template<typename Stream>
void Unserialize(Stream& s) {
RustStream rs(s);
OrchardFullViewingKeyPtr* key = orchard_full_viewing_key_parse(&rs, RustStream<Stream>::read_callback);
if (key == nullptr) {
throw std::ios_base::failure("Failed to parse Orchard full viewing key");
}
inner.reset(key);
}
template<typename Stream>
static OrchardFullViewingKey Read(Stream& stream) {
OrchardFullViewingKey key;
stream >> key;
return key;
}
OrchardIncomingViewingKey ToIncomingViewingKey() const;
};
class OrchardSpendingKey
{
private:
std::unique_ptr<OrchardSpendingKeyPtr, decltype(&orchard_spending_key_free)> inner;
OrchardSpendingKey() : inner(nullptr, orchard_spending_key_free) {}
OrchardSpendingKey(OrchardSpendingKeyPtr* ptr) :
inner(ptr, orchard_spending_key_free) {}
public:
OrchardSpendingKey(OrchardSpendingKey&& key) : inner(std::move(key.inner)) {}
OrchardSpendingKey(const OrchardSpendingKey& key) :
inner(orchard_spending_key_clone(key.inner.get()), orchard_spending_key_free) {}
static OrchardSpendingKey ForAccount(
const HDSeed& seed,
uint32_t bip44CoinType,
libzcash::AccountId accountId);
OrchardSpendingKey& operator=(OrchardSpendingKey&& key)
{
if (this != &key) {
inner = std::move(key.inner);
}
return *this;
}
OrchardSpendingKey& operator=(const OrchardSpendingKey& key)
{
if (this != &key) {
inner.reset(orchard_spending_key_clone(key.inner.get()));
}
return *this;
}
friend bool operator==(const OrchardSpendingKey& a, const OrchardSpendingKey& b)
{
return orchard_spending_key_eq(a.inner.get(), b.inner.get());
}
template<typename Stream>
void Serialize(Stream& s) const {
RustStream rs(s);
if (!orchard_spending_key_serialize(inner.get(), &rs, RustStream<Stream>::write_callback)) {
throw std::ios_base::failure("Failed to serialize Orchard spending key");
}
}
template<typename Stream>
void Unserialize(Stream& s) {
RustStream rs(s);
OrchardSpendingKeyPtr* key = orchard_spending_key_parse(&rs, RustStream<Stream>::read_callback);
if (key == nullptr) {
throw std::ios_base::failure("Failed to parse Orchard spending key");
}
inner.reset(key);
}
template<typename Stream>
static OrchardSpendingKey Read(Stream& stream) {
OrchardSpendingKey key;
stream >> key;
return key;
}
OrchardFullViewingKey ToFullViewingKey() const;
};
} // namespace libzcash
#endif // ZCASH_ADDRESS_ORCHARD_H