// Copyright (c) 2016 The Zcash developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "utiltest.h" #include "consensus/upgrades.h" #include CWalletTx GetValidReceive(ZCJoinSplit& params, const libzcash::SproutSpendingKey& sk, CAmount value, bool randomInputs, int32_t version /* = 2 */) { CMutableTransaction mtx; mtx.nVersion = version; mtx.vin.resize(2); if (randomInputs) { mtx.vin[0].prevout.hash = GetRandHash(); mtx.vin[1].prevout.hash = GetRandHash(); } else { mtx.vin[0].prevout.hash = uint256S("0000000000000000000000000000000000000000000000000000000000000001"); mtx.vin[1].prevout.hash = uint256S("0000000000000000000000000000000000000000000000000000000000000002"); } mtx.vin[0].prevout.n = 0; mtx.vin[1].prevout.n = 0; // Generate an ephemeral keypair. uint256 joinSplitPubKey; unsigned char joinSplitPrivKey[crypto_sign_SECRETKEYBYTES]; crypto_sign_keypair(joinSplitPubKey.begin(), joinSplitPrivKey); mtx.joinSplitPubKey = joinSplitPubKey; std::array inputs = { libzcash::JSInput(), // dummy input libzcash::JSInput() // dummy input }; std::array outputs = { libzcash::JSOutput(sk.address(), value), libzcash::JSOutput(sk.address(), value) }; // Prepare JoinSplits uint256 rt; JSDescription jsdesc {false, params, mtx.joinSplitPubKey, rt, inputs, outputs, 2*value, 0, false}; mtx.vjoinsplit.push_back(jsdesc); if (version >= 4) { // Shielded Output OutputDescription od; mtx.vShieldedOutput.push_back(od); } // Empty output script. uint32_t consensusBranchId = SPROUT_BRANCH_ID; CScript scriptCode; CTransaction signTx(mtx); uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId); // Add the signature assert(crypto_sign_detached(&mtx.joinSplitSig[0], NULL, dataToBeSigned.begin(), 32, joinSplitPrivKey ) == 0); CTransaction tx {mtx}; CWalletTx wtx {NULL, tx}; return wtx; } libzcash::SproutNote GetNote(ZCJoinSplit& params, const libzcash::SproutSpendingKey& sk, const CTransaction& tx, size_t js, size_t n) { ZCNoteDecryption decryptor {sk.receiving_key()}; auto hSig = tx.vjoinsplit[js].h_sig(params, tx.joinSplitPubKey); auto note_pt = libzcash::SproutNotePlaintext::decrypt( decryptor, tx.vjoinsplit[js].ciphertexts[n], tx.vjoinsplit[js].ephemeralKey, hSig, (unsigned char) n); return note_pt.note(sk.address()); } CWalletTx GetValidSpend(ZCJoinSplit& params, const libzcash::SproutSpendingKey& sk, const libzcash::SproutNote& note, CAmount value) { CMutableTransaction mtx; mtx.vout.resize(2); mtx.vout[0].nValue = value; mtx.vout[1].nValue = 0; // Generate an ephemeral keypair. uint256 joinSplitPubKey; unsigned char joinSplitPrivKey[crypto_sign_SECRETKEYBYTES]; crypto_sign_keypair(joinSplitPubKey.begin(), joinSplitPrivKey); mtx.joinSplitPubKey = joinSplitPubKey; // Fake tree for the unused witness SproutMerkleTree tree; libzcash::JSOutput dummyout; libzcash::JSInput dummyin; { if (note.value() > value) { libzcash::SproutSpendingKey dummykey = libzcash::SproutSpendingKey::random(); libzcash::SproutPaymentAddress dummyaddr = dummykey.address(); dummyout = libzcash::JSOutput(dummyaddr, note.value() - value); } else if (note.value() < value) { libzcash::SproutSpendingKey dummykey = libzcash::SproutSpendingKey::random(); libzcash::SproutPaymentAddress dummyaddr = dummykey.address(); libzcash::SproutNote dummynote(dummyaddr.a_pk, (value - note.value()), uint256(), uint256()); tree.append(dummynote.cm()); dummyin = libzcash::JSInput(tree.witness(), dummynote, dummykey); } } tree.append(note.cm()); std::array inputs = { libzcash::JSInput(tree.witness(), note, sk), dummyin }; std::array outputs = { dummyout, // dummy output libzcash::JSOutput() // dummy output }; // Prepare JoinSplits uint256 rt = tree.root(); JSDescription jsdesc {false, params, mtx.joinSplitPubKey, rt, inputs, outputs, 0, value, false}; mtx.vjoinsplit.push_back(jsdesc); // Empty output script. uint32_t consensusBranchId = SPROUT_BRANCH_ID; CScript scriptCode; CTransaction signTx(mtx); uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId); // Add the signature assert(crypto_sign_detached(&mtx.joinSplitSig[0], NULL, dataToBeSigned.begin(), 32, joinSplitPrivKey ) == 0); CTransaction tx {mtx}; CWalletTx wtx {NULL, tx}; return wtx; }