Randomize JoinSplits in z_sendmany

This commit is contained in:
Jack Grigg
2016-10-18 10:41:30 -05:00
parent 7f0aa74666
commit 2eeb6bebde

View File

@@ -29,6 +29,22 @@
using namespace libzcash; using namespace libzcash;
int find_output(Object obj, int n) {
Value outputMapValue = find_value(obj, "outputmap");
if (outputMapValue.type() != array_type) {
throw JSONRPCError(RPC_WALLET_ERROR, "Missing outputmap for JoinSplit operation");
}
Array outputMap = outputMapValue.get_array();
for (size_t i = 0; i < outputMap.size(); i++) {
if (outputMap[i] == n) {
return i;
}
}
return -1;
}
AsyncRPCOperation_sendmany::AsyncRPCOperation_sendmany( AsyncRPCOperation_sendmany::AsyncRPCOperation_sendmany(
std::string fromAddress, std::string fromAddress,
std::vector<SendManyRecipient> tOutputs, std::vector<SendManyRecipient> tOutputs,
@@ -372,6 +388,7 @@ bool AsyncRPCOperation_sendmany::main_impl() {
*/ */
Object obj; Object obj;
CAmount jsChange = 0; // this is updated after each joinsplit CAmount jsChange = 0; // this is updated after each joinsplit
int changeOutputIndex = -1; // this is updated after each joinsplit if jsChange > 0
bool minersFeeProcessed = false; bool minersFeeProcessed = false;
if (t_outputs_total > 0) { if (t_outputs_total > 0) {
@@ -429,6 +446,10 @@ bool AsyncRPCOperation_sendmany::main_impl() {
} }
obj = perform_joinsplit(info, outPoints); obj = perform_joinsplit(info, outPoints);
if (jsChange > 0) {
changeOutputIndex = find_output(obj, 1);
}
} }
} }
@@ -443,9 +464,6 @@ bool AsyncRPCOperation_sendmany::main_impl() {
boost::unordered_map<uint256, ZCIncrementalMerkleTree, CCoinsKeyHasher> intermediates; boost::unordered_map<uint256, ZCIncrementalMerkleTree, CCoinsKeyHasher> intermediates;
std::vector<uint256> previousCommitments; std::vector<uint256> previousCommitments;
// NOTE: Randomization of input and output order could break this in future
const int changeOutputIndex = 1;
while (zOutputsDeque.size() > 0) { while (zOutputsDeque.size() > 0) {
AsyncJoinSplitInfo info; AsyncJoinSplitInfo info;
info.vpub_old = 0; info.vpub_old = 0;
@@ -645,6 +663,10 @@ bool AsyncRPCOperation_sendmany::main_impl() {
} }
obj = perform_joinsplit(info, witnesses, jsAnchor); obj = perform_joinsplit(info, witnesses, jsAnchor);
if (jsChange > 0) {
changeOutputIndex = find_output(obj, 1);
}
} }
} }
@@ -845,11 +867,20 @@ Object AsyncRPCOperation_sendmany::perform_joinsplit(
); );
// Generate the proof, this can take over a minute. // Generate the proof, this can take over a minute.
JSDescription jsdesc(*pzcashParams, boost::array<libzcash::JSInput, ZC_NUM_JS_INPUTS> inputs
{info.vjsin[0], info.vjsin[1]};
boost::array<libzcash::JSOutput, ZC_NUM_JS_OUTPUTS> outputs
{info.vjsout[0], info.vjsout[1]};
boost::array<size_t, ZC_NUM_JS_INPUTS> inputMap;
boost::array<size_t, ZC_NUM_JS_OUTPUTS> outputMap;
JSDescription jsdesc = JSDescription::Randomized(
*pzcashParams,
joinSplitPubKey_, joinSplitPubKey_,
anchor, anchor,
{info.vjsin[0], info.vjsin[1]}, inputs,
{info.vjsout[0], info.vjsout[1]}, outputs,
inputMap,
outputMap,
info.vpub_old, info.vpub_old,
info.vpub_new, info.vpub_new,
!this->testmode); !this->testmode);
@@ -910,10 +941,21 @@ Object AsyncRPCOperation_sendmany::perform_joinsplit(
encryptedNote2 = HexStr(ss2.begin(), ss2.end()); encryptedNote2 = HexStr(ss2.begin(), ss2.end());
} }
Array arrInputMap;
Array arrOutputMap;
for (size_t i = 0; i < ZC_NUM_JS_INPUTS; i++) {
arrInputMap.push_back(inputMap[i]);
}
for (size_t i = 0; i < ZC_NUM_JS_OUTPUTS; i++) {
arrOutputMap.push_back(outputMap[i]);
}
Object obj; Object obj;
obj.push_back(Pair("encryptednote1", encryptedNote1)); obj.push_back(Pair("encryptednote1", encryptedNote1));
obj.push_back(Pair("encryptednote2", encryptedNote2)); obj.push_back(Pair("encryptednote2", encryptedNote2));
obj.push_back(Pair("rawtxn", HexStr(ss.begin(), ss.end()))); obj.push_back(Pair("rawtxn", HexStr(ss.begin(), ss.end())));
obj.push_back(Pair("inputmap", arrInputMap));
obj.push_back(Pair("outputmap", arrOutputMap));
return obj; return obj;
} }