sync jl777:FSM

This commit is contained in:
ca333
2018-12-01 23:39:10 +01:00
parent f4bb3a2861
commit 492d6703ed
393 changed files with 43240 additions and 8042 deletions

View File

@@ -4,9 +4,16 @@
#include "prf.h"
#include "streams.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'};
const uint32_t SAPLING_BRANCH_ID = 0x76b809bb;
namespace libzcash {
uint256 PaymentAddress::GetHash() const {
uint256 SproutPaymentAddress::GetHash() const {
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << *this;
return Hash(ss.begin(), ss.end());
@@ -16,24 +23,122 @@ uint256 ReceivingKey::pk_enc() const {
return ZCNoteEncryption::generate_pubkey(*this);
}
PaymentAddress ViewingKey::address() const {
return PaymentAddress(a_pk, sk_enc.pk_enc());
SproutPaymentAddress SproutViewingKey::address() const {
return SproutPaymentAddress(a_pk, sk_enc.pk_enc());
}
ReceivingKey SpendingKey::receiving_key() const {
ReceivingKey SproutSpendingKey::receiving_key() const {
return ReceivingKey(ZCNoteEncryption::generate_privkey(*this));
}
ViewingKey SpendingKey::viewing_key() const {
return ViewingKey(PRF_addr_a_pk(*this), receiving_key());
SproutViewingKey SproutSpendingKey::viewing_key() const {
return SproutViewingKey(PRF_addr_a_pk(*this), receiving_key());
}
SpendingKey SpendingKey::random() {
return SpendingKey(random_uint252());
SproutSpendingKey SproutSpendingKey::random() {
return SproutSpendingKey(random_uint252());
}
PaymentAddress SpendingKey::address() const {
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();
}
}
class IsValidAddressForNetwork : public boost::static_visitor<bool> {
private:
uint32_t branchId;
public:
IsValidAddressForNetwork(uint32_t consensusBranchId) : branchId(consensusBranchId) {}
bool operator()(const libzcash::SproutPaymentAddress &addr) const {
return true;
}
bool operator()(const libzcash::InvalidEncoding &addr) const {
return false;
}
bool operator()(const libzcash::SaplingPaymentAddress &addr) const {
if (SAPLING_BRANCH_ID == branchId)
return true;
else
return false;
}
};
bool IsValidPaymentAddress(const libzcash::PaymentAddress& zaddr, uint32_t consensusBranchId) {
return boost::apply_visitor(IsValidAddressForNetwork(consensusBranchId), zaddr);
}
bool IsValidViewingKey(const libzcash::ViewingKey& vk) {
return vk.which() != 0;
}

View File

@@ -4,25 +4,40 @@
#include "uint256.h"
#include "uint252.h"
#include "serialize.h"
#include "Zcash.h"
#include <boost/variant.hpp>
namespace libzcash {
class InvalidEncoding {
public:
friend bool operator==(const InvalidEncoding &a, const InvalidEncoding &b) { return true; }
friend bool operator<(const InvalidEncoding &a, const InvalidEncoding &b) { return true; }
};
const size_t SerializedPaymentAddressSize = 64;
const size_t SerializedViewingKeySize = 64;
const size_t SerializedSpendingKeySize = 32;
const size_t SerializedSproutPaymentAddressSize = 64;
const size_t SerializedSproutViewingKeySize = 64;
const size_t SerializedSproutSpendingKeySize = 32;
class PaymentAddress {
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;
PaymentAddress() : a_pk(), pk_enc() { }
PaymentAddress(uint256 a_pk, uint256 pk_enc) : a_pk(a_pk), pk_enc(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, int nType, int nVersion) {
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(a_pk);
READWRITE(pk_enc);
}
@@ -30,10 +45,10 @@ public:
//! Get the 256-bit SHA256d hash of this payment address.
uint256 GetHash() const;
friend inline bool operator==(const PaymentAddress& a, const PaymentAddress& b) {
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 PaymentAddress& a, const PaymentAddress& b) {
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));
}
@@ -47,45 +62,172 @@ public:
uint256 pk_enc() const;
};
class ViewingKey {
class SproutViewingKey {
public:
uint256 a_pk;
ReceivingKey sk_enc;
ViewingKey() : a_pk(), sk_enc() { }
ViewingKey(uint256 a_pk, ReceivingKey sk_enc) : a_pk(a_pk), sk_enc(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, int nType, int nVersion) {
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(a_pk);
READWRITE(sk_enc);
}
PaymentAddress address() const;
SproutPaymentAddress address() const;
friend inline bool operator==(const ViewingKey& a, const ViewingKey& b) {
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 ViewingKey& a, const ViewingKey& b) {
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 SpendingKey : public uint252 {
class SproutSpendingKey : public uint252 {
public:
SpendingKey() : uint252() { }
SpendingKey(uint252 a_sk) : uint252(a_sk) { }
SproutSpendingKey() : uint252() { }
SproutSpendingKey(uint252 a_sk) : uint252(a_sk) { }
static SpendingKey random();
static SproutSpendingKey random();
ReceivingKey receiving_key() const;
ViewingKey viewing_key() const;
PaymentAddress address() 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;
}
/** Check whether a PaymentAddress is not an InvalidEncoding. */
extern const uint32_t SAPLING_BRANCH_ID;
bool IsValidPaymentAddress(const libzcash::PaymentAddress& zaddr, uint32_t consensusBranchId = SAPLING_BRANCH_ID);
/** Check whether a ViewingKey is not an InvalidEncoding. */
bool IsValidViewingKey(const libzcash::ViewingKey& vk);
#endif // ZC_ADDRESS_H_

View File

@@ -9,7 +9,6 @@
#include "libsnark/common/profiling.hpp"
#include "komodo_defs.h"
char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN];
int64_t MAX_MONEY = 200000000 * 100000000LL;
uint16_t BITCOIND_RPCPORT = 7771;
uint32_t ASSETCHAINS_CC = 0;

View File

@@ -5,10 +5,41 @@
#include "zcash/IncrementalMerkleTree.hpp"
#include "crypto/sha256.h"
#include "zcash/util.h"
#include "librustzcash.h"
namespace libzcash {
SHA256Compress SHA256Compress::combine(const SHA256Compress& a, const SHA256Compress& b)
PedersenHash PedersenHash::combine(
const PedersenHash& a,
const PedersenHash& b,
size_t depth
)
{
PedersenHash res = PedersenHash();
librustzcash_merkle_hash(
depth,
a.begin(),
b.begin(),
res.begin()
);
return res;
}
PedersenHash PedersenHash::uncommitted() {
PedersenHash res = PedersenHash();
librustzcash_tree_uncommitted(res.begin());
return res;
}
SHA256Compress SHA256Compress::combine(
const SHA256Compress& a,
const SHA256Compress& b,
size_t depth
)
{
SHA256Compress res = SHA256Compress();
@@ -45,9 +76,6 @@ public:
template<size_t Depth, typename Hash>
EmptyMerkleRoots<Depth, Hash> PathFiller<Depth, Hash>::emptyroots;
template<size_t Depth, typename Hash>
EmptyMerkleRoots<Depth, Hash> IncrementalMerkleTree<Depth, Hash>::emptyroots;
template<size_t Depth, typename Hash>
void IncrementalMerkleTree<Depth, Hash>::wfcheck() const {
if (parents.size() >= Depth) {
@@ -114,7 +142,7 @@ void IncrementalMerkleTree<Depth, Hash>::append(Hash obj) {
right = obj;
} else {
// Combine the leaves and propagate it up the tree
boost::optional<Hash> combined = Hash::combine(*left, *right);
boost::optional<Hash> combined = Hash::combine(*left, *right, 0);
// Set the "left" leaf to the object and make the "right" leaf none
left = obj;
@@ -123,7 +151,7 @@ void IncrementalMerkleTree<Depth, Hash>::append(Hash obj) {
for (size_t i = 0; i < Depth; i++) {
if (i < parents.size()) {
if (parents[i]) {
combined = Hash::combine(*parents[i], *combined);
combined = Hash::combine(*parents[i], *combined, i+1);
parents[i] = boost::none;
} else {
parents[i] = *combined;
@@ -205,15 +233,15 @@ Hash IncrementalMerkleTree<Depth, Hash>::root(size_t depth,
Hash combine_left = left ? *left : filler.next(0);
Hash combine_right = right ? *right : filler.next(0);
Hash root = Hash::combine(combine_left, combine_right);
Hash root = Hash::combine(combine_left, combine_right, 0);
size_t d = 1;
BOOST_FOREACH(const boost::optional<Hash>& parent, parents) {
if (parent) {
root = Hash::combine(*parent, root);
root = Hash::combine(*parent, root, d);
} else {
root = Hash::combine(root, filler.next(d));
root = Hash::combine(root, filler.next(d), d);
}
d++;
@@ -222,7 +250,7 @@ Hash IncrementalMerkleTree<Depth, Hash>::root(size_t depth,
// We may not have parents for ancestor trees, so we fill
// the rest in here.
while (d < depth) {
root = Hash::combine(root, filler.next(d));
root = Hash::combine(root, filler.next(d), d);
d++;
}
@@ -326,4 +354,10 @@ template class IncrementalMerkleTree<INCREMENTAL_MERKLE_TREE_DEPTH_TESTING, SHA2
template class IncrementalWitness<INCREMENTAL_MERKLE_TREE_DEPTH, SHA256Compress>;
template class IncrementalWitness<INCREMENTAL_MERKLE_TREE_DEPTH_TESTING, SHA256Compress>;
template class IncrementalMerkleTree<SAPLING_INCREMENTAL_MERKLE_TREE_DEPTH, PedersenHash>;
template class IncrementalMerkleTree<INCREMENTAL_MERKLE_TREE_DEPTH_TESTING, PedersenHash>;
template class IncrementalWitness<SAPLING_INCREMENTAL_MERKLE_TREE_DEPTH, PedersenHash>;
template class IncrementalWitness<INCREMENTAL_MERKLE_TREE_DEPTH_TESTING, PedersenHash>;
} // end namespace `libzcash`

View File

@@ -1,6 +1,7 @@
#ifndef ZC_INCREMENTALMERKLETREE_H_
#define ZC_INCREMENTALMERKLETREE_H_
#include <array>
#include <deque>
#include <boost/optional.hpp>
#include <boost/static_assert.hpp>
@@ -9,6 +10,7 @@
#include "serialize.h"
#include "Zcash.h"
#include "zcash/util.h"
namespace libzcash {
@@ -20,9 +22,30 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
READWRITE(authentication_path);
READWRITE(index);
inline void SerializationOp(Stream& s, Operation ser_action) {
std::vector<std::vector<unsigned char>> pathBytes;
uint64_t indexInt;
if (ser_action.ForRead()) {
READWRITE(pathBytes);
READWRITE(indexInt);
MerklePath &us = *(const_cast<MerklePath*>(this));
for (size_t i = 0; i < pathBytes.size(); i++) {
us.authentication_path.push_back(convertBytesVectorToVector(pathBytes[i]));
us.index.push_back((indexInt >> ((pathBytes.size() - 1) - i)) & 1);
}
} else {
assert(authentication_path.size() == index.size());
pathBytes.resize(authentication_path.size());
for (size_t i = 0; i < authentication_path.size(); i++) {
pathBytes[i].resize((authentication_path[i].size()+7)/8);
for (unsigned int p = 0; p < authentication_path[i].size(); p++) {
pathBytes[i][p / 8] |= authentication_path[i][p] << (7-(p % 8));
}
}
indexInt = convertVectorToInt(index);
READWRITE(pathBytes);
READWRITE(indexInt);
}
}
MerklePath() { }
@@ -35,9 +58,9 @@ template<size_t Depth, typename Hash>
class EmptyMerkleRoots {
public:
EmptyMerkleRoots() {
empty_roots.at(0) = Hash();
empty_roots.at(0) = Hash::uncommitted();
for (size_t d = 1; d <= Depth; d++) {
empty_roots.at(d) = Hash::combine(empty_roots.at(d-1), empty_roots.at(d-1));
empty_roots.at(d) = Hash::combine(empty_roots.at(d-1), empty_roots.at(d-1), d-1);
}
}
Hash empty_root(size_t depth) {
@@ -47,7 +70,7 @@ public:
friend bool operator==(const EmptyMerkleRoots<D, H>& a,
const EmptyMerkleRoots<D, H>& b);
private:
boost::array<Hash, Depth+1> empty_roots;
std::array<Hash, Depth+1> empty_roots;
};
template<size_t Depth, typename Hash>
@@ -90,7 +113,7 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(left);
READWRITE(right);
READWRITE(parents);
@@ -147,6 +170,10 @@ public:
return tree.last();
}
uint64_t position() const {
return tree.size() - 1;
}
Hash root() const {
return tree.root(Depth, partial_path());
}
@@ -156,7 +183,7 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(tree);
READWRITE(filled);
READWRITE(cursor);
@@ -191,15 +218,46 @@ public:
SHA256Compress() : uint256() {}
SHA256Compress(uint256 contents) : uint256(contents) { }
static SHA256Compress combine(const SHA256Compress& a, const SHA256Compress& b);
static SHA256Compress combine(
const SHA256Compress& a,
const SHA256Compress& b,
size_t depth
);
static SHA256Compress uncommitted() {
return SHA256Compress();
}
};
class PedersenHash : public uint256 {
public:
PedersenHash() : uint256() {}
PedersenHash(uint256 contents) : uint256(contents) { }
static PedersenHash combine(
const PedersenHash& a,
const PedersenHash& b,
size_t depth
);
static PedersenHash uncommitted();
};
template<size_t Depth, typename Hash>
EmptyMerkleRoots<Depth, Hash> IncrementalMerkleTree<Depth, Hash>::emptyroots;
} // end namespace `libzcash`
typedef libzcash::IncrementalMerkleTree<INCREMENTAL_MERKLE_TREE_DEPTH, libzcash::SHA256Compress> ZCIncrementalMerkleTree;
typedef libzcash::IncrementalMerkleTree<INCREMENTAL_MERKLE_TREE_DEPTH_TESTING, libzcash::SHA256Compress> ZCTestingIncrementalMerkleTree;
typedef libzcash::IncrementalMerkleTree<INCREMENTAL_MERKLE_TREE_DEPTH, libzcash::SHA256Compress> SproutMerkleTree;
typedef libzcash::IncrementalMerkleTree<INCREMENTAL_MERKLE_TREE_DEPTH_TESTING, libzcash::SHA256Compress> SproutTestingMerkleTree;
typedef libzcash::IncrementalWitness<INCREMENTAL_MERKLE_TREE_DEPTH, libzcash::SHA256Compress> ZCIncrementalWitness;
typedef libzcash::IncrementalWitness<INCREMENTAL_MERKLE_TREE_DEPTH_TESTING, libzcash::SHA256Compress> ZCTestingIncrementalWitness;
typedef libzcash::IncrementalWitness<INCREMENTAL_MERKLE_TREE_DEPTH, libzcash::SHA256Compress> SproutWitness;
typedef libzcash::IncrementalWitness<INCREMENTAL_MERKLE_TREE_DEPTH_TESTING, libzcash::SHA256Compress> SproutTestingWitness;
typedef libzcash::IncrementalMerkleTree<SAPLING_INCREMENTAL_MERKLE_TREE_DEPTH, libzcash::PedersenHash> SaplingMerkleTree;
typedef libzcash::IncrementalMerkleTree<INCREMENTAL_MERKLE_TREE_DEPTH_TESTING, libzcash::PedersenHash> SaplingTestingMerkleTree;
typedef libzcash::IncrementalWitness<SAPLING_INCREMENTAL_MERKLE_TREE_DEPTH, libzcash::PedersenHash> SaplingWitness;
typedef libzcash::IncrementalWitness<INCREMENTAL_MERKLE_TREE_DEPTH_TESTING, libzcash::PedersenHash> SaplingTestingWitness;
#endif /* ZC_INCREMENTALMERKLETREE_H_ */

View File

@@ -19,14 +19,17 @@
#include "amount.h"
extern int64_t MAX_MONEY;
#include "librustzcash.h"
#include "streams.h"
#include "version.h"
using namespace libsnark;
namespace libzcash {
#include "zcash/circuit/gadget.tcc"
CCriticalSection cs_ParamsIO;
CCriticalSection cs_LoadKeys;
static CCriticalSection cs_ParamsIO;
template<typename T>
void saveToFile(const std::string path, T& obj) {
@@ -100,13 +103,13 @@ public:
}
bool verify(
const ZCProof& proof,
const PHGRProof& proof,
ProofVerifier& verifier,
const uint256& pubKeyHash,
const uint256& joinSplitPubKey,
const uint256& randomSeed,
const boost::array<uint256, NumInputs>& macs,
const boost::array<uint256, NumInputs>& nullifiers,
const boost::array<uint256, NumOutputs>& commitments,
const std::array<uint256, NumInputs>& macs,
const std::array<uint256, NumInputs>& nullifiers,
const std::array<uint256, NumOutputs>& commitments,
uint64_t vpub_old,
uint64_t vpub_new,
const uint256& rt
@@ -114,7 +117,7 @@ public:
try {
auto r1cs_proof = proof.to_libsnark_proof<r1cs_ppzksnark_proof<ppzksnark_ppT>>();
uint256 h_sig = this->h_sig(randomSeed, nullifiers, pubKeyHash);
uint256 h_sig = this->h_sig(randomSeed, nullifiers, joinSplitPubKey);
auto witness = joinsplit_gadget<FieldT, NumInputs, NumOutputs>::witness_map(
rt,
@@ -137,17 +140,18 @@ public:
}
}
ZCProof prove(
const boost::array<JSInput, NumInputs>& inputs,
const boost::array<JSOutput, NumOutputs>& outputs,
boost::array<Note, NumOutputs>& out_notes,
boost::array<ZCNoteEncryption::Ciphertext, NumOutputs>& out_ciphertexts,
SproutProof prove(
bool makeGrothProof,
const std::array<JSInput, NumInputs>& inputs,
const std::array<JSOutput, NumOutputs>& outputs,
std::array<SproutNote, NumOutputs>& out_notes,
std::array<ZCNoteEncryption::Ciphertext, NumOutputs>& out_ciphertexts,
uint256& out_ephemeralKey,
const uint256& pubKeyHash,
const uint256& joinSplitPubKey,
uint256& out_randomSeed,
boost::array<uint256, NumInputs>& out_macs,
boost::array<uint256, NumInputs>& out_nullifiers,
boost::array<uint256, NumOutputs>& out_commitments,
std::array<uint256, NumInputs>& out_macs,
std::array<uint256, NumInputs>& out_nullifiers,
std::array<uint256, NumOutputs>& out_commitments,
uint64_t vpub_old,
uint64_t vpub_new,
const uint256& rt,
@@ -169,7 +173,7 @@ public:
// Sanity checks of input
{
// If note has nonzero value
if (inputs[i].note.value != 0) {
if (inputs[i].note.value() != 0) {
// The witness root must equal the input root.
if (inputs[i].witness.root() != rt) {
throw std::invalid_argument("joinsplit not anchored to the correct root");
@@ -187,11 +191,11 @@ public:
}
// Balance must be sensical
if (inputs[i].note.value > MAX_MONEY) {
if (inputs[i].note.value() > MAX_MONEY) {
throw std::invalid_argument("nonsensical input note value");
}
lhs_value += inputs[i].note.value;
lhs_value += inputs[i].note.value();
if (lhs_value > MAX_MONEY) {
throw std::invalid_argument("nonsensical left hand size of joinsplit balance");
@@ -206,7 +210,7 @@ public:
out_randomSeed = random_uint256();
// Compute h_sig
uint256 h_sig = this->h_sig(out_randomSeed, out_nullifiers, pubKeyHash);
uint256 h_sig = this->h_sig(out_randomSeed, out_nullifiers, joinSplitPubKey);
// Sample phi
uint252 phi = random_uint252();
@@ -247,7 +251,7 @@ public:
ZCNoteEncryption encryptor(h_sig);
for (size_t i = 0; i < NumOutputs; i++) {
NotePlaintext pt(out_notes[i], outputs[i].memo);
SproutNotePlaintext pt(out_notes[i], outputs[i].memo);
out_ciphertexts[i] = pt.encrypt(encryptor, outputs[i].addr.pk_enc);
}
@@ -268,8 +272,57 @@ public:
out_macs[i] = PRF_pk(inputs[i].key, i, h_sig);
}
if (makeGrothProof) {
if (!computeProof) {
return GrothProof();
}
GrothProof proof;
CDataStream ss1(SER_NETWORK, PROTOCOL_VERSION);
ss1 << inputs[0].witness.path();
std::vector<unsigned char> auth1(ss1.begin(), ss1.end());
CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
ss2 << inputs[1].witness.path();
std::vector<unsigned char> auth2(ss2.begin(), ss2.end());
librustzcash_sprout_prove(
proof.begin(),
phi.begin(),
rt.begin(),
h_sig.begin(),
inputs[0].key.begin(),
inputs[0].note.value(),
inputs[0].note.rho.begin(),
inputs[0].note.r.begin(),
auth1.data(),
inputs[1].key.begin(),
inputs[1].note.value(),
inputs[1].note.rho.begin(),
inputs[1].note.r.begin(),
auth2.data(),
out_notes[0].a_pk.begin(),
out_notes[0].value(),
out_notes[0].r.begin(),
out_notes[1].a_pk.begin(),
out_notes[1].value(),
out_notes[1].r.begin(),
vpub_old,
vpub_new
);
return proof;
}
if (!computeProof) {
return ZCProof();
return PHGRProof();
}
protoboard<FieldT> pb;
@@ -307,7 +360,7 @@ public:
throw std::runtime_error(strprintf("could not load param file at %s", pkPath));
}
return ZCProof(r1cs_ppzksnark_prover_streaming<ppzksnark_ppT>(
return PHGRProof(r1cs_ppzksnark_prover_streaming<ppzksnark_ppT>(
fh,
primary_input,
aux_input,
@@ -336,8 +389,8 @@ JoinSplit<NumInputs, NumOutputs>* JoinSplit<NumInputs, NumOutputs>::Prepared(con
template<size_t NumInputs, size_t NumOutputs>
uint256 JoinSplit<NumInputs, NumOutputs>::h_sig(
const uint256& randomSeed,
const boost::array<uint256, NumInputs>& nullifiers,
const uint256& pubKeyHash
const std::array<uint256, NumInputs>& nullifiers,
const uint256& joinSplitPubKey
) {
const unsigned char personalization[crypto_generichash_blake2b_PERSONALBYTES]
= {'Z','c','a','s','h','C','o','m','p','u','t','e','h','S','i','g'};
@@ -348,7 +401,7 @@ uint256 JoinSplit<NumInputs, NumOutputs>::h_sig(
block.insert(block.end(), nullifiers[i].begin(), nullifiers[i].end());
}
block.insert(block.end(), pubKeyHash.begin(), pubKeyHash.end());
block.insert(block.end(), joinSplitPubKey.begin(), joinSplitPubKey.end());
uint256 output;
@@ -365,21 +418,21 @@ uint256 JoinSplit<NumInputs, NumOutputs>::h_sig(
return output;
}
Note JSOutput::note(const uint252& phi, const uint256& r, size_t i, const uint256& h_sig) const {
SproutNote JSOutput::note(const uint252& phi, const uint256& r, size_t i, const uint256& h_sig) const {
uint256 rho = PRF_rho(phi, i, h_sig);
return Note(addr.a_pk, value, rho, r);
return SproutNote(addr.a_pk, value, rho, r);
}
JSOutput::JSOutput() : addr(uint256(), uint256()), value(0) {
SpendingKey a_sk = SpendingKey::random();
SproutSpendingKey a_sk = SproutSpendingKey::random();
addr = a_sk.address();
}
JSInput::JSInput() : witness(ZCIncrementalMerkleTree().witness()),
key(SpendingKey::random()) {
note = Note(key.address().a_pk, 0, random_uint256(), random_uint256());
ZCIncrementalMerkleTree dummy_tree;
JSInput::JSInput() : witness(SproutMerkleTree().witness()),
key(SproutSpendingKey::random()) {
note = SproutNote(key.address().a_pk, 0, random_uint256(), random_uint256());
SproutMerkleTree dummy_tree;
dummy_tree.append(note.cm());
witness = dummy_tree.witness();
}

View File

@@ -11,20 +11,28 @@
#include "uint256.h"
#include "uint252.h"
#include <boost/array.hpp>
#include <array>
namespace libzcash {
static constexpr size_t GROTH_PROOF_SIZE = (
48 + // π_A
96 + // π_B
48); // π_C
typedef std::array<unsigned char, GROTH_PROOF_SIZE> GrothProof;
typedef boost::variant<PHGRProof, GrothProof> SproutProof;
class JSInput {
public:
ZCIncrementalWitness witness;
Note note;
SpendingKey key;
SproutWitness witness;
SproutNote note;
SproutSpendingKey key;
JSInput();
JSInput(ZCIncrementalWitness witness,
Note note,
SpendingKey key) : witness(witness), note(note), key(key) { }
JSInput(SproutWitness witness,
SproutNote note,
SproutSpendingKey key) : witness(witness), note(note), key(key) { }
uint256 nullifier() const {
return note.nullifier(key);
@@ -33,14 +41,14 @@ public:
class JSOutput {
public:
PaymentAddress addr;
SproutPaymentAddress addr;
uint64_t value;
boost::array<unsigned char, ZC_MEMO_SIZE> memo = {{0xF6}}; // 0xF6 is invalid UTF8 as per spec, rest of array is 0x00
std::array<unsigned char, ZC_MEMO_SIZE> memo = {{0xF6}}; // 0xF6 is invalid UTF8 as per spec, rest of array is 0x00
JSOutput();
JSOutput(PaymentAddress addr, uint64_t value) : addr(addr), value(value) { }
JSOutput(SproutPaymentAddress addr, uint64_t value) : addr(addr), value(value) { }
Note note(const uint252& phi, const uint256& r, size_t i, const uint256& h_sig) const;
SproutNote note(const uint252& phi, const uint256& r, size_t i, const uint256& h_sig) const;
};
template<size_t NumInputs, size_t NumOutputs>
@@ -55,21 +63,23 @@ public:
const std::string pkPath);
static uint256 h_sig(const uint256& randomSeed,
const boost::array<uint256, NumInputs>& nullifiers,
const uint256& pubKeyHash
const std::array<uint256, NumInputs>& nullifiers,
const uint256& joinSplitPubKey
);
virtual ZCProof prove(
const boost::array<JSInput, NumInputs>& inputs,
const boost::array<JSOutput, NumOutputs>& outputs,
boost::array<Note, NumOutputs>& out_notes,
boost::array<ZCNoteEncryption::Ciphertext, NumOutputs>& out_ciphertexts,
// Compute nullifiers, macs, note commitments & encryptions, and SNARK proof
virtual SproutProof prove(
bool makeGrothProof,
const std::array<JSInput, NumInputs>& inputs,
const std::array<JSOutput, NumOutputs>& outputs,
std::array<SproutNote, NumOutputs>& out_notes,
std::array<ZCNoteEncryption::Ciphertext, NumOutputs>& out_ciphertexts,
uint256& out_ephemeralKey,
const uint256& pubKeyHash,
const uint256& joinSplitPubKey,
uint256& out_randomSeed,
boost::array<uint256, NumInputs>& out_hmacs,
boost::array<uint256, NumInputs>& out_nullifiers,
boost::array<uint256, NumOutputs>& out_commitments,
std::array<uint256, NumInputs>& out_hmacs,
std::array<uint256, NumInputs>& out_nullifiers,
std::array<uint256, NumOutputs>& out_commitments,
uint64_t vpub_old,
uint64_t vpub_new,
const uint256& rt,
@@ -81,13 +91,13 @@ public:
) = 0;
virtual bool verify(
const ZCProof& proof,
const PHGRProof& proof,
ProofVerifier& verifier,
const uint256& pubKeyHash,
const uint256& joinSplitPubKey,
const uint256& randomSeed,
const boost::array<uint256, NumInputs>& hmacs,
const boost::array<uint256, NumInputs>& nullifiers,
const boost::array<uint256, NumOutputs>& commitments,
const std::array<uint256, NumInputs>& hmacs,
const std::array<uint256, NumInputs>& nullifiers,
const std::array<uint256, NumOutputs>& commitments,
uint64_t vpub_old,
uint64_t vpub_new,
const uint256& rt

View File

@@ -2,28 +2,29 @@
#include "prf.h"
#include "crypto/sha256.h"
#include "random.h"
#include "version.h"
#include "streams.h"
#include "zcash/util.h"
#include "librustzcash.h"
namespace libzcash {
using namespace libzcash;
Note::Note() {
SproutNote::SproutNote() {
a_pk = random_uint256();
rho = random_uint256();
r = random_uint256();
value = 0;
}
uint256 Note::cm() const {
uint256 SproutNote::cm() const {
unsigned char discriminant = 0xb0;
CSHA256 hasher;
hasher.Write(&discriminant, 1);
hasher.Write(a_pk.begin(), 32);
auto value_vec = convertIntToVectorLE(value);
auto value_vec = convertIntToVectorLE(value_);
hasher.Write(&value_vec[0], value_vec.size());
hasher.Write(rho.begin(), 32);
@@ -35,25 +36,72 @@ uint256 Note::cm() const {
return result;
}
uint256 Note::nullifier(const SpendingKey& a_sk) const {
uint256 SproutNote::nullifier(const SproutSpendingKey& a_sk) const {
return PRF_nf(a_sk, rho);
}
NotePlaintext::NotePlaintext(
const Note& note,
boost::array<unsigned char, ZC_MEMO_SIZE> memo) : memo(memo)
// Construct and populate Sapling note for a given payment address and value.
SaplingNote::SaplingNote(const SaplingPaymentAddress& address, const uint64_t value) : BaseNote(value) {
d = address.d;
pk_d = address.pk_d;
librustzcash_sapling_generate_r(r.begin());
}
// Call librustzcash to compute the commitment
boost::optional<uint256> SaplingNote::cm() const {
uint256 result;
if (!librustzcash_sapling_compute_cm(
d.data(),
pk_d.begin(),
value(),
r.begin(),
result.begin()
))
{
return boost::none;
}
return result;
}
// Call librustzcash to compute the nullifier
boost::optional<uint256> SaplingNote::nullifier(const SaplingFullViewingKey& vk, const uint64_t position) const
{
auto ak = vk.ak;
auto nk = vk.nk;
uint256 result;
if (!librustzcash_sapling_compute_nf(
d.data(),
pk_d.begin(),
value(),
r.begin(),
ak.begin(),
nk.begin(),
position,
result.begin()
))
{
return boost::none;
}
return result;
}
SproutNotePlaintext::SproutNotePlaintext(
const SproutNote& note,
std::array<unsigned char, ZC_MEMO_SIZE> memo) : BaseNotePlaintext(note, memo)
{
value = note.value;
rho = note.rho;
r = note.r;
}
Note NotePlaintext::note(const PaymentAddress& addr) const
SproutNote SproutNotePlaintext::note(const SproutPaymentAddress& addr) const
{
return Note(addr.a_pk, value, rho, r);
return SproutNote(addr.a_pk, value_, rho, r);
}
NotePlaintext NotePlaintext::decrypt(const ZCNoteDecryption& decryptor,
SproutNotePlaintext SproutNotePlaintext::decrypt(const ZCNoteDecryption& decryptor,
const ZCNoteDecryption::Ciphertext& ciphertext,
const uint256& ephemeralKey,
const uint256& h_sig,
@@ -65,7 +113,7 @@ NotePlaintext NotePlaintext::decrypt(const ZCNoteDecryption& decryptor,
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << plaintext;
NotePlaintext ret;
SproutNotePlaintext ret;
ss >> ret;
assert(ss.size() == 0);
@@ -73,7 +121,7 @@ NotePlaintext NotePlaintext::decrypt(const ZCNoteDecryption& decryptor,
return ret;
}
ZCNoteEncryption::Ciphertext NotePlaintext::encrypt(ZCNoteEncryption& encryptor,
ZCNoteEncryption::Ciphertext SproutNotePlaintext::encrypt(ZCNoteEncryption& encryptor,
const uint256& pk_enc
) const
{
@@ -89,4 +137,177 @@ ZCNoteEncryption::Ciphertext NotePlaintext::encrypt(ZCNoteEncryption& encryptor,
return encryptor.encrypt(pk_enc, pt);
}
}
// Construct and populate SaplingNotePlaintext for a given note and memo.
SaplingNotePlaintext::SaplingNotePlaintext(
const SaplingNote& note,
std::array<unsigned char, ZC_MEMO_SIZE> memo) : BaseNotePlaintext(note, memo)
{
d = note.d;
rcm = note.r;
}
boost::optional<SaplingNote> SaplingNotePlaintext::note(const SaplingIncomingViewingKey& ivk) const
{
auto addr = ivk.address(d);
if (addr) {
return SaplingNote(d, addr.get().pk_d, value_, rcm);
} else {
return boost::none;
}
}
boost::optional<SaplingOutgoingPlaintext> SaplingOutgoingPlaintext::decrypt(
const SaplingOutCiphertext &ciphertext,
const uint256& ovk,
const uint256& cv,
const uint256& cm,
const uint256& epk
)
{
auto pt = AttemptSaplingOutDecryption(ciphertext, ovk, cv, cm, epk);
if (!pt) {
return boost::none;
}
// Deserialize from the plaintext
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << pt.get();
SaplingOutgoingPlaintext ret;
ss >> ret;
assert(ss.size() == 0);
return ret;
}
boost::optional<SaplingNotePlaintext> SaplingNotePlaintext::decrypt(
const SaplingEncCiphertext &ciphertext,
const uint256 &ivk,
const uint256 &epk,
const uint256 &cmu
)
{
auto pt = AttemptSaplingEncDecryption(ciphertext, ivk, epk);
if (!pt) {
return boost::none;
}
// Deserialize from the plaintext
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << pt.get();
SaplingNotePlaintext ret;
ss >> ret;
assert(ss.size() == 0);
uint256 pk_d;
if (!librustzcash_ivk_to_pkd(ivk.begin(), ret.d.data(), pk_d.begin())) {
return boost::none;
}
uint256 cmu_expected;
if (!librustzcash_sapling_compute_cm(
ret.d.data(),
pk_d.begin(),
ret.value(),
ret.rcm.begin(),
cmu_expected.begin()
))
{
return boost::none;
}
if (cmu_expected != cmu) {
return boost::none;
}
return ret;
}
boost::optional<SaplingNotePlaintext> SaplingNotePlaintext::decrypt(
const SaplingEncCiphertext &ciphertext,
const uint256 &epk,
const uint256 &esk,
const uint256 &pk_d,
const uint256 &cmu
)
{
auto pt = AttemptSaplingEncDecryption(ciphertext, epk, esk, pk_d);
if (!pt) {
return boost::none;
}
// Deserialize from the plaintext
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << pt.get();
SaplingNotePlaintext ret;
ss >> ret;
uint256 cmu_expected;
if (!librustzcash_sapling_compute_cm(
ret.d.data(),
pk_d.begin(),
ret.value(),
ret.rcm.begin(),
cmu_expected.begin()
))
{
return boost::none;
}
if (cmu_expected != cmu) {
return boost::none;
}
assert(ss.size() == 0);
return ret;
}
boost::optional<SaplingNotePlaintextEncryptionResult> SaplingNotePlaintext::encrypt(const uint256& pk_d) const
{
// Get the encryptor
auto sne = SaplingNoteEncryption::FromDiversifier(d);
if (!sne) {
return boost::none;
}
auto enc = sne.get();
// Create the plaintext
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << (*this);
SaplingEncPlaintext pt;
assert(pt.size() == ss.size());
memcpy(&pt[0], &ss[0], pt.size());
// Encrypt the plaintext
auto encciphertext = enc.encrypt_to_recipient(pk_d, pt);
if (!encciphertext) {
return boost::none;
}
return SaplingNotePlaintextEncryptionResult(encciphertext.get(), enc);
}
SaplingOutCiphertext SaplingOutgoingPlaintext::encrypt(
const uint256& ovk,
const uint256& cv,
const uint256& cm,
SaplingNoteEncryption& enc
) const
{
// Create the plaintext
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << (*this);
SaplingOutPlaintext pt;
assert(pt.size() == ss.size());
memcpy(&pt[0], &ss[0], pt.size());
return enc.encrypt_to_ourselves(ovk, cv, cm, pt);
}

View File

@@ -6,55 +6,105 @@
#include "Address.hpp"
#include "NoteEncryption.hpp"
#include <array>
#include <boost/optional.hpp>
namespace libzcash {
class Note {
class BaseNote {
protected:
uint64_t value_ = 0;
public:
uint256 a_pk;
uint64_t value;
uint256 rho;
uint256 r;
BaseNote() {}
BaseNote(uint64_t value) : value_(value) {};
virtual ~BaseNote() {};
Note(uint256 a_pk, uint64_t value, uint256 rho, uint256 r)
: a_pk(a_pk), value(value), rho(rho), r(r) {}
Note();
uint256 cm() const;
uint256 nullifier(const SpendingKey& a_sk) const;
inline uint64_t value() const { return value_; };
};
class NotePlaintext {
class SproutNote : public BaseNote {
public:
uint64_t value = 0;
uint256 a_pk;
uint256 rho;
uint256 r;
boost::array<unsigned char, ZC_MEMO_SIZE> memo;
NotePlaintext() {}
SproutNote(uint256 a_pk, uint64_t value, uint256 rho, uint256 r)
: BaseNote(value), a_pk(a_pk), rho(rho), r(r) {}
NotePlaintext(const Note& note, boost::array<unsigned char, ZC_MEMO_SIZE> memo);
SproutNote();
Note note(const PaymentAddress& addr) const;
virtual ~SproutNote() {};
uint256 cm() const;
uint256 nullifier(const SproutSpendingKey& a_sk) const;
};
class SaplingNote : public BaseNote {
public:
diversifier_t d;
uint256 pk_d;
uint256 r;
SaplingNote(diversifier_t d, uint256 pk_d, uint64_t value, uint256 r)
: BaseNote(value), d(d), pk_d(pk_d), r(r) {}
SaplingNote() {};
SaplingNote(const SaplingPaymentAddress &address, uint64_t value);
virtual ~SaplingNote() {};
boost::optional<uint256> cm() const;
boost::optional<uint256> nullifier(const SaplingFullViewingKey &vk, const uint64_t position) const;
};
class BaseNotePlaintext {
protected:
uint64_t value_ = 0;
std::array<unsigned char, ZC_MEMO_SIZE> memo_;
public:
BaseNotePlaintext() {}
BaseNotePlaintext(const BaseNote& note, std::array<unsigned char, ZC_MEMO_SIZE> memo)
: value_(note.value()), memo_(memo) {}
virtual ~BaseNotePlaintext() {}
inline uint64_t value() const { return value_; }
inline const std::array<unsigned char, ZC_MEMO_SIZE> & memo() const { return memo_; }
};
class SproutNotePlaintext : public BaseNotePlaintext {
public:
uint256 rho;
uint256 r;
SproutNotePlaintext() {}
SproutNotePlaintext(const SproutNote& note, std::array<unsigned char, ZC_MEMO_SIZE> memo);
SproutNote note(const SproutPaymentAddress& addr) const;
virtual ~SproutNotePlaintext() {}
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
inline void SerializationOp(Stream& s, Operation ser_action) {
unsigned char leadingByte = 0x00;
READWRITE(leadingByte);
if (leadingByte != 0x00) {
throw std::ios_base::failure("lead byte of NotePlaintext is not recognized");
throw std::ios_base::failure("lead byte of SproutNotePlaintext is not recognized");
}
READWRITE(value);
READWRITE(value_);
READWRITE(rho);
READWRITE(r);
READWRITE(memo);
READWRITE(memo_);
}
static NotePlaintext decrypt(const ZCNoteDecryption& decryptor,
static SproutNotePlaintext decrypt(const ZCNoteDecryption& decryptor,
const ZCNoteDecryption::Ciphertext& ciphertext,
const uint256& ephemeralKey,
const uint256& h_sig,
@@ -66,6 +116,91 @@ public:
) const;
};
typedef std::pair<SaplingEncCiphertext, SaplingNoteEncryption> SaplingNotePlaintextEncryptionResult;
class SaplingNotePlaintext : public BaseNotePlaintext {
public:
diversifier_t d;
uint256 rcm;
SaplingNotePlaintext() {}
SaplingNotePlaintext(const SaplingNote& note, std::array<unsigned char, ZC_MEMO_SIZE> memo);
static boost::optional<SaplingNotePlaintext> decrypt(
const SaplingEncCiphertext &ciphertext,
const uint256 &ivk,
const uint256 &epk,
const uint256 &cmu
);
static boost::optional<SaplingNotePlaintext> decrypt(
const SaplingEncCiphertext &ciphertext,
const uint256 &epk,
const uint256 &esk,
const uint256 &pk_d,
const uint256 &cmu
);
boost::optional<SaplingNote> note(const SaplingIncomingViewingKey& ivk) const;
virtual ~SaplingNotePlaintext() {}
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
unsigned char leadingByte = 0x01;
READWRITE(leadingByte);
if (leadingByte != 0x01) {
throw std::ios_base::failure("lead byte of SaplingNotePlaintext is not recognized");
}
READWRITE(d); // 11 bytes
READWRITE(value_); // 8 bytes
READWRITE(rcm); // 32 bytes
READWRITE(memo_); // 512 bytes
}
boost::optional<SaplingNotePlaintextEncryptionResult> encrypt(const uint256& pk_d) const;
};
class SaplingOutgoingPlaintext
{
public:
uint256 pk_d;
uint256 esk;
SaplingOutgoingPlaintext() {};
SaplingOutgoingPlaintext(uint256 pk_d, uint256 esk) : pk_d(pk_d), esk(esk) {}
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(pk_d); // 8 bytes
READWRITE(esk); // 8 bytes
}
static boost::optional<SaplingOutgoingPlaintext> decrypt(
const SaplingOutCiphertext &ciphertext,
const uint256& ovk,
const uint256& cv,
const uint256& cm,
const uint256& epk
);
SaplingOutCiphertext encrypt(
const uint256& ovk,
const uint256& cv,
const uint256& cm,
SaplingNoteEncryption& enc
) const;
};
}
#endif // ZC_NOTE_H_

View File

@@ -3,6 +3,7 @@
#include "sodium.h"
#include <boost/static_assert.hpp>
#include "prf.h"
#include "librustzcash.h"
#define NOTEENCRYPTION_CIPHER_KEYSIZE 32
@@ -13,6 +14,58 @@ void clamp_curve25519(unsigned char key[crypto_scalarmult_SCALARBYTES])
key[31] |= 64;
}
void PRF_ock(
unsigned char K[NOTEENCRYPTION_CIPHER_KEYSIZE],
const uint256 &ovk,
const uint256 &cv,
const uint256 &cm,
const uint256 &epk
)
{
unsigned char block[128] = {};
memcpy(block+0, ovk.begin(), 32);
memcpy(block+32, cv.begin(), 32);
memcpy(block+64, cm.begin(), 32);
memcpy(block+96, epk.begin(), 32);
unsigned char personalization[crypto_generichash_blake2b_PERSONALBYTES] = {};
memcpy(personalization, "Zcash_Derive_ock", 16);
if (crypto_generichash_blake2b_salt_personal(K, NOTEENCRYPTION_CIPHER_KEYSIZE,
block, 128,
NULL, 0, // No key.
NULL, // No salt.
personalization
) != 0)
{
throw std::logic_error("hash function failure");
}
}
void KDF_Sapling(
unsigned char K[NOTEENCRYPTION_CIPHER_KEYSIZE],
const uint256 &dhsecret,
const uint256 &epk
)
{
unsigned char block[64] = {};
memcpy(block+0, dhsecret.begin(), 32);
memcpy(block+32, epk.begin(), 32);
unsigned char personalization[crypto_generichash_blake2b_PERSONALBYTES] = {};
memcpy(personalization, "Zcash_SaplingKDF", 16);
if (crypto_generichash_blake2b_salt_personal(K, NOTEENCRYPTION_CIPHER_KEYSIZE,
block, 64,
NULL, 0, // No key.
NULL, // No salt.
personalization
) != 0)
{
throw std::logic_error("hash function failure");
}
}
void KDF(unsigned char K[NOTEENCRYPTION_CIPHER_KEYSIZE],
const uint256 &dhsecret,
const uint256 &epk,
@@ -48,6 +101,192 @@ void KDF(unsigned char K[NOTEENCRYPTION_CIPHER_KEYSIZE],
namespace libzcash {
boost::optional<SaplingNoteEncryption> SaplingNoteEncryption::FromDiversifier(diversifier_t d) {
uint256 epk;
uint256 esk;
// Pick random esk
librustzcash_sapling_generate_r(esk.begin());
// Compute epk given the diversifier
if (!librustzcash_sapling_ka_derivepublic(d.begin(), esk.begin(), epk.begin())) {
return boost::none;
}
return SaplingNoteEncryption(epk, esk);
}
boost::optional<SaplingEncCiphertext> SaplingNoteEncryption::encrypt_to_recipient(
const uint256 &pk_d,
const SaplingEncPlaintext &message
)
{
if (already_encrypted_enc) {
throw std::logic_error("already encrypted to the recipient using this key");
}
uint256 dhsecret;
if (!librustzcash_sapling_ka_agree(pk_d.begin(), esk.begin(), dhsecret.begin())) {
return boost::none;
}
// Construct the symmetric key
unsigned char K[NOTEENCRYPTION_CIPHER_KEYSIZE];
KDF_Sapling(K, dhsecret, epk);
// The nonce is zero because we never reuse keys
unsigned char cipher_nonce[crypto_aead_chacha20poly1305_IETF_NPUBBYTES] = {};
SaplingEncCiphertext ciphertext;
crypto_aead_chacha20poly1305_ietf_encrypt(
ciphertext.begin(), NULL,
message.begin(), ZC_SAPLING_ENCPLAINTEXT_SIZE,
NULL, 0, // no "additional data"
NULL, cipher_nonce, K
);
already_encrypted_enc = true;
return ciphertext;
}
boost::optional<SaplingEncPlaintext> AttemptSaplingEncDecryption(
const SaplingEncCiphertext &ciphertext,
const uint256 &ivk,
const uint256 &epk
)
{
uint256 dhsecret;
if (!librustzcash_sapling_ka_agree(epk.begin(), ivk.begin(), dhsecret.begin())) {
return boost::none;
}
// Construct the symmetric key
unsigned char K[NOTEENCRYPTION_CIPHER_KEYSIZE];
KDF_Sapling(K, dhsecret, epk);
// The nonce is zero because we never reuse keys
unsigned char cipher_nonce[crypto_aead_chacha20poly1305_IETF_NPUBBYTES] = {};
SaplingEncPlaintext plaintext;
if (crypto_aead_chacha20poly1305_ietf_decrypt(
plaintext.begin(), NULL,
NULL,
ciphertext.begin(), ZC_SAPLING_ENCCIPHERTEXT_SIZE,
NULL,
0,
cipher_nonce, K) != 0)
{
return boost::none;
}
return plaintext;
}
boost::optional<SaplingEncPlaintext> AttemptSaplingEncDecryption (
const SaplingEncCiphertext &ciphertext,
const uint256 &epk,
const uint256 &esk,
const uint256 &pk_d
)
{
uint256 dhsecret;
if (!librustzcash_sapling_ka_agree(pk_d.begin(), esk.begin(), dhsecret.begin())) {
return boost::none;
}
// Construct the symmetric key
unsigned char K[NOTEENCRYPTION_CIPHER_KEYSIZE];
KDF_Sapling(K, dhsecret, epk);
// The nonce is zero because we never reuse keys
unsigned char cipher_nonce[crypto_aead_chacha20poly1305_IETF_NPUBBYTES] = {};
SaplingEncPlaintext plaintext;
if (crypto_aead_chacha20poly1305_ietf_decrypt(
plaintext.begin(), NULL,
NULL,
ciphertext.begin(), ZC_SAPLING_ENCCIPHERTEXT_SIZE,
NULL,
0,
cipher_nonce, K) != 0)
{
return boost::none;
}
return plaintext;
}
SaplingOutCiphertext SaplingNoteEncryption::encrypt_to_ourselves(
const uint256 &ovk,
const uint256 &cv,
const uint256 &cm,
const SaplingOutPlaintext &message
)
{
if (already_encrypted_out) {
throw std::logic_error("already encrypted to the recipient using this key");
}
// Construct the symmetric key
unsigned char K[NOTEENCRYPTION_CIPHER_KEYSIZE];
PRF_ock(K, ovk, cv, cm, epk);
// The nonce is zero because we never reuse keys
unsigned char cipher_nonce[crypto_aead_chacha20poly1305_IETF_NPUBBYTES] = {};
SaplingOutCiphertext ciphertext;
crypto_aead_chacha20poly1305_ietf_encrypt(
ciphertext.begin(), NULL,
message.begin(), ZC_SAPLING_OUTPLAINTEXT_SIZE,
NULL, 0, // no "additional data"
NULL, cipher_nonce, K
);
already_encrypted_out = true;
return ciphertext;
}
boost::optional<SaplingOutPlaintext> AttemptSaplingOutDecryption(
const SaplingOutCiphertext &ciphertext,
const uint256 &ovk,
const uint256 &cv,
const uint256 &cm,
const uint256 &epk
)
{
// Construct the symmetric key
unsigned char K[NOTEENCRYPTION_CIPHER_KEYSIZE];
PRF_ock(K, ovk, cv, cm, epk);
// The nonce is zero because we never reuse keys
unsigned char cipher_nonce[crypto_aead_chacha20poly1305_IETF_NPUBBYTES] = {};
SaplingOutPlaintext plaintext;
if (crypto_aead_chacha20poly1305_ietf_decrypt(
plaintext.begin(), NULL,
NULL,
ciphertext.begin(), ZC_SAPLING_OUTCIPHERTEXT_SIZE,
NULL,
0,
cipher_nonce, K) != 0)
{
return boost::none;
}
return plaintext;
}
template<size_t MLEN>
NoteEncryption<MLEN>::NoteEncryption(uint256 hSig) : nonce(0), hSig(hSig) {
// All of this code assumes crypto_scalarmult_BYTES is 32

View File

@@ -6,15 +6,91 @@ https://github.com/zcash/zips/blob/master/protocol/protocol.pdf
#ifndef ZC_NOTE_ENCRYPTION_H_
#define ZC_NOTE_ENCRYPTION_H_
#include <boost/array.hpp>
#include "uint256.h"
#include "uint252.h"
#include "zcash/Zcash.h"
#include "zcash/Address.hpp"
#include <array>
namespace libzcash {
#define NOTEENCRYPTION_AUTH_BYTES 16
// Ciphertext for the recipient to decrypt
typedef std::array<unsigned char, ZC_SAPLING_ENCCIPHERTEXT_SIZE> SaplingEncCiphertext;
typedef std::array<unsigned char, ZC_SAPLING_ENCPLAINTEXT_SIZE> SaplingEncPlaintext;
// Ciphertext for outgoing viewing key to decrypt
typedef std::array<unsigned char, ZC_SAPLING_OUTCIPHERTEXT_SIZE> SaplingOutCiphertext;
typedef std::array<unsigned char, ZC_SAPLING_OUTPLAINTEXT_SIZE> SaplingOutPlaintext;
//! This is not a thread-safe API.
class SaplingNoteEncryption {
protected:
// Ephemeral public key
uint256 epk;
// Ephemeral secret key
uint256 esk;
bool already_encrypted_enc;
bool already_encrypted_out;
SaplingNoteEncryption(uint256 epk, uint256 esk) : epk(epk), esk(esk), already_encrypted_enc(false), already_encrypted_out(false) {
}
public:
static boost::optional<SaplingNoteEncryption> FromDiversifier(diversifier_t d);
boost::optional<SaplingEncCiphertext> encrypt_to_recipient(
const uint256 &pk_d,
const SaplingEncPlaintext &message
);
SaplingOutCiphertext encrypt_to_ourselves(
const uint256 &ovk,
const uint256 &cv,
const uint256 &cm,
const SaplingOutPlaintext &message
);
uint256 get_epk() const {
return epk;
}
uint256 get_esk() const {
return esk;
}
};
// Attempts to decrypt a Sapling note. This will not check that the contents
// of the ciphertext are correct.
boost::optional<SaplingEncPlaintext> AttemptSaplingEncDecryption(
const SaplingEncCiphertext &ciphertext,
const uint256 &ivk,
const uint256 &epk
);
// Attempts to decrypt a Sapling note using outgoing plaintext.
// This will not check that the contents of the ciphertext are correct.
boost::optional<SaplingEncPlaintext> AttemptSaplingEncDecryption (
const SaplingEncCiphertext &ciphertext,
const uint256 &epk,
const uint256 &esk,
const uint256 &pk_d
);
// Attempts to decrypt a Sapling note. This will not check that the contents
// of the ciphertext are correct.
boost::optional<SaplingOutPlaintext> AttemptSaplingOutDecryption(
const SaplingOutCiphertext &ciphertext,
const uint256 &ovk,
const uint256 &cv,
const uint256 &cm,
const uint256 &epk
);
template<size_t MLEN>
class NoteEncryption {
@@ -26,8 +102,8 @@ protected:
uint256 hSig;
public:
typedef boost::array<unsigned char, CLEN> Ciphertext;
typedef boost::array<unsigned char, MLEN> Plaintext;
typedef std::array<unsigned char, CLEN> Ciphertext;
typedef std::array<unsigned char, MLEN> Plaintext;
NoteEncryption(uint256 hSig);
@@ -63,8 +139,8 @@ protected:
uint256 pk_enc;
public:
typedef boost::array<unsigned char, CLEN> Ciphertext;
typedef boost::array<unsigned char, MLEN> Plaintext;
typedef std::array<unsigned char, CLEN> Ciphertext;
typedef std::array<unsigned char, MLEN> Plaintext;
NoteDecryption() { }
NoteDecryption(uint256 sk_enc);
@@ -100,8 +176,8 @@ class PaymentDisclosureNoteDecryption : public NoteDecryption<MLEN> {
protected:
public:
enum { CLEN=MLEN+NOTEENCRYPTION_AUTH_BYTES };
typedef boost::array<unsigned char, CLEN> Ciphertext;
typedef boost::array<unsigned char, MLEN> Plaintext;
typedef std::array<unsigned char, CLEN> Ciphertext;
typedef std::array<unsigned char, MLEN> Plaintext;
PaymentDisclosureNoteDecryption() : NoteDecryption<MLEN>() {}
PaymentDisclosureNoteDecryption(uint256 sk_enc) : NoteDecryption<MLEN>(sk_enc) {}

View File

@@ -171,7 +171,7 @@ curve_G2 CompressedG2::to_libsnark_g2() const
}
template<>
ZCProof::ZCProof(const r1cs_ppzksnark_proof<curve_pp> &proof)
PHGRProof::PHGRProof(const r1cs_ppzksnark_proof<curve_pp> &proof)
{
g_A = CompressedG1(proof.g_A.g);
g_A_prime = CompressedG1(proof.g_A.h);
@@ -184,7 +184,7 @@ ZCProof::ZCProof(const r1cs_ppzksnark_proof<curve_pp> &proof)
}
template<>
r1cs_ppzksnark_proof<curve_pp> ZCProof::to_libsnark_proof() const
r1cs_ppzksnark_proof<curve_pp> PHGRProof::to_libsnark_proof() const
{
r1cs_ppzksnark_proof<curve_pp> proof;
@@ -200,9 +200,9 @@ r1cs_ppzksnark_proof<curve_pp> ZCProof::to_libsnark_proof() const
return proof;
}
ZCProof ZCProof::random_invalid()
PHGRProof PHGRProof::random_invalid()
{
ZCProof p;
PHGRProof p;
p.g_A = curve_G1::random_element();
p.g_A_prime = curve_G1::random_element();
p.g_B = curve_G2::random_element();
@@ -216,7 +216,7 @@ ZCProof ZCProof::random_invalid()
return p;
}
std::once_flag init_public_params_once_flag;
static std::once_flag init_public_params_once_flag;
void initialize_curve_params()
{

View File

@@ -25,7 +25,7 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(data);
}
@@ -58,7 +58,7 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(data);
}
@@ -93,7 +93,7 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
inline void SerializationOp(Stream& s, Operation ser_action) {
unsigned char leadingByte = G1_PREFIX_MASK;
if (y_lsb) {
@@ -143,7 +143,7 @@ public:
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
inline void SerializationOp(Stream& s, Operation ser_action) {
unsigned char leadingByte = G2_PREFIX_MASK;
if (y_gt) {
@@ -176,7 +176,7 @@ public:
};
// Compressed zkSNARK proof
class ZCProof {
class PHGRProof {
private:
CompressedG1 g_A;
CompressedG1 g_A_prime;
@@ -188,23 +188,23 @@ private:
CompressedG1 g_H;
public:
ZCProof() : g_A(), g_A_prime(), g_B(), g_B_prime(), g_C(), g_C_prime(), g_K(), g_H() { }
PHGRProof() : g_A(), g_A_prime(), g_B(), g_B_prime(), g_C(), g_C_prime(), g_K(), g_H() { }
// Produces a compressed proof using a libsnark zkSNARK proof
template<typename libsnark_proof>
ZCProof(const libsnark_proof& proof);
PHGRProof(const libsnark_proof& proof);
// Produces a libsnark zkSNARK proof out of this proof,
// or throws an exception if it is invalid.
template<typename libsnark_proof>
libsnark_proof to_libsnark_proof() const;
static ZCProof random_invalid();
static PHGRProof random_invalid();
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(g_A);
READWRITE(g_A_prime);
READWRITE(g_B);
@@ -215,7 +215,7 @@ public:
READWRITE(g_H);
}
friend bool operator==(const ZCProof& a, const ZCProof& b)
friend bool operator==(const PHGRProof& a, const PHGRProof& b)
{
return (
a.g_A == b.g_A &&
@@ -229,7 +229,7 @@ public:
);
}
friend bool operator!=(const ZCProof& a, const ZCProof& b)
friend bool operator!=(const PHGRProof& a, const PHGRProof& b)
{
return !(a == b);
}

View File

@@ -6,12 +6,25 @@
#define INCREMENTAL_MERKLE_TREE_DEPTH 29
#define INCREMENTAL_MERKLE_TREE_DEPTH_TESTING 4
#define SAPLING_INCREMENTAL_MERKLE_TREE_DEPTH 32
#define NOTEENCRYPTION_AUTH_BYTES 16
#define ZC_NOTEPLAINTEXT_LEADING 1
#define ZC_V_SIZE 8
#define ZC_RHO_SIZE 32
#define ZC_R_SIZE 32
#define ZC_MEMO_SIZE 512
#define ZC_DIVERSIFIER_SIZE 11
#define ZC_JUBJUB_POINT_SIZE 32
#define ZC_JUBJUB_SCALAR_SIZE 32
#define ZC_NOTEPLAINTEXT_SIZE (ZC_NOTEPLAINTEXT_LEADING + ZC_V_SIZE + ZC_RHO_SIZE + ZC_R_SIZE + ZC_MEMO_SIZE)
#define ZC_SAPLING_ENCPLAINTEXT_SIZE (ZC_NOTEPLAINTEXT_LEADING + ZC_DIVERSIFIER_SIZE + ZC_V_SIZE + ZC_R_SIZE + ZC_MEMO_SIZE)
#define ZC_SAPLING_OUTPLAINTEXT_SIZE (ZC_JUBJUB_POINT_SIZE + ZC_JUBJUB_SCALAR_SIZE)
#define ZC_SAPLING_ENCCIPHERTEXT_SIZE (ZC_SAPLING_ENCPLAINTEXT_SIZE + NOTEENCRYPTION_AUTH_BYTES)
#define ZC_SAPLING_OUTCIPHERTEXT_SIZE (ZC_SAPLING_OUTPLAINTEXT_SIZE + NOTEENCRYPTION_AUTH_BYTES)
#endif // ZC_ZCASH_H_

View File

@@ -14,9 +14,9 @@ private:
std::shared_ptr<digest_variable<FieldT>> zk_merkle_root;
std::shared_ptr<digest_variable<FieldT>> zk_h_sig;
boost::array<std::shared_ptr<digest_variable<FieldT>>, NumInputs> zk_input_nullifiers;
boost::array<std::shared_ptr<digest_variable<FieldT>>, NumInputs> zk_input_macs;
boost::array<std::shared_ptr<digest_variable<FieldT>>, NumOutputs> zk_output_commitments;
std::array<std::shared_ptr<digest_variable<FieldT>>, NumInputs> zk_input_nullifiers;
std::array<std::shared_ptr<digest_variable<FieldT>>, NumInputs> zk_input_macs;
std::array<std::shared_ptr<digest_variable<FieldT>>, NumOutputs> zk_output_commitments;
pb_variable_array<FieldT> zk_vpub_old;
pb_variable_array<FieldT> zk_vpub_new;
@@ -26,11 +26,11 @@ private:
pb_variable_array<FieldT> zk_total_uint64;
// Input note gadgets
boost::array<std::shared_ptr<input_note_gadget<FieldT>>, NumInputs> zk_input_notes;
boost::array<std::shared_ptr<PRF_pk_gadget<FieldT>>, NumInputs> zk_mac_authentication;
std::array<std::shared_ptr<input_note_gadget<FieldT>>, NumInputs> zk_input_notes;
std::array<std::shared_ptr<PRF_pk_gadget<FieldT>>, NumInputs> zk_mac_authentication;
// Output note gadgets
boost::array<std::shared_ptr<output_note_gadget<FieldT>>, NumOutputs> zk_output_notes;
std::array<std::shared_ptr<output_note_gadget<FieldT>>, NumOutputs> zk_output_notes;
public:
// PRF_pk only has a 1-bit domain separation "nonce"
@@ -190,8 +190,8 @@ public:
const uint252& phi,
const uint256& rt,
const uint256& h_sig,
const boost::array<JSInput, NumInputs>& inputs,
const boost::array<Note, NumOutputs>& outputs,
const std::array<JSInput, NumInputs>& inputs,
const std::array<SproutNote, NumOutputs>& outputs,
uint64_t vpub_old,
uint64_t vpub_new
) {
@@ -222,7 +222,7 @@ public:
// Witness total_uint64 bits
uint64_t left_side_acc = vpub_old;
for (size_t i = 0; i < NumInputs; i++) {
left_side_acc += inputs[i].note.value;
left_side_acc += inputs[i].note.value();
}
zk_total_uint64.fill_with_bits(
@@ -280,9 +280,9 @@ public:
static r1cs_primary_input<FieldT> witness_map(
const uint256& rt,
const uint256& h_sig,
const boost::array<uint256, NumInputs>& macs,
const boost::array<uint256, NumInputs>& nullifiers,
const boost::array<uint256, NumOutputs>& commitments,
const std::array<uint256, NumInputs>& macs,
const std::array<uint256, NumInputs>& nullifiers,
const std::array<uint256, NumOutputs>& commitments,
uint64_t vpub_old,
uint64_t vpub_new
) {

View File

@@ -52,7 +52,7 @@ public:
// number thing in its API.
size_t path_index = convertVectorToInt(path.index);
positions.fill_with_bits_of_ulong(this->pb, path_index);
positions.fill_with_bits_of_uint64(this->pb, path_index);
authvars->generate_r1cs_witness(path_index, path.authentication_path);
auth->generate_r1cs_witness();

View File

@@ -21,9 +21,9 @@ public:
r->generate_r1cs_constraints();
}
void generate_r1cs_witness(const Note& note) {
void generate_r1cs_witness(const SproutNote& note) {
r->bits.fill_with_bits(this->pb, uint256_to_bool_vector(note.r));
value.fill_with_bits(this->pb, uint64_to_bool_vector(note.value));
value.fill_with_bits(this->pb, uint64_to_bool_vector(note.value()));
}
};
@@ -118,8 +118,8 @@ public:
void generate_r1cs_witness(
const MerklePath& path,
const SpendingKey& key,
const Note& note
const SproutSpendingKey& key,
const SproutNote& note
) {
note_gadget<FieldT>::generate_r1cs_witness(note);
@@ -158,7 +158,7 @@ public:
);
// Set enforce flag for nonzero input value
this->pb.val(value_enforce) = (note.value != 0) ? FieldT::one() : FieldT::zero();
this->pb.val(value_enforce) = (note.value() != 0) ? FieldT::one() : FieldT::zero();
// Witness merkle tree authentication path
witness_input->generate_r1cs_witness(path);
@@ -222,7 +222,7 @@ public:
commit_to_outputs->generate_r1cs_constraints();
}
void generate_r1cs_witness(const Note& note) {
void generate_r1cs_witness(const SproutNote& note) {
note_gadget<FieldT>::generate_r1cs_witness(note);
prevent_faerie_gold->generate_r1cs_witness();

View File

@@ -1,6 +1,80 @@
#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& sk, unsigned char t)
{
std::array<unsigned char, 64> res;
unsigned char blob[33];
memcpy(&blob[0], sk.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, 34);
crypto_generichash_blake2b_final(&state, res.data(), 11);
if (librustzcash_check_diversifier(res.data())) {
break;
} else if (blob[33] == 255) {
throw std::runtime_error("librustzcash_check_diversifier did not return valid diversifier");
}
blob[33] += 1;
}
return res;
}
// Sprout
uint256 PRF(bool a, bool b, bool c, bool d,
const uint252& x,
const uint256& y)

View File

@@ -9,10 +9,20 @@ within the zkSNARK circuit.
#include "uint256.h"
#include "uint252.h"
#include <array>
//! Sprout functions
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);
uint256 PRF_pk(const uint252& a_sk, size_t i0, const uint256& h_sig);
uint256 PRF_rho(const uint252& phi, size_t i0, const uint256& h_sig);
//! Sapling functions
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);
#endif // ZC_PRF_H_

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

@@ -0,0 +1,170 @@
// 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 "zcash/prf.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'};
const unsigned char ZCASH_TADDR_OVK_PERSONAL[crypto_generichash_blake2b_PERSONALBYTES] =
{'Z', 'c', 'T', 'a', 'd', 'd', 'r', 'T', 'o', 'S', 'a', 'p', 'l', 'i', 'n', 'g'};
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();
}
uint256 ovkForShieldingFromTaddr(HDSeed& seed) {
auto rawSeed = seed.RawSeed();
// I = BLAKE2b-512("ZcTaddrToSapling", seed)
crypto_generichash_blake2b_state state;
assert(crypto_generichash_blake2b_init_salt_personal(
&state,
NULL, 0, // No key.
64,
NULL, // No salt.
ZCASH_TADDR_OVK_PERSONAL) == 0);
crypto_generichash_blake2b_update(&state, rawSeed.data(), rawSeed.size());
auto intermediate = std::array<unsigned char, 64>();
crypto_generichash_blake2b_final(&state, intermediate.data(), 64);
// I_L = I[0..32]
uint256 intermediate_L;
memcpy(intermediate_L.begin(), intermediate.data(), 32);
// ovk = truncate_32(PRF^expand(I_L, [0x02]))
return PRF_ovk(intermediate_L);
}
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();
}
}
bool IsValidSpendingKey(const libzcash::SpendingKey& zkey) {
return zkey.which() != 0;
}

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

@@ -0,0 +1,144 @@
// 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);
}
};
// This is not part of ZIP 32, but is here because it's linked to the HD seed.
uint256 ovkForShieldingFromTaddr(HDSeed& seed);
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;
friend inline bool operator==(const SaplingExtendedFullViewingKey& a, const SaplingExtendedFullViewingKey& b) {
return (
a.depth == b.depth &&
a.parentFVKTag == b.parentFVKTag &&
a.childIndex == b.childIndex &&
a.chaincode == b.chaincode &&
a.fvk == b.fvk &&
a.dk == b.dk);
}
friend inline bool operator<(const SaplingExtendedFullViewingKey& a, const SaplingExtendedFullViewingKey& b) {
return (a.depth < b.depth ||
(a.depth == b.depth && a.childIndex < b.childIndex) ||
(a.depth == b.depth && a.childIndex == b.childIndex && a.fvk < b.fvk));
}
};
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;
}
};
typedef boost::variant<InvalidEncoding, SproutSpendingKey, SaplingExtendedSpendingKey> SpendingKey;
}
/** Check whether a SpendingKey is not an InvalidEncoding. */
bool IsValidSpendingKey(const libzcash::SpendingKey& zkey);
#endif // ZCASH_ZIP32_H