Browse Source

Add Sapling key classes to wallet, with new librustzcash APIs

pull/4/head
Jay Graber 6 years ago
parent
commit
11acfe6e9f
  1. 39
      src/zcash/Address.cpp
  2. 112
      src/zcash/Address.hpp
  3. 72
      src/zcash/prf.cpp
  4. 8
      src/zcash/prf.h

39
src/zcash/Address.cpp

@ -4,6 +4,8 @@
#include "prf.h"
#include "streams.h"
#include <librustzcash.h>
namespace libzcash {
uint256 SproutPaymentAddress::GetHash() const {
@ -36,6 +38,43 @@ SproutPaymentAddress SproutSpendingKey::address() const {
return viewing_key().address();
}
//! Sapling
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();
}
SaplingInViewingKey SaplingFullViewingKey::in_viewing_key() const {
uint256 ivk;
librustzcash_crh_ivk(ak.begin(), nk.begin(), ivk.begin());
return SaplingInViewingKey(ivk);
}
SaplingSpendingKey SaplingSpendingKey::random() {
return SaplingSpendingKey(random_uint256());
}
SaplingPaymentAddress SaplingInViewingKey::address(diversifier_t d) const {
uint256 pk_d;
librustzcash_ivk_to_pkd(this->begin(), d.data(), pk_d.begin());
return SaplingPaymentAddress(d, pk_d);
}
SaplingPaymentAddress SaplingSpendingKey::default_address() const {
return full_viewing_key().in_viewing_key().address(default_diversifier(*this));
}
}

112
src/zcash/Address.hpp

@ -18,6 +18,8 @@ const size_t SerializedPaymentAddressSize = 64;
const size_t SerializedViewingKeySize = 64;
const size_t SerializedSpendingKeySize = 32;
typedef std::array<unsigned char, 11> diversifier_t;
class SproutPaymentAddress {
public:
uint256 a_pk;
@ -97,6 +99,116 @@ typedef boost::variant<InvalidEncoding, SproutPaymentAddress> PaymentAddress;
typedef boost::variant<InvalidEncoding, SproutViewingKey> ViewingKey;
typedef boost::variant<InvalidEncoding, SproutSpendingKey> SpendingKey;
//! 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);
}
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 SaplingInViewingKey : public uint256 {
public:
SaplingInViewingKey() : uint256() { }
SaplingInViewingKey(uint256 ivk) : uint256(ivk) { }
// Can pass in diversifier for Sapling addr
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, int nType, int nVersion) {
READWRITE(ak);
READWRITE(nk);
READWRITE(ovk);
}
SaplingInViewingKey in_viewing_key() 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, int nType, int nVersion) {
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;
};
}
/** Check whether a PaymentAddress is not an InvalidEncoding. */

72
src/zcash/prf.cpp

@ -1,6 +1,78 @@
#include "prf.h"
#include "crypto/sha256.h"
#include "hash.h"
#include <array>
#include <librustzcash.h>
const unsigned char ZCASH_EXPANDSEED_PERSONALIZATION[crypto_generichash_blake2b_PERSONALBYTES] = {'Z','c','a','s','h','_','E','x','p','a','n','d','S','e','e','d'};
// Sapling
std::array<unsigned char, 64> PRF_expand(const uint256& x, unsigned char t)
{
std::array<unsigned char, 64> res;
unsigned char blob[33];
memcpy(&blob[0], x.begin(), 32);
blob[32] = t;
crypto_generichash_blake2b_state state;
crypto_generichash_blake2b_init_salt_personal(&state, nullptr, 0, 64, nullptr, ZCASH_EXPANDSEED_PERSONALIZATION);
crypto_generichash_blake2b_update(&state, blob, 33);
crypto_generichash_blake2b_final(&state, res.data(), 64);
return res;
}
uint256 PRF_ask(const uint256& sk)
{
uint256 ask;
auto tmp = PRF_expand(sk, 0);
librustzcash_to_scalar(tmp.data(), ask.begin());
return ask;
}
uint256 PRF_nsk(const uint256& sk)
{
uint256 nsk;
auto tmp = PRF_expand(sk, 1);
librustzcash_to_scalar(tmp.data(), nsk.begin());
return nsk;
}
uint256 PRF_ovk(const uint256& sk)
{
uint256 ovk;
auto tmp = PRF_expand(sk, 2);
memcpy(ovk.begin(), tmp.data(), 32);
return ovk;
}
std::array<unsigned char, 11> default_diversifier(const uint256& sk)
{
std::array<unsigned char, 11> res;
unsigned char blob[34];
memcpy(&blob[0], sk.begin(), 32);
blob[32] = 3;
blob[33] = 0;
while (true) {
crypto_generichash_blake2b_state state;
crypto_generichash_blake2b_init_salt_personal(&state, nullptr, 0, 64, nullptr, ZCASH_EXPANDSEED_PERSONALIZATION);
crypto_generichash_blake2b_update(&state, blob, 33);
crypto_generichash_blake2b_final(&state, res.data(), 11);
if (librustzcash_check_diversifier(res.data())) {
break;
}
blob[33] += 1;
}
return res;
}
// Sprout
uint256 PRF(bool a, bool b, bool c, bool d,
const uint252& x,
const uint256& y)

8
src/zcash/prf.h

@ -9,6 +9,14 @@ within the zkSNARK circuit.
#include "uint256.h"
#include "uint252.h"
#include <array>
uint256 PRF_ask(const uint256& sk);
uint256 PRF_nsk(const uint256& sk);
uint256 PRF_ovk(const uint256& sk);
std::array<unsigned char, 11> default_diversifier(const uint256& sk);
uint256 PRF_addr_a_pk(const uint252& a_sk);
uint256 PRF_addr_sk_enc(const uint252& a_sk);
uint256 PRF_nf(const uint252& a_sk, const uint256& rho);

Loading…
Cancel
Save