![ewillbefull@gmail.com](/assets/img/avatar_default.png)
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