Auto merge of #976 - ebfull:implement-joinsplit-signatures, r=ebfull
Signing pours with ed25519 This is an alternative to #964 which uses ed25519 instead of secp256k1, and avoids the separate hash for fitting the public key into the `h_sig` block. It's based on @defuse's work in that branch. Closes #808.
This commit is contained in:
commit
19769ba6c5
65
src/main.cpp
65
src/main.cpp
|
@ -5,6 +5,8 @@
|
||||||
|
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
|
||||||
|
#include "sodium.h"
|
||||||
|
|
||||||
#include "addrman.h"
|
#include "addrman.h"
|
||||||
#include "alert.h"
|
#include "alert.h"
|
||||||
#include "arith_uint256.h"
|
#include "arith_uint256.h"
|
||||||
|
@ -31,6 +33,7 @@
|
||||||
#include <boost/filesystem/fstream.hpp>
|
#include <boost/filesystem/fstream.hpp>
|
||||||
#include <boost/math/distributions/poisson.hpp>
|
#include <boost/math/distributions/poisson.hpp>
|
||||||
#include <boost/thread.hpp>
|
#include <boost/thread.hpp>
|
||||||
|
#include <boost/static_assert.hpp>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
@ -840,7 +843,30 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& in
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Taken from
|
||||||
|
// https://github.com/jedisct1/libsodium/commit/4099618de2cce5099ac2ec5ce8f2d80f4585606e
|
||||||
|
// which was removed to maintain backwards compatibility in
|
||||||
|
// https://github.com/jedisct1/libsodium/commit/cb07df046f19ee0d5ad600c579df97aaa4295cc3
|
||||||
|
static int
|
||||||
|
crypto_sign_check_S_lt_l(const unsigned char *S)
|
||||||
|
{
|
||||||
|
static const unsigned char l[32] =
|
||||||
|
{ 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58,
|
||||||
|
0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 };
|
||||||
|
unsigned char c = 0;
|
||||||
|
unsigned char n = 1;
|
||||||
|
unsigned int i = 32;
|
||||||
|
|
||||||
|
do {
|
||||||
|
i--;
|
||||||
|
c |= ((S[i] - l[i]) >> 8) & n;
|
||||||
|
n &= ((S[i] ^ l[i]) - 1) >> 8;
|
||||||
|
} while (i != 0);
|
||||||
|
|
||||||
|
return -(c == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -956,16 +982,39 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state)
|
||||||
return state.DoS(10, error("CheckTransaction(): prevout is null"),
|
return state.DoS(10, error("CheckTransaction(): prevout is null"),
|
||||||
REJECT_INVALID, "bad-txns-prevout-null");
|
REJECT_INVALID, "bad-txns-prevout-null");
|
||||||
|
|
||||||
// Ensure that zk-SNARKs verify
|
if (tx.vpour.size() > 0) {
|
||||||
|
// TODO: #966.
|
||||||
|
static const uint256 one(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));
|
||||||
|
// Empty output script.
|
||||||
|
CScript scriptCode;
|
||||||
|
uint256 dataToBeSigned = SignatureHash(scriptCode, tx, NOT_AN_INPUT, SIGHASH_ALL);
|
||||||
|
if (dataToBeSigned == one) {
|
||||||
|
return state.DoS(100, error("CheckTransaction(): error computing signature hash"),
|
||||||
|
REJECT_INVALID, "error-computing-signature-hash");
|
||||||
|
}
|
||||||
|
|
||||||
if (state.PerformPourVerification()) {
|
BOOST_STATIC_ASSERT(crypto_sign_PUBLICKEYBYTES == 32);
|
||||||
BOOST_FOREACH(const CPourTx &pour, tx.vpour) {
|
|
||||||
// TODO: #808
|
|
||||||
uint256 pubKeyHash;
|
|
||||||
|
|
||||||
if (!pour.Verify(*pzcashParams, pubKeyHash)) {
|
if (crypto_sign_verify_detached(&tx.joinSplitSig[0],
|
||||||
return state.DoS(100, error("CheckTransaction(): pour does not verify"),
|
dataToBeSigned.begin(), 32,
|
||||||
REJECT_INVALID, "bad-txns-pour-verification-failed");
|
tx.joinSplitPubKey.begin()
|
||||||
|
) != 0) {
|
||||||
|
return state.DoS(100, error("CheckTransaction(): invalid joinsplit signature"),
|
||||||
|
REJECT_INVALID, "bad-txns-invalid-joinsplit-signature");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (crypto_sign_check_S_lt_l(&tx.joinSplitSig[32]) != 0) {
|
||||||
|
return state.DoS(100, error("CheckTransaction(): non-canonical ed25519 signature"),
|
||||||
|
REJECT_INVALID, "non-canonical-ed25519-signature");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.PerformPourVerification()) {
|
||||||
|
// Ensure that zk-SNARKs verify
|
||||||
|
BOOST_FOREACH(const CPourTx &pour, tx.vpour) {
|
||||||
|
if (!pour.Verify(*pzcashParams, tx.joinSplitPubKey)) {
|
||||||
|
return state.DoS(100, error("CheckTransaction(): pour does not verify"),
|
||||||
|
REJECT_INVALID, "bad-txns-pour-verification-failed");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,7 +110,11 @@ std::string CTxOut::ToString() const
|
||||||
}
|
}
|
||||||
|
|
||||||
CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::CURRENT_VERSION), nLockTime(0) {}
|
CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::CURRENT_VERSION), nLockTime(0) {}
|
||||||
CMutableTransaction::CMutableTransaction(const CTransaction& tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime), vpour(tx.vpour) {}
|
CMutableTransaction::CMutableTransaction(const CTransaction& tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime),
|
||||||
|
vpour(tx.vpour), joinSplitPubKey(tx.joinSplitPubKey), joinSplitSig(tx.joinSplitSig)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
uint256 CMutableTransaction::GetHash() const
|
uint256 CMutableTransaction::GetHash() const
|
||||||
{
|
{
|
||||||
|
@ -122,9 +126,11 @@ void CTransaction::UpdateHash() const
|
||||||
*const_cast<uint256*>(&hash) = SerializeHash(*this);
|
*const_cast<uint256*>(&hash) = SerializeHash(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
CTransaction::CTransaction() : nVersion(CTransaction::CURRENT_VERSION), vin(), vout(), nLockTime(0), vpour() { }
|
CTransaction::CTransaction() : nVersion(CTransaction::CURRENT_VERSION), vin(), vout(), nLockTime(0), vpour(), joinSplitPubKey(), joinSplitSig() { }
|
||||||
|
|
||||||
CTransaction::CTransaction(const CMutableTransaction &tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime), vpour(tx.vpour) {
|
CTransaction::CTransaction(const CMutableTransaction &tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime), vpour(tx.vpour),
|
||||||
|
joinSplitPubKey(tx.joinSplitPubKey), joinSplitSig(tx.joinSplitSig)
|
||||||
|
{
|
||||||
UpdateHash();
|
UpdateHash();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,6 +140,8 @@ CTransaction& CTransaction::operator=(const CTransaction &tx) {
|
||||||
*const_cast<std::vector<CTxOut>*>(&vout) = tx.vout;
|
*const_cast<std::vector<CTxOut>*>(&vout) = tx.vout;
|
||||||
*const_cast<unsigned int*>(&nLockTime) = tx.nLockTime;
|
*const_cast<unsigned int*>(&nLockTime) = tx.nLockTime;
|
||||||
*const_cast<std::vector<CPourTx>*>(&vpour) = tx.vpour;
|
*const_cast<std::vector<CPourTx>*>(&vpour) = tx.vpour;
|
||||||
|
*const_cast<uint256*>(&joinSplitPubKey) = tx.joinSplitPubKey;
|
||||||
|
*const_cast<joinsplit_sig_t*>(&joinSplitSig) = tx.joinSplitSig;
|
||||||
*const_cast<uint256*>(&hash) = tx.hash;
|
*const_cast<uint256*>(&hash) = tx.hash;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
|
@ -290,6 +290,8 @@ private:
|
||||||
void UpdateHash() const;
|
void UpdateHash() const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
typedef boost::array<unsigned char, 64> joinsplit_sig_t;
|
||||||
|
|
||||||
static const int32_t CURRENT_VERSION=1;
|
static const int32_t CURRENT_VERSION=1;
|
||||||
|
|
||||||
// The local variables are made const to prevent unintended modification
|
// The local variables are made const to prevent unintended modification
|
||||||
|
@ -302,6 +304,8 @@ public:
|
||||||
const std::vector<CTxOut> vout;
|
const std::vector<CTxOut> vout;
|
||||||
const uint32_t nLockTime;
|
const uint32_t nLockTime;
|
||||||
const std::vector<CPourTx> vpour;
|
const std::vector<CPourTx> vpour;
|
||||||
|
const uint256 joinSplitPubKey;
|
||||||
|
const joinsplit_sig_t joinSplitSig;
|
||||||
|
|
||||||
/** Construct a CTransaction that qualifies as IsNull() */
|
/** Construct a CTransaction that qualifies as IsNull() */
|
||||||
CTransaction();
|
CTransaction();
|
||||||
|
@ -322,6 +326,10 @@ public:
|
||||||
READWRITE(*const_cast<uint32_t*>(&nLockTime));
|
READWRITE(*const_cast<uint32_t*>(&nLockTime));
|
||||||
if (nVersion >= 2) {
|
if (nVersion >= 2) {
|
||||||
READWRITE(*const_cast<std::vector<CPourTx>*>(&vpour));
|
READWRITE(*const_cast<std::vector<CPourTx>*>(&vpour));
|
||||||
|
if (vpour.size() > 0) {
|
||||||
|
READWRITE(*const_cast<uint256*>(&joinSplitPubKey));
|
||||||
|
READWRITE(*const_cast<joinsplit_sig_t*>(&joinSplitSig));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (ser_action.ForRead())
|
if (ser_action.ForRead())
|
||||||
UpdateHash();
|
UpdateHash();
|
||||||
|
@ -375,6 +383,8 @@ struct CMutableTransaction
|
||||||
std::vector<CTxOut> vout;
|
std::vector<CTxOut> vout;
|
||||||
uint32_t nLockTime;
|
uint32_t nLockTime;
|
||||||
std::vector<CPourTx> vpour;
|
std::vector<CPourTx> vpour;
|
||||||
|
uint256 joinSplitPubKey;
|
||||||
|
CTransaction::joinsplit_sig_t joinSplitSig;
|
||||||
|
|
||||||
CMutableTransaction();
|
CMutableTransaction();
|
||||||
CMutableTransaction(const CTransaction& tx);
|
CMutableTransaction(const CTransaction& tx);
|
||||||
|
@ -390,6 +400,10 @@ struct CMutableTransaction
|
||||||
READWRITE(nLockTime);
|
READWRITE(nLockTime);
|
||||||
if (nVersion >= 2) {
|
if (nVersion >= 2) {
|
||||||
READWRITE(vpour);
|
READWRITE(vpour);
|
||||||
|
if (vpour.size() > 0) {
|
||||||
|
READWRITE(joinSplitPubKey);
|
||||||
|
READWRITE(joinSplitSig);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1030,6 +1030,7 @@ public:
|
||||||
// Serialize the prevout
|
// Serialize the prevout
|
||||||
::Serialize(s, txTo.vin[nInput].prevout, nType, nVersion);
|
::Serialize(s, txTo.vin[nInput].prevout, nType, nVersion);
|
||||||
// Serialize the script
|
// Serialize the script
|
||||||
|
assert(nInput != NOT_AN_INPUT);
|
||||||
if (nInput != nIn)
|
if (nInput != nIn)
|
||||||
// Blank out other inputs' signatures
|
// Blank out other inputs' signatures
|
||||||
::Serialize(s, CScript(), nType, nVersion);
|
::Serialize(s, CScript(), nType, nVersion);
|
||||||
|
@ -1073,22 +1074,19 @@ public:
|
||||||
|
|
||||||
// Serialize vpour
|
// Serialize vpour
|
||||||
if (txTo.nVersion >= 2) {
|
if (txTo.nVersion >= 2) {
|
||||||
// TODO:
|
|
||||||
//
|
//
|
||||||
// SIGHASH_* functions will hash portions of
|
// SIGHASH_* functions will hash portions of
|
||||||
// the transaction for use in signatures. This
|
// the transaction for use in signatures. This
|
||||||
// keeps the pour cryptographically bound to
|
// keeps the JoinSplit cryptographically bound
|
||||||
// the transaction from the perspective of the
|
// to the transaction.
|
||||||
// inputs (but not from the perspective of the
|
|
||||||
// pour).
|
|
||||||
//
|
//
|
||||||
// This must be rectified in the future.
|
|
||||||
// See zcash/#529
|
|
||||||
//
|
|
||||||
// It will be necessary to change this API to
|
|
||||||
// be abstract over whether an input script is
|
|
||||||
// being skipped or a pour is being skipped.
|
|
||||||
::Serialize(s, txTo.vpour, nType, nVersion);
|
::Serialize(s, txTo.vpour, nType, nVersion);
|
||||||
|
if (txTo.vpour.size() > 0) {
|
||||||
|
::Serialize(s, txTo.joinSplitPubKey, nType, nVersion);
|
||||||
|
|
||||||
|
CTransaction::joinsplit_sig_t nullSig = {};
|
||||||
|
::Serialize(s, nullSig, nType, nVersion);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1098,7 +1096,7 @@ public:
|
||||||
uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType)
|
uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType)
|
||||||
{
|
{
|
||||||
static const uint256 one(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));
|
static const uint256 one(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));
|
||||||
if (nIn >= txTo.vin.size()) {
|
if (nIn >= txTo.vin.size() && nIn != NOT_AN_INPUT) {
|
||||||
// nIn out of range
|
// nIn out of range
|
||||||
return one;
|
return one;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,12 +12,16 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <climits>
|
||||||
|
|
||||||
class CPubKey;
|
class CPubKey;
|
||||||
class CScript;
|
class CScript;
|
||||||
class CTransaction;
|
class CTransaction;
|
||||||
class uint256;
|
class uint256;
|
||||||
|
|
||||||
|
/** Special case nIn for signing JoinSplits. */
|
||||||
|
const unsigned int NOT_AN_INPUT = UINT_MAX;
|
||||||
|
|
||||||
/** Signature hash types/flags */
|
/** Signature hash types/flags */
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -81,6 +81,9 @@ uint256 static SignatureHashOld(CScript scriptCode, const CTransaction& txTo, un
|
||||||
txTmp.vin.resize(1);
|
txTmp.vin.resize(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Blank out the joinsplit signature.
|
||||||
|
memset(&txTmp.joinSplitSig[0], 0, txTmp.joinSplitSig.size());
|
||||||
|
|
||||||
// Serialize and hash
|
// Serialize and hash
|
||||||
CHashWriter ss(SER_GETHASH, 0);
|
CHashWriter ss(SER_GETHASH, 0);
|
||||||
ss << txTmp << nHashType;
|
ss << txTmp << nHashType;
|
||||||
|
@ -139,6 +142,22 @@ void static RandomTransaction(CMutableTransaction &tx, bool fSingle) {
|
||||||
|
|
||||||
tx.vpour.push_back(pourtx);
|
tx.vpour.push_back(pourtx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned char joinSplitPrivKey[crypto_sign_SECRETKEYBYTES];
|
||||||
|
crypto_sign_keypair(tx.joinSplitPubKey.begin(), joinSplitPrivKey);
|
||||||
|
|
||||||
|
// TODO: #966.
|
||||||
|
static const uint256 one(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));
|
||||||
|
// Empty output script.
|
||||||
|
CScript scriptCode;
|
||||||
|
CTransaction signTx(tx);
|
||||||
|
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL);
|
||||||
|
BOOST_CHECK(dataToBeSigned != one);
|
||||||
|
|
||||||
|
assert(crypto_sign_detached(&tx.joinSplitSig[0], NULL,
|
||||||
|
dataToBeSigned.begin(), 32,
|
||||||
|
joinSplitPrivKey
|
||||||
|
) == 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
#include "script/script_error.h"
|
#include "script/script_error.h"
|
||||||
#include "primitives/transaction.h"
|
#include "primitives/transaction.h"
|
||||||
|
|
||||||
|
#include "sodium.h"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
@ -379,6 +381,9 @@ BOOST_AUTO_TEST_CASE(test_simple_pour_invalidity)
|
||||||
CMutableTransaction newTx(tx);
|
CMutableTransaction newTx(tx);
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
|
|
||||||
|
unsigned char joinSplitPrivKey[crypto_sign_SECRETKEYBYTES];
|
||||||
|
crypto_sign_keypair(newTx.joinSplitPubKey.begin(), joinSplitPrivKey);
|
||||||
|
|
||||||
state.SetPerformPourVerification(false); // don't verify the snark
|
state.SetPerformPourVerification(false); // don't verify the snark
|
||||||
|
|
||||||
// No pours, vin and vout, means it should be invalid.
|
// No pours, vin and vout, means it should be invalid.
|
||||||
|
@ -396,7 +401,23 @@ BOOST_AUTO_TEST_CASE(test_simple_pour_invalidity)
|
||||||
pourtx->serials[0] = GetRandHash();
|
pourtx->serials[0] = GetRandHash();
|
||||||
pourtx->serials[1] = GetRandHash();
|
pourtx->serials[1] = GetRandHash();
|
||||||
|
|
||||||
BOOST_CHECK_MESSAGE(CheckTransaction(newTx, state), state.GetRejectReason());
|
BOOST_CHECK(!CheckTransaction(newTx, state));
|
||||||
|
BOOST_CHECK(state.GetRejectReason() == "bad-txns-invalid-joinsplit-signature");
|
||||||
|
|
||||||
|
// TODO: #966.
|
||||||
|
static const uint256 one(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));
|
||||||
|
// Empty output script.
|
||||||
|
CScript scriptCode;
|
||||||
|
CTransaction signTx(newTx);
|
||||||
|
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL);
|
||||||
|
BOOST_CHECK(dataToBeSigned != one);
|
||||||
|
|
||||||
|
assert(crypto_sign_detached(&newTx.joinSplitSig[0], NULL,
|
||||||
|
dataToBeSigned.begin(), 32,
|
||||||
|
joinSplitPrivKey
|
||||||
|
) == 0);
|
||||||
|
|
||||||
|
BOOST_CHECK(CheckTransaction(newTx, state));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
// Ensure that values within the pour are well-formed.
|
// Ensure that values within the pour are well-formed.
|
||||||
|
|
|
@ -18,6 +18,9 @@
|
||||||
#include "walletdb.h"
|
#include "walletdb.h"
|
||||||
#include "primitives/transaction.h"
|
#include "primitives/transaction.h"
|
||||||
#include "zcbenchmarks.h"
|
#include "zcbenchmarks.h"
|
||||||
|
#include "script/interpreter.h"
|
||||||
|
|
||||||
|
#include "sodium.h"
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
@ -2650,22 +2653,48 @@ Value zc_raw_pour(const json_spirit::Array& params, bool fHelp)
|
||||||
throw runtime_error("unsupported pour input/output counts");
|
throw runtime_error("unsupported pour input/output counts");
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: #808
|
uint256 joinSplitPubKey;
|
||||||
uint256 pubKeyHash;
|
unsigned char joinSplitPrivKey[crypto_sign_SECRETKEYBYTES];
|
||||||
|
crypto_sign_keypair(joinSplitPubKey.begin(), joinSplitPrivKey);
|
||||||
|
|
||||||
|
CMutableTransaction mtx(tx);
|
||||||
|
mtx.nVersion = 2;
|
||||||
|
mtx.joinSplitPubKey = joinSplitPubKey;
|
||||||
|
|
||||||
CPourTx pourtx(*pzcashParams,
|
CPourTx pourtx(*pzcashParams,
|
||||||
pubKeyHash,
|
joinSplitPubKey,
|
||||||
anchor,
|
anchor,
|
||||||
{vpourin[0], vpourin[1]},
|
{vpourin[0], vpourin[1]},
|
||||||
{vpourout[0], vpourout[1]},
|
{vpourout[0], vpourout[1]},
|
||||||
vpub_old,
|
vpub_old,
|
||||||
vpub_new);
|
vpub_new);
|
||||||
|
|
||||||
assert(pourtx.Verify(*pzcashParams, pubKeyHash));
|
assert(pourtx.Verify(*pzcashParams, joinSplitPubKey));
|
||||||
|
|
||||||
CMutableTransaction mtx(tx);
|
|
||||||
mtx.nVersion = 2;
|
|
||||||
mtx.vpour.push_back(pourtx);
|
mtx.vpour.push_back(pourtx);
|
||||||
|
|
||||||
|
// TODO: #966.
|
||||||
|
static const uint256 one(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));
|
||||||
|
// Empty output script.
|
||||||
|
CScript scriptCode;
|
||||||
|
CTransaction signTx(mtx);
|
||||||
|
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL);
|
||||||
|
if (dataToBeSigned == one) {
|
||||||
|
throw runtime_error("SignatureHash failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the signature
|
||||||
|
assert(crypto_sign_detached(&mtx.joinSplitSig[0], NULL,
|
||||||
|
dataToBeSigned.begin(), 32,
|
||||||
|
joinSplitPrivKey
|
||||||
|
) == 0);
|
||||||
|
|
||||||
|
// Sanity check
|
||||||
|
assert(crypto_sign_verify_detached(&mtx.joinSplitSig[0],
|
||||||
|
dataToBeSigned.begin(), 32,
|
||||||
|
mtx.joinSplitPubKey.begin()
|
||||||
|
) == 0);
|
||||||
|
|
||||||
CTransaction rawTx(mtx);
|
CTransaction rawTx(mtx);
|
||||||
|
|
||||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||||
|
@ -2678,7 +2707,7 @@ Value zc_raw_pour(const json_spirit::Array& params, bool fHelp)
|
||||||
ss2 << ((unsigned char) 0x00);
|
ss2 << ((unsigned char) 0x00);
|
||||||
ss2 << pourtx.ephemeralKey;
|
ss2 << pourtx.ephemeralKey;
|
||||||
ss2 << pourtx.ciphertexts[0];
|
ss2 << pourtx.ciphertexts[0];
|
||||||
ss2 << pourtx.h_sig(*pzcashParams, pubKeyHash);
|
ss2 << pourtx.h_sig(*pzcashParams, joinSplitPubKey);
|
||||||
|
|
||||||
encryptedBucket1 = HexStr(ss2.begin(), ss2.end());
|
encryptedBucket1 = HexStr(ss2.begin(), ss2.end());
|
||||||
}
|
}
|
||||||
|
@ -2687,7 +2716,7 @@ Value zc_raw_pour(const json_spirit::Array& params, bool fHelp)
|
||||||
ss2 << ((unsigned char) 0x01);
|
ss2 << ((unsigned char) 0x01);
|
||||||
ss2 << pourtx.ephemeralKey;
|
ss2 << pourtx.ephemeralKey;
|
||||||
ss2 << pourtx.ciphertexts[1];
|
ss2 << pourtx.ciphertexts[1];
|
||||||
ss2 << pourtx.h_sig(*pzcashParams, pubKeyHash);
|
ss2 << pourtx.h_sig(*pzcashParams, joinSplitPubKey);
|
||||||
|
|
||||||
encryptedBucket2 = HexStr(ss2.begin(), ss2.end());
|
encryptedBucket2 = HexStr(ss2.begin(), ss2.end());
|
||||||
}
|
}
|
||||||
|
|
|
@ -301,7 +301,7 @@ uint256 JoinSplit<NumInputs, NumOutputs>::h_sig(
|
||||||
const boost::array<uint256, NumInputs>& nullifiers,
|
const boost::array<uint256, NumInputs>& nullifiers,
|
||||||
const uint256& pubKeyHash
|
const uint256& pubKeyHash
|
||||||
) {
|
) {
|
||||||
unsigned char personalization[crypto_generichash_blake2b_PERSONALBYTES]
|
const unsigned char personalization[crypto_generichash_blake2b_PERSONALBYTES]
|
||||||
= {'Z','c','a','s','h','C','o','m','p','u','t','e','h','S','i','g'};
|
= {'Z','c','a','s','h','C','o','m','p','u','t','e','h','S','i','g'};
|
||||||
|
|
||||||
std::vector<unsigned char> block(randomSeed.begin(), randomSeed.end());
|
std::vector<unsigned char> block(randomSeed.begin(), randomSeed.end());
|
||||||
|
@ -349,4 +349,4 @@ JSInput::JSInput() : witness(ZCIncrementalMerkleTree().witness()),
|
||||||
template class JoinSplit<ZC_NUM_JS_INPUTS,
|
template class JoinSplit<ZC_NUM_JS_INPUTS,
|
||||||
ZC_NUM_JS_OUTPUTS>;
|
ZC_NUM_JS_OUTPUTS>;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,7 +64,6 @@ double benchmark_parameter_loading()
|
||||||
|
|
||||||
double benchmark_create_joinsplit()
|
double benchmark_create_joinsplit()
|
||||||
{
|
{
|
||||||
// TODO: #808
|
|
||||||
uint256 pubKeyHash;
|
uint256 pubKeyHash;
|
||||||
|
|
||||||
/* Get the anchor of an empty commitment tree. */
|
/* Get the anchor of an empty commitment tree. */
|
||||||
|
@ -87,7 +86,6 @@ double benchmark_create_joinsplit()
|
||||||
double benchmark_verify_joinsplit(const CPourTx &joinsplit)
|
double benchmark_verify_joinsplit(const CPourTx &joinsplit)
|
||||||
{
|
{
|
||||||
timer_start();
|
timer_start();
|
||||||
// TODO: #808
|
|
||||||
uint256 pubKeyHash;
|
uint256 pubKeyHash;
|
||||||
joinsplit.Verify(*pzcashParams, pubKeyHash);
|
joinsplit.Verify(*pzcashParams, pubKeyHash);
|
||||||
return timer_stop();
|
return timer_stop();
|
||||||
|
|
Loading…
Reference in New Issue