|
|
@ -5,6 +5,7 @@ |
|
|
|
|
|
|
|
#include "interpreter.h" |
|
|
|
|
|
|
|
#include "consensus/upgrades.h" |
|
|
|
#include "primitives/transaction.h" |
|
|
|
#include "crypto/ripemd160.h" |
|
|
|
#include "crypto/sha1.h" |
|
|
@ -1056,8 +1057,17 @@ public: |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
const unsigned char ZCASH_PREVOUTS_HASH_PERSONALIZATION[crypto_generichash_blake2b_PERSONALBYTES] = |
|
|
|
{'Z','c','a','s','h','P','r','e','v','o','u','t','H','a','s','h'}; |
|
|
|
const unsigned char ZCASH_SEQUENCE_HASH_PERSONALIZATION[crypto_generichash_blake2b_PERSONALBYTES] = |
|
|
|
{'Z','c','a','s','h','S','e','q','u','e','n','c','H','a','s','h'}; |
|
|
|
const unsigned char ZCASH_OUTPUTS_HASH_PERSONALIZATION[crypto_generichash_blake2b_PERSONALBYTES] = |
|
|
|
{'Z','c','a','s','h','O','u','t','p','u','t','s','H','a','s','h'}; |
|
|
|
const unsigned char ZCASH_JOINSPLITS_HASH_PERSONALIZATION[crypto_generichash_blake2b_PERSONALBYTES] = |
|
|
|
{'Z','c','a','s','h','J','S','p','l','i','t','s','H','a','s','h'}; |
|
|
|
|
|
|
|
uint256 GetPrevoutHash(const CTransaction& txTo) { |
|
|
|
CHashWriter ss(SER_GETHASH, 0); |
|
|
|
CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_PREVOUTS_HASH_PERSONALIZATION); |
|
|
|
for (unsigned int n = 0; n < txTo.vin.size(); n++) { |
|
|
|
ss << txTo.vin[n].prevout; |
|
|
|
} |
|
|
@ -1065,7 +1075,7 @@ uint256 GetPrevoutHash(const CTransaction& txTo) { |
|
|
|
} |
|
|
|
|
|
|
|
uint256 GetSequenceHash(const CTransaction& txTo) { |
|
|
|
CHashWriter ss(SER_GETHASH, 0); |
|
|
|
CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_SEQUENCE_HASH_PERSONALIZATION); |
|
|
|
for (unsigned int n = 0; n < txTo.vin.size(); n++) { |
|
|
|
ss << txTo.vin[n].nSequence; |
|
|
|
} |
|
|
@ -1073,13 +1083,22 @@ uint256 GetSequenceHash(const CTransaction& txTo) { |
|
|
|
} |
|
|
|
|
|
|
|
uint256 GetOutputsHash(const CTransaction& txTo) { |
|
|
|
CHashWriter ss(SER_GETHASH, 0); |
|
|
|
CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_OUTPUTS_HASH_PERSONALIZATION); |
|
|
|
for (unsigned int n = 0; n < txTo.vout.size(); n++) { |
|
|
|
ss << txTo.vout[n]; |
|
|
|
} |
|
|
|
return ss.GetHash(); |
|
|
|
} |
|
|
|
|
|
|
|
uint256 GetJoinSplitsHash(const CTransaction& txTo) { |
|
|
|
CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_JOINSPLITS_HASH_PERSONALIZATION); |
|
|
|
for (unsigned int n = 0; n < txTo.vjoinsplit.size(); n++) { |
|
|
|
ss << txTo.vjoinsplit[n]; |
|
|
|
} |
|
|
|
ss << txTo.joinSplitPubKey; |
|
|
|
return ss.GetHash(); |
|
|
|
} |
|
|
|
|
|
|
|
} // anon namespace
|
|
|
|
|
|
|
|
PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo) |
|
|
@ -1087,6 +1106,7 @@ PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo) |
|
|
|
hashPrevouts = GetPrevoutHash(txTo); |
|
|
|
hashSequence = GetSequenceHash(txTo); |
|
|
|
hashOutputs = GetOutputsHash(txTo); |
|
|
|
hashJoinSplits = GetJoinSplitsHash(txTo); |
|
|
|
} |
|
|
|
|
|
|
|
SigVersion SignatureHashVersion(const CTransaction& txTo) |
|
|
@ -1118,6 +1138,7 @@ uint256 SignatureHash( |
|
|
|
uint256 hashPrevouts; |
|
|
|
uint256 hashSequence; |
|
|
|
uint256 hashOutputs; |
|
|
|
uint256 hashJoinSplits; |
|
|
|
|
|
|
|
if (!(nHashType & SIGHASH_ANYONECANPAY)) { |
|
|
|
hashPrevouts = cache ? cache->hashPrevouts : GetPrevoutHash(txTo); |
|
|
@ -1127,37 +1148,54 @@ uint256 SignatureHash( |
|
|
|
hashSequence = cache ? cache->hashSequence : GetSequenceHash(txTo); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if ((nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) { |
|
|
|
hashOutputs = cache ? cache->hashOutputs : GetOutputsHash(txTo); |
|
|
|
} else if ((nHashType & 0x1f) == SIGHASH_SINGLE && nIn < txTo.vout.size()) { |
|
|
|
CHashWriter ss(SER_GETHASH, 0); |
|
|
|
CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_OUTPUTS_HASH_PERSONALIZATION); |
|
|
|
ss << txTo.vout[nIn]; |
|
|
|
hashOutputs = ss.GetHash(); |
|
|
|
} |
|
|
|
|
|
|
|
CHashWriter ss(SER_GETHASH, 0); |
|
|
|
// Version
|
|
|
|
ss << txTo.nVersion; |
|
|
|
if (!txTo.vjoinsplit.empty()) { |
|
|
|
hashJoinSplits = cache ? cache->hashJoinSplits : GetJoinSplitsHash(txTo); |
|
|
|
} |
|
|
|
|
|
|
|
uint32_t leConsensusBranchId = htole32(consensusBranchId); |
|
|
|
unsigned char personalization[16] = {}; |
|
|
|
memcpy(personalization, "ZcashSigHash", 12); |
|
|
|
memcpy(personalization+12, &leConsensusBranchId, 4); |
|
|
|
|
|
|
|
CBLAKE2bWriter ss(SER_GETHASH, 0, personalization); |
|
|
|
// Header
|
|
|
|
ss << txTo.GetHeader(); |
|
|
|
// Version group ID
|
|
|
|
ss << txTo.nVersionGroupId; |
|
|
|
// Input prevouts/nSequence (none/all, depending on flags)
|
|
|
|
ss << hashPrevouts; |
|
|
|
ss << hashSequence; |
|
|
|
// The input being signed (replacing the scriptSig with scriptCode + amount)
|
|
|
|
// The prevout may already be contained in hashPrevout, and the nSequence
|
|
|
|
// may already be contained in hashSequence.
|
|
|
|
if (nIn != NOT_AN_INPUT) |
|
|
|
ss << txTo.vin[nIn].prevout; |
|
|
|
ss << scriptCode; |
|
|
|
ss << amount; |
|
|
|
if (nIn != NOT_AN_INPUT) |
|
|
|
ss << txTo.vin[nIn].nSequence; |
|
|
|
// Outputs (none/one/all, depending on flags)
|
|
|
|
ss << hashOutputs; |
|
|
|
// JoinSplits
|
|
|
|
ss << hashJoinSplits; |
|
|
|
// Locktime
|
|
|
|
ss << txTo.nLockTime; |
|
|
|
// Expiry height
|
|
|
|
ss << txTo.nExpiryHeight; |
|
|
|
// Sighash type
|
|
|
|
ss << nHashType; |
|
|
|
|
|
|
|
// If this hash is for a transparent input signature
|
|
|
|
// (i.e. not for txTo.joinSplitSig):
|
|
|
|
if (nIn != NOT_AN_INPUT){ |
|
|
|
// The input being signed (replacing the scriptSig with scriptCode + amount)
|
|
|
|
// The prevout may already be contained in hashPrevout, and the nSequence
|
|
|
|
// may already be contained in hashSequence.
|
|
|
|
ss << txTo.vin[nIn].prevout; |
|
|
|
ss << scriptCode; |
|
|
|
ss << amount; |
|
|
|
ss << txTo.vin[nIn].nSequence; |
|
|
|
} |
|
|
|
|
|
|
|
return ss.GetHash(); |
|
|
|
} |
|
|
|
|
|
|
|