diff --git a/depends/packages/librustzcash.mk b/depends/packages/librustzcash.mk index b15857fa5..277d78d06 100644 --- a/depends/packages/librustzcash.mk +++ b/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 diff --git a/src/gtest/test_joinsplit.cpp b/src/gtest/test_joinsplit.cpp index c7f4577a3..0ad480574 100644 --- a/src/gtest/test_joinsplit.cpp +++ b/src/gtest/test_joinsplit.cpp @@ -3,6 +3,7 @@ #include "utilstrencodings.h" #include +#include #include "zcash/prf.h" #include "util.h" @@ -42,7 +43,7 @@ void test_full_api(ZCJoinSplit* js) boost::array commitments; uint256 rt = tree.root(); boost::array ciphertexts; - ZCProof proof; + SproutProof proof; { boost::array 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(&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(&proof); + // Verify the transaction: ASSERT_TRUE(js->verify( - proof, + *sprout_proof, verifier, pubKeyHash, randomSeed, @@ -185,7 +192,8 @@ void invokeAPI( boost::array output_notes; - ZCProof proof = js->prove( + SproutProof proof = js->prove( + false, inputs, outputs, output_notes, diff --git a/src/gtest/test_transaction.cpp b/src/gtest/test_transaction.cpp index ee674c6e2..44c047364 100644 --- a/src/gtest/test_transaction.cpp +++ b/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, diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp index a18e8f65a..a3ee0302c 100644 --- a/src/primitives/transaction.cpp +++ b/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& inputs, - const boost::array& 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& inputs, + const boost::array& 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 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& inputs, - boost::array& outputs, - boost::array& inputMap, - boost::array& outputMap, - CAmount vpub_old, - CAmount vpub_new, - bool computeProof, - uint256 *esk, // payment disclosure - std::function gen - ) + bool makeGrothProof, + ZCJoinSplit& params, + const uint256& pubKeyHash, + const uint256& anchor, + boost::array& inputs, + boost::array& outputs, + boost::array& inputMap, + boost::array& outputMap, + CAmount vpub_old, + CAmount vpub_new, + bool computeProof, + uint256 *esk, // payment disclosure + std::function 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 + ); } }; diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index 1066601a1..bea2485e9 100644 --- a/src/primitives/transaction.h +++ b/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 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 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& inputs, @@ -262,6 +255,7 @@ public: ); static JSDescription Randomized( + bool makeGrothProof, ZCJoinSplit& params, const uint256& pubKeyHash, const uint256& rt, diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index fa1238edc..6ca651981 100644 --- a/src/test/transaction_tests.cpp +++ b/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)); } diff --git a/src/utiltest.cpp b/src/utiltest.cpp index 6f43afbfa..dbc92bca9 100644 --- a/src/utiltest.cpp +++ b/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); diff --git a/src/wallet/asyncrpcoperation_mergetoaddress.cpp b/src/wallet/asyncrpcoperation_mergetoaddress.cpp index 4ea230c4f..a29527e29 100644 --- a/src/wallet/asyncrpcoperation_mergetoaddress.cpp +++ b/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, diff --git a/src/wallet/asyncrpcoperation_sendmany.cpp b/src/wallet/asyncrpcoperation_sendmany.cpp index 1df7bcd93..b62e64469 100644 --- a/src/wallet/asyncrpcoperation_sendmany.cpp +++ b/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, diff --git a/src/wallet/asyncrpcoperation_shieldcoinbase.cpp b/src/wallet/asyncrpcoperation_shieldcoinbase.cpp index 2cb5a7499..51e3a581c 100644 --- a/src/wallet/asyncrpcoperation_shieldcoinbase.cpp +++ b/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, diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index e372c1cf4..ddceccbeb 100644 --- a/src/wallet/rpcwallet.cpp +++ b/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); diff --git a/src/zcash/JoinSplit.cpp b/src/zcash/JoinSplit.cpp index a503cb455..ef92d3967 100644 --- a/src/zcash/JoinSplit.cpp +++ b/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& inputs, const boost::array& outputs, boost::array& 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 auth1(ss1.begin(), ss1.end()); + + CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION); + ss2 << inputs[1].witness.path(); + std::vector 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(); } diff --git a/src/zcash/JoinSplit.hpp b/src/zcash/JoinSplit.hpp index 03c499ff0..7b095a6e9 100644 --- a/src/zcash/JoinSplit.hpp +++ b/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 GrothProof; +typedef boost::variant 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& inputs, const boost::array& outputs, boost::array& out_notes, diff --git a/src/zcbenchmarks.cpp b/src/zcbenchmarks.cpp index 9a794089c..4c60fec40 100644 --- a/src/zcbenchmarks.cpp +++ b/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()},