mirror of https://github.com/zcash/zips.git
292 lines
11 KiB
ReStructuredText
292 lines
11 KiB
ReStructuredText
::
|
|
|
|
ZIP: 243
|
|
Title: Transaction Signature Verification for Sapling
|
|
Author: Jack Grigg <jack@z.cash>
|
|
Daira Hopwood <daira@z.cash>
|
|
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. [#RFC2119]_
|
|
|
|
The terms "branch" and "network upgrade" in this document are to be interpreted as described in ZIP 200. [#zip-0200]_
|
|
|
|
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 a transparent input (i.e. this hash is not for a JoinSplit signature,
|
|
Spend authorization signature, or binding signature):
|
|
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
|
|
JoinSplit descriptions (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;
|
|
// JoinSplit descriptions
|
|
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<const CScriptBase&>(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
|
|
==========
|
|
|
|
.. [#RFC2119] `Key words for use in RFCs to Indicate Requirement Levels <https://tools.ietf.org/html/rfc2119>`_
|
|
.. [#BLAKE2-personalization] `"BLAKE2: simpler, smaller, fast as MD5", Section 2.8 <https://blake2.net/blake2.pdf>`_
|
|
.. [#zip-0143] `ZIP 143: Transaction Signature Verification for Overwinter <https://github.com/zcash/zips/blob/master/zip-0143.rst>`_
|
|
.. [#zip-0200] `ZIP 200: Network Upgrade Mechanism <https://github.com/zcash/zips/blob/master/zip-0200.rst>`_
|