Skip to content

Commit d73ed0a

Browse files
committed
Sapling signature hash (Custom version of ZIP 243)
1 parent b3cfc3c commit d73ed0a

File tree

2 files changed

+61
-3
lines changed

2 files changed

+61
-3
lines changed

src/script/interpreter.cpp

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1092,6 +1092,12 @@ const unsigned char PIVX_SEQUENCE_HASH_PERSONALIZATION[crypto_generichash_blake2
10921092
{'P','I','V','X','S','e','q','u','e','n','c','H','a','s','h'};
10931093
const unsigned char PIVX_OUTPUTS_HASH_PERSONALIZATION[crypto_generichash_blake2b_PERSONALBYTES] =
10941094
{'P','I','V','X','O','u','t','p','u','t','s','H','a','s','h'};
1095+
const unsigned char PIVX_SHIELDED_SPENDS_HASH_PERSONALIZATION[crypto_generichash_blake2b_PERSONALBYTES] =
1096+
{'P','I','V','X','S','S','p','e','n','d','s','H','a','s','h'};
1097+
const unsigned char PIVX_SHIELDED_OUTPUTS_HASH_PERSONALIZATION[crypto_generichash_blake2b_PERSONALBYTES] =
1098+
{'P','I','V','X','S','O','u','t','p','u','t','H','a','s','h'};
1099+
1100+
10951101

10961102
uint256 GetPrevoutHash(const CTransaction& txTo) {
10971103
CBLAKE2bWriter ss(SER_GETHASH, 0, PIVX_PREVOUTS_HASH_PERSONALIZATION);
@@ -1117,13 +1123,39 @@ uint256 GetOutputsHash(const CTransaction& txTo) {
11171123
return ss.GetHash();
11181124
}
11191125

1126+
uint256 GetShieldedSpendsHash(const CTransaction& txTo) {
1127+
CBLAKE2bWriter ss(SER_GETHASH, 0, PIVX_SHIELDED_SPENDS_HASH_PERSONALIZATION);
1128+
auto sapData = txTo.sapData;
1129+
for (const auto& n : sapData->vShieldedSpend) {
1130+
ss << n.cv;
1131+
ss << n.anchor;
1132+
ss << n.nullifier;
1133+
ss << n.rk;
1134+
ss << n.zkproof;
1135+
}
1136+
return ss.GetHash();
1137+
}
1138+
1139+
uint256 GetShieldedOutputsHash(const CTransaction& txTo) {
1140+
CBLAKE2bWriter ss(SER_GETHASH, 0, PIVX_SHIELDED_OUTPUTS_HASH_PERSONALIZATION);
1141+
auto sapData = txTo.sapData;
1142+
for (const auto& n : sapData->vShieldedOutput) {
1143+
ss << n;
1144+
}
1145+
return ss.GetHash();
1146+
}
1147+
11201148
} // anon namespace
11211149

11221150
PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo)
11231151
{
11241152
hashPrevouts = GetPrevoutHash(txTo);
11251153
hashSequence = GetSequenceHash(txTo);
11261154
hashOutputs = GetOutputsHash(txTo);
1155+
if (txTo.sapData) {
1156+
hashShieldedSpends = GetShieldedSpendsHash(txTo);
1157+
hashShieldedOutputs = GetShieldedOutputsHash(txTo);
1158+
}
11271159
}
11281160

11291161
uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache)
@@ -1138,6 +1170,9 @@ uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsig
11381170
uint256 hashPrevouts;
11391171
uint256 hashSequence;
11401172
uint256 hashOutputs;
1173+
uint256 hashShieldedSpends;
1174+
uint256 hashShieldedOutputs;
1175+
bool hasSapData = false;
11411176

11421177
if (!(nHashType & SIGHASH_ANYONECANPAY)) {
11431178
hashPrevouts = cache ? cache->hashPrevouts : GetPrevoutHash(txTo);
@@ -1155,6 +1190,18 @@ uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsig
11551190
hashOutputs = ss.GetHash();
11561191
}
11571192

1193+
if (txTo.sapData) {
1194+
if (!txTo.sapData->vShieldedSpend.empty()) {
1195+
hashShieldedSpends = cache ? cache->hashShieldedSpends : GetShieldedSpendsHash(txTo);
1196+
hasSapData = true;
1197+
}
1198+
1199+
if (!txTo.sapData->vShieldedOutput.empty()) {
1200+
hashShieldedOutputs = cache ? cache->hashShieldedOutputs : GetShieldedOutputsHash(txTo);
1201+
hasSapData = true;
1202+
}
1203+
}
1204+
11581205
// todo: complete branch id with the active network upgrade
11591206
uint32_t leConsensusBranchId = htole32(0);
11601207
unsigned char personalization[16] = {};
@@ -1167,15 +1214,26 @@ uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsig
11671214
// Input prevouts/nSequence (none/all, depending on flags)
11681215
ss << hashPrevouts;
11691216
ss << hashSequence;
1217+
// Outputs (none/one/all, depending on flags)
1218+
ss << hashOutputs;
1219+
1220+
if (hasSapData) {
1221+
// Spend descriptions
1222+
ss << hashShieldedSpends;
1223+
// Output descriptions
1224+
ss << hashShieldedOutputs;
1225+
// Sapling value balance
1226+
ss << txTo.sapData->valueBalance;
1227+
}
1228+
11701229
// The input being signed (replacing the scriptSig with scriptCode + amount)
11711230
// The prevout may already be contained in hashPrevout, and the nSequence
11721231
// may already be contained in hashSequence.
11731232
ss << txTo.vin[nIn].prevout;
11741233
ss << static_cast<const CScriptBase&>(scriptCode);
11751234
ss << amount;
11761235
ss << txTo.vin[nIn].nSequence;
1177-
// Outputs (none/one/all, depending on flags)
1178-
ss << hashOutputs;
1236+
11791237
// Locktime
11801238
ss << txTo.nLockTime;
11811239
// Sighash type

src/script/interpreter.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned i
8888

8989
struct PrecomputedTransactionData
9090
{
91-
uint256 hashPrevouts, hashSequence, hashOutputs;
91+
uint256 hashPrevouts, hashSequence, hashOutputs, hashShieldedSpends, hashShieldedOutputs;
9292

9393
PrecomputedTransactionData(const CTransaction& tx);
9494
};

0 commit comments

Comments
 (0)