Add JSDescriptionInfo for constructing JSDescriptions

This matches the existing transaction builder structs:
- SpendDescriptionInfo
- OutputDescriptionInfo
- TransparentInputInfo

It also removes the dependency of the transaction format on the proving
system.
This commit is contained in:
Jack Grigg 2020-07-09 19:40:06 +12:00
parent 726c5c8b19
commit b1aa9365af
14 changed files with 136 additions and 123 deletions

View File

@ -826,11 +826,13 @@ TEST(ChecktransactionTests, SaplingSproutInputSumsTooLarge) {
std::array<size_t, ZC_NUM_JS_INPUTS> inputMap;
std::array<size_t, ZC_NUM_JS_OUTPUTS> outputMap;
auto jsdesc = JSDescription::Randomized(
auto jsdesc = JSDescriptionInfo(
joinSplitPubKey, rt,
inputs, outputs,
0, 0
).BuildRandomized(
inputMap, outputMap,
0, 0, false);
false);
mtx.vJoinSplit.push_back(jsdesc);
}

View File

@ -10,6 +10,7 @@
#include "serialize.h"
#include "primitives/transaction.h"
#include "proof_verifier.h"
#include "transaction_builder.h"
#include "zcash/JoinSplit.hpp"
#include "zcash/Note.hpp"
#include "zcash/NoteEncryption.hpp"
@ -31,7 +32,7 @@ JSDescription makeSproutProof(
uint64_t vpub_new,
const uint256& rt
){
return JSDescription(joinSplitPubKey, rt, inputs, outputs, vpub_old, vpub_new);
return JSDescriptionInfo(joinSplitPubKey, rt, inputs, outputs, vpub_old, vpub_new).BuildDeterministic();
}
bool verifySproutProof(

View File

@ -2,6 +2,7 @@
#include "gtest/utils.h"
#include "primitives/transaction.h"
#include "transaction_builder.h"
#include "zcash/Note.hpp"
#include "zcash/Address.hpp"
@ -43,11 +44,13 @@ TEST(Transaction, JSDescriptionRandomized) {
std::array<size_t, ZC_NUM_JS_OUTPUTS> outputMap;
{
auto jsdesc = JSDescription::Randomized(
auto jsdesc = JSDescriptionInfo(
joinSplitPubKey, rt,
inputs, outputs,
0, 0
).BuildRandomized(
inputMap, outputMap,
0, 0, false);
false);
std::set<size_t> inputSet(inputMap.begin(), inputMap.end());
std::set<size_t> expectedInputSet {0, 1};
@ -59,11 +62,13 @@ TEST(Transaction, JSDescriptionRandomized) {
}
{
auto jsdesc = JSDescription::Randomized(
auto jsdesc = JSDescriptionInfo(
joinSplitPubKey, rt,
inputs, outputs,
0, 0
).BuildRandomized(
inputMap, outputMap,
0, 0, false, nullptr, GenZero);
false, nullptr, GenZero);
std::array<size_t, ZC_NUM_JS_INPUTS> expectedInputMap {1, 0};
std::array<size_t, ZC_NUM_JS_OUTPUTS> expectedOutputMap {1, 0};
@ -72,11 +77,13 @@ TEST(Transaction, JSDescriptionRandomized) {
}
{
auto jsdesc = JSDescription::Randomized(
auto jsdesc = JSDescriptionInfo(
joinSplitPubKey, rt,
inputs, outputs,
0, 0
).BuildRandomized(
inputMap, outputMap,
0, 0, false, nullptr, GenMax);
false, nullptr, GenMax);
std::array<size_t, ZC_NUM_JS_INPUTS> expectedInputMap {0, 1};
std::array<size_t, ZC_NUM_JS_OUTPUTS> expectedOutputMap {0, 1};

View File

@ -9,68 +9,6 @@
#include "tinyformat.h"
#include "utilstrencodings.h"
JSDescription::JSDescription(
const Ed25519VerificationKey& joinSplitPubKey,
const uint256& anchor,
const std::array<libzcash::JSInput, ZC_NUM_JS_INPUTS>& inputs,
const std::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)
{
std::array<libzcash::SproutNote, ZC_NUM_JS_OUTPUTS> notes;
proof = ZCJoinSplit::prove(
inputs,
outputs,
notes,
ciphertexts,
ephemeralKey,
joinSplitPubKey,
randomSeed,
macs,
nullifiers,
commitments,
vpub_old,
vpub_new,
anchor,
computeProof,
esk // payment disclosure
);
}
JSDescription JSDescription::Randomized(
const Ed25519VerificationKey& joinSplitPubKey,
const uint256& anchor,
std::array<libzcash::JSInput, ZC_NUM_JS_INPUTS>& inputs,
std::array<libzcash::JSOutput, ZC_NUM_JS_OUTPUTS>& outputs,
std::array<size_t, ZC_NUM_JS_INPUTS>& inputMap,
std::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};
outputMap = {0, 1};
assert(gen);
MappedShuffle(inputs.begin(), inputMap.begin(), ZC_NUM_JS_INPUTS, gen);
MappedShuffle(outputs.begin(), outputMap.begin(), ZC_NUM_JS_OUTPUTS, gen);
return JSDescription(
joinSplitPubKey, anchor, inputs, outputs,
vpub_old, vpub_new, computeProof,
esk // payment disclosure
);
}
uint256 JSDescription::h_sig(const Ed25519VerificationKey& joinSplitPubKey) const
{
return ZCJoinSplit::h_sig(randomSeed, nullifiers, joinSplitPubKey);

View File

@ -7,7 +7,6 @@
#define BITCOIN_PRIMITIVES_TRANSACTION_H
#include "amount.h"
#include "random.h"
#include "script/script.h"
#include "serialize.h"
#include "streams.h"
@ -236,31 +235,6 @@ public:
JSDescription(): vpub_old(0), vpub_new(0) { }
JSDescription(
const Ed25519VerificationKey& joinSplitPubKey,
const uint256& rt,
const std::array<libzcash::JSInput, ZC_NUM_JS_INPUTS>& inputs,
const std::array<libzcash::JSOutput, ZC_NUM_JS_OUTPUTS>& outputs,
CAmount vpub_old,
CAmount vpub_new,
bool computeProof = true, // Set to false in some tests
uint256 *esk = nullptr // payment disclosure
);
static JSDescription Randomized(
const Ed25519VerificationKey& joinSplitPubKey,
const uint256& rt,
std::array<libzcash::JSInput, ZC_NUM_JS_INPUTS>& inputs,
std::array<libzcash::JSOutput, ZC_NUM_JS_OUTPUTS>& outputs,
std::array<size_t, ZC_NUM_JS_INPUTS>& inputMap,
std::array<size_t, ZC_NUM_JS_OUTPUTS>& outputMap,
CAmount vpub_old,
CAmount vpub_new,
bool computeProof = true, // Set to false in some tests
uint256 *esk = nullptr, // payment disclosure
std::function<int(int)> gen = GetRandInt
);
// Returns the calculated h_sig
uint256 h_sig(const Ed25519VerificationKey& joinSplitPubKey) const;

View File

@ -22,6 +22,7 @@
#include "script/sign.h"
#include "test/test_util.h"
#include "primitives/transaction.h"
#include "transaction_builder.h"
#include <array>
#include <map>
@ -321,7 +322,7 @@ BOOST_AUTO_TEST_CASE(test_basic_joinsplit_verification)
auto verifier = ProofVerifier::Strict();
{
JSDescription jsdesc(joinSplitPubKey, rt, inputs, outputs, 0, 0);
auto jsdesc = JSDescriptionInfo(joinSplitPubKey, rt, inputs, outputs, 0, 0).BuildDeterministic();
BOOST_CHECK(verifier.VerifySprout(jsdesc, joinSplitPubKey));
CDataStream ss(SER_DISK, CLIENT_VERSION);
@ -337,13 +338,13 @@ BOOST_AUTO_TEST_CASE(test_basic_joinsplit_verification)
{
// Ensure that the balance equation is working.
BOOST_CHECK_THROW(JSDescription(joinSplitPubKey, rt, inputs, outputs, 10, 0), std::invalid_argument);
BOOST_CHECK_THROW(JSDescription(joinSplitPubKey, rt, inputs, outputs, 0, 10), std::invalid_argument);
BOOST_CHECK_THROW(JSDescriptionInfo(joinSplitPubKey, rt, inputs, outputs, 10, 0).BuildDeterministic(), std::invalid_argument);
BOOST_CHECK_THROW(JSDescriptionInfo(joinSplitPubKey, rt, inputs, outputs, 0, 10).BuildDeterministic(), std::invalid_argument);
}
{
// Ensure that it won't verify if the root is changed.
auto test = JSDescription(joinSplitPubKey, rt, inputs, outputs, 0, 0);
auto test = JSDescriptionInfo(joinSplitPubKey, rt, inputs, outputs, 0, 0).BuildDeterministic();
test.anchor = GetRandHash();
BOOST_CHECK(!verifier.VerifySprout(test, joinSplitPubKey));
}

View File

@ -71,6 +71,57 @@ std::optional<OutputDescription> OutputDescriptionInfo::Build(void* ctx) {
return odesc;
}
JSDescription JSDescriptionInfo::BuildDeterministic(
bool computeProof,
uint256 *esk // payment disclosure
) {
JSDescription jsdesc;
jsdesc.vpub_old = vpub_old;
jsdesc.vpub_new = vpub_new;
jsdesc.anchor = anchor;
std::array<libzcash::SproutNote, ZC_NUM_JS_OUTPUTS> notes;
jsdesc.proof = ZCJoinSplit::prove(
inputs,
outputs,
notes,
jsdesc.ciphertexts,
jsdesc.ephemeralKey,
joinSplitPubKey,
jsdesc.randomSeed,
jsdesc.macs,
jsdesc.nullifiers,
jsdesc.commitments,
vpub_old,
vpub_new,
anchor,
computeProof,
esk // payment disclosure
);
return jsdesc;
}
JSDescription JSDescriptionInfo::BuildRandomized(
std::array<size_t, ZC_NUM_JS_INPUTS>& inputMap,
std::array<size_t, ZC_NUM_JS_OUTPUTS>& outputMap,
bool computeProof,
uint256 *esk, // payment disclosure
std::function<int(int)> gen
)
{
// Randomize the order of the inputs and outputs
inputMap = {0, 1};
outputMap = {0, 1};
assert(gen);
MappedShuffle(inputs.begin(), inputMap.begin(), ZC_NUM_JS_INPUTS, gen);
MappedShuffle(outputs.begin(), outputMap.begin(), ZC_NUM_JS_OUTPUTS, gen);
return BuildDeterministic(computeProof, esk);
}
TransactionBuilderResult::TransactionBuilderResult(const CTransaction& tx) : maybeTx(tx) {}
TransactionBuilderResult::TransactionBuilderResult(const std::string& error) : maybeError(error) {}
@ -714,15 +765,16 @@ void TransactionBuilder::CreateJSDescription(
// Generate the proof, this can take over a minute.
assert(mtx.fOverwintered && (mtx.nVersion >= SAPLING_TX_VERSION));
JSDescription jsdesc = JSDescription::Randomized(
JSDescription jsdesc = JSDescriptionInfo(
mtx.joinSplitPubKey,
vjsin[0].witness.root(),
vjsin,
vjsout,
vpub_old,
vpub_new
).BuildRandomized(
inputMap,
outputMap,
vpub_old,
vpub_new,
true, //!this->testmode,
&esk); // parameter expects pointer to esk, so pass in address

View File

@ -9,6 +9,7 @@
#include "consensus/params.h"
#include "keystore.h"
#include "primitives/transaction.h"
#include "random.h"
#include "script/script.h"
#include "script/standard.h"
#include "uint256.h"
@ -49,6 +50,36 @@ struct OutputDescriptionInfo {
std::optional<OutputDescription> Build(void* ctx);
};
struct JSDescriptionInfo {
Ed25519VerificationKey joinSplitPubKey;
uint256 anchor;
std::array<libzcash::JSInput, ZC_NUM_JS_INPUTS> inputs;
std::array<libzcash::JSOutput, ZC_NUM_JS_OUTPUTS> outputs;
CAmount vpub_old;
CAmount vpub_new;
JSDescriptionInfo(
Ed25519VerificationKey joinSplitPubKey,
uint256 anchor,
std::array<libzcash::JSInput, ZC_NUM_JS_INPUTS> inputs,
std::array<libzcash::JSOutput, ZC_NUM_JS_OUTPUTS> outputs,
CAmount vpub_old,
CAmount vpub_new) : joinSplitPubKey(joinSplitPubKey), anchor(anchor), inputs(inputs), outputs(outputs), vpub_old(vpub_old), vpub_new(vpub_new) {}
JSDescription BuildDeterministic(
bool computeProof = true, // Set to false in some tests
uint256* esk = nullptr // payment disclosure
);
JSDescription BuildRandomized(
std::array<size_t, ZC_NUM_JS_INPUTS>& inputMap,
std::array<size_t, ZC_NUM_JS_OUTPUTS>& outputMap,
bool computeProof = true, // Set to false in some tests
uint256* esk = nullptr, // payment disclosure
std::function<int(int)> gen = GetRandInt
);
};
struct TransparentInputInfo {
CScript scriptPubKey;
CAmount value;

View File

@ -52,8 +52,8 @@ CMutableTransaction GetValidSproutReceiveTransaction(
// Prepare JoinSplits
uint256 rt;
JSDescription jsdesc {mtx.joinSplitPubKey, rt,
inputs, outputs, 2*value, 0, false};
auto jsdesc = JSDescriptionInfo(mtx.joinSplitPubKey, rt,
inputs, outputs, 2*value, 0).BuildDeterministic(false);
mtx.vJoinSplit.push_back(jsdesc);
// Consider: The following is a bit misleading (given the name of this function)
@ -173,8 +173,8 @@ CWalletTx GetValidSproutSpend(const libzcash::SproutSpendingKey& sk,
// Prepare JoinSplits
uint256 rt = tree.root();
JSDescription jsdesc {mtx.joinSplitPubKey, rt,
inputs, outputs, 0, value, false};
auto jsdesc = JSDescriptionInfo(mtx.joinSplitPubKey, rt,
inputs, outputs, 0, value).BuildDeterministic(false);
mtx.vJoinSplit.push_back(jsdesc);
// Empty output script.

View File

@ -20,6 +20,7 @@
#include "rpc/server.h"
#include "script/interpreter.h"
#include "timedata.h"
#include "transaction_builder.h"
#include "util.h"
#include "utilmoneystr.h"
#include "utiltime.h"
@ -799,15 +800,16 @@ UniValue AsyncRPCOperation_mergetoaddress::perform_joinsplit(
uint256 esk; // payment disclosure - secret
assert(mtx.fOverwintered && (mtx.nVersion >= SAPLING_TX_VERSION));
JSDescription jsdesc = JSDescription::Randomized(
JSDescription jsdesc = JSDescriptionInfo(
joinSplitPubKey_,
anchor,
inputs,
outputs,
info.vpub_old,
info.vpub_new
).BuildRandomized(
inputMap,
outputMap,
info.vpub_old,
info.vpub_new,
!this->testmode,
&esk); // parameter expects pointer to esk, so pass in address
{

View File

@ -18,6 +18,7 @@
#include "proof_verifier.h"
#include "rpc/protocol.h"
#include "rpc/server.h"
#include "transaction_builder.h"
#include "timedata.h"
#include "util.h"
#include "utilmoneystr.h"
@ -1048,15 +1049,16 @@ UniValue AsyncRPCOperation_sendmany::perform_joinsplit(
uint256 esk; // payment disclosure - secret
assert(mtx.fOverwintered && (mtx.nVersion >= SAPLING_TX_VERSION));
JSDescription jsdesc = JSDescription::Randomized(
JSDescription jsdesc = JSDescriptionInfo(
joinSplitPubKey_,
anchor,
inputs,
outputs,
info.vpub_old,
info.vpub_new
).BuildRandomized(
inputMap,
outputMap,
info.vpub_old,
info.vpub_new,
!this->testmode,
&esk); // parameter expects pointer to esk, so pass in address
{

View File

@ -18,6 +18,7 @@
#include "proof_verifier.h"
#include "rpc/protocol.h"
#include "rpc/server.h"
#include "transaction_builder.h"
#include "timedata.h"
#include "util.h"
#include "utilmoneystr.h"
@ -311,15 +312,16 @@ UniValue AsyncRPCOperation_shieldcoinbase::perform_joinsplit(ShieldCoinbaseJSInf
uint256 esk; // payment disclosure - secret
assert(mtx.fOverwintered && (mtx.nVersion >= SAPLING_TX_VERSION));
JSDescription jsdesc = JSDescription::Randomized(
JSDescription jsdesc = JSDescriptionInfo(
joinSplitPubKey_,
anchor,
inputs,
outputs,
info.vpub_old,
info.vpub_new
).BuildRandomized(
inputMap,
outputMap,
info.vpub_old,
info.vpub_new,
!this->testmode,
&esk); // parameter expects pointer to esk, so pass in address
{

View File

@ -2777,12 +2777,12 @@ UniValue zc_sample_joinsplit(const UniValue& params, bool fHelp)
Ed25519VerificationKey joinSplitPubKey;
uint256 anchor = SproutMerkleTree().root();
JSDescription samplejoinsplit(joinSplitPubKey,
auto samplejoinsplit = JSDescriptionInfo(joinSplitPubKey,
anchor,
{JSInput(), JSInput()},
{JSOutput(), JSOutput()},
0,
0);
0).BuildDeterministic();
CDataStream ss(SER_NETWORK, SAPLING_TX_VERSION | (1 << 31));
ss << samplejoinsplit;
@ -3152,12 +3152,12 @@ UniValue zc_raw_joinsplit(const UniValue& params, bool fHelp)
mtx.nVersionGroupId = SAPLING_VERSION_GROUP_ID;
mtx.joinSplitPubKey = joinSplitPubKey;
JSDescription jsdesc(joinSplitPubKey,
auto jsdesc = JSDescriptionInfo(joinSplitPubKey,
anchor,
{vjsin[0], vjsin[1]},
{vjsout[0], vjsout[1]},
vpub_old,
vpub_new);
vpub_new).BuildDeterministic();
{
auto verifier = ProofVerifier::Strict();

View File

@ -23,6 +23,7 @@
#include "rpc/server.h"
#include "script/sign.h"
#include "streams.h"
#include "transaction_builder.h"
#include "txdb.h"
#include "utiltest.h"
#include "wallet/wallet.h"
@ -103,12 +104,12 @@ double benchmark_create_joinsplit()
struct timeval tv_start;
timer_start(tv_start);
JSDescription jsdesc(joinSplitPubKey,
auto jsdesc = JSDescriptionInfo(joinSplitPubKey,
anchor,
{JSInput(), JSInput()},
{JSOutput(), JSOutput()},
0,
0);
0).BuildDeterministic();
double ret = timer_stop(tv_start);
auto verifier = ProofVerifier::Strict();