154 lines
5.3 KiB
C++
154 lines
5.3 KiB
C++
// 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 <array>
|
|
|
|
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<libzcash::JSInput, 2> inputs = {
|
|
libzcash::JSInput(), // dummy input
|
|
libzcash::JSInput() // dummy input
|
|
};
|
|
|
|
std::array<libzcash::JSOutput, 2> 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<libzcash::JSInput, 2> inputs = {
|
|
libzcash::JSInput(tree.witness(), note, sk),
|
|
dummyin
|
|
};
|
|
|
|
std::array<libzcash::JSOutput, 2> 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;
|
|
}
|