Implement Sapling signature hash (ZIP 243)

This commit is contained in:
Jack Grigg 2018-05-01 23:10:58 +01:00
parent 53fa6f1315
commit b391b70736
No known key found for this signature in database
GPG Key ID: 665DBCD284F7DAFF
2 changed files with 54 additions and 3 deletions

View File

@ -1065,6 +1065,10 @@ const unsigned char ZCASH_OUTPUTS_HASH_PERSONALIZATION[crypto_generichash_blake2
{'Z','c','a','s','h','O','u','t','p','u','t','s','H','a','s','h'}; {'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] = 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'}; {'Z','c','a','s','h','J','S','p','l','i','t','s','H','a','s','h'};
const unsigned char ZCASH_SHIELDED_SPENDS_HASH_PERSONALIZATION[crypto_generichash_blake2b_PERSONALBYTES] =
{'Z','c','a','s','h','S','S','p','e','n','d','s','H','a','s','h'};
const unsigned char ZCASH_SHIELDED_OUTPUTS_HASH_PERSONALIZATION[crypto_generichash_blake2b_PERSONALBYTES] =
{'Z','c','a','s','h','S','O','u','t','p','u','t','H','a','s','h'};
uint256 GetPrevoutHash(const CTransaction& txTo) { uint256 GetPrevoutHash(const CTransaction& txTo) {
CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_PREVOUTS_HASH_PERSONALIZATION); CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_PREVOUTS_HASH_PERSONALIZATION);
@ -1099,6 +1103,26 @@ uint256 GetJoinSplitsHash(const CTransaction& txTo) {
return ss.GetHash(); return ss.GetHash();
} }
uint256 GetShieldedSpendsHash(const CTransaction& txTo) {
CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_SHIELDED_SPENDS_HASH_PERSONALIZATION);
for (unsigned int n = 0; n < txTo.vShieldedSpend.size(); n++) {
ss << txTo.vShieldedSpend[n].cv;
ss << txTo.vShieldedSpend[n].anchor;
ss << txTo.vShieldedSpend[n].nullifier;
ss << txTo.vShieldedSpend[n].rk;
ss << txTo.vShieldedSpend[n].zkproof;
}
return ss.GetHash();
}
uint256 GetShieldedOutputsHash(const CTransaction& txTo) {
CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_SHIELDED_OUTPUTS_HASH_PERSONALIZATION);
for (unsigned int n = 0; n < txTo.vShieldedOutput.size(); n++) {
ss << txTo.vShieldedOutput[n];
}
return ss.GetHash();
}
} // anon namespace } // anon namespace
PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo) PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo)
@ -1107,12 +1131,18 @@ PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo)
hashSequence = GetSequenceHash(txTo); hashSequence = GetSequenceHash(txTo);
hashOutputs = GetOutputsHash(txTo); hashOutputs = GetOutputsHash(txTo);
hashJoinSplits = GetJoinSplitsHash(txTo); hashJoinSplits = GetJoinSplitsHash(txTo);
hashShieldedSpends = GetShieldedSpendsHash(txTo);
hashShieldedOutputs = GetShieldedOutputsHash(txTo);
} }
SigVersion SignatureHashVersion(const CTransaction& txTo) SigVersion SignatureHashVersion(const CTransaction& txTo)
{ {
if (txTo.fOverwintered) { if (txTo.fOverwintered) {
return SIGVERSION_OVERWINTER; if (txTo.nVersionGroupId == SAPLING_VERSION_GROUP_ID) {
return SIGVERSION_SAPLING;
} else {
return SIGVERSION_OVERWINTER;
}
} else { } else {
return SIGVERSION_SPROUT; return SIGVERSION_SPROUT;
} }
@ -1134,11 +1164,13 @@ uint256 SignatureHash(
auto sigversion = SignatureHashVersion(txTo); auto sigversion = SignatureHashVersion(txTo);
if (sigversion == SIGVERSION_OVERWINTER) { if (sigversion == SIGVERSION_OVERWINTER || sigversion == SIGVERSION_SAPLING) {
uint256 hashPrevouts; uint256 hashPrevouts;
uint256 hashSequence; uint256 hashSequence;
uint256 hashOutputs; uint256 hashOutputs;
uint256 hashJoinSplits; uint256 hashJoinSplits;
uint256 hashShieldedSpends;
uint256 hashShieldedOutputs;
if (!(nHashType & SIGHASH_ANYONECANPAY)) { if (!(nHashType & SIGHASH_ANYONECANPAY)) {
hashPrevouts = cache ? cache->hashPrevouts : GetPrevoutHash(txTo); hashPrevouts = cache ? cache->hashPrevouts : GetPrevoutHash(txTo);
@ -1160,6 +1192,14 @@ uint256 SignatureHash(
hashJoinSplits = cache ? cache->hashJoinSplits : GetJoinSplitsHash(txTo); hashJoinSplits = cache ? cache->hashJoinSplits : GetJoinSplitsHash(txTo);
} }
if (!txTo.vShieldedSpend.empty()) {
hashShieldedSpends = cache ? cache->hashShieldedSpends : GetShieldedSpendsHash(txTo);
}
if (!txTo.vShieldedOutput.empty()) {
hashShieldedOutputs = cache ? cache->hashShieldedOutputs : GetShieldedOutputsHash(txTo);
}
uint32_t leConsensusBranchId = htole32(consensusBranchId); uint32_t leConsensusBranchId = htole32(consensusBranchId);
unsigned char personalization[16] = {}; unsigned char personalization[16] = {};
memcpy(personalization, "ZcashSigHash", 12); memcpy(personalization, "ZcashSigHash", 12);
@ -1177,10 +1217,20 @@ uint256 SignatureHash(
ss << hashOutputs; ss << hashOutputs;
// JoinSplits // JoinSplits
ss << hashJoinSplits; ss << hashJoinSplits;
if (sigversion == SIGVERSION_SAPLING) {
// Spend descriptions
ss << hashShieldedSpends;
// Output descriptions
ss << hashShieldedOutputs;
}
// Locktime // Locktime
ss << txTo.nLockTime; ss << txTo.nLockTime;
// Expiry height // Expiry height
ss << txTo.nExpiryHeight; ss << txTo.nExpiryHeight;
if (sigversion == SIGVERSION_SAPLING) {
// Sapling value balance
ss << txTo.valueBalance;
}
// Sighash type // Sighash type
ss << nHashType; ss << nHashType;

View File

@ -92,7 +92,7 @@ bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned i
struct PrecomputedTransactionData struct PrecomputedTransactionData
{ {
uint256 hashPrevouts, hashSequence, hashOutputs, hashJoinSplits; uint256 hashPrevouts, hashSequence, hashOutputs, hashJoinSplits, hashShieldedSpends, hashShieldedOutputs;
PrecomputedTransactionData(const CTransaction& tx); PrecomputedTransactionData(const CTransaction& tx);
}; };
@ -101,6 +101,7 @@ enum SigVersion
{ {
SIGVERSION_SPROUT = 0, SIGVERSION_SPROUT = 0,
SIGVERSION_OVERWINTER = 1, SIGVERSION_OVERWINTER = 1,
SIGVERSION_SAPLING = 2,
}; };
uint256 SignatureHash( uint256 SignatureHash(