-
Notifications
You must be signed in to change notification settings - Fork 158
[ZIP 143] Transaction Signature Verification for Overwinter #129
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
WRT replay protection, we decided in a meeting today that the branch ID in the transaction's block serialization format would be used for replay protection, so its presence in the personalization field is no longer specifically needed for replay protection. But we will leave it there because it is good practice to personalize the hash function over the desired domain (in our case, the branch "epoch" as referred to in #128). |
2. hashPrevouts (32-byte hash) | ||
3. hashSequence (32-byte hash) | ||
4. hashOutputs (32-byte hash) | ||
5. hashJoinSplits (32-byte hash) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(in reply to str4d@3d29239#r26720276)
@daira I was thinking that we might end up having separate hashes for input and output Sapling circuits, ie:
5. hashJoinSplits (32-byte hash)
6. hashShieldedInputs (32-byte hash)
7. hashShieldedOutputs (32-byte hash)
I'm not sure whether we need this kind of flexibility though, in the way that it is useful for the different transparent sighash types (because I expect we'd want to implement those in a zero-knowledge way, which doing inside a visible signature would not be).
Note that we will need to have another ZIP with a newer SigHash specification anyway when we address transaction malleability.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We discussed this in a pairing, and decided that we don't need to add anything for Sapling in advance; we can conditionally add it to the algorithm (gated on transaction version) when we add Sapling.
|
||
2: ``hashPrevouts`` | ||
``````````````````` | ||
* If the ``ANYONECANPAY`` flag is not set, ``hashPrevouts`` is the double SHA256 of the serialization of all |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(in reply to str4d@3d29239#r26723101)
@daira these are the inner hashes. Do we want to change these to BLAKE2 as well? And if so, we should personalize them too.
5: ``hashJoinSplits`` | ||
````````````````````` | ||
* If ``vjoinsplits`` is non-empty, ``hashJoinSplits`` is the double SHA256 of the serialization of all | ||
JoinSplits concatenated with the joinSplitPubKey; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(in reply to str4d@3d29239#r26723268)
@daira I don't think we want this encoded as in a transaction:
- The transaction uses a
std::vector
encoding forvin
,vout
, andvjoinsplit
, whereas the otherhash*
in this proposal (of data fromvin
andvout
) use simple concatenation. We should follow the latter here for consistency withvjoinsplit
. - In Sprout we serialized a "null"
joinSplitSig
. I see no need to do that here.
inside CTxOuts); | ||
|
||
* If sighash type is ``SINGLE`` and the input index is smaller than the number of outputs, ``hashOutputs`` is | ||
the double SHA256 of the output amount with ``scriptPubKey`` of the same index as the input; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(in reply to str4d@3d29239#r26723147)
@daira agreed, the wording from BIP 143 isn't clear. It means the same serialization as the first case, but only of the output corresponding to the input signature being created (instead of the whole vout
).
#. ``SINGLE`` does not commit to the input index. When ``ANYONECANPAY`` is not set, the semantics are | ||
unchanged since ``hashPrevouts`` and ``outpoint`` together implictly commit to the input index. When | ||
``SINGLE`` is used with ``ANYONECANPAY``, omission of the index commitment allows permutation of the | ||
input-output pairs, as long as each pair is located at an equivalent index. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(in reply to str4d@3d29239#r26723093)
@daira I don't think there's any security issue. It just allows shuffling of the order of transparent input/output pairs, in the same way Sapling will allow shuffling of the order of input circuits and output circuits (not in pairs).
Title: Transaction Signature Verification for Overwinter | ||
Author: Jack Grigg <jack@z.cash> | ||
Daira Hopwood <daira@z.cash> | ||
Credits: Johnson Lau <jl2012@xbt.hk> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should also credit BitcoinABC because they inspired ticket #2584 by writing up a spec https://github.com/Bitcoin-UAHF/spec/blob/master/uahf-technical-spec.md and https://github.com/Bitcoin-ABC/bitcoin-abc/blob/master/doc/abc/replay-protected-sighash.md demonstrating how to extract the relevant bits from BIP 143 etc.
4. hashSequence (32-byte hash) | ||
5. hashOutputs (32-byte hash) | ||
6. hashJoinSplits (32-byte hash) | ||
7. nLockTime of the transaction (8-byte little endian) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nLockTime is uint32_t
5. hashOutputs (32-byte hash) | ||
6. hashJoinSplits (32-byte hash) | ||
7. nLockTime of the transaction (8-byte little endian) | ||
8. nExpiryTime of the transaction (8-byte little endian) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rename to nExpiryHeight. Also both nLockTime and nExpiryHeight are uint32_t so 4-byte little endian, not 8-byte.
|
||
"ZcashSigHash" || BLOCK_BRANCH_ID | ||
|
||
``BLOCK_BRANCH_ID`` is the ``BRANCH_ID`` for the epoch of the transaction's parent block. [#ZIP-activation-mechanism]_ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we think of terminology that better clarifies the different identifiers? e.g. FAMILY_BRANCH_ID (I think family, e.g. Zcash or some clone) whereas EPOCH_ID (epoch makes me think of time so then I start thinking that the ID will expire, makes me less confident/comfortable for some reason).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Above comment is probably not relevant given recent discussion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Decided to name it CONSENSUS_BRANCH_ID
to match usage in the code.
The BLAKE2b personalization field for the inner hashes should be "Zcash_Inner_Hash". |
Overwinter SignatureHash Implements zcash/zips#129. Includes code cherry-picked from the following upstream PRs: - bitcoin/bitcoin#7276 - bitcoin/bitcoin#7976 - bitcoin/bitcoin#8118 - bitcoin/bitcoin#8149 - Only amount validation and SignatureHash commits. - bitcoin/bitcoin#6915 - Only the rework of `mempool.check()` calls that the next PR depends on. - bitcoin/bitcoin#8346 - bitcoin/bitcoin#8524 Part of #2254. Closes #1408 and #2584.
A new transaction digest algorithm is defined, but only applicable from the Overwinter upgrade block height | ||
[#ZIP0000]_:: | ||
BLAKE2b-256 of the serialization of: | ||
1. nVersion of the transaction (4-byte little endian) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Referred to in the transaction format zip as header. you could break this into compontents fOverwintered flag and nVersion.
[#ZIP0000]_:: | ||
BLAKE2b-256 of the serialization of: | ||
1. nVersion of the transaction (4-byte little endian) | ||
2. nVersionBranch of the transaction (4-byte little endian) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now: nVersionGroupId
c. value of the output spent by this input (8-byte little endian) | ||
d. nSequence of the input (4-byte little endian) | ||
|
||
The BLAKE2b-256 personalization field is set to:: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add link/reference to blake2
* 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. | ||
|
||
* Transaction validators MUST NOT use ``nVersionBranch`` as the ``BLOCK_BRANCH_ID``: while these are both a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
WIth nVersionGroupId, this bullet point is rendundant and could be removed.
Field definitions | ||
----------------- | ||
|
||
The items 1, 7, 9, 10a, 10d have the same meaning as the original algorithm. [#wiki-checksig]_ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Item 1 is now the header and not nversion.
|
||
The items 1, 7, 9, 10a, 10d have the same meaning as the original algorithm. [#wiki-checksig]_ | ||
|
||
2: ``nVersionBranch`` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nVersionGroupId - so this section should be reworked.
The ``BRANCH_ID`` of the epoch in which the transaction format corresponding to ``nVersion`` was introduced. | ||
[#ZIP-overwinter-tx-format]_ | ||
|
||
3: ``hashPrevouts`` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So most of this document here is the same as BIP143 and this should be made clearer at start of ZIP.
It would be helpful if we clearly labelled which sections are Zcash only, which are pure BIP143 and which are BIP143+ZcashModification This will help folk who are familiar with that BIP.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a note about this being based on BIP 143. Note that none of the document is pure BIP 143 anymore, so while some code reuse is possible, it will likely be of the copy-paste form (e.g. hashPrevouts
now uses BLAKE2b, not SHA256d, so a function for calculating that can't trivially be reused).
JoinSplits (in their canonical transaction serialization format) concatenated with the joinSplitPubKey; | ||
|
||
* Note that the JoinSplit proofs are included in the signature hash, as with v1 and v2 transactions. In a | ||
future transaction digest algorithm, the proofs will likely be omitted as authentication data, in the same |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove "In a future..." as not relevant to current spec.
|
||
* Otherwise, ``hashJoinSplits`` is a ``uint256`` of ``0x0000......0000``. | ||
|
||
8: ``nExpiryTime`` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nExpiryHeight
|
||
8: ``nExpiryTime`` | ||
`````````````` | ||
The block height or time at which the transaction becomes unilaterally invalid, and can never be mined. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only block height, not time.
The last block height a transaction can be valid.
Added extra review comments, seems to be broken up by Github into two sections above. |
@bitcartel addressed your comments. |
----- | ||
|
||
When generating ``hashPrevouts``, ``hashSequence``, ``hashOutputs``, and ``hashJoinSplits``, the BLAKE2b-256 | ||
personalization field is set to ``Zcash_Inner_Hash``. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a specific reason for sharing the personalization field across all 4 input types? It seems better to domain separate these different input types if possible. (To be clear I don't see any specific problem caused by this, and perhaps using a single string allows some optimization I've missed - but if so, maybe the text should mention said optimization.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, let's change these to:
ZcashPrevoutHash
ZcashSequencHash
[spelling intended]ZcashOutputsHash
ZcashJSplitsHash
Credits: Johnson Lau <jl2012@xbt.hk> | ||
Pieter Wuille <pieter.wuille@gmail.com> | ||
Bitcoin-ABC | ||
Category: Process |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Category: Consensus
|
||
There are 4 ECDSA signature verification codes in the original Zcash script system: ``CHECKSIG``, | ||
``CHECKSIGVERIFY``, ``CHECKMULTISIG``, ``CHECKMULTISIGVERIFY`` ("sigops"). According to the sighash type | ||
(``ALL``, ``NONE``, or ``SINGLE``, possibly modified by ``ANYONECANPAY``), a transaction digest is generated |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is rst not Markdown, so single backticks for monospace throughout the document.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Per http://docutils.sourceforge.net/docs/user/rst/quickref.html#inline-markup double backticks is an inline literal rendered as monospace, while single backticks are interpreted text, which could be for explicit descriptive markup like program identifiers. Markdown is single ticks for code.
The new algorithm MUST be used for signatures created over the Overwinter transaction format. | ||
[#ZIP-overwinter-tx-format]_ Combined with the new consensus rule that v1 and v2 transaction formats will be | ||
invalid from the Overwinter upgrade, [#ZIP-overwinter-tx-format]_ this effectively means that all transactions | ||
signatures from the Overwinter activation height will use the new algorithm. [#ZIP0000]_ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is #ZIP0000
intended to reference?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I planned to link to whichever ZIP contained the activation heights.
transaction. Therefore, data hashing grows in O(n\ :sup:`2`) as the number of sigops in a transaction | ||
increases. While a 1 MB block would normally take 2 seconds to verify with an average computer in 2015, a | ||
1MB transaction with 5569 sigops may take 25 seconds to verify. This could be fixed by optimizing the digest | ||
algorithm by introducing some reusable “midstate”, so the time complexity becomes O(n). [#quadratic]_ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Non-ASCII quotes are used here, plain ASCII quotes elsewhere (e.g. "cold wallet"). Unicode is allowed in ZIPs, but consistency is preferable. I would suggest just using plain quotes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This wording leaves questions in a reader's mind: what is "midstate"? Does the proposal adopted in this ZIP use midstate?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the same wording as in BIP 143, so I'm fine leaving it as-is, unless you have an alternative suggestion.
7. nLockTime of the transaction (4-byte little endian) | ||
8. nExpiryHeight of the transaction (4-byte little endian) | ||
9. sighash type of the signature (4-byte little endian) | ||
10. If we are serializing an input (ie. this is not a JoinSplit signature hash): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/ie./i.e./
{'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'}; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a comment that the default values are zeros.
hashJoinSplits = ss.GetHash(); | ||
} | ||
|
||
uint32_t leConsensusBranchId = htole32(consensusBranchId); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aside: I've never really liked htole32
and friends; they seem to me to be making a type error that is then compensated for by another type error at the memcpy
. (Does not block.)
----- | ||
|
||
The ``hashPrevouts``, ``hashSequence``, ``hashOutputs``, and ``hashJoinSplits`` calculated in an earlier | ||
verification may be reused in other inputs of the same transaction, so that the time complexity of the whole |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/may/can/
Deployment | ||
========== | ||
|
||
This proposal is deployed with the Overwinter network upgrade. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reference ZIP 201 for the activation heights.
Example | ||
======= | ||
|
||
TBC |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An example is not needed to merge this, but please file a ticket to add one.
Overwinter SignatureHash Implements zcash/zips#129. Includes code cherry-picked from the following upstream PRs: - bitcoin/bitcoin#7276 - bitcoin/bitcoin#7976 - bitcoin/bitcoin#8118 - bitcoin/bitcoin#8149 - Only amount validation and SignatureHash commits. - bitcoin/bitcoin#6915 - Only the rework of `mempool.check()` calls that the next PR depends on. - bitcoin/bitcoin#8346 - bitcoin/bitcoin#8524 Part of #2074 and #2254. Closes #1408 and #2584.
In zcash/zcash#2584 (comment) @daira wrote:
Do you still want this? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK
No description provided.