From 301ad7cea924b99e44d575409936842089103ab6 Mon Sep 17 00:00:00 2001 From: str4d Date: Wed, 11 Apr 2018 14:36:12 -0600 Subject: [PATCH] ZIP 243: Transaction Signature Verification for Sapling --- zip-0243.rst | 291 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 291 insertions(+) create mode 100644 zip-0243.rst diff --git a/zip-0243.rst b/zip-0243.rst new file mode 100644 index 00000000..226afaa6 --- /dev/null +++ b/zip-0243.rst @@ -0,0 +1,291 @@ +:: + + ZIP: 243 + Title: Transaction Signature Verification for Sapling + Author: Jack Grigg + Daira Hopwood + Category: Consensus + Created: 2018-04-10 + License: MIT + + +Terminology +=========== + +The key words "MUST" and "MUST NOT" in this document are to be interpreted as described in RFC 2119. + +The terms "branch" and "network upgrade" in this document are to be interpreted as described in ZIP 200. [#zip-0200]_ + +The term "Overwinter" in this document is to be interpreted as described in ZIP 201. [#zip-0201]_ + +The term "Sapling" in this document is to be interpreted as described in ZIP XXX. [#zip-0XXX]_ + + +Abstract +======== + +This proposal defines a new transaction digest algorithm for signature verification from the Sapling network +upgrade, to account for the presence of Sapling shielded inputs and outputs in transactions. + + +Motivation +========== + +The Sapling network upgrade introduced new shielded inputs and outputs. We want these to be covered by the +transaction digest algorithm used for signatures, in order to ensure they are correctly bound. + + +Specification +============= + +A new transaction digest algorithm is defined:: + + BLAKE2b-256 hash of the serialization of: + 1. header of the transaction (4-byte little endian) + 2. nVersionGroupId of the transaction (4-byte little endian) + 3. hashPrevouts (32-byte hash) + 4. hashSequence (32-byte hash) + 5. hashOutputs (32-byte hash) + 6. hashJoinSplits (32-byte hash) + 7. hashShieldedSpends (32-byte hash) + 8. hashShieldedOutputs (32-byte hash) + 9. nLockTime of the transaction (4-byte little endian) + 10. nExpiryHeight of the transaction (4-byte little endian) + 11. valueBalance of the transaction (8-byte little endian) + 12. sighash type of the signature (4-byte little endian) + + 13. If we are serializing an input (i.e. this is not a JoinSplit signature hash): + a. outpoint (32-byte hash + 4-byte little endian) + b. scriptCode of the input (serialized as scripts inside CTxOuts) + c. value of the output spent by this input (8-byte little endian) + d. nSequence of the input (4-byte little endian) + +The new algorithm is based on the transaction digest algorithm defined in ZIP 143 [#zip-0143]_. + +The new algorithm MUST be used for signatures created over the Sapling transaction format [#zip-0XXX]_. +Combined with the new consensus rule that v3 transaction formats will be invalid from the Sapling upgrade +[#zip-0XXX]_, this effectively means that all transaction signatures from the Sapling activation height will +use the new algorithm [#zip-0XXX]_. + +The BLAKE2b-256 personalization field [#BLAKE2-personalization]_ is set to:: + + "ZcashSigHash" || CONSENSUS_BRANCH_ID + +``CONSENSUS_BRANCH_ID`` is the little-endian encoding of ``BRANCH_ID`` for the epoch of the block containing +the transaction. [#zip-0200]_ Domain separation of the signature hash across parallel branches provides replay +protection: transactions targeted for one branch will have invalid signatures on other branches. + +Transaction creators MUST specify the epoch they want their transaction to be mined in. Across a network +upgrade, this means that if a transaction is not mined before the activation height, it will never be mined. + +Semantics of the original sighash types are as in ZIP 143 [#zip-0143]_. + +Field definitions +----------------- + +The items 1, 2, 3, 4, 5, 9, 10, 12, and 13 have the same meaning as in ZIP 143 [#zip-0143]_. + +6: ``hashJoinSplits`` +````````````````````` +* If ``vjoinsplits`` is non-empty, ``hashJoinSplits`` is the BLAKE2b-256 hash of the serialization of all + JoinSplits (in their canonical v4 transaction serialization format) concatenated with the + ``joinSplitPubKey``; + + * The BLAKE2b-256 personalization field is set to ``ZcashJSplitsHash``. + + * Note that while signatures are ommitted, the JoinSplit proofs are included in the signature hash, as with + v1, v2, and v3 transactions. + +* Otherwise, ``hashJoinSplits`` is a ``uint256`` of ``0x0000......0000``. + +7: ``hashShieldedSpends`` +````````````````````````` + +* If ``vShieldedSpend`` is non-empty, ``hashShieldedSpends`` is the BLAKE2b-256 hash of the serialization of + all Spend Descriptions (in their canonical transaction serialization format minus ``spendAuthSig``); + + * The BLAKE2b-256 personalization field is set to ``ZcashSSpendsHash``. + + * Note that the Spend proofs are included in the signature hash, as with JoinSplit proofs in v1, v2, and v3 + transactions. + +* Otherwise, ``hashShieldedSpends`` is a ``uint256`` of ``0x0000......0000``. + +8: ``hashShieldedOutputs`` +`````````````````````````` + +* If ``vShieldedOutput`` is non-empty, ``hashShieldedOutputs`` is the BLAKE2b-256 hash of the serialization of + all Output Descriptions (in their canonical transaction serialization format); + + * The BLAKE2b-256 personalization field is set to ``ZcashSOutputHash``. + + * Note that the Output proofs are included in the signature hash, as with JoinSplit proofs in v1, v2, and v3 + transactions. + +* Otherwise, ``hashShieldedOutputs`` is a ``uint256`` of ``0x0000......0000``. + +11: ``valueBalance`` +```````````````````` +An 8-byte signed two's-complement little-endian value of the net amount, in zatoshi, exiting the Sapling value +pool. For clarity, a negative value corresponds to an amount *entering* the Sapling value pool. + +Notes +----- + +The ``hashPrevouts``, ``hashSequence``, ``hashOutputs``, ``hashJoinSplits``, ``hashShieldedSpends``, and +``hashShieldedOutputs`` calculated in an earlier verification can be reused in other inputs of the same +transaction, so that the time complexity of the whole hashing process reduces from O(n\ :sup:`2`) to O(n). + +Refer to the reference implementation, reproduced below, for the precise algorithm: + +.. code:: cpp + + 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; + + 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 & 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.vShieldedSpends.empty()) { + CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_SHIELDED_SPENDS_HASH_PERSONALIZATION); + for (unsigned int n = 0; n < txTo.vShieldedSpends.size(); n++) { + ss << txTo.vShieldedSpends[n]; + } + hashShieldedSpends = ss.GetHash(); + } + + if (!txTo.vShieldedOutputs.empty()) { + CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_SHIELDED_OUTPUTS_HASH_PERSONALIZATION); + for (unsigned int n = 0; n < txTo.vShieldedOutputs.size(); n++) { + ss << txTo.vShieldedOutputs[n]; + } + hashShieldedOutputs = ss.GetHash(); + } + + uint32_t leConsensusBranchId = htole32(consensusBranchId); + unsigned char personalization[16] = {}; + memcpy(personalization, "ZcashSigHash", 12); + memcpy(personalization+12, &leConsensusBranchId, 4); + + CBLAKE2bWriter ss(SER_GETHASH, 0, personalization); + // fOverwintered and nVersion + ss << txTo.GetHeader(); + // Version group ID + ss << txTo.nVersionGroupId; + // Input prevouts/nSequence (none/all, depending on flags) + ss << hashPrevouts; + ss << hashSequence; + // Outputs (none/one/all, depending on flags) + ss << hashOutputs; + // JoinSplits + ss << hashJoinSplits; + // Spend Descriptions + ss << hashShieldedSpends; + // Output Descriptions + ss << hashShieldedOutputs; + // Locktime + ss << txTo.nLockTime; + // Expiry height + ss << txTo.nExpiryHeight; + // Sapling value balance + ss << txTo.valueBalance; + // Sighash type + ss << nHashType; + + 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(scriptCode); + ss << amount; + ss << txTo.vin[nIn].nSequence; + } + + return ss.GetHash(); + + +Example +======= + +TBC + + +Deployment +========== + +This proposal is deployed with the Sapling network upgrade. [#zip-0XXX]_ + + +Backward compatibility +====================== + +This proposal is backwards-compatible with old UTXOs. It is **not** backwards-compatible with older software. +All transactions will be required to use this transaction digest algorithm for signatures, and so transactions +created by older software will be rejected by the network. + + +Reference Implementation +======================== + +https://github.com/zcash/zcash/pull/XXXX + + +References +========== + +.. [#BLAKE2-personalization] `"BLAKE2: simpler, smaller, fast as MD5", Section 2.8 `_ +.. [#zip-0200] `ZIP 200: Network Upgrade Mechanism `_ +.. [#zip-0201] `ZIP 201: Network Peer Management for Overwinter `_