Introduce new `libzcash` Zcash protocol API and crypto constructions surrounding the zkSNARK circuit.
This commit is contained in:
parent
5961dcb6da
commit
369df06583
|
@ -16,6 +16,9 @@ src/zerocash/tests/utilTest
|
|||
src/zerocash/tests/zerocashTest
|
||||
src/zerocash/tests/test_zerocash_pour_ppzksnark
|
||||
|
||||
*zcashTest.pk
|
||||
*zcashTest.vk
|
||||
|
||||
# autoreconf
|
||||
Makefile.in
|
||||
aclocal.m4
|
||||
|
|
|
@ -86,6 +86,9 @@ LIBZEROCASH_H = \
|
|||
zerocash/zerocash_pour_params.hpp \
|
||||
zerocash/utils/util.h \
|
||||
zcash/NoteEncryption.hpp \
|
||||
zcash/Address.hpp \
|
||||
zcash/JoinSplit.hpp \
|
||||
zcash/Note.hpp \
|
||||
zcash/prf.h
|
||||
|
||||
.PHONY: FORCE
|
||||
|
@ -427,6 +430,9 @@ libzerocash_a_SOURCES = \
|
|||
zerocash/ZerocashParams.cpp \
|
||||
zerocash/utils/util.cpp \
|
||||
zcash/NoteEncryption.cpp \
|
||||
zcash/Address.cpp \
|
||||
zcash/JoinSplit.cpp \
|
||||
zcash/Note.cpp \
|
||||
zcash/prf.cpp
|
||||
|
||||
libzerocash_a_CPPFLAGS = -fPIC -DCURVE_ALT_BN128 -DBOOST_SPIRIT_THREADSAFE -DHAVE_BUILD_INFO -D__STDC_FORMAT_MACROS -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -std=c++11 -pipe -O2 -O0 -g -Wstack-protector -fstack-protector-all -fPIE -fvisibility=hidden -DSTATIC $(BITCOIN_INCLUDES)
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
#include "Address.hpp"
|
||||
#include "NoteEncryption.hpp"
|
||||
#include "prf.h"
|
||||
|
||||
namespace libzcash {
|
||||
|
||||
uint256 ViewingKey::pk_enc() {
|
||||
return ZCNoteEncryption::generate_pubkey(*this);
|
||||
}
|
||||
|
||||
ViewingKey SpendingKey::viewing_key() {
|
||||
return ViewingKey(ZCNoteEncryption::generate_privkey(*this));
|
||||
}
|
||||
|
||||
SpendingKey SpendingKey::random() {
|
||||
return SpendingKey(random_uint256());
|
||||
}
|
||||
|
||||
PaymentAddress SpendingKey::address() {
|
||||
return PaymentAddress(PRF_addr_a_pk(*this), viewing_key().pk_enc());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
#ifndef _ZCADDRESS_H_
|
||||
#define _ZCADDRESS_H_
|
||||
|
||||
#include "uint256.h"
|
||||
#include "serialize.h"
|
||||
|
||||
namespace libzcash {
|
||||
|
||||
class PaymentAddress {
|
||||
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) { }
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
||||
unsigned char leadingByte = 0x92;
|
||||
READWRITE(leadingByte);
|
||||
|
||||
if (leadingByte != 0x92) {
|
||||
throw std::ios_base::failure("unrecognized payment address lead byte");
|
||||
}
|
||||
|
||||
READWRITE(a_pk);
|
||||
READWRITE(pk_enc);
|
||||
}
|
||||
};
|
||||
|
||||
class ViewingKey : public uint256 {
|
||||
public:
|
||||
ViewingKey(uint256 sk_enc) : uint256(sk_enc) { }
|
||||
|
||||
uint256 pk_enc();
|
||||
};
|
||||
|
||||
class SpendingKey : public uint256 {
|
||||
public:
|
||||
SpendingKey() : uint256() { }
|
||||
SpendingKey(uint256 a_sk) : uint256(a_sk) { }
|
||||
|
||||
static SpendingKey random();
|
||||
|
||||
ViewingKey viewing_key();
|
||||
PaymentAddress address();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // _ZCADDRESS_H_
|
|
@ -0,0 +1,339 @@
|
|||
#include "JoinSplit.hpp"
|
||||
#include "prf.h"
|
||||
#include "sodium.h"
|
||||
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <fstream>
|
||||
#include "libsnark/common/default_types/r1cs_ppzksnark_pp.hpp"
|
||||
#include "libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp"
|
||||
#include "libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp"
|
||||
#include "libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp"
|
||||
|
||||
#include "sync.h"
|
||||
|
||||
using namespace libsnark;
|
||||
|
||||
namespace libzcash {
|
||||
|
||||
#include "zcash/circuit/gadget.tcc"
|
||||
|
||||
CCriticalSection cs_ParamsIO;
|
||||
CCriticalSection cs_InitializeParams;
|
||||
|
||||
template<typename T>
|
||||
void saveToFile(std::string path, T& obj) {
|
||||
LOCK(cs_ParamsIO);
|
||||
|
||||
std::stringstream ss;
|
||||
ss << obj;
|
||||
std::ofstream fh;
|
||||
fh.open(path, std::ios::binary);
|
||||
ss.rdbuf()->pubseekpos(0, std::ios_base::out);
|
||||
fh << ss.rdbuf();
|
||||
fh.flush();
|
||||
fh.close();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void loadFromFile(std::string path, boost::optional<T>& objIn) {
|
||||
LOCK(cs_ParamsIO);
|
||||
|
||||
std::stringstream ss;
|
||||
std::ifstream fh(path, std::ios::binary);
|
||||
|
||||
if(!fh.is_open()) {
|
||||
throw std::runtime_error((boost::format("could not load param file at %s") % path).str());
|
||||
}
|
||||
|
||||
ss << fh.rdbuf();
|
||||
fh.close();
|
||||
|
||||
ss.rdbuf()->pubseekpos(0, std::ios_base::in);
|
||||
|
||||
T obj;
|
||||
ss >> obj;
|
||||
|
||||
objIn = std::move(obj);
|
||||
}
|
||||
|
||||
template<size_t NumInputs, size_t NumOutputs>
|
||||
class JoinSplitCircuit : public JoinSplit<NumInputs, NumOutputs> {
|
||||
public:
|
||||
typedef default_r1cs_ppzksnark_pp ppzksnark_ppT;
|
||||
typedef Fr<ppzksnark_ppT> FieldT;
|
||||
|
||||
boost::optional<r1cs_ppzksnark_proving_key<ppzksnark_ppT>> pk;
|
||||
boost::optional<r1cs_ppzksnark_verification_key<ppzksnark_ppT>> vk;
|
||||
boost::optional<std::string> pkPath;
|
||||
|
||||
static void initialize() {
|
||||
LOCK(cs_InitializeParams);
|
||||
|
||||
ppzksnark_ppT::init_public_params();
|
||||
}
|
||||
|
||||
void setProvingKeyPath(std::string path) {
|
||||
pkPath = path;
|
||||
}
|
||||
|
||||
void loadProvingKey() {
|
||||
if (!pk) {
|
||||
if (!pkPath) {
|
||||
throw std::runtime_error("proving key path unknown");
|
||||
}
|
||||
loadFromFile(*pkPath, pk);
|
||||
}
|
||||
}
|
||||
|
||||
void saveProvingKey(std::string path) {
|
||||
if (pk) {
|
||||
saveToFile(path, *pk);
|
||||
} else {
|
||||
throw std::runtime_error("cannot save proving key; key doesn't exist");
|
||||
}
|
||||
}
|
||||
void loadVerifyingKey(std::string path) {
|
||||
loadFromFile(path, vk);
|
||||
}
|
||||
void saveVerifyingKey(std::string path) {
|
||||
if (vk) {
|
||||
saveToFile(path, *vk);
|
||||
} else {
|
||||
throw std::runtime_error("cannot save verifying key; key doesn't exist");
|
||||
}
|
||||
}
|
||||
|
||||
void generate() {
|
||||
protoboard<FieldT> pb;
|
||||
|
||||
joinsplit_gadget<FieldT, NumInputs, NumOutputs> g(pb);
|
||||
g.generate_r1cs_constraints();
|
||||
|
||||
const r1cs_constraint_system<FieldT> constraint_system = pb.get_constraint_system();
|
||||
r1cs_ppzksnark_keypair<ppzksnark_ppT> keypair = r1cs_ppzksnark_generator<ppzksnark_ppT>(constraint_system);
|
||||
|
||||
pk = keypair.pk;
|
||||
vk = keypair.vk;
|
||||
}
|
||||
|
||||
JoinSplitCircuit() {}
|
||||
|
||||
bool verify(
|
||||
const std::string& proof,
|
||||
const uint256& pubKeyHash,
|
||||
const uint256& randomSeed,
|
||||
const boost::array<uint256, NumInputs>& hmacs,
|
||||
const boost::array<uint256, NumInputs>& nullifiers,
|
||||
const boost::array<uint256, NumOutputs>& commitments,
|
||||
uint64_t vpub_old,
|
||||
uint64_t vpub_new,
|
||||
const uint256& rt
|
||||
) {
|
||||
if (!vk) {
|
||||
throw std::runtime_error("JoinSplit verifying key not loaded");
|
||||
}
|
||||
|
||||
r1cs_ppzksnark_proof<ppzksnark_ppT> r1cs_proof;
|
||||
std::stringstream ss;
|
||||
ss.str(proof);
|
||||
ss >> r1cs_proof;
|
||||
|
||||
uint256 h_sig = this->h_sig(randomSeed, nullifiers, pubKeyHash);
|
||||
|
||||
auto witness = joinsplit_gadget<FieldT, NumInputs, NumOutputs>::witness_map(
|
||||
rt,
|
||||
h_sig,
|
||||
hmacs,
|
||||
nullifiers,
|
||||
commitments,
|
||||
vpub_old,
|
||||
vpub_new
|
||||
);
|
||||
|
||||
return r1cs_ppzksnark_verifier_strong_IC<ppzksnark_ppT>(*vk, witness, r1cs_proof);
|
||||
}
|
||||
|
||||
std::string 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,
|
||||
uint256& out_ephemeralKey,
|
||||
const uint256& pubKeyHash,
|
||||
uint256& out_randomSeed,
|
||||
boost::array<uint256, NumInputs>& out_macs,
|
||||
boost::array<uint256, NumInputs>& out_nullifiers,
|
||||
boost::array<uint256, NumOutputs>& out_commitments,
|
||||
uint64_t vpub_old,
|
||||
uint64_t vpub_new,
|
||||
const uint256& rt
|
||||
) {
|
||||
if (!pk) {
|
||||
throw std::runtime_error("JoinSplit proving key not loaded");
|
||||
}
|
||||
|
||||
// Compute nullifiers of inputs
|
||||
for (size_t i = 0; i < NumInputs; i++) {
|
||||
out_nullifiers[i] = inputs[i].nullifier();
|
||||
}
|
||||
|
||||
// Sample randomSeed
|
||||
out_randomSeed = random_uint256();
|
||||
|
||||
// Compute h_sig
|
||||
uint256 h_sig = this->h_sig(out_randomSeed, out_nullifiers, pubKeyHash);
|
||||
|
||||
// Sample phi
|
||||
uint256 phi = random_uint256();
|
||||
|
||||
// Compute notes for outputs
|
||||
for (size_t i = 0; i < NumOutputs; i++) {
|
||||
// Sample r
|
||||
uint256 r = random_uint256();
|
||||
|
||||
out_notes[i] = outputs[i].note(phi, r, i, h_sig);
|
||||
}
|
||||
|
||||
// Compute the output commitments
|
||||
for (size_t i = 0; i < NumOutputs; i++) {
|
||||
out_commitments[i] = out_notes[i].cm();
|
||||
}
|
||||
|
||||
// Encrypt the ciphertexts containing the note
|
||||
// plaintexts to the recipients of the value.
|
||||
{
|
||||
ZCNoteEncryption encryptor(h_sig);
|
||||
|
||||
for (size_t i = 0; i < NumOutputs; i++) {
|
||||
// TODO: expose memo in the public interface
|
||||
// 0xF6 is invalid UTF8 as per spec
|
||||
boost::array<unsigned char, ZC_MEMO_SIZE> memo = {{0xF6}};
|
||||
|
||||
NotePlaintext pt(out_notes[i], memo);
|
||||
|
||||
out_ciphertexts[i] = pt.encrypt(encryptor, outputs[i].addr.pk_enc);
|
||||
}
|
||||
|
||||
out_ephemeralKey = encryptor.get_epk();
|
||||
}
|
||||
|
||||
// Authenticate h_sig with each of the input
|
||||
// spending keys, producing macs which protect
|
||||
// against malleability.
|
||||
for (size_t i = 0; i < NumInputs; i++) {
|
||||
out_macs[i] = PRF_pk(inputs[i].key, i, h_sig);
|
||||
}
|
||||
|
||||
std::vector<FieldT> primary_input;
|
||||
std::vector<FieldT> aux_input;
|
||||
|
||||
{
|
||||
protoboard<FieldT> pb;
|
||||
{
|
||||
joinsplit_gadget<FieldT, NumInputs, NumOutputs> g(pb);
|
||||
g.generate_r1cs_constraints();
|
||||
g.generate_r1cs_witness(
|
||||
phi,
|
||||
rt,
|
||||
h_sig,
|
||||
inputs,
|
||||
out_notes,
|
||||
vpub_old,
|
||||
vpub_new
|
||||
);
|
||||
}
|
||||
|
||||
if (!pb.is_satisfied()) {
|
||||
throw std::invalid_argument("Constraint system not satisfied by inputs");
|
||||
}
|
||||
|
||||
primary_input = pb.primary_input();
|
||||
aux_input = pb.auxiliary_input();
|
||||
}
|
||||
|
||||
auto proof = r1cs_ppzksnark_prover<ppzksnark_ppT>(
|
||||
*pk,
|
||||
primary_input,
|
||||
aux_input
|
||||
);
|
||||
|
||||
std::stringstream ss;
|
||||
ss << proof;
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
template<size_t NumInputs, size_t NumOutputs>
|
||||
JoinSplit<NumInputs, NumOutputs>* JoinSplit<NumInputs, NumOutputs>::Generate()
|
||||
{
|
||||
JoinSplitCircuit<NumInputs, NumOutputs>::initialize();
|
||||
auto js = new JoinSplitCircuit<NumInputs, NumOutputs>();
|
||||
js->generate();
|
||||
|
||||
return js;
|
||||
}
|
||||
|
||||
template<size_t NumInputs, size_t NumOutputs>
|
||||
JoinSplit<NumInputs, NumOutputs>* JoinSplit<NumInputs, NumOutputs>::Unopened()
|
||||
{
|
||||
JoinSplitCircuit<NumInputs, NumOutputs>::initialize();
|
||||
return new JoinSplitCircuit<NumInputs, NumOutputs>();
|
||||
}
|
||||
|
||||
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
|
||||
) {
|
||||
unsigned char personalization[crypto_generichash_blake2b_PERSONALBYTES]
|
||||
= {'Z','c','a','s','h','C','o','m','p','u','t','e','h','S','i','g'};
|
||||
|
||||
std::vector<unsigned char> block(randomSeed.begin(), randomSeed.end());
|
||||
|
||||
for (size_t i = 0; i < NumInputs; i++) {
|
||||
block.insert(block.end(), nullifiers[i].begin(), nullifiers[i].end());
|
||||
}
|
||||
|
||||
block.insert(block.end(), pubKeyHash.begin(), pubKeyHash.end());
|
||||
|
||||
uint256 output;
|
||||
|
||||
if (crypto_generichash_blake2b_salt_personal(output.begin(), 32,
|
||||
&block[0], block.size(),
|
||||
NULL, 0, // No key.
|
||||
NULL, // No salt.
|
||||
personalization
|
||||
) != 0)
|
||||
{
|
||||
throw std::logic_error("hash function failure");
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
Note JSOutput::note(const uint256& 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);
|
||||
}
|
||||
|
||||
JSOutput::JSOutput() : addr(uint256(), uint256()), value(0) {
|
||||
SpendingKey a_sk(random_uint256());
|
||||
addr = a_sk.address();
|
||||
}
|
||||
|
||||
JSInput::JSInput() : witness(ZCIncrementalMerkleTree().witness()),
|
||||
key(random_uint256()) {
|
||||
note = Note(key.address().a_pk, 0, random_uint256(), random_uint256());
|
||||
ZCIncrementalMerkleTree dummy_tree;
|
||||
dummy_tree.append(note.cm());
|
||||
witness = dummy_tree.witness();
|
||||
}
|
||||
|
||||
template class JoinSplit<ZC_NUM_JS_INPUTS,
|
||||
ZC_NUM_JS_OUTPUTS>;
|
||||
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
#ifndef _ZCJOINSPLIT_H_
|
||||
#define _ZCJOINSPLIT_H_
|
||||
|
||||
#include "Zcash.h"
|
||||
#include "Address.hpp"
|
||||
#include "Note.hpp"
|
||||
#include "IncrementalMerkleTree.hpp"
|
||||
#include "NoteEncryption.hpp"
|
||||
|
||||
#include "uint256.h"
|
||||
|
||||
#include <boost/array.hpp>
|
||||
|
||||
namespace libzcash {
|
||||
|
||||
class JSInput {
|
||||
public:
|
||||
ZCIncrementalWitness witness;
|
||||
Note note;
|
||||
SpendingKey key;
|
||||
|
||||
JSInput();
|
||||
JSInput(ZCIncrementalWitness witness,
|
||||
Note note,
|
||||
SpendingKey key) : witness(witness), note(note), key(key) { }
|
||||
|
||||
uint256 nullifier() const {
|
||||
return note.nullifier(key);
|
||||
}
|
||||
};
|
||||
|
||||
class JSOutput {
|
||||
public:
|
||||
PaymentAddress addr;
|
||||
uint64_t value;
|
||||
|
||||
JSOutput();
|
||||
JSOutput(PaymentAddress addr, uint64_t value) : addr(addr), value(value) { }
|
||||
|
||||
Note note(const uint256& phi, const uint256& r, size_t i, const uint256& h_sig) const;
|
||||
};
|
||||
|
||||
template<size_t NumInputs, size_t NumOutputs>
|
||||
class JoinSplit {
|
||||
public:
|
||||
static JoinSplit<NumInputs, NumOutputs>* Generate();
|
||||
static JoinSplit<NumInputs, NumOutputs>* Unopened();
|
||||
static uint256 h_sig(const uint256& randomSeed,
|
||||
const boost::array<uint256, NumInputs>& nullifiers,
|
||||
const uint256& pubKeyHash
|
||||
);
|
||||
|
||||
// TODO: #789
|
||||
virtual void setProvingKeyPath(std::string) = 0;
|
||||
virtual void loadProvingKey() = 0;
|
||||
|
||||
virtual void saveProvingKey(std::string path) = 0;
|
||||
virtual void loadVerifyingKey(std::string path) = 0;
|
||||
virtual void saveVerifyingKey(std::string path) = 0;
|
||||
|
||||
virtual std::string 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,
|
||||
uint256& out_ephemeralKey,
|
||||
const uint256& pubKeyHash,
|
||||
uint256& out_randomSeed,
|
||||
boost::array<uint256, NumInputs>& out_hmacs,
|
||||
boost::array<uint256, NumInputs>& out_nullifiers,
|
||||
boost::array<uint256, NumOutputs>& out_commitments,
|
||||
uint64_t vpub_old,
|
||||
uint64_t vpub_new,
|
||||
const uint256& rt
|
||||
) = 0;
|
||||
|
||||
virtual bool verify(
|
||||
const std::string& proof,
|
||||
const uint256& pubKeyHash,
|
||||
const uint256& randomSeed,
|
||||
const boost::array<uint256, NumInputs>& hmacs,
|
||||
const boost::array<uint256, NumInputs>& nullifiers,
|
||||
const boost::array<uint256, NumOutputs>& commitments,
|
||||
uint64_t vpub_old,
|
||||
uint64_t vpub_new,
|
||||
const uint256& rt
|
||||
) = 0;
|
||||
|
||||
protected:
|
||||
JoinSplit() {}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
typedef libzcash::JoinSplit<ZC_NUM_JS_INPUTS,
|
||||
ZC_NUM_JS_OUTPUTS> ZCJoinSplit;
|
||||
|
||||
#endif // _ZCJOINSPLIT_H_
|
|
@ -0,0 +1,92 @@
|
|||
#include "Note.hpp"
|
||||
#include "prf.h"
|
||||
#include "crypto/sha256.h"
|
||||
#include "zerocash/utils/util.h"
|
||||
|
||||
#include "version.h"
|
||||
#include "streams.h"
|
||||
|
||||
namespace libzcash {
|
||||
|
||||
Note::Note() {
|
||||
a_pk = random_uint256();
|
||||
rho = random_uint256();
|
||||
r = random_uint256();
|
||||
value = 0;
|
||||
}
|
||||
|
||||
uint256 Note::cm() const {
|
||||
unsigned char discriminant = 0xb0;
|
||||
|
||||
CSHA256 hasher;
|
||||
hasher.Write(&discriminant, 1);
|
||||
hasher.Write(a_pk.begin(), 32);
|
||||
|
||||
std::vector<unsigned char> value_vec(sizeof(value), 0);
|
||||
libzerocash::convertIntToBytesVector(value, value_vec);
|
||||
|
||||
hasher.Write(&value_vec[0], value_vec.size());
|
||||
hasher.Write(rho.begin(), 32);
|
||||
hasher.Write(r.begin(), 32);
|
||||
|
||||
uint256 result;
|
||||
hasher.Finalize(result.begin());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint256 Note::nullifier(const SpendingKey& a_sk) const {
|
||||
return PRF_nf(a_sk, rho);
|
||||
}
|
||||
|
||||
NotePlaintext::NotePlaintext(
|
||||
const Note& note,
|
||||
boost::array<unsigned char, ZCASH_MEMO_SIZE> memo) : memo(memo)
|
||||
{
|
||||
value = note.value;
|
||||
rho = note.rho;
|
||||
r = note.r;
|
||||
}
|
||||
|
||||
Note NotePlaintext::note(const PaymentAddress& addr) const
|
||||
{
|
||||
return Note(addr.a_pk, value, rho, r);
|
||||
}
|
||||
|
||||
NotePlaintext NotePlaintext::decrypt(const ZCNoteDecryption& decryptor,
|
||||
const ZCNoteDecryption::Ciphertext& ciphertext,
|
||||
const uint256& ephemeralKey,
|
||||
const uint256& h_sig,
|
||||
unsigned char nonce
|
||||
)
|
||||
{
|
||||
auto plaintext = decryptor.decrypt(ciphertext, ephemeralKey, h_sig, nonce);
|
||||
|
||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss << plaintext;
|
||||
|
||||
NotePlaintext ret;
|
||||
ss >> ret;
|
||||
|
||||
assert(ss.size() == 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ZCNoteEncryption::Ciphertext NotePlaintext::encrypt(ZCNoteEncryption& encryptor,
|
||||
const uint256& pk_enc
|
||||
) const
|
||||
{
|
||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss << (*this);
|
||||
|
||||
ZCNoteEncryption::Plaintext pt;
|
||||
|
||||
assert(pt.size() == ss.size());
|
||||
|
||||
memcpy(&pt[0], &ss[0], pt.size());
|
||||
|
||||
return encryptor.encrypt(pk_enc, pt);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
#ifndef _ZCNOTE_H_
|
||||
#define _ZCNOTE_H_
|
||||
|
||||
#include "uint256.h"
|
||||
#include "Zcash.h"
|
||||
#include "Address.hpp"
|
||||
#include "NoteEncryption.hpp"
|
||||
|
||||
namespace libzcash {
|
||||
|
||||
class Note {
|
||||
public:
|
||||
uint256 a_pk;
|
||||
uint64_t value;
|
||||
uint256 rho;
|
||||
uint256 r;
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
class NotePlaintext {
|
||||
public:
|
||||
uint64_t value;
|
||||
uint256 rho;
|
||||
uint256 r;
|
||||
boost::array<unsigned char, ZC_MEMO_SIZE> memo;
|
||||
|
||||
NotePlaintext() {}
|
||||
|
||||
NotePlaintext(const Note& note, boost::array<unsigned char, ZC_MEMO_SIZE> memo);
|
||||
|
||||
Note note(const PaymentAddress& addr) const;
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
||||
unsigned char leadingByte = 0x00;
|
||||
READWRITE(leadingByte);
|
||||
|
||||
if (leadingByte != 0x00) {
|
||||
throw std::ios_base::failure("lead byte of NotePlaintext is not recognized");
|
||||
}
|
||||
|
||||
READWRITE(value);
|
||||
READWRITE(rho);
|
||||
READWRITE(r);
|
||||
READWRITE(memo);
|
||||
}
|
||||
|
||||
static NotePlaintext decrypt(const ZCNoteDecryption& decryptor,
|
||||
const ZCNoteDecryption::Ciphertext& ciphertext,
|
||||
const uint256& ephemeralKey,
|
||||
const uint256& h_sig,
|
||||
unsigned char nonce
|
||||
);
|
||||
|
||||
ZCNoteEncryption::Ciphertext encrypt(ZCNoteEncryption& encryptor,
|
||||
const uint256& pk_enc
|
||||
) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // _ZCNOTE_H_
|
|
@ -0,0 +1,44 @@
|
|||
template<typename FieldT, size_t NumInputs, size_t NumOutputs>
|
||||
class joinsplit_gadget : gadget<FieldT> {
|
||||
public:
|
||||
joinsplit_gadget(protoboard<FieldT> &pb) : gadget<FieldT>(pb) {
|
||||
pb_variable_array<FieldT> test;
|
||||
test.allocate(pb, 1);
|
||||
pb.set_input_sizes(1);
|
||||
|
||||
// TODO!
|
||||
}
|
||||
|
||||
void generate_r1cs_constraints() {
|
||||
// TODO!
|
||||
}
|
||||
|
||||
void generate_r1cs_witness(
|
||||
const uint256& phi,
|
||||
const uint256& rt,
|
||||
const uint256& h_sig,
|
||||
const boost::array<JSInput, NumInputs>& inputs,
|
||||
const boost::array<Note, NumOutputs>& outputs,
|
||||
uint64_t vpub_old,
|
||||
uint64_t vpub_new
|
||||
) {
|
||||
// TODO!
|
||||
}
|
||||
|
||||
static r1cs_primary_input<FieldT> witness_map(
|
||||
const uint256& rt,
|
||||
const uint256& h_sig,
|
||||
const boost::array<uint256, NumInputs>& hmacs,
|
||||
const boost::array<uint256, NumInputs>& nullifiers,
|
||||
const boost::array<uint256, NumOutputs>& commitments,
|
||||
uint64_t vpub_old,
|
||||
uint64_t vpub_new
|
||||
) {
|
||||
// todo
|
||||
|
||||
std::vector<FieldT> input_as_field_elements;
|
||||
input_as_field_elements.push_back(FieldT::zero());
|
||||
|
||||
return input_as_field_elements;
|
||||
}
|
||||
};
|
Loading…
Reference in New Issue