|
|
@ -13,131 +13,22 @@ |
|
|
|
#include "tinyformat.h" |
|
|
|
#include "sync.h" |
|
|
|
#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" |
|
|
|
|
|
|
|
static CCriticalSection cs_ParamsIO; |
|
|
|
|
|
|
|
template<typename T> |
|
|
|
void saveToFile(const 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(const std::string path, T& objIn) { |
|
|
|
LOCK(cs_ParamsIO); |
|
|
|
|
|
|
|
std::stringstream ss; |
|
|
|
std::ifstream fh(path, std::ios::binary); |
|
|
|
|
|
|
|
if(!fh.is_open()) { |
|
|
|
throw std::runtime_error(strprintf("could not load param file at %s", path)); |
|
|
|
} |
|
|
|
|
|
|
|
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; |
|
|
|
|
|
|
|
r1cs_ppzksnark_verification_key<ppzksnark_ppT> vk; |
|
|
|
r1cs_ppzksnark_processed_verification_key<ppzksnark_ppT> vk_precomp; |
|
|
|
std::string pkPath; |
|
|
|
|
|
|
|
JoinSplitCircuit(const std::string vkPath, const std::string pkPath) : pkPath(pkPath) { |
|
|
|
loadFromFile(vkPath, vk); |
|
|
|
vk_precomp = r1cs_ppzksnark_verifier_process_vk(vk); |
|
|
|
} |
|
|
|
JoinSplitCircuit() {} |
|
|
|
~JoinSplitCircuit() {} |
|
|
|
|
|
|
|
static void generate(const std::string r1csPath, |
|
|
|
const std::string vkPath, |
|
|
|
const std::string pkPath) |
|
|
|
{ |
|
|
|
protoboard<FieldT> pb; |
|
|
|
|
|
|
|
joinsplit_gadget<FieldT, NumInputs, NumOutputs> g(pb); |
|
|
|
g.generate_r1cs_constraints(); |
|
|
|
|
|
|
|
auto r1cs = pb.get_constraint_system(); |
|
|
|
|
|
|
|
saveToFile(r1csPath, r1cs); |
|
|
|
|
|
|
|
r1cs_ppzksnark_keypair<ppzksnark_ppT> keypair = r1cs_ppzksnark_generator<ppzksnark_ppT>(r1cs); |
|
|
|
|
|
|
|
saveToFile(vkPath, keypair.vk); |
|
|
|
saveToFile(pkPath, keypair.pk); |
|
|
|
} |
|
|
|
|
|
|
|
bool verify( |
|
|
|
const PHGRProof& proof, |
|
|
|
ProofVerifier& verifier, |
|
|
|
const uint256& joinSplitPubKey, |
|
|
|
const uint256& randomSeed, |
|
|
|
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 |
|
|
|
) { |
|
|
|
try { |
|
|
|
auto r1cs_proof = proof.to_libsnark_proof<r1cs_ppzksnark_proof<ppzksnark_ppT>>(); |
|
|
|
|
|
|
|
uint256 h_sig = this->h_sig(randomSeed, nullifiers, joinSplitPubKey); |
|
|
|
|
|
|
|
auto witness = joinsplit_gadget<FieldT, NumInputs, NumOutputs>::witness_map( |
|
|
|
rt, |
|
|
|
h_sig, |
|
|
|
macs, |
|
|
|
nullifiers, |
|
|
|
commitments, |
|
|
|
vpub_old, |
|
|
|
vpub_new |
|
|
|
); |
|
|
|
|
|
|
|
return verifier.check( |
|
|
|
vk, |
|
|
|
vk_precomp, |
|
|
|
witness, |
|
|
|
r1cs_proof |
|
|
|
); |
|
|
|
} catch (...) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
SproutProof prove( |
|
|
|
bool makeGrothProof, |
|
|
|
const std::array<JSInput, NumInputs>& inputs, |
|
|
|
const std::array<JSOutput, NumOutputs>& outputs, |
|
|
|
std::array<SproutNote, NumOutputs>& out_notes, |
|
|
@ -268,74 +159,59 @@ public: |
|
|
|
out_macs[i] = PRF_pk(inputs[i].key, i, h_sig); |
|
|
|
} |
|
|
|
|
|
|
|
if (makeGrothProof) { |
|
|
|
if (!computeProof) { |
|
|
|
return GrothProof(); |
|
|
|
} |
|
|
|
|
|
|
|
GrothProof proof; |
|
|
|
if (!computeProof) { |
|
|
|
return GrothProof(); |
|
|
|
} |
|
|
|
|
|
|
|
CDataStream ss1(SER_NETWORK, PROTOCOL_VERSION); |
|
|
|
ss1 << inputs[0].witness.path(); |
|
|
|
std::vector<unsigned char> auth1(ss1.begin(), ss1.end()); |
|
|
|
GrothProof proof; |
|
|
|
|
|
|
|
CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION); |
|
|
|
ss2 << inputs[1].witness.path(); |
|
|
|
std::vector<unsigned char> auth2(ss2.begin(), ss2.end()); |
|
|
|
CDataStream ss1(SER_NETWORK, PROTOCOL_VERSION); |
|
|
|
ss1 << inputs[0].witness.path(); |
|
|
|
std::vector<unsigned char> auth1(ss1.begin(), ss1.end()); |
|
|
|
|
|
|
|
librustzcash_sprout_prove( |
|
|
|
proof.begin(), |
|
|
|
CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION); |
|
|
|
ss2 << inputs[1].witness.path(); |
|
|
|
std::vector<unsigned char> auth2(ss2.begin(), ss2.end()); |
|
|
|
|
|
|
|
phi.begin(), |
|
|
|
rt.begin(), |
|
|
|
h_sig.begin(), |
|
|
|
librustzcash_sprout_prove( |
|
|
|
proof.begin(), |
|
|
|
|
|
|
|
inputs[0].key.begin(), |
|
|
|
inputs[0].note.value(), |
|
|
|
inputs[0].note.rho.begin(), |
|
|
|
inputs[0].note.r.begin(), |
|
|
|
auth1.data(), |
|
|
|
phi.begin(), |
|
|
|
rt.begin(), |
|
|
|
h_sig.begin(), |
|
|
|
|
|
|
|
inputs[1].key.begin(), |
|
|
|
inputs[1].note.value(), |
|
|
|
inputs[1].note.rho.begin(), |
|
|
|
inputs[1].note.r.begin(), |
|
|
|
auth2.data(), |
|
|
|
inputs[0].key.begin(), |
|
|
|
inputs[0].note.value(), |
|
|
|
inputs[0].note.rho.begin(), |
|
|
|
inputs[0].note.r.begin(), |
|
|
|
auth1.data(), |
|
|
|
|
|
|
|
out_notes[0].a_pk.begin(), |
|
|
|
out_notes[0].value(), |
|
|
|
out_notes[0].r.begin(), |
|
|
|
inputs[1].key.begin(), |
|
|
|
inputs[1].note.value(), |
|
|
|
inputs[1].note.rho.begin(), |
|
|
|
inputs[1].note.r.begin(), |
|
|
|
auth2.data(), |
|
|
|
|
|
|
|
out_notes[1].a_pk.begin(), |
|
|
|
out_notes[1].value(), |
|
|
|
out_notes[1].r.begin(), |
|
|
|
out_notes[0].a_pk.begin(), |
|
|
|
out_notes[0].value(), |
|
|
|
out_notes[0].r.begin(), |
|
|
|
|
|
|
|
vpub_old, |
|
|
|
vpub_new |
|
|
|
); |
|
|
|
out_notes[1].a_pk.begin(), |
|
|
|
out_notes[1].value(), |
|
|
|
out_notes[1].r.begin(), |
|
|
|
|
|
|
|
return proof; |
|
|
|
} |
|
|
|
vpub_old, |
|
|
|
vpub_new |
|
|
|
); |
|
|
|
|
|
|
|
throw std::invalid_argument("Cannot create non-Groth16 Sprout proofs"); |
|
|
|
return proof; |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
template<size_t NumInputs, size_t NumOutputs> |
|
|
|
void JoinSplit<NumInputs, NumOutputs>::Generate(const std::string r1csPath, |
|
|
|
const std::string vkPath, |
|
|
|
const std::string pkPath) |
|
|
|
{ |
|
|
|
initialize_curve_params(); |
|
|
|
JoinSplitCircuit<NumInputs, NumOutputs>::generate(r1csPath, vkPath, pkPath); |
|
|
|
} |
|
|
|
|
|
|
|
template<size_t NumInputs, size_t NumOutputs> |
|
|
|
JoinSplit<NumInputs, NumOutputs>* JoinSplit<NumInputs, NumOutputs>::Prepared(const std::string vkPath, |
|
|
|
const std::string pkPath) |
|
|
|
JoinSplit<NumInputs, NumOutputs>* JoinSplit<NumInputs, NumOutputs>::Prepared() |
|
|
|
{ |
|
|
|
initialize_curve_params(); |
|
|
|
return new JoinSplitCircuit<NumInputs, NumOutputs>(vkPath, pkPath); |
|
|
|
return new JoinSplitCircuit<NumInputs, NumOutputs>(); |
|
|
|
} |
|
|
|
|
|
|
|
template<size_t NumInputs, size_t NumOutputs> |
|
|
|