update SignatureHash according to Overwinter spec
with help from str4d
This commit is contained in:
parent
132dc81f7d
commit
7245f32835
|
@ -383,12 +383,7 @@ public:
|
||||||
*const_cast<bool*>(&fOverwintered) = header >> 31;
|
*const_cast<bool*>(&fOverwintered) = header >> 31;
|
||||||
*const_cast<int32_t*>(&this->nVersion) = header & 0x7FFFFFFF;
|
*const_cast<int32_t*>(&this->nVersion) = header & 0x7FFFFFFF;
|
||||||
} else {
|
} else {
|
||||||
// When serializing v1 and v2, the 4 byte header is nVersion
|
uint32_t header = GetHeader();
|
||||||
uint32_t header = this->nVersion;
|
|
||||||
// When serializing Overwintered tx, the 4 byte header is the combination of fOverwintered and nVersion
|
|
||||||
if (fOverwintered) {
|
|
||||||
header |= 1 << 31;
|
|
||||||
}
|
|
||||||
READWRITE(header);
|
READWRITE(header);
|
||||||
}
|
}
|
||||||
nVersion = this->nVersion;
|
nVersion = this->nVersion;
|
||||||
|
@ -428,6 +423,16 @@ public:
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t GetHeader() const {
|
||||||
|
// When serializing v1 and v2, the 4 byte header is nVersion
|
||||||
|
uint32_t header = this->nVersion;
|
||||||
|
// When serializing Overwintered tx, the 4 byte header is the combination of fOverwintered and nVersion
|
||||||
|
if (fOverwintered) {
|
||||||
|
header |= 1 << 31;
|
||||||
|
}
|
||||||
|
return header;
|
||||||
|
}
|
||||||
|
|
||||||
// Return sum of txouts.
|
// Return sum of txouts.
|
||||||
CAmount GetValueOut() const;
|
CAmount GetValueOut() const;
|
||||||
// GetValueIn() is a method on CCoinsViewCache, because
|
// GetValueIn() is a method on CCoinsViewCache, because
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include "interpreter.h"
|
#include "interpreter.h"
|
||||||
|
|
||||||
|
#include "consensus/upgrades.h"
|
||||||
#include "primitives/transaction.h"
|
#include "primitives/transaction.h"
|
||||||
#include "crypto/ripemd160.h"
|
#include "crypto/ripemd160.h"
|
||||||
#include "crypto/sha1.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) {
|
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++) {
|
for (unsigned int n = 0; n < txTo.vin.size(); n++) {
|
||||||
ss << txTo.vin[n].prevout;
|
ss << txTo.vin[n].prevout;
|
||||||
}
|
}
|
||||||
|
@ -1065,7 +1075,7 @@ uint256 GetPrevoutHash(const CTransaction& txTo) {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint256 GetSequenceHash(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++) {
|
for (unsigned int n = 0; n < txTo.vin.size(); n++) {
|
||||||
ss << txTo.vin[n].nSequence;
|
ss << txTo.vin[n].nSequence;
|
||||||
}
|
}
|
||||||
|
@ -1073,13 +1083,22 @@ uint256 GetSequenceHash(const CTransaction& txTo) {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint256 GetOutputsHash(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++) {
|
for (unsigned int n = 0; n < txTo.vout.size(); n++) {
|
||||||
ss << txTo.vout[n];
|
ss << txTo.vout[n];
|
||||||
}
|
}
|
||||||
return ss.GetHash();
|
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
|
} // anon namespace
|
||||||
|
|
||||||
PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo)
|
PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo)
|
||||||
|
@ -1087,6 +1106,7 @@ PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo)
|
||||||
hashPrevouts = GetPrevoutHash(txTo);
|
hashPrevouts = GetPrevoutHash(txTo);
|
||||||
hashSequence = GetSequenceHash(txTo);
|
hashSequence = GetSequenceHash(txTo);
|
||||||
hashOutputs = GetOutputsHash(txTo);
|
hashOutputs = GetOutputsHash(txTo);
|
||||||
|
hashJoinSplits = GetJoinSplitsHash(txTo);
|
||||||
}
|
}
|
||||||
|
|
||||||
SigVersion SignatureHashVersion(const CTransaction& txTo)
|
SigVersion SignatureHashVersion(const CTransaction& txTo)
|
||||||
|
@ -1118,6 +1138,7 @@ uint256 SignatureHash(
|
||||||
uint256 hashPrevouts;
|
uint256 hashPrevouts;
|
||||||
uint256 hashSequence;
|
uint256 hashSequence;
|
||||||
uint256 hashOutputs;
|
uint256 hashOutputs;
|
||||||
|
uint256 hashJoinSplits;
|
||||||
|
|
||||||
if (!(nHashType & SIGHASH_ANYONECANPAY)) {
|
if (!(nHashType & SIGHASH_ANYONECANPAY)) {
|
||||||
hashPrevouts = cache ? cache->hashPrevouts : GetPrevoutHash(txTo);
|
hashPrevouts = cache ? cache->hashPrevouts : GetPrevoutHash(txTo);
|
||||||
|
@ -1127,36 +1148,53 @@ uint256 SignatureHash(
|
||||||
hashSequence = cache ? cache->hashSequence : GetSequenceHash(txTo);
|
hashSequence = cache ? cache->hashSequence : GetSequenceHash(txTo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if ((nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) {
|
if ((nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) {
|
||||||
hashOutputs = cache ? cache->hashOutputs : GetOutputsHash(txTo);
|
hashOutputs = cache ? cache->hashOutputs : GetOutputsHash(txTo);
|
||||||
} else if ((nHashType & 0x1f) == SIGHASH_SINGLE && nIn < txTo.vout.size()) {
|
} 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];
|
ss << txTo.vout[nIn];
|
||||||
hashOutputs = ss.GetHash();
|
hashOutputs = ss.GetHash();
|
||||||
}
|
}
|
||||||
|
|
||||||
CHashWriter ss(SER_GETHASH, 0);
|
if (!txTo.vjoinsplit.empty()) {
|
||||||
// Version
|
hashJoinSplits = cache ? cache->hashJoinSplits : GetJoinSplitsHash(txTo);
|
||||||
ss << txTo.nVersion;
|
}
|
||||||
|
|
||||||
|
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)
|
// Input prevouts/nSequence (none/all, depending on flags)
|
||||||
ss << hashPrevouts;
|
ss << hashPrevouts;
|
||||||
ss << hashSequence;
|
ss << hashSequence;
|
||||||
|
// 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 input being signed (replacing the scriptSig with scriptCode + amount)
|
||||||
// The prevout may already be contained in hashPrevout, and the nSequence
|
// The prevout may already be contained in hashPrevout, and the nSequence
|
||||||
// may already be contained in hashSequence.
|
// may already be contained in hashSequence.
|
||||||
if (nIn != NOT_AN_INPUT)
|
|
||||||
ss << txTo.vin[nIn].prevout;
|
ss << txTo.vin[nIn].prevout;
|
||||||
ss << scriptCode;
|
ss << scriptCode;
|
||||||
ss << amount;
|
ss << amount;
|
||||||
if (nIn != NOT_AN_INPUT)
|
|
||||||
ss << txTo.vin[nIn].nSequence;
|
ss << txTo.vin[nIn].nSequence;
|
||||||
// Outputs (none/one/all, depending on flags)
|
}
|
||||||
ss << hashOutputs;
|
|
||||||
// Locktime
|
|
||||||
ss << txTo.nLockTime;
|
|
||||||
// Sighash type
|
|
||||||
ss << nHashType;
|
|
||||||
|
|
||||||
return ss.GetHash();
|
return ss.GetHash();
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,7 +90,7 @@ enum
|
||||||
|
|
||||||
struct PrecomputedTransactionData
|
struct PrecomputedTransactionData
|
||||||
{
|
{
|
||||||
uint256 hashPrevouts, hashSequence, hashOutputs;
|
uint256 hashPrevouts, hashSequence, hashOutputs, hashJoinSplits;
|
||||||
|
|
||||||
PrecomputedTransactionData(const CTransaction& tx);
|
PrecomputedTransactionData(const CTransaction& tx);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue