From ab5a94592e9e56f050908b42e6e66cdb188f4302 Mon Sep 17 00:00:00 2001
From: Daira Emma Hopwood The Refer to the reference implementation, reproduced below, for the precise algorithm: The Zcash block chain is broken into "epochs" of block height intervals When a consensus rule depends on activation of a particular upgrade, its implementation (and that of any network behavior or surrounding code that depends on it) MUST be gated by a block height check. For example: Incoming blocks known to have a particular height (due to their parent chain being entirely known) MUST be validated under the consensus rules corresponding to the expected consensus branch ID for that height. Incoming blocks with unknown heights (because at least one block header in their parent chain is unknown) MAY be cached, so that they can be reconsidered in the future after all their parents have been received.Notes
hashPrevouts
, hashSequence
, hashOutputs
, and hashJoinSplits
calculated in an earlier validation can be reused in other inputs of the same transaction, so that the time complexity of the whole hashing process reduces from O(n2) to O(n).const unsigned char ZCASH_PREVOUTS_HASH_PERSONALIZATION[16] =
- {'Z','c','a','s','h','P','r','e','v','o','u','t','H','a','s','h'};
-const unsigned char ZCASH_SEQUENCE_HASH_PERSONALIZATION[16] =
- {'Z','c','a','s','h','S','e','q','u','e','n','c','H','a','s','h'};
-const unsigned char ZCASH_OUTPUTS_HASH_PERSONALIZATION[16] =
- {'Z','c','a','s','h','O','u','t','p','u','t','s','H','a','s','h'};
-const unsigned char ZCASH_JOINSPLITS_HASH_PERSONALIZATION[16] =
- {'Z','c','a','s','h','J','S','p','l','i','t','s','H','a','s','h'};
+
const unsigned char ZCASH_PREVOUTS_HASH_PERSONALIZATION[16] =
+ {'Z','c','a','s','h','P','r','e','v','o','u','t','H','a','s','h'};
+const unsigned char ZCASH_SEQUENCE_HASH_PERSONALIZATION[16] =
+ {'Z','c','a','s','h','S','e','q','u','e','n','c','H','a','s','h'};
+const unsigned char ZCASH_OUTPUTS_HASH_PERSONALIZATION[16] =
+ {'Z','c','a','s','h','O','u','t','p','u','t','s','H','a','s','h'};
+const unsigned char ZCASH_JOINSPLITS_HASH_PERSONALIZATION[16] =
+ {'Z','c','a','s','h','J','S','p','l','i','t','s','H','a','s','h'};
// The default values are zeroes
-uint256 hashPrevouts;
-uint256 hashSequence;
-uint256 hashOutputs;
-uint256 hashJoinSplits;
+uint256 hashPrevouts;
+uint256 hashSequence;
+uint256 hashOutputs;
+uint256 hashJoinSplits;
-if (!(nHashType & SIGHASH_ANYONECANPAY)) {
- CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_PREVOUTS_HASH_PERSONALIZATION);
- for (unsigned int n = 0; n < txTo.vin.size(); n++) {
- ss << txTo.vin[n].prevout;
- }
- hashPrevouts = ss.GetHash();
-}
+if (!(nHashType & SIGHASH_ANYONECANPAY)) {
+ CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_PREVOUTS_HASH_PERSONALIZATION);
+ for (unsigned int n = 0; n < txTo.vin.size(); n++) {
+ ss << txTo.vin[n].prevout;
+ }
+ hashPrevouts = ss.GetHash();
+}
-if (!(nHashType & SIGHASH_ANYONECANPAY) && (nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) {
- CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_SEQUENCE_HASH_PERSONALIZATION);
- for (unsigned int n = 0; n < txTo.vin.size(); n++) {
- ss << txTo.vin[n].nSequence;
- }
- hashSequence = ss.GetHash();
-}
+if (!(nHashType & SIGHASH_ANYONECANPAY) && (nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) {
+ CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_SEQUENCE_HASH_PERSONALIZATION);
+ for (unsigned int n = 0; n < txTo.vin.size(); n++) {
+ ss << txTo.vin[n].nSequence;
+ }
+ hashSequence = ss.GetHash();
+}
-if ((nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) {
- CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_OUTPUTS_HASH_PERSONALIZATION);
- for (unsigned int n = 0; n < txTo.vout.size(); n++) {
- ss << txTo.vout[n];
- }
- hashOutputs = ss.GetHash();
-} else if ((nHashType & 0x1f) == SIGHASH_SINGLE && nIn < txTo.vout.size()) {
- CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_OUTPUTS_HASH_PERSONALIZATION);
- ss << txTo.vout[nIn];
- hashOutputs = ss.GetHash();
-}
+if ((nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) {
+ CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_OUTPUTS_HASH_PERSONALIZATION);
+ for (unsigned int n = 0; n < txTo.vout.size(); n++) {
+ ss << txTo.vout[n];
+ }
+ hashOutputs = ss.GetHash();
+} else if ((nHashType & 0x1f) == SIGHASH_SINGLE && nIn < txTo.vout.size()) {
+ CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_OUTPUTS_HASH_PERSONALIZATION);
+ ss << txTo.vout[nIn];
+ hashOutputs = ss.GetHash();
+}
-if (!txTo.vjoinsplit.empty()) {
- 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;
- hashJoinSplits = ss.GetHash();
-}
+if (!txTo.vjoinsplit.empty()) {
+ 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;
+ hashJoinSplits = ss.GetHash();
+}
-uint32_t leConsensusBranchId = htole32(consensusBranchId);
-unsigned char personalization[16] = {};
-memcpy(personalization, "ZcashSigHash", 12);
-memcpy(personalization+12, &leConsensusBranchId, 4);
+uint32_t leConsensusBranchId = htole32(consensusBranchId);
+unsigned char personalization[16] = {};
+memcpy(personalization, "ZcashSigHash", 12);
+memcpy(personalization+12, &leConsensusBranchId, 4);
-CBLAKE2bWriter ss(SER_GETHASH, 0, personalization);
+CBLAKE2bWriter ss(SER_GETHASH, 0, personalization);
// fOverwintered and nVersion
-ss << txTo.GetHeader();
+ss << txTo.GetHeader();
// Version group ID
-ss << txTo.nVersionGroupId;
+ss << txTo.nVersionGroupId;
// Input prevouts/nSequence (none/all, depending on flags)
-ss << hashPrevouts;
-ss << hashSequence;
+ss << hashPrevouts;
+ss << hashSequence;
// Outputs (none/one/all, depending on flags)
-ss << hashOutputs;
+ss << hashOutputs;
// JoinSplits
-ss << hashJoinSplits;
+ss << hashJoinSplits;
// Locktime
-ss << txTo.nLockTime;
+ss << txTo.nLockTime;
// Expiry height
-ss << txTo.nExpiryHeight;
+ss << txTo.nExpiryHeight;
// Sighash type
-ss << nHashType;
+ss << nHashType;
-if (nIn != NOT_AN_INPUT) {
+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 << static_cast<const CScriptBase&>(scriptCode);
- ss << amount;
- ss << txTo.vin[nIn].nSequence;
-}
+ ss << txTo.vin[nIn].prevout;
+ ss << static_cast<const CScriptBase&>(scriptCode);
+ ss << amount;
+ ss << txTo.vin[nIn].nSequence;
+}
-return ss.GetHash();
+return ss.GetHash();Example
diff --git a/zip-0200.html b/zip-0200.html
index 6f4414ba..c8757dd4 100644
--- a/zip-0200.html
+++ b/zip-0200.html
@@ -70,19 +70,19 @@ License: MIT
Activation mechanism
[ACTIVATION_HEIGHT_N, ACTIVATION_HEIGHT_{N+1})
(i.e. including ACTIVATION_HEIGHT_N
and excluding ACTIVATION_HEIGHT_{N+1}
), on which consensus rule sets are defined.if (CurrentEpoch(chainActive.Height(), Params().GetConsensus()) == Consensus::UPGRADE_OVERWINTER) {
+
if (CurrentEpoch(chainActive.Height(), Params().GetConsensus()) == Consensus::UPGRADE_OVERWINTER) {
// Overwinter-specific logic
-} else {
+} else {
// Non-Overwinter logic
-}
+}
// ...
-if (NetworkUpgradeActive(pindex->nHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER)) {
+if (NetworkUpgradeActive(pindex->nHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER)) {
// Overwinter consensus rules applied to block
-} else {
+} else {
// Pre-Overwinter consensus rules applied to block
-}
+}Block validation
// Fix the sign of `u` if necessary -let flip_sign = Choice::from((u.to_bytes()[0] ^ sign) & 1); -let u_negated = -u; -let final_u = Fq::conditional_select(&u, &u_negated, flip_sign);+let flip_sign = Choice::from((u.to_bytes()[0] ^ sign) & 1); +let u_negated = -u; +let final_u = Fq::conditional_select(&u, &u_negated, flip_sign);
This code accepts either sign bit, because u_negated == u
.
There are two points on the Jubjub curve with
\(u\!\)
diff --git a/zip-0221.html b/zip-0221.html
index a03cc5dc..1f6d6862 100644
--- a/zip-0221.html
+++ b/zip-0221.html
@@ -391,7 +391,7 @@ License: MIT
@classmethod
def from_block(Z, block: ZcashBlock) -> ZcashMMRNode:
- '''Create a leaf node from a block'''
+ '''Create a leaf node from a block'''
return Z(
left_child=None,
right_child=None,
@@ -412,7 +412,7 @@ License: MIT
consensusBranchId=block.consensusBranchId)
def serialize(self) -> bytes:
- '''serializes a node'''
+ '''serializes a node'''
buf = (self.hashSubtreeCommitment
+ serialize_uint32(self.nEarliestTimestamp)
+ serialize_uint32(self.nLatestTimestamp)
@@ -457,7 +457,7 @@ License: MIT
consensusBranchId=left_child.consensusBranchId)
def make_root_commitment(root: ZcashMMRNode) -> bytes:
- '''Makes the root commitment for a blockheader'''
+ '''Makes the root commitment for a blockheader'''
return H(root.serialize(), root.consensusBranchId)
Incremental push and pop (pseudocode)
@@ -488,7 +488,7 @@ License: MIT
def bag_peaks(peaks: List[ZcashMMRNode]) -> ZcashMMRNode:
- '''
+ '''
"Bag" a list of peaks, and return the final root
'''
root = peaks[0]
@@ -498,7 +498,7 @@ License: MIT
def append(root: ZcashMMRNode, leaf: ZcashMMRNode) -> ZcashMMRNode:
- '''Append a leaf to an existing tree, return the new tree root'''
+ '''Append a leaf to an existing tree, return the new tree root'''
# recursively find a list of peaks in the current tree
peaks: List[ZcashMMRNode] = get_peaks(root)
merged: List[ZcashMMRNode] = []
@@ -525,7 +525,7 @@ License: MIT
\(k\)
is the number of leaves in the right subtree of the MMR root.
def delete(root: ZcashMMRNode) -> ZcashMMRNode: - ''' + ''' Delete the rightmost leaf node from an existing MMR Return the new tree root ''' diff --git a/zip-0243.html b/zip-0243.html index 03b2d1a8..5d2c371f 100644 --- a/zip-0243.html +++ b/zip-0243.html @@ -97,125 +97,125 @@ License: MIT
The hashPrevouts
, hashSequence
, hashOutputs
, hashJoinSplits
, hashShieldedSpends
, and hashShieldedOutputs
calculated in an earlier validation can be reused in other inputs of the same transaction, so that the time complexity of the whole hashing process reduces from O(n2) to O(n).
Refer to the reference implementation, reproduced below, for the precise algorithm:
-const unsigned char ZCASH_PREVOUTS_HASH_PERSONALIZATION[16] = - {'Z','c','a','s','h','P','r','e','v','o','u','t','H','a','s','h'}; -const unsigned char ZCASH_SEQUENCE_HASH_PERSONALIZATION[16] = - {'Z','c','a','s','h','S','e','q','u','e','n','c','H','a','s','h'}; -const unsigned char ZCASH_OUTPUTS_HASH_PERSONALIZATION[16] = - {'Z','c','a','s','h','O','u','t','p','u','t','s','H','a','s','h'}; -const unsigned char ZCASH_JOINSPLITS_HASH_PERSONALIZATION[16] = - {'Z','c','a','s','h','J','S','p','l','i','t','s','H','a','s','h'}; -const unsigned char ZCASH_SHIELDED_SPENDS_HASH_PERSONALIZATION[16] = - {'Z','c','a','s','h','S','S','p','e','n','d','s','H','a','s','h'}; -const unsigned char ZCASH_SHIELDED_OUTPUTS_HASH_PERSONALIZATION[16] = - {'Z','c','a','s','h','S','O','u','t','p','u','t','H','a','s','h'}; +const unsigned char ZCASH_PREVOUTS_HASH_PERSONALIZATION[16] = + {'Z','c','a','s','h','P','r','e','v','o','u','t','H','a','s','h'}; +const unsigned char ZCASH_SEQUENCE_HASH_PERSONALIZATION[16] = + {'Z','c','a','s','h','S','e','q','u','e','n','c','H','a','s','h'}; +const unsigned char ZCASH_OUTPUTS_HASH_PERSONALIZATION[16] = + {'Z','c','a','s','h','O','u','t','p','u','t','s','H','a','s','h'}; +const unsigned char ZCASH_JOINSPLITS_HASH_PERSONALIZATION[16] = + {'Z','c','a','s','h','J','S','p','l','i','t','s','H','a','s','h'}; +const unsigned char ZCASH_SHIELDED_SPENDS_HASH_PERSONALIZATION[16] = + {'Z','c','a','s','h','S','S','p','e','n','d','s','H','a','s','h'}; +const unsigned char ZCASH_SHIELDED_OUTPUTS_HASH_PERSONALIZATION[16] = + {'Z','c','a','s','h','S','O','u','t','p','u','t','H','a','s','h'}; // The default values are zeroes -uint256 hashPrevouts; -uint256 hashSequence; -uint256 hashOutputs; -uint256 hashJoinSplits; -uint256 hashShieldedSpends; -uint256 hashShieldedOutputs; +uint256 hashPrevouts; +uint256 hashSequence; +uint256 hashOutputs; +uint256 hashJoinSplits; +uint256 hashShieldedSpends; +uint256 hashShieldedOutputs; -if (!(nHashType & SIGHASH_ANYONECANPAY)) { - CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_PREVOUTS_HASH_PERSONALIZATION); - for (unsigned int n = 0; n < txTo.vin.size(); n++) { - ss << txTo.vin[n].prevout; - } - hashPrevouts = ss.GetHash(); -} +if (!(nHashType & SIGHASH_ANYONECANPAY)) { + CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_PREVOUTS_HASH_PERSONALIZATION); + for (unsigned int n = 0; n < txTo.vin.size(); n++) { + ss << txTo.vin[n].prevout; + } + hashPrevouts = ss.GetHash(); +} -if (!(nHashType & SIGHASH_ANYONECANPAY) && (nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) { - CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_SEQUENCE_HASH_PERSONALIZATION); - for (unsigned int n = 0; n < txTo.vin.size(); n++) { - ss << txTo.vin[n].nSequence; - } - hashSequence = ss.GetHash(); -} +if (!(nHashType & SIGHASH_ANYONECANPAY) && (nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) { + CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_SEQUENCE_HASH_PERSONALIZATION); + for (unsigned int n = 0; n < txTo.vin.size(); n++) { + ss << txTo.vin[n].nSequence; + } + hashSequence = ss.GetHash(); +} -if ((nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) { - CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_OUTPUTS_HASH_PERSONALIZATION); - for (unsigned int n = 0; n < txTo.vout.size(); n++) { - ss << txTo.vout[n]; - } - hashOutputs = ss.GetHash(); -} else if ((nHashType & 0x1f) == SIGHASH_SINGLE && nIn < txTo.vout.size()) { - CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_OUTPUTS_HASH_PERSONALIZATION); - ss << txTo.vout[nIn]; - hashOutputs = ss.GetHash(); -} +if ((nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) { + CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_OUTPUTS_HASH_PERSONALIZATION); + for (unsigned int n = 0; n < txTo.vout.size(); n++) { + ss << txTo.vout[n]; + } + hashOutputs = ss.GetHash(); +} else if ((nHashType & 0x1f) == SIGHASH_SINGLE && nIn < txTo.vout.size()) { + CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_OUTPUTS_HASH_PERSONALIZATION); + ss << txTo.vout[nIn]; + hashOutputs = ss.GetHash(); +} -if (!txTo.vjoinsplit.empty()) { - 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; - hashJoinSplits = ss.GetHash(); -} +if (!txTo.vjoinsplit.empty()) { + 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; + hashJoinSplits = ss.GetHash(); +} -if (!txTo.vShieldedSpend.empty()) { - 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; - } - hashShieldedSpends = ss.GetHash(); -} +if (!txTo.vShieldedSpend.empty()) { + 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; + } + hashShieldedSpends = ss.GetHash(); +} -if (!txTo.vShieldedOutput.empty()) { - CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_SHIELDED_OUTPUTS_HASH_PERSONALIZATION); - for (unsigned int n = 0; n < txTo.vShieldedOutput.size(); n++) { - ss << txTo.vShieldedOutput[n]; - } - hashShieldedOutputs = ss.GetHash(); -} +if (!txTo.vShieldedOutput.empty()) { + CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_SHIELDED_OUTPUTS_HASH_PERSONALIZATION); + for (unsigned int n = 0; n < txTo.vShieldedOutput.size(); n++) { + ss << txTo.vShieldedOutput[n]; + } + hashShieldedOutputs = ss.GetHash(); +} -uint32_t leConsensusBranchId = htole32(consensusBranchId); -unsigned char personalization[16] = {}; -memcpy(personalization, "ZcashSigHash", 12); -memcpy(personalization+12, &leConsensusBranchId, 4); +uint32_t leConsensusBranchId = htole32(consensusBranchId); +unsigned char personalization[16] = {}; +memcpy(personalization, "ZcashSigHash", 12); +memcpy(personalization+12, &leConsensusBranchId, 4); -CBLAKE2bWriter ss(SER_GETHASH, 0, personalization); +CBLAKE2bWriter ss(SER_GETHASH, 0, personalization); // fOverwintered and nVersion -ss << txTo.GetHeader(); +ss << txTo.GetHeader(); // Version group ID -ss << txTo.nVersionGroupId; +ss << txTo.nVersionGroupId; // Input prevouts/nSequence (none/all, depending on flags) -ss << hashPrevouts; -ss << hashSequence; +ss << hashPrevouts; +ss << hashSequence; // Outputs (none/one/all, depending on flags) -ss << hashOutputs; +ss << hashOutputs; // JoinSplit descriptions -ss << hashJoinSplits; +ss << hashJoinSplits; // Spend descriptions -ss << hashShieldedSpends; +ss << hashShieldedSpends; // Output descriptions -ss << hashShieldedOutputs; +ss << hashShieldedOutputs; // Locktime -ss << txTo.nLockTime; +ss << txTo.nLockTime; // Expiry height -ss << txTo.nExpiryHeight; +ss << txTo.nExpiryHeight; // Sapling value balance -ss << txTo.valueBalance; +ss << txTo.valueBalance; // Sighash type -ss << nHashType; +ss << nHashType; -if (nIn != NOT_AN_INPUT) { +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 << static_cast<const CScriptBase&>(scriptCode); - ss << amount; - ss << txTo.vin[nIn].nSequence; -} + ss << txTo.vin[nIn].prevout; + ss << static_cast<const CScriptBase&>(scriptCode); + ss << amount; + ss << txTo.vin[nIn].nSequence; +} -return ss.GetHash();+return ss.GetHash();