Sean Bowe
8 years ago
9 changed files with 729 additions and 0 deletions
@ -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