Browse Source

Integrate Groth16 verification and proving.

pull/4/head
Sean Bowe 6 years ago
parent
commit
b7a6c32178
  1. 4
      depends/packages/librustzcash.mk
  2. 16
      src/gtest/test_joinsplit.cpp
  3. 3
      src/gtest/test_transaction.cpp
  4. 69
      src/primitives/transaction.cpp
  5. 16
      src/primitives/transaction.h
  6. 8
      src/test/transaction_tests.cpp
  7. 4
      src/utiltest.cpp
  8. 1
      src/wallet/asyncrpcoperation_mergetoaddress.cpp
  9. 1
      src/wallet/asyncrpcoperation_sendmany.cpp
  10. 1
      src/wallet/asyncrpcoperation_shieldcoinbase.cpp
  11. 14
      src/wallet/rpcwallet.cpp
  12. 56
      src/zcash/JoinSplit.cpp
  13. 11
      src/zcash/JoinSplit.hpp
  14. 3
      src/zcbenchmarks.cpp

4
depends/packages/librustzcash.mk

@ -3,8 +3,8 @@ $(package)_version=0.1
$(package)_download_path=https://github.com/zcash/$(package)/archive/
$(package)_file_name=$(package)-$($(package)_git_commit).tar.gz
$(package)_download_file=$($(package)_git_commit).tar.gz
$(package)_sha256_hash=65363973dfbdde3bc9cb4427724db399c201f580eb42fb02b0b86e043931c90b
$(package)_git_commit=5e220695e5961c8619a1095a3b9022509c6c9b9d
$(package)_sha256_hash=22cd7afa38b0f60a0b326d1810f1c48204972946d3bf2d2ed6e3feb79e10d554
$(package)_git_commit=fefa46b4c4f2815819e0c7f2d1771239596ea450
$(package)_dependencies=rust $(rust_crates)
$(package)_patches=cargo.config

16
src/gtest/test_joinsplit.cpp

@ -3,6 +3,7 @@
#include "utilstrencodings.h"
#include <boost/foreach.hpp>
#include <boost/variant/get.hpp>
#include "zcash/prf.h"
#include "util.h"
@ -42,7 +43,7 @@ void test_full_api(ZCJoinSplit* js)
boost::array<uint256, 2> commitments;
uint256 rt = tree.root();
boost::array<ZCNoteEncryption::Ciphertext, 2> ciphertexts;
ZCProof proof;
SproutProof proof;
{
boost::array<JSInput, 2> inputs = {
@ -59,6 +60,7 @@ void test_full_api(ZCJoinSplit* js)
// Perform the proof
proof = js->prove(
false,
inputs,
outputs,
output_notes,
@ -75,9 +77,11 @@ void test_full_api(ZCJoinSplit* js)
);
}
auto sprout_proof = boost::relaxed_get<ZCProof, ZCProof, GrothProof>(&proof);
// Verify the transaction:
ASSERT_TRUE(js->verify(
proof,
*sprout_proof,
verifier,
pubKeyHash,
randomSeed,
@ -134,6 +138,7 @@ void test_full_api(ZCJoinSplit* js)
// Perform the proof
proof = js->prove(
false,
inputs,
outputs,
output_notes,
@ -150,9 +155,11 @@ void test_full_api(ZCJoinSplit* js)
);
}
sprout_proof = boost::relaxed_get<ZCProof, ZCProof, GrothProof>(&proof);
// Verify the transaction:
ASSERT_TRUE(js->verify(
proof,
*sprout_proof,
verifier,
pubKeyHash,
randomSeed,
@ -185,7 +192,8 @@ void invokeAPI(
boost::array<SproutNote, 2> output_notes;
ZCProof proof = js->prove(
SproutProof proof = js->prove(
false,
inputs,
outputs,
output_notes,

3
src/gtest/test_transaction.cpp

@ -43,6 +43,7 @@ TEST(Transaction, JSDescriptionRandomized) {
{
auto jsdesc = JSDescription::Randomized(
false,
*params, pubKeyHash, rt,
inputs, outputs,
inputMap, outputMap,
@ -59,6 +60,7 @@ TEST(Transaction, JSDescriptionRandomized) {
{
auto jsdesc = JSDescription::Randomized(
false,
*params, pubKeyHash, rt,
inputs, outputs,
inputMap, outputMap,
@ -72,6 +74,7 @@ TEST(Transaction, JSDescriptionRandomized) {
{
auto jsdesc = JSDescription::Randomized(
false,
*params, pubKeyHash, rt,
inputs, outputs,
inputMap, outputMap,

69
src/primitives/transaction.cpp

@ -9,20 +9,25 @@
#include "tinyformat.h"
#include "utilstrencodings.h"
JSDescription::JSDescription(ZCJoinSplit& params,
const uint256& pubKeyHash,
const uint256& anchor,
const boost::array<libzcash::JSInput, ZC_NUM_JS_INPUTS>& inputs,
const boost::array<libzcash::JSOutput, ZC_NUM_JS_OUTPUTS>& outputs,
CAmount vpub_old,
CAmount vpub_new,
bool computeProof,
uint256 *esk // payment disclosure
) : vpub_old(vpub_old), vpub_new(vpub_new), anchor(anchor)
#include "librustzcash.h"
JSDescription::JSDescription(
bool makeGrothProof,
ZCJoinSplit& params,
const uint256& pubKeyHash,
const uint256& anchor,
const boost::array<libzcash::JSInput, ZC_NUM_JS_INPUTS>& inputs,
const boost::array<libzcash::JSOutput, ZC_NUM_JS_OUTPUTS>& outputs,
CAmount vpub_old,
CAmount vpub_new,
bool computeProof,
uint256 *esk // payment disclosure
) : vpub_old(vpub_old), vpub_new(vpub_new), anchor(anchor)
{
boost::array<libzcash::SproutNote, ZC_NUM_JS_OUTPUTS> notes;
proof = params.prove(
makeGrothProof,
inputs,
outputs,
notes,
@ -42,19 +47,20 @@ JSDescription::JSDescription(ZCJoinSplit& params,
}
JSDescription JSDescription::Randomized(
ZCJoinSplit& params,
const uint256& pubKeyHash,
const uint256& anchor,
boost::array<libzcash::JSInput, ZC_NUM_JS_INPUTS>& inputs,
boost::array<libzcash::JSOutput, ZC_NUM_JS_OUTPUTS>& outputs,
boost::array<size_t, ZC_NUM_JS_INPUTS>& inputMap,
boost::array<size_t, ZC_NUM_JS_OUTPUTS>& outputMap,
CAmount vpub_old,
CAmount vpub_new,
bool computeProof,
uint256 *esk, // payment disclosure
std::function<int(int)> gen
)
bool makeGrothProof,
ZCJoinSplit& params,
const uint256& pubKeyHash,
const uint256& anchor,
boost::array<libzcash::JSInput, ZC_NUM_JS_INPUTS>& inputs,
boost::array<libzcash::JSOutput, ZC_NUM_JS_OUTPUTS>& outputs,
boost::array<size_t, ZC_NUM_JS_INPUTS>& inputMap,
boost::array<size_t, ZC_NUM_JS_OUTPUTS>& outputMap,
CAmount vpub_old,
CAmount vpub_new,
bool computeProof,
uint256 *esk, // payment disclosure
std::function<int(int)> gen
)
{
// Randomize the order of the inputs and outputs
inputMap = {0, 1};
@ -66,6 +72,7 @@ JSDescription JSDescription::Randomized(
MappedShuffle(outputs.begin(), outputMap.begin(), ZC_NUM_JS_OUTPUTS, gen);
return JSDescription(
makeGrothProof,
params, pubKeyHash, anchor, inputs, outputs,
vpub_old, vpub_new, computeProof,
esk // payment disclosure
@ -105,7 +112,21 @@ public:
bool operator()(const libzcash::GrothProof& proof) const
{
return false;
uint256 h_sig = params.h_sig(jsdesc.randomSeed, jsdesc.nullifiers, pubKeyHash);
return librustzcash_sprout_verify(
proof.begin(),
jsdesc.anchor.begin(),
h_sig.begin(),
jsdesc.macs[0].begin(),
jsdesc.macs[1].begin(),
jsdesc.nullifiers[0].begin(),
jsdesc.nullifiers[1].begin(),
jsdesc.commitments[0].begin(),
jsdesc.commitments[1].begin(),
jsdesc.vpub_old,
jsdesc.vpub_new
);
}
};

16
src/primitives/transaction.h

@ -36,15 +36,6 @@ static_assert(SAPLING_TX_VERSION >= SAPLING_MIN_TX_VERSION,
static_assert(SAPLING_TX_VERSION <= SAPLING_MAX_TX_VERSION,
"Sapling tx version must not be higher than maximum");
static constexpr size_t GROTH_PROOF_SIZE = (
48 + // π_A
96 + // π_B
48); // π_C
namespace libzcash {
typedef boost::array<unsigned char, GROTH_PROOF_SIZE> GrothProof;
}
/**
* A shielded input to a transaction. It contains data that describes a Spend transfer.
*/
@ -246,11 +237,13 @@ public:
// JoinSplit proof
// This is a zk-SNARK which ensures that this JoinSplit is valid.
boost::variant<libzcash::ZCProof, libzcash::GrothProof> proof;
libzcash::SproutProof proof;
JSDescription(): vpub_old(0), vpub_new(0) { }
JSDescription(ZCJoinSplit& params,
JSDescription(
bool makeGrothProof,
ZCJoinSplit& params,
const uint256& pubKeyHash,
const uint256& rt,
const boost::array<libzcash::JSInput, ZC_NUM_JS_INPUTS>& inputs,
@ -262,6 +255,7 @@ public:
);
static JSDescription Randomized(
bool makeGrothProof,
ZCJoinSplit& params,
const uint256& pubKeyHash,
const uint256& rt,

8
src/test/transaction_tests.cpp

@ -372,7 +372,7 @@ BOOST_AUTO_TEST_CASE(test_basic_joinsplit_verification)
auto verifier = libzcash::ProofVerifier::Strict();
{
JSDescription jsdesc(*pzcashParams, pubKeyHash, rt, inputs, outputs, 0, 0);
JSDescription jsdesc(false, *pzcashParams, pubKeyHash, rt, inputs, outputs, 0, 0);
BOOST_CHECK(jsdesc.Verify(*pzcashParams, verifier, pubKeyHash));
CDataStream ss(SER_DISK, CLIENT_VERSION);
@ -387,13 +387,13 @@ BOOST_AUTO_TEST_CASE(test_basic_joinsplit_verification)
{
// Ensure that the balance equation is working.
BOOST_CHECK_THROW(JSDescription(*pzcashParams, pubKeyHash, rt, inputs, outputs, 10, 0), std::invalid_argument);
BOOST_CHECK_THROW(JSDescription(*pzcashParams, pubKeyHash, rt, inputs, outputs, 0, 10), std::invalid_argument);
BOOST_CHECK_THROW(JSDescription(false, *pzcashParams, pubKeyHash, rt, inputs, outputs, 10, 0), std::invalid_argument);
BOOST_CHECK_THROW(JSDescription(false, *pzcashParams, pubKeyHash, rt, inputs, outputs, 0, 10), std::invalid_argument);
}
{
// Ensure that it won't verify if the root is changed.
auto test = JSDescription(*pzcashParams, pubKeyHash, rt, inputs, outputs, 0, 0);
auto test = JSDescription(false, *pzcashParams, pubKeyHash, rt, inputs, outputs, 0, 0);
test.anchor = GetRandHash();
BOOST_CHECK(!test.Verify(*pzcashParams, verifier, pubKeyHash));
}

4
src/utiltest.cpp

@ -40,7 +40,7 @@ CWalletTx GetValidReceive(ZCJoinSplit& params,
// Prepare JoinSplits
uint256 rt;
JSDescription jsdesc {params, mtx.joinSplitPubKey, rt,
JSDescription jsdesc {false, params, mtx.joinSplitPubKey, rt,
inputs, outputs, 2*value, 0, false};
mtx.vjoinsplit.push_back(jsdesc);
@ -123,7 +123,7 @@ CWalletTx GetValidSpend(ZCJoinSplit& params,
// Prepare JoinSplits
uint256 rt = tree.root();
JSDescription jsdesc {params, mtx.joinSplitPubKey, rt,
JSDescription jsdesc {false, params, mtx.joinSplitPubKey, rt,
inputs, outputs, 0, value, false};
mtx.vjoinsplit.push_back(jsdesc);

1
src/wallet/asyncrpcoperation_mergetoaddress.cpp

@ -768,6 +768,7 @@ UniValue AsyncRPCOperation_mergetoaddress::perform_joinsplit(
uint256 esk; // payment disclosure - secret
JSDescription jsdesc = JSDescription::Randomized(
mtx.fOverwintered && (mtx.nVersion >= SAPLING_TX_VERSION),
*pzcashParams,
joinSplitPubKey_,
anchor,

1
src/wallet/asyncrpcoperation_sendmany.cpp

@ -990,6 +990,7 @@ UniValue AsyncRPCOperation_sendmany::perform_joinsplit(
uint256 esk; // payment disclosure - secret
JSDescription jsdesc = JSDescription::Randomized(
mtx.fOverwintered && (mtx.nVersion >= SAPLING_TX_VERSION),
*pzcashParams,
joinSplitPubKey_,
anchor,

1
src/wallet/asyncrpcoperation_shieldcoinbase.cpp

@ -359,6 +359,7 @@ UniValue AsyncRPCOperation_shieldcoinbase::perform_joinsplit(ShieldCoinbaseJSInf
uint256 esk; // payment disclosure - secret
JSDescription jsdesc = JSDescription::Randomized(
mtx.fOverwintered && (mtx.nVersion >= SAPLING_TX_VERSION),
*pzcashParams,
joinSplitPubKey_,
anchor,

14
src/wallet/rpcwallet.cpp

@ -2640,7 +2640,8 @@ UniValue zc_sample_joinsplit(const UniValue& params, bool fHelp)
uint256 pubKeyHash;
uint256 anchor = ZCIncrementalMerkleTree().root();
JSDescription samplejoinsplit(*pzcashParams,
JSDescription samplejoinsplit(false,
*pzcashParams,
pubKeyHash,
anchor,
{JSInput(), JSInput()},
@ -2991,7 +2992,8 @@ UniValue zc_raw_joinsplit(const UniValue& params, bool fHelp)
mtx.nVersion = 2;
mtx.joinSplitPubKey = joinSplitPubKey;
JSDescription jsdesc(*pzcashParams,
JSDescription jsdesc(false,
*pzcashParams,
joinSplitPubKey,
anchor,
{vjsin[0], vjsin[1]},
@ -3667,7 +3669,13 @@ UniValue z_sendmany(const UniValue& params, bool fHelp)
size_t txsize = 0;
for (int i = 0; i < zaddrRecipients.size(); i++) {
// TODO Check whether the recipient is a Sprout or Sapling address
mtx.vjoinsplit.push_back(JSDescription());
JSDescription jsdesc;
if (mtx.fOverwintered && (mtx.nVersion >= SAPLING_TX_VERSION)) {
jsdesc.proof = GrothProof();
}
mtx.vjoinsplit.push_back(jsdesc);
}
CTransaction tx(mtx);
txsize += GetSerializeSize(tx, SER_NETWORK, tx.nVersion);

56
src/zcash/JoinSplit.cpp

@ -18,6 +18,10 @@
#include "sync.h"
#include "amount.h"
#include "librustzcash.h"
#include "streams.h"
#include "version.h"
using namespace libsnark;
namespace libzcash {
@ -135,7 +139,8 @@ public:
}
}
ZCProof prove(
SproutProof prove(
bool makeGrothProof,
const boost::array<JSInput, NumInputs>& inputs,
const boost::array<JSOutput, NumOutputs>& outputs,
boost::array<SproutNote, NumOutputs>& out_notes,
@ -266,6 +271,55 @@ 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();
}

11
src/zcash/JoinSplit.hpp

@ -15,6 +15,14 @@
namespace libzcash {
static constexpr size_t GROTH_PROOF_SIZE = (
48 + // π_A
96 + // π_B
48); // π_C
typedef boost::array<unsigned char, GROTH_PROOF_SIZE> GrothProof;
typedef boost::variant<ZCProof, GrothProof> SproutProof;
class JSInput {
public:
ZCIncrementalWitness witness;
@ -59,7 +67,8 @@ public:
const uint256& pubKeyHash
);
virtual ZCProof prove(
virtual SproutProof prove(
bool makeGrothProof,
const boost::array<JSInput, NumInputs>& inputs,
const boost::array<JSOutput, NumOutputs>& outputs,
boost::array<SproutNote, NumOutputs>& out_notes,

3
src/zcbenchmarks.cpp

@ -116,7 +116,8 @@ double benchmark_create_joinsplit()
struct timeval tv_start;
timer_start(tv_start);
JSDescription jsdesc(*pzcashParams,
JSDescription jsdesc(false, // TODO: ?
*pzcashParams,
pubKeyHash,
anchor,
{JSInput(), JSInput()},

Loading…
Cancel
Save