From 7b2806d828595217a7cdee26acd7145ad2820b1d Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood Date: Wed, 12 Aug 2026 16:06:21 +0100 Subject: [PATCH 01/51] ZIPs 209 and 213: add missing references. Signed-off-by: Daira-Emma Hopwood --- zips/zip-0209.rst | 2 ++ zips/zip-0213.rst | 1 + 2 files changed, 3 insertions(+) diff --git a/zips/zip-0209.rst b/zips/zip-0209.rst index f390f10e7..a1087ce6b 100644 --- a/zips/zip-0209.rst +++ b/zips/zip-0209.rst @@ -98,3 +98,5 @@ References .. [#protocol-networks] `Zcash Protocol Specification, Version 2021.2.16 or later. Section 3.12: Mainnet and Testnet `_ .. [#zip-0200] `ZIP 200: Network Upgrade Mechanism `_ .. [#zip-0252] `ZIP 252: Deployment of the NU5 Network Upgrade `_ +.. [#zip-0256] `ZIP 256: Deployment of Consensus Bug Fixes Between NU6.1 and NU6.2 `_ +.. [#zip-0258] `ZIP 258: Deployment of the NU6.3 Network Upgrade `_ diff --git a/zips/zip-0213.rst b/zips/zip-0213.rst index 34c7ba2ce..b917e5838 100644 --- a/zips/zip-0213.rst +++ b/zips/zip-0213.rst @@ -210,6 +210,7 @@ References .. [#zip-0200] `ZIP 200: Network Upgrade Mechanism `_ .. [#zip-0205] `ZIP 205: Deployment of the Sapling Network Upgrade `_ .. [#zip-0207] `ZIP 207: Funding Streams `_ +.. [#zip-0229] `ZIP 229: Version 6 Transaction Format `_ .. [#zip-0250] `ZIP 250: Deployment of the Heartwood Network Upgrade `_ .. [#zip-0252] `ZIP 252: Deployment of the NU5 Network Upgrade `_ .. [#zip-0315-anchor-selection] `ZIP 315: Best Practices for Wallet Implementations — Anchor selection `_ From 276e7c2fa34950be8f83d1d997931c58d3b68b35 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Sat, 10 Jan 2026 17:20:38 -0700 Subject: [PATCH 02/51] [ZIP 248]: Add motivation & notes for design of an extensible transaction format. --- zips/zip-0248.rst | 396 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 396 insertions(+) create mode 100644 zips/zip-0248.rst diff --git a/zips/zip-0248.rst b/zips/zip-0248.rst new file mode 100644 index 000000000..b084d0dba --- /dev/null +++ b/zips/zip-0248.rst @@ -0,0 +1,396 @@ +:: + + ZIP: 248 + Title: Extensible Transaction Format + Owners: Jack Grigg + Kris Nuttycombe + Daira-Emma Hopwood + Schell Scivally + Status: Draft + Category: Consensus / Wallet + Created: 2025-12-17 + License: MIT + Discussions-To: + Pull-Request: + +Terminology +=========== + +{Edit this to reflect the key words that are actually used.} +The key words "MUST", "REQUIRED", "MUST NOT", "SHOULD", and "MAY" in this +document are to be interpreted as described in BCP 14 [^BCP14] when, and only +when, they appear in all capitals. + +The character § is used when referring to sections of the Zcash Protocol +Specification. [^protocol] + +The terms "Mainnet" and "Testnet" are to be interpreted as described in § 3.12 +‘Mainnet and Testnet’. [^protocol-networks] + +The term "full validator" in this document is to be interpreted as defined in § +3.3 ‘The Block Chain’. [^protocol-blockchain]. + +The terms below are to be interpreted as follows: + +{Term to be defined} + +: {Definition.} + + +Abstract +======== + +This ZIP proposes an encoding for V6 Zcash transactions that is intended to +reduce the impact of future changes to the Zcash transaction format on the +Zcash ecosystem. It defines a new typecode-length-value encoding for a sequence +of protocol bundles, and a "value balance" map that describes the effect of +each bundle on the transparent chain value balance, much in the same fashion +as the Sapling and Orchard value balance fields have done in the past. + +Motivation +========== + +In the past, Zcash network upgrades that change the transaction format have +resulted in substantial disruption for wallets and other third-party clients in +the Zcash ecosystem. In order to continue functioning after a network upgrade, +clients were required to upgrade their Zcash transaction parsers to read the +new format, even if the context in which those parsers were being used didn't +need or couldn't make use of newly added transaction data; an example of this +is that transparent-only wallets were forced to update their parsers to +understand the Sapling and Orchard parts of transactions, even if they would +never read or act upon those parts. This has led on occasion to significant +problems in the Zcash ecosystem, including situations where funds have been +locked and rendered unspendable from transparent-only wallets. + +For some kinds of changes to consensus features, it's imperative that every +wallet be aware of and be adapted to those changes, and in those cases making a +major (breaking) transaction version update as we've done in the past is +appropriate. For many new features, however, it is possible for a wallet to +continue functioning correctly without having to fully understand a transaction +using that feature. + +For example, if TZEs were to be added to the protocol, it wouild be possible +for wallets to continue operating with transparent/Sapling/Orchard +functionality, ignoring TZE parts. There is substantial precedent for this sort +of behavior; transparent-only hardware wallets are currently still important in +the Zcash ecosystem, and many wallets didn't begin interacting with Orchard +transaction parts until quite a while after Orchard activation. + +After this change to transaction encoding, wallets and other third parties will +not be required to update their transaction parsers in advance of a network +upgrade for the introduction of many (and perhaps most) types of new protocol +features. This will enable the Zcash ecosystem to make smaller and more +incremental network upgrades without breaking existing wallets. + +Privacy Implications +==================== + + +Requirements +============ + +* The transaction format can be parsed without any knowledge of any Zcash + payment protocols. +* Movement of value into and out of the transparent value pool(s) can be + understood with only partial knowledge of the Zcash payment protocols. + + +Non-requirements +================ + + +Specification +============= + +Sketch of the format: +- Transaction version (like now) + - Version + - Version group ID +- Transaction header + - Expiry height etc + - Likely need some kind of key-value map here to allow additional fields to be added, or maybe version the header to allow evolution? +- Transparent transaction value pool "traffic map" + - Option 1: BundleVersionID -> (valueBalance, AssetId -> valueBalance) + - Key: Bundle version ID + - Value: + - ZEC `valueBalance` + - CompactSize len(generalizedValueBalances) + - Zero or more generalized value balances + - `AssetId` (not `AssetBase` because those are protocol-specific, and we want generalized value balances to be understandable independently of protocol changes) + - `valueBalance` + - Option 2: (BundleVersionID, Option[AssetId]) -> valueBalance + - Key: Bundle version ID encoded as u8 || { Option[AssetId] } + - Value: `valueBalance` + - Option 3: BundleVersionID -> Option[AssetId] -> valueBalance + - Key: Bundle version ID + - Value: + - Map containing one or more generalized value balances + - { Option[AssetId] } + - `valueBalance` +- Sequence of bundles (maybe with a length prefix?) + - Bundle version ID + - Flag bits, either in the version ID or next to it, that indicate how an opaquely-parsing wallet should interpret the bundle, e.g.: + - A bit that says whether or not the bundle interacts with the transparent transaction value pool (which memo bundles would not have). + - Counterpoint: The traffic map already specifies whether a given bundle *does* have an interaction with the transparent tx value pool for this tx. This is different from whether that kind of bundle *can* interact with the transparent tx value pool, but it the latter needed? + - A bit that says whether the bundle has any other effect than what is specified in the traffic map. + - Counterpoint: We should split apart effecting and authorizing data in the encoding, and then a bundle must be assumed effecting iff it has non-null effecting data. + - CompactSize len(effectingData) + - effectingData + - CompactSize len(authorizingData) + - authorizingData + - effectingData and authorizingData would be opaque to the initial parser. + - Parsers that support parsing (tx_version, bundle_version) know how to interpret its internals + +Transaction Format +------------------ + ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| Bytes | Name | Data Type | Description | ++=============================+==============================+================================================+=====================================================================+ +| **Common Transaction Fields** | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| 4 |``header`` |``uint32`` |Contains: | +| | | | | +| | | |* ``fOverwintered`` flag (bit 31, always set) | +| | | |* ``version`` (bits 30 .. 0) – transaction version. | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| 4 |``nVersionGroupId`` |``uint32`` |Version group ID (nonzero). | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| 4 |``nConsensusBranchId`` |``uint32`` |Consensus branch ID (nonzero). | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| 4 |``lock_time`` |``uint32`` |Unix-epoch UTC time or block height, encoded as in Bitcoin. | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| 4 |``nExpiryHeight`` |``uint32`` |A block height in the range {1 .. 499999999} after which | +| | | |the transaction will expire, or 0 to disable expiry. [#zip-0203]_ | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| **Transparent transaction value pool balance map** | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| varies |``nValuePoolDeltas`` |``compactSize`` |Number of entries in the ``mValuePoolDeltas`` map. | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| varies |``mValuePoolDeltas`` |``ValuePoolDelta[nValuePoolDeltas]`` |A map describing the change to the transparent value pool produced by| +| | | |each bundle. Only bundles that produces changes to the transparent | +| | | |value balance will have corresponding entries in this map. | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| **Bundles** | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| varies |``nBundles`` |``compactSize`` |Number of bundles in the transaction that have per-bundle data. | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| varies |``vBundles`` |``BundleDescription[nBundles]`` |A sequence of Bundle descriptions. | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ + +* `vBundles` MUST NOT contain duplicate `BundleDescription. + +ValuePoolDelta +-------------- + ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| Bytes | Name | Data Type | Description | ++=============================+==============================+================================================+=====================================================================+ +| 1 |``bundleType`` |``uint8`` |A bundle type identifier. | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| 1 |``assetClass`` |``uint8`` |An asset class identifier. 0 for the ZEC asset, nonzero for any | +| | | |other asset type. | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| varies |``assetId`` |``byte[varies]`` |If `assetClass == 0`, the zero-length byte array, otherwise a byte | +| | | |containing the asset ID for the asset. The length of this array | +| | | |depends on the asset class; ordinarily it will be 32 bytes. | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| 8 |``value`` |``int64`` |The net change to the transparent value pool produced by the bundle | +| | | |corresponding to the bundle type identifier. | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ + + +## Bundle version ID Registry + ++------------------------------+----------------------+-------------------------------------------------------------+ +| Can appear in value pool map | Can have bundle data | Bundle kind | ++==============================+======================+=============================================================+ +|✅ |❌ | Transaction fee | ++------------------------------+----------------------+-------------------------------------------------------------+ +|✅ |❌ | ZIP 233 NSM field | ++------------------------------+----------------------+-------------------------------------------------------------+ +|✅ |✅ | Transparent | ++------------------------------+----------------------+-------------------------------------------------------------+ +|✅ |✅ | Sapling-pre-ZIP 231 (if ZIP 231 activated after this ZIP) | ++------------------------------+----------------------+-------------------------------------------------------------+ +|✅ |✅ | Orchard-pre-ZIP 231 | ++------------------------------+----------------------+-------------------------------------------------------------+ +|✅ |✅ | Sapling-post-ZIP 231 (if ZIP 231 activated after this ZIP) | ++------------------------------+----------------------+-------------------------------------------------------------+ +|✅ |✅ | Orchard-post-ZIP 231 | ++------------------------------+----------------------+-------------------------------------------------------------+ +|✅ |✅ | OrchardZSA | ++------------------------------+----------------------+-------------------------------------------------------------+ +|✅ |✅ | TZEs | ++------------------------------+----------------------+-------------------------------------------------------------+ +|❌ |✅ | ZIP 231 Memos | ++------------------------------+----------------------+-------------------------------------------------------------+ +|✅ |✅ | ZSA Issuance | ++------------------------------+----------------------+-------------------------------------------------------------+ +|❌ |✅ | Key rotation | ++------------------------------+----------------------+-------------------------------------------------------------+ +|✅ |✅ | Lockbox disbursement / "Consensus accounts" | +| | | (for miner payouts, lockbox, etc) | ++------------------------------+----------------------+-------------------------------------------------------------+ +|✅ |✅ | Pool that only has a long-term storage protocol (PQ, very | +| | | simple thus insulated from counterfeiting fears, can be | +| | | used for payments but higher latency for that purpose) | ++------------------------------+----------------------+-------------------------------------------------------------+ +|✅ |✅ | Tachyon | ++------------------------------+----------------------+-------------------------------------------------------------+ +|✅ |✅ | Staking | ++------------------------------+----------------------+-------------------------------------------------------------+ +|✅ |✅ | Unstaking (if it can't be combined with the Staking bundle) | ++------------------------------+----------------------+-------------------------------------------------------------+ +|✅ |✅ | Post-quantum fast payment protocol | ++------------------------------+----------------------+-------------------------------------------------------------+ + +Rationale +========= + +TODO: Document why we take the specific approach we do on what the format constrains vs what wallets are expected (required?) to notify users of (once we decide on the approach). + + +Deployment +========== + + +Reference implementation +======================== + + +Open issues +=========== + +Design Considerations +===================== + +It is okay that a wallet might not be able to see parts of the transaction that +depend on new features, as long as they do not create such parts themselves. + +If a wallet needs to actively do something differently (for example, +advertizing addresses in a new format or creating an output with a TZE +precondition) in order to be affected by a new feature, then it is reasonably +safe for it to ignore the feature as long as it can still parse transactions +and, and create and sign transactions that don't make use of those features. + +Wallets or consensus-dependent applications that send transactions might do +something wrong that compromises user funds or privacy if they do not take into +account consensus changes in an upgrade. In particular, consensus rules may +change in such a way that a wallet doing what it has done in the past causes +risk of loss of funds, and in those cases, major transaction version bumps will +still be required. An example of this was [ZIP +212](https://zips.z.cash/zip-0212). In that case the existing mechanisms failed +to prevent loss of funds because in practice, wallets updated the consensus +branch ID without updating note encryption. In this case we made the mistake of +requiring wallets to change their behaviour for an existing transaction +version. Except for certain cases involving severe security flaws, we can avoid +doing that again. + +Loss of funds is unacceptable. Temporary inaccessibility of funds in certain +circumstances can be okay -- provided that this potential inaccessiblity and +the circumstances where it can occur is documented and an explicit design +decision. + +References +========== + +[^BCP14]: [Information on BCP 14 — "RFC 2119: Key words for use in RFCs to Indicate Requirement Levels" and "RFC 8174: Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words"](https://www.rfc-editor.org/info/bcp14) + +[^protocol]: [Zcash Protocol Specification, Version 2025.6.3 [NU6.1] or later](protocol/protocol.pdf) + +[^protocol-blockchain]: [Zcash Protocol Specification, Version 2025.6.3 [NU6.1]. Section 3.3: The Block Chain](protocol/protocol.pdf#blockchain) + +[^protocol]: [Zcash Protocol Specification, Version 2025.6.3 [NU6.1]. Section 3.12: Mainnet and Testnet](protocol/protocol.pdf#networks) + + + + + +--- + +# Notes on consensus branch ID & transaction format updates + +Wallets or consensus-dependent applications that send transactions, might do something wrong that compromises user funds or privacy if they do not take into account consensus changes in an upgrade. + +In particular, consensus rules may change in such a way that a wallet doing what it has done in the past causes risk of loss of funds. + +An example of this was [ZIP 212](https://zips.z.cash/zip-0212). In that case the existing mechanisms failed to prevent loss of funds because in practice, wallets updated the consensus branch ID without updating note encryption. + +> We made the mistake of requiring wallets to change their behaviour for an existing transaction version. Except for certain cases involving severe security flaws, we can avoid doing that again. + +For some new features, it might be possible for a wallet to continue functioning correctly without having to fully understand a transaction using that feature. For instance, if a wallet needs to actively do something differently (for example, advertizing addresses in a new format or creating an output with a TZE precondition) in order to be affected by a new feature, then it is reasonably safe for it to ignore the feature as long as it can still parse transactions and sign them. + +For example, if TZEs were to be added, it might be possible for wallets to continue operating with transparent/Sapling/Orchard functionality, ignoring TZE parts. There is some precedent for this as many wallets didn't begin interacting with Orchard transaction parts until quite a while after Orchard activation. + +It is okay that such a wallet might not be able to see funds that depend on new features, as long as they do not create such funds themselves. + +Loss of funds is unacceptable. Temporary inaccessibility of funds in certain circumstances can be okay -- provided that this potential inaccessiblity and the circumstances where it can occur is documented and an explicit design decision. + +## Strawman + +Modify how we approach transaction format evolution, such that (after one more change to transaction encoding) it is possible for a wallet that has not adopted a parser for a given transaction format to continue to function after an *additive* change to the transaction format. Another way to state this is that we should make it possible to make "semver-compatible" transaction format changes. + +- @str4d: We could use a TLV approach where each "bundle" has a value balance. The NSM burn amount field could be its own bundle, the explicit fee data could be its own bundle and the consensus rule could be that all value balances sum to zero. + - generically, you want a value balance vector, where you have zero or more value balances moving between bundles in other assets. + +- @nuttycom: You could have pre-ZSA and post-ZSA Orchard bundles. + +## Strawman II + +Treat bundles as individually versioned. +- Each bundle is registered with an ID relative to a tx version group ID. +- The bundle ID encoding also has some flag bits indicating how it interacts with the tx as a whole. +- Transactions then have two "bundle maps": + - The first encodes how value moves between the different bundles. + - The second encodes data specific to a bundle (e.g. how value moves within a bundle) + - Bundles that don't have any data would just appear in the first map, and bundles that don't produce or consume value would just appear in the second map. +- We can re-interpret various other facets of transactions as "bundles" + - Explicit fees are a bundle that never produces value + - NSM field similarly never produces value + - ZSA burns would be split into "value balance out of Orchard pool" and "value balance being removed from ZSA issuance" + - See also the conversation we had about refactoring coinbase transactions. TODO: Figure out how to integrate the two. +- Privacy effect is minimal + - We already follow a bundle approach with a transparent transaction value pool, for the turnstiles. This leans into it, while preserving the bundle boundary within which we implement each privacy protocol. + - Some combinations of bundles would be permitted by the tx format that were not previously permitted. + - However, we can still restrict which combinations of bundles can be mined in the consensus rules. + +Sketch of the format: +- Transaction version (like now) + - Version + - Version group ID +- Transaction header + - Expiry height etc + - Likely need some kind of key-value map here to allow additional fields to be added, or maybe version the header to allow evolution? +- Transparent transaction value pool "traffic map" + - Key: Bundle version ID + - Value: + - ZEC `valueBalance` + - CompactSize len(generalizedValueBalances) + - Zero or more generalized value balances + - `AssetId` (not `AssetBase` because those are protocol-specific, and we want generalized value balances to be understandable independently of protocol changes) + - `valueBalance` +- Sequence of bundles (maybe with a length prefix?) + - Bundle version ID + - Flag bits, either in the version ID or next to it, that indicate how an opaquely-parsing wallet should interpret the bundle, e.g.: + - A bit that says whether or not the bundle interacts with the transparent transaction value pool (which memo bundles would not have). + - Counterpoint: The traffic map already specifies whether a given bundle *does* have an interaction with the transparent tx value pool for this tx. This is different from whether that kind of bundle *can* interact with the transparent tx value pool, but it the latter needed? + - A bit that says whether the bundle has any other effect than what is specified in the traffic map. + - Counterpoint: We should split apart effecting and authorizing data in the encoding, and then a bundle must be assumed effecting iff it has non-null effecting data. + - CompactSize len(effectingData) + - effectingData + - CompactSize len(authorizingData) + - authorizingData + - effectingData and authorizingData would be opaque to the initial parser. + - Parsers that support parsing (tx_version, bundle_version) know how to interpret its internals + +Questions: +- Is it okay for fee calculations to be opaque to wallet parsers, as long as the fee amounts can be calculated in consensus? + - Yes: + - When receiving, all you care about is knowing the actual fee amount; you see that in the fee bundle's value balance. + - When sending, you need to understand all bundles you are including, and then you can calculate the fee. +- Can wallets still compute the txid and wtxid of an arbitrary transaction? + - Yes, provided that effecting and authorizing data is separated. Then they can hash the effecting data even without understanding it to compute the txid, and they can hash the authorizing data even without understanding it to compute the authorizing data commitment part of the wtxid [[ZIP 239]](https://zips.z.cash/zip-0239). + - *However*, this reintroduces a more direct linkage between the [w]txid computation and the transaction encoding. It's arguably fine, and potentially simpler -- since the [w]txid computation need not change at all for most protocol changes. + - If the hashing uses flat hashes over the effectingData and authorizingData of each bundle (which it has to because the internal structure is not known), then it might be more difficult to do Merkle proofs over subsets of the data within a bundle. We haven't used that so far; is it really needed? + From 879aa575ad97276ed157e5d720c38d68a8a6a3de Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Mon, 19 Jan 2026 12:14:45 -0700 Subject: [PATCH 03/51] [ZIP 248]: Fill in Privacy Implications section. --- zips/zip-0248.rst | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/zips/zip-0248.rst b/zips/zip-0248.rst index b084d0dba..d32536eef 100644 --- a/zips/zip-0248.rst +++ b/zips/zip-0248.rst @@ -85,6 +85,25 @@ incremental network upgrades without breaking existing wallets. Privacy Implications ==================== +This change alters the encoding of transactions, but does not alter the +information content of the transaction. As such, the only implication of this +change is that the use of this transaction format acts as a 1-bit distinguisher +that reveals that the wallet that generated the transaction has been updated to +be aware of the new format. This information leakage is unavoidable for any +transaction format change. + +In the future, this change may reduce the amount of information leakage, since +transactions created using the proposed TLV format will include bundles only +for those protocols for which the transaction modifies chain state. For example, +if this transaction format change is deployed in NU7 and NU8 defines a bundle +type for TZE components, it will not be possible for a chain observer to +distinguish whether or not the wallet that produced an Orchard-only transaction +is one that has been updated to understand the TZE component. Under prior +practices for changing the transaction format, this would have been +distinguishable. + +In summary, this proposal provides a net improvement in user privacy in +addition to its other benefits. Requirements ============ From c4957ce05e85a14140bf17035e6bcb0695f13ab1 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Mon, 19 Jan 2026 13:17:13 -0700 Subject: [PATCH 04/51] [ZIP 248]: Add `BundleDescription` --- zips/zip-0248.rst | 108 +++++++++++++++++++++------------------------- 1 file changed, 50 insertions(+), 58 deletions(-) diff --git a/zips/zip-0248.rst b/zips/zip-0248.rst index d32536eef..671e6a3c3 100644 --- a/zips/zip-0248.rst +++ b/zips/zip-0248.rst @@ -47,6 +47,7 @@ of protocol bundles, and a "value balance" map that describes the effect of each bundle on the transparent chain value balance, much in the same fashion as the Sapling and Orchard value balance fields have done in the past. + Motivation ========== @@ -67,14 +68,14 @@ wallet be aware of and be adapted to those changes, and in those cases making a major (breaking) transaction version update as we've done in the past is appropriate. For many new features, however, it is possible for a wallet to continue functioning correctly without having to fully understand a transaction -using that feature. +using that feature. For example, if TZEs were to be added to the protocol, it wouild be possible for wallets to continue operating with transparent/Sapling/Orchard functionality, ignoring TZE parts. There is substantial precedent for this sort of behavior; transparent-only hardware wallets are currently still important in the Zcash ecosystem, and many wallets didn't begin interacting with Orchard -transaction parts until quite a while after Orchard activation. +transaction parts until quite a while after Orchard activation. After this change to transaction encoding, wallets and other third parties will not be required to update their transaction parsers in advance of a network @@ -82,6 +83,7 @@ upgrade for the introduction of many (and perhaps most) types of new protocol features. This will enable the Zcash ecosystem to make smaller and more incremental network upgrades without breaking existing wallets. + Privacy Implications ==================== @@ -93,7 +95,7 @@ be aware of the new format. This information leakage is unavoidable for any transaction format change. In the future, this change may reduce the amount of information leakage, since -transactions created using the proposed TLV format will include bundles only +transactions created using the proposed TLV format will include bundles only for those protocols for which the transaction modifies chain state. For example, if this transaction format change is deployed in NU7 and NU8 defines a bundle type for TZE components, it will not be possible for a chain observer to @@ -105,6 +107,7 @@ distinguishable. In summary, this proposal provides a net improvement in user privacy in addition to its other benefits. + Requirements ============ @@ -112,6 +115,9 @@ Requirements payment protocols. * Movement of value into and out of the transparent value pool(s) can be understood with only partial knowledge of the Zcash payment protocols. +* The information content of transactions should not change as part of + this ZIP. Other ZIPs activated along with this ZIP may however make + use of it in introducing such changes. Non-requirements @@ -121,45 +127,6 @@ Non-requirements Specification ============= -Sketch of the format: -- Transaction version (like now) - - Version - - Version group ID -- Transaction header - - Expiry height etc - - Likely need some kind of key-value map here to allow additional fields to be added, or maybe version the header to allow evolution? -- Transparent transaction value pool "traffic map" - - Option 1: BundleVersionID -> (valueBalance, AssetId -> valueBalance) - - Key: Bundle version ID - - Value: - - ZEC `valueBalance` - - CompactSize len(generalizedValueBalances) - - Zero or more generalized value balances - - `AssetId` (not `AssetBase` because those are protocol-specific, and we want generalized value balances to be understandable independently of protocol changes) - - `valueBalance` - - Option 2: (BundleVersionID, Option[AssetId]) -> valueBalance - - Key: Bundle version ID encoded as u8 || { Option[AssetId] } - - Value: `valueBalance` - - Option 3: BundleVersionID -> Option[AssetId] -> valueBalance - - Key: Bundle version ID - - Value: - - Map containing one or more generalized value balances - - { Option[AssetId] } - - `valueBalance` -- Sequence of bundles (maybe with a length prefix?) - - Bundle version ID - - Flag bits, either in the version ID or next to it, that indicate how an opaquely-parsing wallet should interpret the bundle, e.g.: - - A bit that says whether or not the bundle interacts with the transparent transaction value pool (which memo bundles would not have). - - Counterpoint: The traffic map already specifies whether a given bundle *does* have an interaction with the transparent tx value pool for this tx. This is different from whether that kind of bundle *can* interact with the transparent tx value pool, but it the latter needed? - - A bit that says whether the bundle has any other effect than what is specified in the traffic map. - - Counterpoint: We should split apart effecting and authorizing data in the encoding, and then a bundle must be assumed effecting iff it has non-null effecting data. - - CompactSize len(effectingData) - - effectingData - - CompactSize len(authorizingData) - - authorizingData - - effectingData and authorizingData would be opaque to the initial parser. - - Parsers that support parsing (tx_version, bundle_version) know how to interpret its internals - Transaction Format ------------------ @@ -182,13 +149,16 @@ Transaction Format | 4 |``nExpiryHeight`` |``uint32`` |A block height in the range {1 .. 499999999} after which | | | | |the transaction will expire, or 0 to disable expiry. [#zip-0203]_ | +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ -| **Transparent transaction value pool balance map** | +| **Transaction transparent value pool balance map** | +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ | varies |``nValuePoolDeltas`` |``compactSize`` |Number of entries in the ``mValuePoolDeltas`` map. | +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ -| varies |``mValuePoolDeltas`` |``ValuePoolDelta[nValuePoolDeltas]`` |A map describing the change to the transparent value pool produced by| +| varies |``mValuePoolDeltas`` |``ValuePoolDelta[nValuePoolDeltas]`` |A map describing the change to the transparent value pool produced by| | | | |each bundle. Only bundles that produces changes to the transparent | -| | | |value balance will have corresponding entries in this map. | +| | | |value balance will have corresponding entries in this map. For | +| | | |bundles that have no data except for a value, such as the ZIP 233 | +| | | |amount, no additional bundle data will be present in the ``Bundles`` | +| | | |section. | +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ | **Bundles** | +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ @@ -210,12 +180,24 @@ ValuePoolDelta | 1 |``assetClass`` |``uint8`` |An asset class identifier. 0 for the ZEC asset, nonzero for any | | | | |other asset type. | +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ -| varies |``assetId`` |``byte[varies]`` |If `assetClass == 0`, the zero-length byte array, otherwise a byte | -| | | |containing the asset ID for the asset. The length of this array | -| | | |depends on the asset class; ordinarily it will be 32 bytes. | +| one of {0, 32} |``assetId`` |``byte[0] or byte[32]`` |If `assetClass == 0`, the zero-length byte array, otherwise a byte | +| | | |array containing the 32-byte asset ID for the asset. | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| 8 |``value`` |``int64`` |The net change to the transparent value pool of the given asset | +| | | |produced by the bundle corresponding to the bundle type identifier. | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ + +BundleDescription +----------------- + ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| Bytes | Name | Data Type | Description | ++=============================+==============================+================================================+=====================================================================+ +| 1 |``bundleType`` |``uint8`` |A bundle type identifier. | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| varies |``nBundleLength`` |``compactSize`` |The length of the ``vBundleData`` byte array. | +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ -| 8 |``value`` |``int64`` |The net change to the transparent value pool produced by the bundle | -| | | |corresponding to the bundle type identifier. | +| varies |``vBundleData`` |``byte[nBundleLength]`` |The bundle data. | +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ @@ -350,7 +332,7 @@ Loss of funds is unacceptable. Temporary inaccessibility of funds in certain cir Modify how we approach transaction format evolution, such that (after one more change to transaction encoding) it is possible for a wallet that has not adopted a parser for a given transaction format to continue to function after an *additive* change to the transaction format. Another way to state this is that we should make it possible to make "semver-compatible" transaction format changes. -- @str4d: We could use a TLV approach where each "bundle" has a value balance. The NSM burn amount field could be its own bundle, the explicit fee data could be its own bundle and the consensus rule could be that all value balances sum to zero. +- @str4d: We could use a TLV approach where each "bundle" has a value balance. The NSM burn amount field could be its own bundle, the explicit fee data could be its own bundle and the consensus rule could be that all value balances sum to zero. - generically, you want a value balance vector, where you have zero or more value balances moving between bundles in other assets. - @nuttycom: You could have pre-ZSA and post-ZSA Orchard bundles. @@ -382,13 +364,23 @@ Sketch of the format: - Expiry height etc - Likely need some kind of key-value map here to allow additional fields to be added, or maybe version the header to allow evolution? - Transparent transaction value pool "traffic map" - - Key: Bundle version ID - - Value: - - ZEC `valueBalance` - - CompactSize len(generalizedValueBalances) - - Zero or more generalized value balances - - `AssetId` (not `AssetBase` because those are protocol-specific, and we want generalized value balances to be understandable independently of protocol changes) - - `valueBalance` + - Option 1: BundleVersionID -> (valueBalance, AssetId -> valueBalance) + - Key: Bundle version ID + - Value: + - ZEC `valueBalance` + - CompactSize len(generalizedValueBalances) + - Zero or more generalized value balances + - `AssetId` (not `AssetBase` because those are protocol-specific, and we want generalized value balances to be understandable independently of protocol changes) + - `valueBalance` + - Option 2: (BundleVersionID, Option[AssetId]) -> valueBalance + - Key: Bundle version ID encoded as u8 || { Option[AssetId] } + - Value: `valueBalance` + - Option 3: BundleVersionID -> Option[AssetId] -> valueBalance + - Key: Bundle version ID + - Value: + - Map containing one or more generalized value balances + - { Option[AssetId] } + - `valueBalance` - Sequence of bundles (maybe with a length prefix?) - Bundle version ID - Flag bits, either in the version ID or next to it, that indicate how an opaquely-parsing wallet should interpret the bundle, e.g.: From 57860297320bcf2f117e2e7123b8463b3c5c1969 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Mon, 19 Jan 2026 19:17:13 -0700 Subject: [PATCH 05/51] [ZIP 248]: Add bundle ID registry --- zips/zip-0248.rst | 415 +++++++++++++++++++++++++++------------------- 1 file changed, 248 insertions(+), 167 deletions(-) diff --git a/zips/zip-0248.rst b/zips/zip-0248.rst index 671e6a3c3..7714cca93 100644 --- a/zips/zip-0248.rst +++ b/zips/zip-0248.rst @@ -118,6 +118,17 @@ Requirements * The information content of transactions should not change as part of this ZIP. Other ZIPs activated along with this ZIP may however make use of it in introducing such changes. +* It must be possible for wallets to parse any transaction that is valid within + a version group that it understands, even if it doesn't have handling for or + understand all of the bundle types that are valid for that version group. In + such a situation, however, such a wallet must still be able to accurately + describe any transparent movement of funds effected by the transaction, and + alert the user if the transaction contains bundles that it does not + understand. +* It must be possible for a wallet to correctly construct and sign transactions + for a given transaction version group that it understands, even if it doesn't + have handling for or understand all of the bundle types that are valid for + transactions in that version group. Non-requirements @@ -164,10 +175,12 @@ Transaction Format +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ | varies |``nBundles`` |``compactSize`` |Number of bundles in the transaction that have per-bundle data. | +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ -| varies |``vBundles`` |``BundleDescription[nBundles]`` |A sequence of Bundle descriptions. | +| varies |``vBundles`` |``Bundle[nBundles]`` |A sequence of ``Bundle`` values. | +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ -* `vBundles` MUST NOT contain duplicate `BundleDescription. +``mValuePoolDeltas`` MUST NOT contain more than a single entry for a given +``(bundleType, assetClass, assetId)`` tuple, which is treated as the "key" of +the map. ValuePoolDelta -------------- @@ -175,76 +188,109 @@ ValuePoolDelta +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ | Bytes | Name | Data Type | Description | +=============================+==============================+================================================+=====================================================================+ -| 1 |``bundleType`` |``uint8`` |A bundle type identifier. | +| varies |``bundleType`` |``compactSize`` |An encoding of the bundle type identifier. | +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ -| 1 |``assetClass`` |``uint8`` |An asset class identifier. 0 for the ZEC asset, nonzero for any | -| | | |other asset type. | +| 1 |``assetClass`` |``uint8`` |An asset class identifier. 0x00 for the ZEC asset, 0x01 for ZSA | +| | | |assets. All other values are reserved for future use. | +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ | one of {0, 32} |``assetId`` |``byte[0] or byte[32]`` |If `assetClass == 0`, the zero-length byte array, otherwise a byte | | | | |array containing the 32-byte asset ID for the asset. | +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ -| 8 |``value`` |``int64`` |The net change to the transparent value pool of the given asset | +| 8 |``value`` |``nonzero int64`` |The net change to the transparent value pool of the given asset | | | | |produced by the bundle corresponding to the bundle type identifier. | +| | | |This value MUST be nonzero; if a ``ValuePoolDelta`` record would | +| | | |have zero value, it MUST be elided from the encoding | +| | | |of ``mValuePoolDeltas`` instead. | +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ -BundleDescription ------------------ +Bundle +------ +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ | Bytes | Name | Data Type | Description | +=============================+==============================+================================================+=====================================================================+ -| 1 |``bundleType`` |``uint8`` |A bundle type identifier. | +| varies |``bundleType`` |``compactSize`` |An encoding of the bundle type identifier. | +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ -| varies |``nBundleLength`` |``compactSize`` |The length of the ``vBundleData`` byte array. | +| varies |``nBundleEffectsLen`` |``compactSize`` |The length of the ``vBundleEffectsData`` byte array. | +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ -| varies |``vBundleData`` |``byte[nBundleLength]`` |The bundle data. | +| varies |``vBundleEffectsData`` |``byte[nBundleEffectsLen]`` |The "effecting" data for the bundle. This consists of any | +| | | |information in the bundle that induces a state change in the | +| | | |blockchain and must therefore be committed to by the txid. | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| varies |``nBundleAuthLen`` |``compactSize`` |The length of the ``vBundleAuthData`` byte array. | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| varies |``vBundleAuthData`` |``byte[nBundleAuthLen]`` |The authorizing data for the bundle. | +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ -## Bundle version ID Registry - -+------------------------------+----------------------+-------------------------------------------------------------+ -| Can appear in value pool map | Can have bundle data | Bundle kind | -+==============================+======================+=============================================================+ -|✅ |❌ | Transaction fee | -+------------------------------+----------------------+-------------------------------------------------------------+ -|✅ |❌ | ZIP 233 NSM field | -+------------------------------+----------------------+-------------------------------------------------------------+ -|✅ |✅ | Transparent | -+------------------------------+----------------------+-------------------------------------------------------------+ -|✅ |✅ | Sapling-pre-ZIP 231 (if ZIP 231 activated after this ZIP) | -+------------------------------+----------------------+-------------------------------------------------------------+ -|✅ |✅ | Orchard-pre-ZIP 231 | -+------------------------------+----------------------+-------------------------------------------------------------+ -|✅ |✅ | Sapling-post-ZIP 231 (if ZIP 231 activated after this ZIP) | -+------------------------------+----------------------+-------------------------------------------------------------+ -|✅ |✅ | Orchard-post-ZIP 231 | -+------------------------------+----------------------+-------------------------------------------------------------+ -|✅ |✅ | OrchardZSA | -+------------------------------+----------------------+-------------------------------------------------------------+ -|✅ |✅ | TZEs | -+------------------------------+----------------------+-------------------------------------------------------------+ -|❌ |✅ | ZIP 231 Memos | -+------------------------------+----------------------+-------------------------------------------------------------+ -|✅ |✅ | ZSA Issuance | -+------------------------------+----------------------+-------------------------------------------------------------+ -|❌ |✅ | Key rotation | -+------------------------------+----------------------+-------------------------------------------------------------+ -|✅ |✅ | Lockbox disbursement / "Consensus accounts" | -| | | (for miner payouts, lockbox, etc) | -+------------------------------+----------------------+-------------------------------------------------------------+ -|✅ |✅ | Pool that only has a long-term storage protocol (PQ, very | -| | | simple thus insulated from counterfeiting fears, can be | -| | | used for payments but higher latency for that purpose) | -+------------------------------+----------------------+-------------------------------------------------------------+ -|✅ |✅ | Tachyon | -+------------------------------+----------------------+-------------------------------------------------------------+ -|✅ |✅ | Staking | -+------------------------------+----------------------+-------------------------------------------------------------+ -|✅ |✅ | Unstaking (if it can't be combined with the Staking bundle) | -+------------------------------+----------------------+-------------------------------------------------------------+ -|✅ |✅ | Post-quantum fast payment protocol | -+------------------------------+----------------------+-------------------------------------------------------------+ +Bundle type identifier ID Registry +---------------------------------- + +The following integers are registered as bundle type identifiers for the V6 +transaction format. All currently-defined IDs are encoded as single-byte +``CompactSize`` values where they appear in the transaction format. + +The "Can appear in ``mValuePoolDeltas``" column indicates whether or not an +entry for this value type is allowed to appear in ``mValuePoolDeltas``. For +rows where an ❌ is present, the value pool delta for every pool is guaranteed +to be zero, and so entries in ``mValuePoolDeltas`` are disallowed. + +The "Can appear in ``vBundles``" column indicates whether or not an entry for +this value type is allowed to appear in ``vBundles``. For rows where an ❌ is +present, the bundle is guaranteed to have no effecting or authorizing data, and +so no entry in ``vBundles`` is permitted. + ++------------+------------------------------------+----------------------------+-------------------------------------------------------------+ +| BundleType | Can appear in ``mValuePoolDeltas`` | Can appear in ``vBundles`` | Bundle kind | ++============+====================================+============================+=============================================================+ +| 0 |✅ |✅ | Transparent | ++------------+------------------------------------+----------------------------+-------------------------------------------------------------+ +| 1 |✅ |✅ | Reserved | ++------------+------------------------------------+----------------------------+-------------------------------------------------------------+ +| 2 |✅ |✅ | Sapling | ++------------+------------------------------------+----------------------------+-------------------------------------------------------------+ +| 3 |✅ |✅ | Orchard | ++------------+------------------------------------+----------------------------+-------------------------------------------------------------+ +| 4* |✅ |❌ | Transaction fee (*if ZIP 2002 activated) | ++------------+------------------------------------+----------------------------+-------------------------------------------------------------+ +| 5* |✅ |❌ | ZIP 233 NSM field (*if ZIP 233 activated) | ++------------+------------------------------------+----------------------------+-------------------------------------------------------------+ +| 6* |❌ |✅ | ZIP 270 Key rotation (*if ZIP 270 activated) | ++------------+------------------------------------+----------------------------+-------------------------------------------------------------+ +| 7* |✅ |✅ | Lockbox disbursement / "Consensus accounts" | +| | | | (*for miner payouts, lockbox, etc if ZIP activated) | ++------------+------------------------------------+----------------------------+-------------------------------------------------------------+ +| |❌ |✅ | ZIP 231 Memos | ++------------+------------------------------------+----------------------------+-------------------------------------------------------------+ +| |✅ |✅ | Sapling-post-ZIP 231 (if ZIP 231 activated after this ZIP) | ++------------+------------------------------------+----------------------------+-------------------------------------------------------------+ +| |✅ |✅ | Orchard-post-ZIP 231 (if ZIP 231 activated after this ZIP) | ++------------+------------------------------------+----------------------------+-------------------------------------------------------------+ +| |✅ |✅ | ZSA Issuance | ++------------+------------------------------------+----------------------------+-------------------------------------------------------------+ +| |✅ |✅ | OrchardZSA | ++------------+------------------------------------+----------------------------+-------------------------------------------------------------+ + +The following entries are provided to illustrate how potential future upgrades +might affect the value pool delta map. + ++------------+------------------------------------+----------------------------+-------------------------------------------------------------+ +| BundleType | Can appear in ``mValuePoolDeltas`` | Can appear in ``vBundles`` | Bundle kind | ++============+====================================+============================+=============================================================+ +| |✅ |✅ | TZEs | ++------------+------------------------------------+----------------------------+-------------------------------------------------------------+ +| |✅ |✅ | Pool that only has a long-term storage protocol (PQ, very | +| | | | simple thus insulated from counterfeiting fears, can be | +| | | | used for payments but higher latency for that purpose) | ++------------+------------------------------------+----------------------------+-------------------------------------------------------------+ +| |✅ |✅ | Tachyon | ++------------+------------------------------------+----------------------------+-------------------------------------------------------------+ +| |✅ |✅ | Staking | ++------------+------------------------------------+----------------------------+-------------------------------------------------------------+ +| |✅ |✅ | Unstaking (if it can't be combined with the Staking bundle) | ++------------+------------------------------------+----------------------------+-------------------------------------------------------------+ +| |✅ |✅ | Post-quantum fast payment protocol | ++------------+------------------------------------+----------------------------+-------------------------------------------------------------+ Rationale ========= @@ -263,36 +309,6 @@ Reference implementation Open issues =========== -Design Considerations -===================== - -It is okay that a wallet might not be able to see parts of the transaction that -depend on new features, as long as they do not create such parts themselves. - -If a wallet needs to actively do something differently (for example, -advertizing addresses in a new format or creating an output with a TZE -precondition) in order to be affected by a new feature, then it is reasonably -safe for it to ignore the feature as long as it can still parse transactions -and, and create and sign transactions that don't make use of those features. - -Wallets or consensus-dependent applications that send transactions might do -something wrong that compromises user funds or privacy if they do not take into -account consensus changes in an upgrade. In particular, consensus rules may -change in such a way that a wallet doing what it has done in the past causes -risk of loss of funds, and in those cases, major transaction version bumps will -still be required. An example of this was [ZIP -212](https://zips.z.cash/zip-0212). In that case the existing mechanisms failed -to prevent loss of funds because in practice, wallets updated the consensus -branch ID without updating note encryption. In this case we made the mistake of -requiring wallets to change their behaviour for an existing transaction -version. Except for certain cases involving severe security flaws, we can avoid -doing that again. - -Loss of funds is unacceptable. Temporary inaccessibility of funds in certain -circumstances can be okay -- provided that this potential inaccessiblity and -the circumstances where it can occur is documented and an explicit design -decision. - References ========== @@ -306,102 +322,167 @@ References +Notes from design sessions +========================== +This section should be removed as soon as all the considerations described here +are accounted for in ZIP. ---- - -# Notes on consensus branch ID & transaction format updates - -Wallets or consensus-dependent applications that send transactions, might do something wrong that compromises user funds or privacy if they do not take into account consensus changes in an upgrade. - -In particular, consensus rules may change in such a way that a wallet doing what it has done in the past causes risk of loss of funds. - -An example of this was [ZIP 212](https://zips.z.cash/zip-0212). In that case the existing mechanisms failed to prevent loss of funds because in practice, wallets updated the consensus branch ID without updating note encryption. +Wallets or consensus-dependent applications that send transactions, might do +something wrong that compromises user funds or privacy if they do not take into +account consensus changes in an upgrade; therefore, only a subset of consensus +changes can be safely adapted to using this mechanism. -> We made the mistake of requiring wallets to change their behaviour for an existing transaction version. Except for certain cases involving severe security flaws, we can avoid doing that again. +In particular, consensus rules may change in such a way that a wallet doing +what it has done in the past causes risk of loss of funds. -For some new features, it might be possible for a wallet to continue functioning correctly without having to fully understand a transaction using that feature. For instance, if a wallet needs to actively do something differently (for example, advertizing addresses in a new format or creating an output with a TZE precondition) in order to be affected by a new feature, then it is reasonably safe for it to ignore the feature as long as it can still parse transactions and sign them. +An example of this was [ZIP 212](https://zips.z.cash/zip-0212). In that case +the existing mechanisms failed to prevent loss of funds because in practice, +wallets updated the consensus branch ID without updating note encryption. We +made the mistake of requiring wallets to change their behaviour for an existing +transaction version. Except for certain cases involving severe security flaws, +we should avoid doing that again. -For example, if TZEs were to be added, it might be possible for wallets to continue operating with transparent/Sapling/Orchard functionality, ignoring TZE parts. There is some precedent for this as many wallets didn't begin interacting with Orchard transaction parts until quite a while after Orchard activation. +If a wallet needs to actively do something differently (for example, +advertizing addresses in a new format or creating an output with a TZE +precondition) in order to be affected by a new feature, then it is reasonably +safe for it to ignore the feature as long as it can still parse transactions +and, and create and sign transactions that don't make use of those features. -It is okay that such a wallet might not be able to see funds that depend on new features, as long as they do not create such funds themselves. +It is okay that such a wallet might not be able to see funds that depend on new +features, as long as they do not create such funds themselves. -Loss of funds is unacceptable. Temporary inaccessibility of funds in certain circumstances can be okay -- provided that this potential inaccessiblity and the circumstances where it can occur is documented and an explicit design decision. +Loss of funds is unacceptable. Temporary inaccessibility of funds in certain +circumstances can be okay -- provided that this potential inaccessiblity and +the circumstances where it can occur is documented and an explicit design +decision. -## Strawman +Strawman +-------- -Modify how we approach transaction format evolution, such that (after one more change to transaction encoding) it is possible for a wallet that has not adopted a parser for a given transaction format to continue to function after an *additive* change to the transaction format. Another way to state this is that we should make it possible to make "semver-compatible" transaction format changes. +Modify how we approach transaction format evolution, such that (after one more +change to transaction encoding) it is possible for a wallet that has not +adopted a parser for a given transaction format to continue to function after +an *additive* change to the transaction format. Another way to state this is +that we should make it possible to make "semver-compatible" transaction format +changes. -- @str4d: We could use a TLV approach where each "bundle" has a value balance. The NSM burn amount field could be its own bundle, the explicit fee data could be its own bundle and the consensus rule could be that all value balances sum to zero. - - generically, you want a value balance vector, where you have zero or more value balances moving between bundles in other assets. +* @str4d: We could use a TLV approach where each "bundle" has a value balance. + The NSM burn amount field could be its own bundle, the explicit fee data + could be its own bundle and the consensus rule could be that all value + balances sum to zero. + * generically, you want a value balance vector, where you have zero or more + value balances moving between bundles in other assets. -- @nuttycom: You could have pre-ZSA and post-ZSA Orchard bundles. +* @nuttycom: You could have pre-ZSA and post-ZSA Orchard bundles. -## Strawman II +Strawman II +----------- Treat bundles as individually versioned. -- Each bundle is registered with an ID relative to a tx version group ID. -- The bundle ID encoding also has some flag bits indicating how it interacts with the tx as a whole. -- Transactions then have two "bundle maps": - - The first encodes how value moves between the different bundles. - - The second encodes data specific to a bundle (e.g. how value moves within a bundle) - - Bundles that don't have any data would just appear in the first map, and bundles that don't produce or consume value would just appear in the second map. -- We can re-interpret various other facets of transactions as "bundles" - - Explicit fees are a bundle that never produces value - - NSM field similarly never produces value - - ZSA burns would be split into "value balance out of Orchard pool" and "value balance being removed from ZSA issuance" - - See also the conversation we had about refactoring coinbase transactions. TODO: Figure out how to integrate the two. -- Privacy effect is minimal - - We already follow a bundle approach with a transparent transaction value pool, for the turnstiles. This leans into it, while preserving the bundle boundary within which we implement each privacy protocol. - - Some combinations of bundles would be permitted by the tx format that were not previously permitted. - - However, we can still restrict which combinations of bundles can be mined in the consensus rules. +* Each bundle is registered with an ID relative to a tx version group ID. +* The bundle ID encoding also has some flag bits indicating how it interacts + with the tx as a whole. +* Transactions then have two "bundle maps": + * The first encodes how value moves between the different bundles. + * The second encodes data specific to a bundle (e.g. how value moves within a bundle) + * Bundles that don't have any data would just appear in the first map, and + bundles that don't produce or consume value would just appear in the + second map. +* We can re-interpret various other facets of transactions as "bundles" + * Explicit fees are a bundle that never produces value + * NSM field similarly never produces value + * ZSA burns would be split into "value balance out of Orchard pool" and + "value balance being removed from ZSA issuance" + * See also the conversation we had about refactoring coinbase transactions. + TODO: Figure out how to integrate the two. +* Privacy effect is minimal + * We already follow a bundle approach with a transparent transaction value + pool, for the turnstiles. This leans into it, while preserving the bundle + boundary within which we implement each privacy protocol. + * Some combinations of bundles would be permitted by the tx format that + were not previously permitted. + * However, we can still restrict which combinations of bundles can be + mined in the consensus rules. Sketch of the format: -- Transaction version (like now) - - Version - - Version group ID -- Transaction header - - Expiry height etc - - Likely need some kind of key-value map here to allow additional fields to be added, or maybe version the header to allow evolution? -- Transparent transaction value pool "traffic map" - - Option 1: BundleVersionID -> (valueBalance, AssetId -> valueBalance) - - Key: Bundle version ID - - Value: - - ZEC `valueBalance` - - CompactSize len(generalizedValueBalances) - - Zero or more generalized value balances - - `AssetId` (not `AssetBase` because those are protocol-specific, and we want generalized value balances to be understandable independently of protocol changes) - - `valueBalance` - - Option 2: (BundleVersionID, Option[AssetId]) -> valueBalance - - Key: Bundle version ID encoded as u8 || { Option[AssetId] } - - Value: `valueBalance` - - Option 3: BundleVersionID -> Option[AssetId] -> valueBalance - - Key: Bundle version ID - - Value: - - Map containing one or more generalized value balances - - { Option[AssetId] } - - `valueBalance` -- Sequence of bundles (maybe with a length prefix?) - - Bundle version ID - - Flag bits, either in the version ID or next to it, that indicate how an opaquely-parsing wallet should interpret the bundle, e.g.: - - A bit that says whether or not the bundle interacts with the transparent transaction value pool (which memo bundles would not have). - - Counterpoint: The traffic map already specifies whether a given bundle *does* have an interaction with the transparent tx value pool for this tx. This is different from whether that kind of bundle *can* interact with the transparent tx value pool, but it the latter needed? - - A bit that says whether the bundle has any other effect than what is specified in the traffic map. - - Counterpoint: We should split apart effecting and authorizing data in the encoding, and then a bundle must be assumed effecting iff it has non-null effecting data. - - CompactSize len(effectingData) - - effectingData - - CompactSize len(authorizingData) - - authorizingData - - effectingData and authorizingData would be opaque to the initial parser. - - Parsers that support parsing (tx_version, bundle_version) know how to interpret its internals - -Questions: -- Is it okay for fee calculations to be opaque to wallet parsers, as long as the fee amounts can be calculated in consensus? - - Yes: - - When receiving, all you care about is knowing the actual fee amount; you see that in the fee bundle's value balance. - - When sending, you need to understand all bundles you are including, and then you can calculate the fee. -- Can wallets still compute the txid and wtxid of an arbitrary transaction? - - Yes, provided that effecting and authorizing data is separated. Then they can hash the effecting data even without understanding it to compute the txid, and they can hash the authorizing data even without understanding it to compute the authorizing data commitment part of the wtxid [[ZIP 239]](https://zips.z.cash/zip-0239). - - *However*, this reintroduces a more direct linkage between the [w]txid computation and the transaction encoding. It's arguably fine, and potentially simpler -- since the [w]txid computation need not change at all for most protocol changes. - - If the hashing uses flat hashes over the effectingData and authorizingData of each bundle (which it has to because the internal structure is not known), then it might be more difficult to do Merkle proofs over subsets of the data within a bundle. We haven't used that so far; is it really needed? +* Transaction version (like now) + * Version + * Version group ID +* Transaction header + * Expiry height etc + * Likely need some kind of key-value map here to allow additional fields to + be added, or maybe version the header to allow evolution? +* Transparent transaction value pool "traffic map" + * Option 1: BundleVersionID -> (valueBalance, AssetId -> valueBalance) + * Key: Bundle version ID + * Value: + * ZEC `valueBalance` + * CompactSize len(generalizedValueBalances) + * Zero or more generalized value balances + * `AssetId` (not `AssetBase` because those are + protocol-specific, and we want generalized value balances to + be understandable independently of protocol changes) + * `valueBalance` + * Option 2: (BundleVersionID, Option[AssetId]) -> valueBalance + * Key: Bundle version ID encoded as u8 || { Option[AssetId] } + * Value: `valueBalance` + * Option 3: BundleVersionID -> Option[AssetId] -> valueBalance + * Key: Bundle version ID + * Value: + * Map containing one or more generalized value balances + * { Option[AssetId] } + * `valueBalance` +* Sequence of bundles (maybe with a length prefix?) + * Bundle version ID + * Maybe flag bits, either in the version ID or next to it, that + indicate how an opaquely-parsing wallet should interpret the bundle, + e.g.: + * A bit that says whether or not the bundle interacts with the + transparent transaction value pool (which memo bundles would not + have). + * Counterpoint: The traffic map already specifies whether a + given bundle *does* have an interaction with the transparent + tx value pool for this tx. This is different from whether + that kind of bundle *can* interact with the transparent tx + value pool, but it the latter needed? + * A bit that says whether the bundle has any other effect than what + is specified in the traffic map. + * Counterpoint: We should split apart effecting and authorizing + data in the encoding, and then a bundle must be assumed + effecting iff it has non-null effecting data. + * CompactSize len(effectingData) + * effectingData + * CompactSize len(authorizingData) + * authorizingData + * effectingData and authorizingData would be opaque to the initial + parser. + * Parsers that support parsing (tx_version, bundle_version) know how to + interpret its internals + +Questions +--------- + +* Is it okay for fee calculations to be opaque to wallet parsers, as long as + the fee amounts can be calculated in consensus? + * Yes: + * When receiving, all you care about is knowing the actual fee amount; + you see that in the fee bundle's value balance. + * When sending, you need to understand all bundles you are including, + and then you can calculate the fee. +* Can wallets still compute the txid and wtxid of an arbitrary transaction? + * Yes, provided that effecting and authorizing data is separated. Then they + can hash the effecting data even without understanding it to compute the + txid, and they can hash the authorizing data even without understanding + it to compute the authorizing data commitment part of the wtxid [[ZIP + 239]](https://zips.z.cash/zip-0239). + * *However*, this reintroduces a more direct linkage between the [w]txid + computation and the transaction encoding. It's arguably fine, and + potentially simpler -- since the [w]txid computation need not change at + all for most protocol changes. + * If the hashing uses flat hashes over the effectingData and + authorizingData of each bundle (which it has to because the internal + structure is not known), then it might be more difficult to do Merkle + proofs over subsets of the data within a bundle. We haven't used that so + far; is it really needed? From 3ec87bb4f1170064a5cecac6ee727b3166910a27 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Mon, 19 Jan 2026 19:49:48 -0700 Subject: [PATCH 06/51] [ZIP 248]: Fix rst rendering --- README.rst | 2 + zips/zip-0248.rst | 255 ++++++++++++++++++++++++++-------------------- 2 files changed, 147 insertions(+), 110 deletions(-) diff --git a/README.rst b/README.rst index 8a430c86a..3aa3a0e08 100644 --- a/README.rst +++ b/README.rst @@ -195,6 +195,7 @@ written. 235 Remove 60% of Transaction Fees From Circulation Draft zips#924 240 Standard Transaction Rules Reserved zips#648 245 Transaction Identifier Digests & Signature Validation for Transparent Zcash Extensions Draft zips#384 + 248 Extensible Transaction Format Draft zips/pull/1163 258 Deployment of the NU6.3 Network Upgrade Draft zips#1304 260 Extending Block Messages with Additional Authentication Data Reserved zips#522 270 Key Rotation for Tracked Signing Keys Reserved zips#1047 @@ -345,6 +346,7 @@ Index of ZIPs 244 Transaction Identifier Non-Malleability Final 245 Transaction Identifier Digests & Signature Validation for Transparent Zcash Extensions Draft 246 Digests for the Withdrawn Version 6 Transaction Format Withdrawn + 248 Extensible Transaction Format Draft 250 Deployment of the Heartwood Network Upgrade Final 251 Deployment of the Canopy Network Upgrade Final 252 Deployment of the NU5 Network Upgrade Final diff --git a/zips/zip-0248.rst b/zips/zip-0248.rst index 7714cca93..80cba293c 100644 --- a/zips/zip-0248.rst +++ b/zips/zip-0248.rst @@ -22,13 +22,13 @@ document are to be interpreted as described in BCP 14 [^BCP14] when, and only when, they appear in all capitals. The character § is used when referring to sections of the Zcash Protocol -Specification. [^protocol] +Specification. [#protocol]_ The terms "Mainnet" and "Testnet" are to be interpreted as described in § 3.12 -‘Mainnet and Testnet’. [^protocol-networks] +‘Mainnet and Testnet’. [#protocol-networks]_ The term "full validator" in this document is to be interpreted as defined in § -3.3 ‘The Block Chain’. [^protocol-blockchain]. +3.3 ‘The Block Chain’. [#protocol-blockchain]_ The terms below are to be interpreted as follows: @@ -251,14 +251,14 @@ so no entry in ``vBundles`` is permitted. +------------+------------------------------------+----------------------------+-------------------------------------------------------------+ | 3 |✅ |✅ | Orchard | +------------+------------------------------------+----------------------------+-------------------------------------------------------------+ -| 4* |✅ |❌ | Transaction fee (*if ZIP 2002 activated) | +| 4\* |✅ |❌ | Transaction fee (\*if ZIP 2002 activated) | +------------+------------------------------------+----------------------------+-------------------------------------------------------------+ -| 5* |✅ |❌ | ZIP 233 NSM field (*if ZIP 233 activated) | +| 5\* |✅ |❌ | ZIP 233 NSM field (\*if ZIP 233 activated) | +------------+------------------------------------+----------------------------+-------------------------------------------------------------+ -| 6* |❌ |✅ | ZIP 270 Key rotation (*if ZIP 270 activated) | +| 6\* |❌ |✅ | ZIP 270 Key rotation (\*if ZIP 270 activated) | +------------+------------------------------------+----------------------------+-------------------------------------------------------------+ -| 7* |✅ |✅ | Lockbox disbursement / "Consensus accounts" | -| | | | (*for miner payouts, lockbox, etc if ZIP activated) | +| 7\* |✅ |✅ | Lockbox disbursement / "Consensus accounts" | +| | | | (\*for miner payouts, lockbox, etc if ZIP activated) | +------------+------------------------------------+----------------------------+-------------------------------------------------------------+ | |❌ |✅ | ZIP 231 Memos | +------------+------------------------------------+----------------------------+-------------------------------------------------------------+ @@ -309,19 +309,6 @@ Reference implementation Open issues =========== -References -========== - -[^BCP14]: [Information on BCP 14 — "RFC 2119: Key words for use in RFCs to Indicate Requirement Levels" and "RFC 8174: Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words"](https://www.rfc-editor.org/info/bcp14) - -[^protocol]: [Zcash Protocol Specification, Version 2025.6.3 [NU6.1] or later](protocol/protocol.pdf) - -[^protocol-blockchain]: [Zcash Protocol Specification, Version 2025.6.3 [NU6.1]. Section 3.3: The Block Chain](protocol/protocol.pdf#blockchain) - -[^protocol]: [Zcash Protocol Specification, Version 2025.6.3 [NU6.1]. Section 3.12: Mainnet and Testnet](protocol/protocol.pdf#networks) - - - Notes from design sessions ========================== @@ -336,7 +323,7 @@ changes can be safely adapted to using this mechanism. In particular, consensus rules may change in such a way that a wallet doing what it has done in the past causes risk of loss of funds. -An example of this was [ZIP 212](https://zips.z.cash/zip-0212). In that case +An example of this was ZIP 212 [#zip-0212]_. In that case the existing mechanisms failed to prevent loss of funds because in practice, wallets updated the consensus branch ID without updating note encryption. We made the mistake of requiring wallets to change their behaviour for an existing @@ -371,8 +358,9 @@ changes. The NSM burn amount field could be its own bundle, the explicit fee data could be its own bundle and the consensus rule could be that all value balances sum to zero. - * generically, you want a value balance vector, where you have zero or more - value balances moving between bundles in other assets. + + * generically, you want a value balance vector, where you have zero or more + value balances moving between bundles in other assets. * @nuttycom: You could have pre-ZSA and post-ZSA Orchard bundles. @@ -380,109 +368,156 @@ Strawman II ----------- Treat bundles as individually versioned. + * Each bundle is registered with an ID relative to a tx version group ID. * The bundle ID encoding also has some flag bits indicating how it interacts with the tx as a whole. * Transactions then have two "bundle maps": - * The first encodes how value moves between the different bundles. - * The second encodes data specific to a bundle (e.g. how value moves within a bundle) - * Bundles that don't have any data would just appear in the first map, and - bundles that don't produce or consume value would just appear in the - second map. + + * The first encodes how value moves between the different bundles. + * The second encodes data specific to a bundle (e.g. how value moves within a bundle) + * Bundles that don't have any data would just appear in the first map, and + bundles that don't produce or consume value would just appear in the + second map. * We can re-interpret various other facets of transactions as "bundles" - * Explicit fees are a bundle that never produces value - * NSM field similarly never produces value - * ZSA burns would be split into "value balance out of Orchard pool" and - "value balance being removed from ZSA issuance" - * See also the conversation we had about refactoring coinbase transactions. - TODO: Figure out how to integrate the two. + + * Explicit fees are a bundle that never produces value + * NSM field similarly never produces value + * ZSA burns would be split into "value balance out of Orchard pool" and + "value balance being removed from ZSA issuance" + * See also the conversation we had about refactoring coinbase transactions. + TODO: Figure out how to integrate the two. * Privacy effect is minimal - * We already follow a bundle approach with a transparent transaction value - pool, for the turnstiles. This leans into it, while preserving the bundle - boundary within which we implement each privacy protocol. - * Some combinations of bundles would be permitted by the tx format that - were not previously permitted. - * However, we can still restrict which combinations of bundles can be - mined in the consensus rules. + + * We already follow a bundle approach with a transparent transaction value + pool, for the turnstiles. This leans into it, while preserving the bundle + boundary within which we implement each privacy protocol. + * Some combinations of bundles would be permitted by the tx format that + were not previously permitted. + + * However, we can still restrict which combinations of bundles can be + mined in the consensus rules. Sketch of the format: + * Transaction version (like now) - * Version - * Version group ID + + * Version + * Version group ID + * Transaction header - * Expiry height etc - * Likely need some kind of key-value map here to allow additional fields to - be added, or maybe version the header to allow evolution? + + * Expiry height etc + * Likely need some kind of key-value map here to allow additional fields to + be added, or maybe version the header to allow evolution? + * Transparent transaction value pool "traffic map" - * Option 1: BundleVersionID -> (valueBalance, AssetId -> valueBalance) - * Key: Bundle version ID - * Value: - * ZEC `valueBalance` - * CompactSize len(generalizedValueBalances) - * Zero or more generalized value balances - * `AssetId` (not `AssetBase` because those are - protocol-specific, and we want generalized value balances to - be understandable independently of protocol changes) - * `valueBalance` - * Option 2: (BundleVersionID, Option[AssetId]) -> valueBalance - * Key: Bundle version ID encoded as u8 || { Option[AssetId] } - * Value: `valueBalance` - * Option 3: BundleVersionID -> Option[AssetId] -> valueBalance - * Key: Bundle version ID - * Value: - * Map containing one or more generalized value balances - * { Option[AssetId] } - * `valueBalance` + + * Option 1: BundleVersionID -> (valueBalance, AssetId -> valueBalance) + + * Key: Bundle version ID + * Value: + + * ZEC `valueBalance` + * CompactSize len(generalizedValueBalances) + * Zero or more generalized value balances + + * `AssetId` (not `AssetBase` because those are + protocol-specific, and we want generalized value balances to + be understandable independently of protocol changes) + * `valueBalance` + + * Option 2: (BundleVersionID, Option[AssetId]) -> valueBalance + + * Key: Bundle version ID encoded as u8 || { Option[AssetId] } + * Value: `valueBalance` + + * Option 3: BundleVersionID -> Option[AssetId] -> valueBalance + + * Key: Bundle version ID + * Value: + + * Map containing one or more generalized value balances + + * { Option[AssetId] } + * `valueBalance` * Sequence of bundles (maybe with a length prefix?) - * Bundle version ID - * Maybe flag bits, either in the version ID or next to it, that - indicate how an opaquely-parsing wallet should interpret the bundle, - e.g.: - * A bit that says whether or not the bundle interacts with the - transparent transaction value pool (which memo bundles would not - have). - * Counterpoint: The traffic map already specifies whether a - given bundle *does* have an interaction with the transparent - tx value pool for this tx. This is different from whether - that kind of bundle *can* interact with the transparent tx - value pool, but it the latter needed? - * A bit that says whether the bundle has any other effect than what - is specified in the traffic map. - * Counterpoint: We should split apart effecting and authorizing - data in the encoding, and then a bundle must be assumed - effecting iff it has non-null effecting data. - * CompactSize len(effectingData) - * effectingData - * CompactSize len(authorizingData) - * authorizingData - * effectingData and authorizingData would be opaque to the initial - parser. - * Parsers that support parsing (tx_version, bundle_version) know how to - interpret its internals + + * Bundle version ID + + * Maybe flag bits, either in the version ID or next to it, that + indicate how an opaquely-parsing wallet should interpret the bundle, + e.g.: + + * A bit that says whether or not the bundle interacts with the + transparent transaction value pool (which memo bundles would not + have). + + * Counterpoint: The traffic map already specifies whether a + given bundle *does* have an interaction with the transparent + tx value pool for this tx. This is different from whether + that kind of bundle *can* interact with the transparent tx + value pool, but it the latter needed? + + * A bit that says whether the bundle has any other effect than what + is specified in the traffic map. + + * Counterpoint: We should split apart effecting and authorizing + data in the encoding, and then a bundle must be assumed + effecting iff it has non-null effecting data. + + * CompactSize len(effectingData) + + * effectingData + + * CompactSize len(authorizingData) + + * authorizingData + + * effectingData and authorizingData would be opaque to the initial + parser. + * Parsers that support parsing (tx_version, bundle_version) know how to + interpret its internals Questions --------- * Is it okay for fee calculations to be opaque to wallet parsers, as long as the fee amounts can be calculated in consensus? - * Yes: - * When receiving, all you care about is knowing the actual fee amount; - you see that in the fee bundle's value balance. - * When sending, you need to understand all bundles you are including, - and then you can calculate the fee. + + * Yes: + + * When receiving, all you care about is knowing the actual fee amount; + you see that in the fee bundle's value balance. + * When sending, you need to understand all bundles you are including, + and then you can calculate the fee. + * Can wallets still compute the txid and wtxid of an arbitrary transaction? - * Yes, provided that effecting and authorizing data is separated. Then they - can hash the effecting data even without understanding it to compute the - txid, and they can hash the authorizing data even without understanding - it to compute the authorizing data commitment part of the wtxid [[ZIP - 239]](https://zips.z.cash/zip-0239). - * *However*, this reintroduces a more direct linkage between the [w]txid - computation and the transaction encoding. It's arguably fine, and - potentially simpler -- since the [w]txid computation need not change at - all for most protocol changes. - * If the hashing uses flat hashes over the effectingData and - authorizingData of each bundle (which it has to because the internal - structure is not known), then it might be more difficult to do Merkle - proofs over subsets of the data within a bundle. We haven't used that so - far; is it really needed? + + * Yes, provided that effecting and authorizing data is separated. Then they + can hash the effecting data even without understanding it to compute the + txid, and they can hash the authorizing data even without understanding + it to compute the authorizing data commitment part of the wtxid (ZIP + 239 [#zip-0239]_). + * *However*, this reintroduces a more direct linkage between the [w]txid + computation and the transaction encoding. It's arguably fine, and + potentially simpler -- since the [w]txid computation need not change at + all for most protocol changes. + * If the hashing uses flat hashes over the effectingData and + authorizingData of each bundle (which it has to because the internal + structure is not known), then it might be more difficult to do Merkle + proofs over subsets of the data within a bundle. We haven't used that so + far; is it really needed? + + +References +========== + +.. [#BCP14] `Information on BCP 14 — "RFC 2119: Key words for use in RFCs to Indicate Requirement Levels" and "RFC 8174: Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words `_ +.. [#protocol] `Zcash Protocol Specification, Version 2025.6.3 [NU6.1] or later `_ +.. [#protocol-blockchain] `Zcash Protocol Specification, Version 2025.6.3 [NU6.1]. Section 3.3: The Block Chain `_ +.. [#protocol-networks] `Zcash Protocol Specification, Version 2025.6.3 [NU6.1]. Section 3.12: Mainnet and Testnet `_ +.. [#zip-0203] `ZIP 203: Transaction Expiry `_ +.. [#zip-0212] `ZIP 212: Allow Recipient to Derive Ephemeral Secret from Note Plaintext `_ +.. [#zip-0239] `ZIP 239: Relay of Version 5 Transactions `_ From f0ae468793ad92ad801dae4564d1f21388c2d9f0 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Thu, 22 Jan 2026 18:52:51 -0700 Subject: [PATCH 07/51] [ZIP 248]: Add consensus rules for transaction value balance. --- zips/zip-0248.rst | 75 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 62 insertions(+), 13 deletions(-) diff --git a/zips/zip-0248.rst b/zips/zip-0248.rst index 80cba293c..529708c6a 100644 --- a/zips/zip-0248.rst +++ b/zips/zip-0248.rst @@ -32,9 +32,12 @@ The term "full validator" in this document is to be interpreted as defined in § The terms below are to be interpreted as follows: -{Term to be defined} - -: {Definition.} +transparent transaction value pool + An ephemeral value for the balance of an asset within the scope of a single + transaction, which is modified by additions and subtractions in the + processing of the effects of transaction bundles. When all of the effects of + a transaction are accounted for, each such balance is zero; i.e, the total of + additions to the balance equals the total of subtractions from it. Abstract @@ -44,19 +47,20 @@ This ZIP proposes an encoding for V6 Zcash transactions that is intended to reduce the impact of future changes to the Zcash transaction format on the Zcash ecosystem. It defines a new typecode-length-value encoding for a sequence of protocol bundles, and a "value balance" map that describes the effect of -each bundle on the transparent chain value balance, much in the same fashion -as the Sapling and Orchard value balance fields have done in the past. +each bundle on the transparent transaction value pool for each asset. The +entries of this map serve the same purpose as the Sapling and Orchard value +balance fields have done in the past. Motivation ========== -In the past, Zcash network upgrades that change the transaction format have +In the past, Zcash network upgrades that changed the transaction format have resulted in substantial disruption for wallets and other third-party clients in the Zcash ecosystem. In order to continue functioning after a network upgrade, clients were required to upgrade their Zcash transaction parsers to read the new format, even if the context in which those parsers were being used didn't -need or couldn't make use of newly added transaction data; an example of this +need or couldn't make use of newly added transaction data. An example of this is that transparent-only wallets were forced to update their parsers to understand the Sapling and Orchard parts of transactions, even if they would never read or act upon those parts. This has led on occasion to significant @@ -113,8 +117,9 @@ Requirements * The transaction format can be parsed without any knowledge of any Zcash payment protocols. -* Movement of value into and out of the transparent value pool(s) can be - understood with only partial knowledge of the Zcash payment protocols. +* Movement of value into and out of the transparent value pools (the ZEC + transparent value pool, plus the transparent value pool for each ZSA asset) + can be understood with only partial knowledge of the Zcash payment protocols. * The information content of transactions should not change as part of this ZIP. Other ZIPs activated along with this ZIP may however make use of it in introducing such changes. @@ -178,10 +183,6 @@ Transaction Format | varies |``vBundles`` |``Bundle[nBundles]`` |A sequence of ``Bundle`` values. | +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ -``mValuePoolDeltas`` MUST NOT contain more than a single entry for a given -``(bundleType, assetClass, assetId)`` tuple, which is treated as the "key" of -the map. - ValuePoolDelta -------------- @@ -203,6 +204,20 @@ ValuePoolDelta | | | |of ``mValuePoolDeltas`` instead. | +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +In definitions below, $[0]^{32}$ is treated as the asset identifier for the ZEC asset. + +.. math:: + + \mathsf{AssetId} = + \begin{cases} + [0]^{32} & \text{if } \mathsf{assetClass} = 0 \\ + \mathsf{assetId} & \text{otherwise} + \end{cases} + +``mValuePoolDeltas`` is interpreted as a map keyed by the tuple +$(\mathsf{BundleType}, \mathsf{AssetId})$. The map MUST NOT contain more than +a single entry for a given key. + Bundle ------ @@ -292,6 +307,40 @@ might affect the value pool delta map. | |✅ |✅ | Post-quantum fast payment protocol | +------------+------------------------------------+----------------------------+-------------------------------------------------------------+ +Consensus Rules +--------------- + +Full node implementations MUST verify that: + +* The ``assetClass`` value for any entry in ``mValuePoolDeltas`` having + ``bundleType = 4`` (fees) is 0 (fee amounts are denominated in ZEC + and no other asset.) + +* For the coinbase transaction, the sum of value pool deltas in the ZEC asset + is equal to the negative of the block subsidy for that block; the block + subsidy adds an implicit input value to the transparent transaction value + pool that the coinbase outputs consume. + +.. math:: + + \sum_{\mathsf{d} \in \mathsf{mValuePoolDeltas} | \mathsf{d}.\mathsf{bundleType} = 4} \mathsf{d.value} = \mathsf{BlockSubsidy}(\mathsf{height}) + +* For the coinbase transaction, the value of the fee bundle is equal to the + negative of the total fees produced by the non-coinbase transactions in the + block. $\mathsf{T}$ is the set of non-coinbase transactions included in the + block. + +.. math:: + + \mathsf{mValuePoolDeltas}[(4, [0]^{32})].\mathsf{value} = -\sum_{\mathsf{t} \in \mathsf{T}}\mathsf{mValuePoolDeltas}_{\mathsf{t}}[(4, [0]^{32})].\mathsf{value} + +* For all non-coinbase transactions, the sum of value pool delta values in each + asset equals 0. + +.. math:: + + \forall bundleType,assetId. \sum\mathsf{mValuePoolDeltas}[(bundleType, assetId)].\mathsf{value} = 0 + Rationale ========= From bd47bd57deff88b0789867792753f601488a3820 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Fri, 23 Jan 2026 15:35:39 -0700 Subject: [PATCH 08/51] [ZIP 248]: Separate effecting data bundles from authorizing data bundles. --- zips/zip-0248.rst | 226 +++++++++++++++++++++++++++------------------- 1 file changed, 131 insertions(+), 95 deletions(-) diff --git a/zips/zip-0248.rst b/zips/zip-0248.rst index 529708c6a..5c7501534 100644 --- a/zips/zip-0248.rst +++ b/zips/zip-0248.rst @@ -178,10 +178,19 @@ Transaction Format +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ | **Bundles** | +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ -| varies |``nBundles`` |``compactSize`` |Number of bundles in the transaction that have per-bundle data. | +| varies |``nEffectBundles`` |``compactSize`` |Number of bundles in the transaction that have per-bundle data. | +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ -| varies |``vBundles`` |``Bundle[nBundles]`` |A sequence of ``Bundle`` values. | +| varies |``mEffectBundles`` |``BundleData[nEffectBundles]`` |A map from bundle identifier to the effecting data of a bundle. | +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| varies |``nAuthBundles`` |``compactSize`` |Number of bundles in the transaction that have per-bundle data. | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| varies |``mAuthBundles`` |``BundleData[nAuthBundles]`` |A map from bundle identifier to the authorizing data of a bundle. | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ + +``mEffectBundles`` and ``mAuthBundles`` are interpreted as a maps keyed by +bundle type. Each map MUST NOT contain more than a single entry for a given +key. For each key that exists in ``mAuthBundles``, a corresponding entry +must exist in ``mEffectBundles``. ValuePoolDelta -------------- @@ -191,11 +200,12 @@ ValuePoolDelta +=============================+==============================+================================================+=====================================================================+ | varies |``bundleType`` |``compactSize`` |An encoding of the bundle type identifier. | +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ -| 1 |``assetClass`` |``uint8`` |An asset class identifier. 0x00 for the ZEC asset, 0x01 for ZSA | -| | | |assets. All other values are reserved for future use. | +| 1 |``assetClass`` |``uint8`` |An asset class identifier. 0x00 for the ZEC asset, 0x01 for other | +| | | |assets. | +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ -| one of {0, 32} |``assetId`` |``byte[0] or byte[32]`` |If `assetClass == 0`, the zero-length byte array, otherwise a byte | -| | | |array containing the 32-byte asset ID for the asset. | +| one of {0, 64} |``assetUuid`` |``byte[0] or byte[64]`` |If `assetClass == 0`, the zero-length byte array, otherwise a byte | +| | | |array containing a universally unique 64-byte identifier for the | +| | | |asset. | +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ | 8 |``value`` |``nonzero int64`` |The net change to the transparent value pool of the given asset | | | | |produced by the bundle corresponding to the bundle type identifier. | @@ -204,37 +214,35 @@ ValuePoolDelta | | | |of ``mValuePoolDeltas`` instead. | +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ -In definitions below, $[0]^{32}$ is treated as the asset identifier for the ZEC asset. +``mValuePoolDeltas`` is interpreted as a map keyed by the tuple +$(\mathsf{BundleType}, \mathsf{AssetUuid}).$ The map MUST NOT contain more than +a single entry for a given key. Lookups in this map are denoted with the +syntax $\mathsf{mValuePoolDeltas}[(\mathsf{BundleType}, \mathsf{AssetUuid})].$ + +Let $\mathsf{AssetUuid}_\mathsf{d}$ be the asset indicated by the ``mValuePoolDeltas`` entry $\mathsf{d}.$ .. math:: - \mathsf{AssetId} = + \mathsf{AssetUuid} = \begin{cases} - [0]^{32} & \text{if } \mathsf{assetClass} = 0 \\ - \mathsf{assetId} & \text{otherwise} + \mathsf{Zec} & \text{if } \mathsf{d}.\mathsf{assetClass} = 0 \\ + \mathsf{d}.\mathsf{assetUuid} & \text{if } \mathsf{d}.\mathsf{assetClass} = 1 \\ + \bot \text{otherwise} \end{cases} -``mValuePoolDeltas`` is interpreted as a map keyed by the tuple -$(\mathsf{BundleType}, \mathsf{AssetId})$. The map MUST NOT contain more than -a single entry for a given key. - -Bundle ------- +BundleData +---------- +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ | Bytes | Name | Data Type | Description | +=============================+==============================+================================================+=====================================================================+ | varies |``bundleType`` |``compactSize`` |An encoding of the bundle type identifier. | +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ -| varies |``nBundleEffectsLen`` |``compactSize`` |The length of the ``vBundleEffectsData`` byte array. | -+-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ -| varies |``vBundleEffectsData`` |``byte[nBundleEffectsLen]`` |The "effecting" data for the bundle. This consists of any | -| | | |information in the bundle that induces a state change in the | -| | | |blockchain and must therefore be committed to by the txid. | -+-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ -| varies |``nBundleAuthLen`` |``compactSize`` |The length of the ``vBundleAuthData`` byte array. | +| varies |``nBundleDataLen`` |``compactSize`` |The length of the ``vBundleData`` byte array. | +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ -| varies |``vBundleAuthData`` |``byte[nBundleAuthLen]`` |The authorizing data for the bundle. | +| varies |``vBundleData`` |``byte[nBundleDataLen]`` |The effecting or authorizing data for the bundle, dependent upon | +| | | |whether the ``BundleData`` occurs in ``mEffectBundles`` or | +| | | |``mAuthBundles``. | +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ @@ -245,106 +253,123 @@ The following integers are registered as bundle type identifiers for the V6 transaction format. All currently-defined IDs are encoded as single-byte ``CompactSize`` values where they appear in the transaction format. -The "Can appear in ``mValuePoolDeltas``" column indicates whether or not an -entry for this value type is allowed to appear in ``mValuePoolDeltas``. For -rows where an ❌ is present, the value pool delta for every pool is guaranteed -to be zero, and so entries in ``mValuePoolDeltas`` are disallowed. +The ``mValuePoolDeltas`` column indicates whether or not an entry for this +value type is allowed to appear in ``mValuePoolDeltas``. For rows where an ❌ +is present, the value pool delta for every pool is guaranteed to be zero, and +so entries in ``mValuePoolDeltas`` are disallowed. -The "Can appear in ``vBundles``" column indicates whether or not an entry for -this value type is allowed to appear in ``vBundles``. For rows where an ❌ is +The ``mEffectBundles`` column indicates whether or not an entry for this value +type is allowed to appear in ``mEffectBundles``. For rows where an ❌ is present, the bundle is guaranteed to have no effecting or authorizing data, and -so no entry in ``vBundles`` is permitted. - -+------------+------------------------------------+----------------------------+-------------------------------------------------------------+ -| BundleType | Can appear in ``mValuePoolDeltas`` | Can appear in ``vBundles`` | Bundle kind | -+============+====================================+============================+=============================================================+ -| 0 |✅ |✅ | Transparent | -+------------+------------------------------------+----------------------------+-------------------------------------------------------------+ -| 1 |✅ |✅ | Reserved | -+------------+------------------------------------+----------------------------+-------------------------------------------------------------+ -| 2 |✅ |✅ | Sapling | -+------------+------------------------------------+----------------------------+-------------------------------------------------------------+ -| 3 |✅ |✅ | Orchard | -+------------+------------------------------------+----------------------------+-------------------------------------------------------------+ -| 4\* |✅ |❌ | Transaction fee (\*if ZIP 2002 activated) | -+------------+------------------------------------+----------------------------+-------------------------------------------------------------+ -| 5\* |✅ |❌ | ZIP 233 NSM field (\*if ZIP 233 activated) | -+------------+------------------------------------+----------------------------+-------------------------------------------------------------+ -| 6\* |❌ |✅ | ZIP 270 Key rotation (\*if ZIP 270 activated) | -+------------+------------------------------------+----------------------------+-------------------------------------------------------------+ -| 7\* |✅ |✅ | Lockbox disbursement / "Consensus accounts" | -| | | | (\*for miner payouts, lockbox, etc if ZIP activated) | -+------------+------------------------------------+----------------------------+-------------------------------------------------------------+ -| |❌ |✅ | ZIP 231 Memos | -+------------+------------------------------------+----------------------------+-------------------------------------------------------------+ -| |✅ |✅ | Sapling-post-ZIP 231 (if ZIP 231 activated after this ZIP) | -+------------+------------------------------------+----------------------------+-------------------------------------------------------------+ -| |✅ |✅ | Orchard-post-ZIP 231 (if ZIP 231 activated after this ZIP) | -+------------+------------------------------------+----------------------------+-------------------------------------------------------------+ -| |✅ |✅ | ZSA Issuance | -+------------+------------------------------------+----------------------------+-------------------------------------------------------------+ -| |✅ |✅ | OrchardZSA | -+------------+------------------------------------+----------------------------+-------------------------------------------------------------+ +so no entry in ``mEffectBundles`` is permitted. + +The ``mAuthBundles`` column indicates whether or not an entry for this value +type is allowed to appear in ``mAuthBundles``. For rows where an ❌ is present, +the bundle is guaranteed to have no authorizing data, and so no entry in +``mAuthBundles`` is permitted. + ++------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ +| BundleType | ``mValuePoolDeltas`` | ``mEffectBundles`` | ``mAuthBundles`` | Bundle kind | ++============+======================+====================+==================+=============================================================+ +| 0 |✅ |✅ |✅ | Transparent | ++------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ +| 1 | | | | Reserved | ++------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ +| 2 |✅ |✅ |✅ | Sapling | ++------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ +| 3 |✅ |✅ |✅ | Orchard | ++------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ +| 4\* |✅ |❌ |❌ | Transaction fee (\*if ZIP 2002 activated) | ++------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ +| 5\* |✅ |❌ |❌ | ZIP 233 NSM field (\*if ZIP 233 activated) | ++------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ +| 6\* |❌ |✅ |✅ | ZIP 270 Key rotation (\*if ZIP 270 activated) | ++------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ +| 7\* |✅ |✅ |✅ | Lockbox disbursement / "Consensus accounts" | +| | | | | (\*for miner payouts, lockbox, etc if ZIP activated) | ++------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ +| |❌ |✅ |❌ | ZIP 231 Memos | ++------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ +| |✅ |✅ |✅ | Sapling-post-ZIP 231 (if ZIP 231 activated after this ZIP) | ++------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ +| |✅ |✅ |✅ | Orchard-post-ZIP 231 (if ZIP 231 activated after this ZIP) | ++------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ +| |✅ |✅ |✅ | ZSA Issuance | ++------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ +| |✅ |✅ |✅ | OrchardZSA | ++------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ The following entries are provided to illustrate how potential future upgrades might affect the value pool delta map. -+------------+------------------------------------+----------------------------+-------------------------------------------------------------+ -| BundleType | Can appear in ``mValuePoolDeltas`` | Can appear in ``vBundles`` | Bundle kind | -+============+====================================+============================+=============================================================+ -| |✅ |✅ | TZEs | -+------------+------------------------------------+----------------------------+-------------------------------------------------------------+ -| |✅ |✅ | Pool that only has a long-term storage protocol (PQ, very | -| | | | simple thus insulated from counterfeiting fears, can be | -| | | | used for payments but higher latency for that purpose) | -+------------+------------------------------------+----------------------------+-------------------------------------------------------------+ -| |✅ |✅ | Tachyon | -+------------+------------------------------------+----------------------------+-------------------------------------------------------------+ -| |✅ |✅ | Staking | -+------------+------------------------------------+----------------------------+-------------------------------------------------------------+ -| |✅ |✅ | Unstaking (if it can't be combined with the Staking bundle) | -+------------+------------------------------------+----------------------------+-------------------------------------------------------------+ -| |✅ |✅ | Post-quantum fast payment protocol | -+------------+------------------------------------+----------------------------+-------------------------------------------------------------+ ++------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ +| BundleType | ``mValuePoolDeltas`` | ``mEffectBundles`` | ``mAuthBundles`` | Bundle kind | ++============+======================+====================+==================+=============================================================+ +| |✅ |✅ |✅ | TZEs | ++------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ +| |✅ |✅ |✅ | Pool that only has a long-term storage protocol (PQ, very | +| | | | | simple thus insulated from counterfeiting fears, can be | +| | | | | used for payments but higher latency for that purpose) | ++------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ +| |✅ |✅ |✅ | Tachyon | ++------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ +| |✅ |✅ |❌ | Staking | ++------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ +| |✅ |✅ |✅ | Unstaking (if it can't be combined with the Staking bundle) | ++------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ +| |✅ |✅ |✅ | Post-quantum fast payment protocol | ++------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ Consensus Rules --------------- +Let ``FeeBundleId`` be the identifier of the fee bundle. In V6 transactions, +$\mathsf{FeeBundleId} = 4$ as defined in the table above. + Full node implementations MUST verify that: * The ``assetClass`` value for any entry in ``mValuePoolDeltas`` having - ``bundleType = 4`` (fees) is 0 (fee amounts are denominated in ZEC + ``bundleType = FeeBundleId`` is 0 (fee amounts are denominated in ZEC and no other asset.) +* For coinbase transaction, the value of $\mathsf{mValuePoolDeltas}[(\mathsf{FeeBundleId}, \mathsf{Zec})]$ must be nonnegative. + +* For non-coinbase transactions, the value of $\mathsf{mValuePoolDeltas}[(\mathsf{FeeBundleId}, \mathsf{Zec})]$ must be nonpositive. + +* Within the scope of a block, the sum of the fee bundle values must equal 0. + * For the coinbase transaction, the sum of value pool deltas in the ZEC asset is equal to the negative of the block subsidy for that block; the block subsidy adds an implicit input value to the transparent transaction value - pool that the coinbase outputs consume. - -.. math:: + pool that the coinbase outputs consume. - \sum_{\mathsf{d} \in \mathsf{mValuePoolDeltas} | \mathsf{d}.\mathsf{bundleType} = 4} \mathsf{d.value} = \mathsf{BlockSubsidy}(\mathsf{height}) + .. math:: -* For the coinbase transaction, the value of the fee bundle is equal to the - negative of the total fees produced by the non-coinbase transactions in the - block. $\mathsf{T}$ is the set of non-coinbase transactions included in the - block. + \sum_{\mathsf{d} \in \mathsf{mValuePoolDeltas} | \mathsf{AssetUuid}_\mathsf{d} = \mathsf{Zec}} \mathsf{d.value} = -\mathsf{BlockSubsidy}(\mathsf{height}) -.. math:: - - \mathsf{mValuePoolDeltas}[(4, [0]^{32})].\mathsf{value} = -\sum_{\mathsf{t} \in \mathsf{T}}\mathsf{mValuePoolDeltas}_{\mathsf{t}}[(4, [0]^{32})].\mathsf{value} + where $\mathsf{BlockSubsidy}$ is defined in § 7.8 'Block Subsidy and + Founders' Reward'. [#protocol-subsidies]_ * For all non-coinbase transactions, the sum of value pool delta values in each - asset equals 0. + asset equals 0. -.. math:: + .. math:: + + \forall \mathsf{a}. \sum_{\mathsf{d} \in \mathsf{mValuePoolDeltas} | \mathsf{AssetUuid}_\mathsf{d} = \mathsf{a}} \mathsf{d.value} = 0 - \forall bundleType,assetId. \sum\mathsf{mValuePoolDeltas}[(bundleType, assetId)].\mathsf{value} = 0 +V0 Digest Algorithm +------------------- Rationale ========= -TODO: Document why we take the specific approach we do on what the format constrains vs what wallets are expected (required?) to notify users of (once we decide on the approach). +TODO: Document why we take the specific approach we do on what the format +constrains vs what wallets are expected (required?) to notify users of (once we +decide on the approach). + +Effecting data bundles and authorizing data bundles are stored separately in +the transaction format so that the authorizing data may be pruned by +straightforward truncation of the encoded representation of the transaction. Deployment @@ -558,6 +583,16 @@ Questions proofs over subsets of the data within a bundle. We haven't used that so far; is it really needed? + * Should the authorizing data be entirely separate from the effecting data, + and encoded at the end of the transaction in a batch, so that pruning is + simply truncation? + + +TODO +==== + +Rename ``assetDigest`` to ``assetUuid`` in ZIP 227 + References ========== @@ -566,6 +601,7 @@ References .. [#protocol] `Zcash Protocol Specification, Version 2025.6.3 [NU6.1] or later `_ .. [#protocol-blockchain] `Zcash Protocol Specification, Version 2025.6.3 [NU6.1]. Section 3.3: The Block Chain `_ .. [#protocol-networks] `Zcash Protocol Specification, Version 2025.6.3 [NU6.1]. Section 3.12: Mainnet and Testnet `_ +.. [#protocol-subsidies] `Zcash Protocol Specification, Version 2025.6.3 [NU6.1]. Section 7.8: Block Subsidy and Founders' Reward `_ .. [#zip-0203] `ZIP 203: Transaction Expiry `_ .. [#zip-0212] `ZIP 212: Allow Recipient to Derive Ephemeral Secret from Note Plaintext `_ .. [#zip-0239] `ZIP 239: Relay of Version 5 Transactions `_ From bb7e3a57ab1c4389a463ab06555136cf16b57675 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Sun, 25 Jan 2026 11:07:51 -0700 Subject: [PATCH 09/51] [ZIP 248]: Add bundle format specifications for Transparent, Sapling, and Orchard. Specifies the effecting and authorizing data structures for each bundle type, with value balance moved to mValuePoolDeltas as per the extensible tx format design. Co-Authored-By: Claude Opus 4.5 --- zips/zip-0248.rst | 257 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 257 insertions(+) diff --git a/zips/zip-0248.rst b/zips/zip-0248.rst index 5c7501534..4a125be7d 100644 --- a/zips/zip-0248.rst +++ b/zips/zip-0248.rst @@ -246,6 +246,262 @@ BundleData +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +Transparent Bundle +------------------ + +Transparent Effecting Data +`````````````````````````` + +The effecting data for the transparent bundle describes the transparent inputs +being spent and the transparent outputs being created. + ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +| Bytes | Name | Data Type | Description | ++=============================+==========================+========================================+=====================================================================+ +|``varies`` |``tx_in_count`` |``compactSize`` |Number of transparent inputs. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``varies`` |``tx_in_effecting`` |``TransparentInputEffecting[tx_in_count]``|Effecting data for each transparent input. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``varies`` |``tx_out_count`` |``compactSize`` |Number of transparent outputs. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``varies`` |``tx_out`` |``TransparentOutput[tx_out_count]`` |Transparent outputs. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ + +TransparentInputEffecting +''''''''''''''''''''''''' + ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +| Bytes | Name | Data Type | Description | ++=============================+==========================+========================================+=====================================================================+ +|``32`` |``prevout_hash`` |``byte[32]`` |The transaction ID of the output being spent. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``4`` |``prevout_index`` |``uint32`` |The index of the output being spent within that transaction. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``4`` |``nSequence`` |``uint32`` |Sequence number, encoded as in Bitcoin. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ + +TransparentOutput +''''''''''''''''' + ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +| Bytes | Name | Data Type | Description | ++=============================+==========================+========================================+=====================================================================+ +|``8`` |``value`` |``int64`` |The value of the output in zatoshi. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``varies`` |``scriptPubKeyLen`` |``compactSize`` |Length of the scriptPubKey. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``scriptPubKeyLen`` |``scriptPubKey`` |``byte[scriptPubKeyLen]`` |The script that must be satisfied to spend this output. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ + +Transparent Authorizing Data +```````````````````````````` + +The authorizing data for the transparent bundle contains the scripts that +authorize spending of the referenced transparent inputs. + ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +| Bytes | Name | Data Type | Description | ++=============================+==========================+========================================+=====================================================================+ +|``varies`` |``tx_in_auth`` |``TransparentInputAuth[tx_in_count]`` |Authorizing data for each transparent input. The number of entries | +| | | |MUST equal ``tx_in_count`` from the effecting data. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ + +TransparentInputAuth +'''''''''''''''''''' + ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +| Bytes | Name | Data Type | Description | ++=============================+==========================+========================================+=====================================================================+ +|``varies`` |``scriptSigLen`` |``compactSize`` |Length of the scriptSig. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``scriptSigLen`` |``scriptSig`` |``byte[scriptSigLen]`` |The script satisfying the conditions of the referenced output's | +| | | |scriptPubKey. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ + + +Sapling Bundle +-------------- + +Sapling Effecting Data +`````````````````````` + +The effecting data for the Sapling bundle describes the Sapling spends and +outputs. Unlike the V5 transaction format defined in ZIP 225 [#zip-0225]_, +the value balance is not included here; it appears in ``mValuePoolDeltas`` +instead. + ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +| Bytes | Name | Data Type | Description | ++=============================+==========================+========================================+=====================================================================+ +|``varies`` |``nSpendsSapling`` |``compactSize`` |Number of Sapling Spend descriptions. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``96 * nSpendsSapling`` |``vSpendsSapling`` |``SaplingSpendEffecting[nSpendsSapling]``|Effecting data for each Sapling Spend. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``varies`` |``nOutputsSapling`` |``compactSize`` |Number of Sapling Output descriptions. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``756 * nOutputsSapling`` |``vOutputsSapling`` |``SaplingOutput[nOutputsSapling]`` |Sapling Output descriptions. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``32`` |``anchorSapling`` |``byte[32]`` |A root of the Sapling note commitment tree at some block height | +| | | |in the past. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ + +* The field ``anchorSapling`` is present if and only if $\mathtt{nSpendsSapling} > 0$. + +SaplingSpendEffecting +''''''''''''''''''''' + ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +| Bytes | Name | Data Type | Description | ++=============================+==========================+========================================+=====================================================================+ +|``32`` |``cv`` |``byte[32]`` |A value commitment to the net value of the input note. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``32`` |``nullifier`` |``byte[32]`` |The nullifier of the input note. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``32`` |``rk`` |``byte[32]`` |The randomized validating key for this Spend. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ + +SaplingOutput +''''''''''''' + +This is identical to ``OutputDescriptionV5`` as defined in ZIP 225 [#zip-0225]_. + ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +| Bytes | Name | Data Type | Description | ++=============================+==========================+========================================+=====================================================================+ +|``32`` |``cv`` |``byte[32]`` |A value commitment to the net value of the output note. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``32`` |``cmu`` |``byte[32]`` |The $u$-coordinate of the note commitment for the output note. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``32`` |``ephemeralKey`` |``byte[32]`` |An encoding of an ephemeral Jubjub public key. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``580`` |``encCiphertext`` |``byte[580]`` |The encrypted contents of the note plaintext. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``80`` |``outCiphertext`` |``byte[80]`` |The encrypted contents of the byte string created by concatenation | +| | | |of the transmission key with the ephemeral secret key. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ + +Sapling Authorizing Data +```````````````````````` + +The authorizing data for the Sapling bundle contains the proofs and signatures +that authorize the spends and validate the outputs. + ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +| Bytes | Name | Data Type | Description | ++=============================+==========================+========================================+=====================================================================+ +|``192 * nSpendsSapling`` |``vSpendProofsSapling`` |``byte[192 * nSpendsSapling]`` |Encodings of the zk-SNARK proofs for each Sapling Spend. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``64 * nSpendsSapling`` |``vSpendAuthSigsSapling`` |``byte[64 * nSpendsSapling]`` |Authorizing signatures for each Sapling Spend. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``192 * nOutputsSapling`` |``vOutputProofsSapling`` |``byte[192 * nOutputsSapling]`` |Encodings of the zk-SNARK proofs for each Sapling Output. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``64`` |``bindingSigSapling`` |``byte[64]`` |A Sapling binding signature on the SIGHASH transaction hash. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ + +* The values of ``nSpendsSapling`` and ``nOutputsSapling`` are not re-encoded in + the authorizing data; they are taken from the corresponding effecting data. + +* The field ``bindingSigSapling`` is present if and only if + $\mathtt{nSpendsSapling} + \mathtt{nOutputsSapling} > 0$. + +* The elements of ``vSpendProofsSapling`` and ``vSpendAuthSigsSapling`` have a + 1:1 correspondence to the elements of ``vSpendsSapling`` in the effecting data + and MUST be ordered such that the element at a given index corresponds to the + ``SaplingSpendEffecting`` at the same index. + +* The elements of ``vOutputProofsSapling`` have a 1:1 correspondence to the + elements of ``vOutputsSapling`` in the effecting data and MUST be ordered such + that the proof at a given index corresponds to the ``SaplingOutput`` at the + same index. + + +Orchard Bundle +-------------- + +Orchard Effecting Data +`````````````````````` + +The effecting data for the Orchard bundle describes the Orchard actions. Unlike +the V5 transaction format defined in ZIP 225 [#zip-0225]_, the value balance is +not included here; it appears in ``mValuePoolDeltas`` instead. + ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +| Bytes | Name | Data Type | Description | ++=============================+==========================+========================================+=====================================================================+ +|``varies`` |``nActionsOrchard`` |``compactSize`` |The number of Orchard Action descriptions. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``820 * nActionsOrchard`` |``vActionsOrchard`` |``OrchardActionEffecting[nActionsOrchard]``|Effecting data for each Orchard Action. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``1`` |``flagsOrchard`` |``byte`` |An 8-bit value representing a set of flags. Ordered from LSB to MSB: | +| | | | | +| | | |* ``enableSpendsOrchard`` | +| | | |* ``enableOutputsOrchard`` | +| | | |* The remaining bits are set to $0$. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``32`` |``anchorOrchard`` |``byte[32]`` |A root of the Orchard note commitment tree at some block height | +| | | |in the past. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ + +* The fields ``flagsOrchard`` and ``anchorOrchard`` are present if and only if + $\mathtt{nActionsOrchard} > 0$. + +* For coinbase transactions, the ``enableSpendsOrchard`` bit MUST be set to $0$. + +OrchardActionEffecting +'''''''''''''''''''''' + ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +| Bytes | Name | Data Type | Description | ++=============================+==========================+========================================+=====================================================================+ +|``32`` |``cv`` |``byte[32]`` |A value commitment to the net value of the input note minus the | +| | | |output note. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``32`` |``nullifier`` |``byte[32]`` |The nullifier of the input note. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``32`` |``rk`` |``byte[32]`` |The randomized validating key for this Action. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``32`` |``cmx`` |``byte[32]`` |The $x$-coordinate of the note commitment for the output note. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``32`` |``ephemeralKey`` |``byte[32]`` |An encoding of an ephemeral Pallas public key. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``580`` |``encCiphertext`` |``byte[580]`` |The encrypted contents of the note plaintext. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``80`` |``outCiphertext`` |``byte[80]`` |The encrypted contents of the byte string created by concatenation | +| | | |of the transmission key with the ephemeral secret key. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ + +Orchard Authorizing Data +```````````````````````` + +The authorizing data for the Orchard bundle contains the proofs and signatures +that authorize the actions. + ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +| Bytes | Name | Data Type | Description | ++=============================+==========================+========================================+=====================================================================+ +|``varies`` |``sizeProofsOrchard`` |``compactSize`` |Length in bytes of ``proofsOrchard``. Value is | +| | | |$2720 + 2272 \cdot \mathtt{nActionsOrchard}$. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``sizeProofsOrchard`` |``proofsOrchard`` |``byte[sizeProofsOrchard]`` |Encoding of aggregated zk-SNARK proofs for Orchard Actions. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``64 * nActionsOrchard`` |``vSpendAuthSigsOrchard`` |``byte[64 * nActionsOrchard]`` |Authorizing signatures for each Orchard Action. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``64`` |``bindingSigOrchard`` |``byte[64]`` |An Orchard binding signature on the SIGHASH transaction hash. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ + +* The value of ``nActionsOrchard`` is not re-encoded in the authorizing data; it + is taken from the corresponding effecting data. + +* The fields ``sizeProofsOrchard``, ``proofsOrchard``, and ``bindingSigOrchard`` + are present if and only if $\mathtt{nActionsOrchard} > 0$. + +* The proofs aggregated in ``proofsOrchard``, and the elements of + ``vSpendAuthSigsOrchard``, each have a 1:1 correspondence to the elements of + ``vActionsOrchard`` in the effecting data and MUST be ordered such that the + proof or signature at a given index corresponds to the + ``OrchardActionEffecting`` at the same index. + + Bundle type identifier ID Registry ---------------------------------- @@ -604,5 +860,6 @@ References .. [#protocol-subsidies] `Zcash Protocol Specification, Version 2025.6.3 [NU6.1]. Section 7.8: Block Subsidy and Founders' Reward `_ .. [#zip-0203] `ZIP 203: Transaction Expiry `_ .. [#zip-0212] `ZIP 212: Allow Recipient to Derive Ephemeral Secret from Note Plaintext `_ +.. [#zip-0225] `ZIP 225: Version 5 Transaction Format `_ .. [#zip-0239] `ZIP 239: Relay of Version 5 Transactions `_ From 9b529976f11bbbe5ccfe01059364620c6c63c0e7 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Sun, 25 Jan 2026 11:27:25 -0700 Subject: [PATCH 10/51] [ZIP 248]: Add digest algorithms for txid, signature, and auth commitment. Specifies the V6 transaction digest algorithms: - TxId digest with separate value_pool_deltas_digest and dynamic effects_bundles_digest - Signature digest for transparent input signing with hash_type support - Authorizing data commitment for witness data Key design decisions: - Value balances committed via top-level value_pool_deltas_digest (not per-bundle) - effects_bundles_digest uses tagged concatenation (bundle_type_id || root_hash) - Unknown bundle types supported by accepting their root hash externally Co-Authored-By: Claude Opus 4.5 --- zips/zip-0248.rst | 643 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 641 insertions(+), 2 deletions(-) diff --git a/zips/zip-0248.rst b/zips/zip-0248.rst index 4a125be7d..6b2c570c0 100644 --- a/zips/zip-0248.rst +++ b/zips/zip-0248.rst @@ -613,8 +613,644 @@ Full node implementations MUST verify that: \forall \mathsf{a}. \sum_{\mathsf{d} \in \mathsf{mValuePoolDeltas} | \mathsf{AssetUuid}_\mathsf{d} = \mathsf{a}} \mathsf{d.value} = 0 -V0 Digest Algorithm -------------------- +Digest Algorithms +----------------- + +All digests are personalized BLAKE2b-256 hashes. In cases where no elements are +available for hashing (for example, if there are no transparent transaction +inputs), a personalized hash of the empty byte array will be used. The +personalization string therefore provides domain separation for the hashes of +even empty data fields. + +The notation ``BLAKE2b-256(personalization_string, [])`` is used to refer to +hashes constructed in this manner. + +TxId Digest +``````````` + +A new transaction digest algorithm is defined that constructs the identifier for +a V6 transaction from a tree of hashes. The overall structure of the hash is as +follows:: + + txid_digest + ├── header_digest + ├── value_pool_deltas_digest + └── effects_bundles_digest + ├─ (bundle_type_id || transparent_effects_digest) + ├─ (bundle_type_id || sapling_effects_digest) + │ ├── sapling_spends_digest + │ │ ├── sapling_spends_compact_digest + │ │ └── sapling_spends_noncompact_digest + │ └── sapling_outputs_digest + │ ├── sapling_outputs_compact_digest + │ ├── sapling_outputs_memos_digest + │ └── sapling_outputs_noncompact_digest + ├─ (bundle_type_id || orchard_effects_digest) + │ ├── orchard_actions_compact_digest + │ ├── orchard_actions_memos_digest + │ └── orchard_actions_noncompact_digest + └─ (bundle_type_id || unknown_bundle_effects_digest) ... + +Each node written as ``snake_case`` in this tree is a BLAKE2b-256 hash of its +children, initialized with a personalization string specific to that branch +of the tree. Nodes that are not themselves digests are written in ``camelCase``. +In the specification below, nodes of the tree are presented in depth-first order. + +txid_digest +........... + +A BLAKE2b-256 hash of the following values:: + + T.1: header_digest (32-byte hash output) + T.2: value_pool_deltas_digest (32-byte hash output) + T.3: effects_bundles_digest (32-byte hash output) + +The personalization field of this hash is set to:: + + "ZcashTxHash_" || CONSENSUS_BRANCH_ID + +``ZcashTxHash_`` has 1 underscore character. + +As in ZIP 143 [#zip-0143]_, CONSENSUS_BRANCH_ID is the 4-byte little-endian +encoding of the consensus branch ID for the epoch of the block containing the +transaction. + +T.1: header_digest +.................. + +A BLAKE2b-256 hash of the following values:: + + T.1a: version (4-byte little-endian version identifier including overwintered flag) + T.1b: nVersionGroupId (4-byte little-endian version group identifier) + T.1c: nConsensusBranchId (4-byte little-endian consensus branch id) + T.1d: lock_time (4-byte little-endian nLockTime value) + T.1e: nExpiryHeight (4-byte little-endian block height) + +The personalization field of this hash is set to:: + + "ZTxIdHeadersHash" + +T.2: value_pool_deltas_digest +............................. + +A BLAKE2b-256 hash of the concatenated encodings of all entries in +``mValuePoolDeltas``, ordered by ``(bundleType, assetClass, assetUuid)``. +For each entry, the following values are concatenated:: + + T.2a: bundleType (compactSize encoding) + T.2b: assetClass (1 byte) + T.2c: assetUuid (0 or 64 bytes, depending on assetClass) + T.2d: value (8-byte signed little-endian) + +The personalization field of this hash is set to:: + + "ZTxIdVPDeltaHash" + +In the case that the transaction has no value pool delta entries (which would +only occur for transactions that have no effect on any value pool), +``value_pool_deltas_digest`` is:: + + BLAKE2b-256("ZTxIdVPDeltaHash", []) + +T.3: effects_bundles_digest +........................... + +A BLAKE2b-256 hash of the concatenated tagged bundle effect digests for all +bundles present in ``mEffectBundles``, ordered by ``bundleType``. For each +bundle, the following values are concatenated:: + + T.3a: bundleType (compactSize encoding) + T.3b: bundle_effects_digest (32-byte hash output) + +where ``bundle_effects_digest`` is the root hash of the bundle's effecting data +tree, as defined below for each known bundle type. + +The personalization field of this hash is set to:: + + "ZTxIdEffBndHash" + +In the case that the transaction has no effect bundles, ``effects_bundles_digest`` +is:: + + BLAKE2b-256("ZTxIdEffBndHash", []) + +For bundle types not recognized by a wallet, the wallet MUST be provided with the +32-byte ``bundle_effects_digest`` value in order to compute the transaction +identifier. This enables partial verification of transactions containing unknown +bundle types. + +T.3.0: transparent_effects_digest +''''''''''''''''''''''''''''''''' + +In the case that transparent inputs or outputs are present, the transparent +effects digest is a BLAKE2b-256 hash of the following values:: + + T.3.0a: prevouts_digest (32-byte hash) + T.3.0b: sequence_digest (32-byte hash) + T.3.0c: outputs_digest (32-byte hash) + +The personalization field of this hash is set to:: + + "ZTxIdTranspaHash" + +In the case that the transaction has no transparent components, +``transparent_effects_digest`` is:: + + BLAKE2b-256("ZTxIdTranspaHash", []) + +T.3.0a: prevouts_digest +~~~~~~~~~~~~~~~~~~~~~~~ + +A BLAKE2b-256 hash of the field encoding of all ``(prevout_hash, prevout_index)`` +pairs from the transparent effecting data. + +The personalization field of this hash is set to:: + + "ZTxIdPrevoutHash" + +In the case that the transaction has transparent outputs but no transparent +inputs, ``prevouts_digest`` is:: + + BLAKE2b-256("ZTxIdPrevoutHash", []) + +T.3.0b: sequence_digest +~~~~~~~~~~~~~~~~~~~~~~~ + +A BLAKE2b-256 hash of the 32-bit little-endian representation of all ``nSequence`` +field values from the transparent effecting data. + +The personalization field of this hash is set to:: + + "ZTxIdSequencHash" + +In the case that the transaction has transparent outputs but no transparent +inputs, ``sequence_digest`` is:: + + BLAKE2b-256("ZTxIdSequencHash", []) + +T.3.0c: outputs_digest +~~~~~~~~~~~~~~~~~~~~~~ + +A BLAKE2b-256 hash of the concatenated field encodings of all transparent +outputs. The field encoding of each output consists of the encoded output +``value`` (8-byte little endian) followed by the ``scriptPubKey`` byte array +(with leading ``compactSize`` length). + +The personalization field of this hash is set to:: + + "ZTxIdOutputsHash" + +In the case that the transaction has transparent inputs but no transparent +outputs, ``outputs_digest`` is:: + + BLAKE2b-256("ZTxIdOutputsHash", []) + +T.3.2: sapling_effects_digest +''''''''''''''''''''''''''''' + +In the case that Sapling spends or outputs are present, the Sapling effects +digest is a BLAKE2b-256 hash of the following values:: + + T.3.2a: sapling_spends_digest (32-byte hash) + T.3.2b: sapling_outputs_digest (32-byte hash) + T.3.2c: anchorSapling (32 bytes) + +The personalization field of this hash is set to:: + + "ZTxIdSaplingHash" + +Note that unlike ZIP 244, the value balance is not included here; it is committed +via ``value_pool_deltas_digest`` instead. + +In the case that the transaction has no Sapling spends or outputs, +``sapling_effects_digest`` is:: + + BLAKE2b-256("ZTxIdSaplingHash", []) + +T.3.2a: sapling_spends_digest +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In the case that Sapling spends are present, this digest is a BLAKE2b-256 hash +of the following values:: + + T.3.2a.i: sapling_spends_compact_digest (32-byte hash) + T.3.2a.ii: sapling_spends_noncompact_digest (32-byte hash) + +The personalization field of this hash is set to:: + + "ZTxIdSSpendsHash" + +In the case that the transaction has Sapling outputs but no Sapling spends, +``sapling_spends_digest`` is:: + + BLAKE2b-256("ZTxIdSSpendsHash", []) + +T.3.2a.i: sapling_spends_compact_digest +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A BLAKE2b-256 hash of the field encoding of all ``nullifier`` field values +of Sapling spends belonging to the transaction. + +The personalization field of this hash is set to:: + + "ZTxIdSSpendCHash" + +T.3.2a.ii: sapling_spends_noncompact_digest +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A BLAKE2b-256 hash of the non-nullifier information for all Sapling spends +belonging to the transaction. For each spend, the following elements are +included in the hash:: + + T.3.2a.ii.1: cv (32 bytes) + T.3.2a.ii.2: anchor (32 bytes) + T.3.2a.ii.3: rk (32 bytes) + +The anchor is hashed for *each* spend (even though it is shared in the encoding). + +The personalization field of this hash is set to:: + + "ZTxIdSSpendNHash" + +T.3.2b: sapling_outputs_digest +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In the case that Sapling outputs are present, this digest is a BLAKE2b-256 hash +of the following values:: + + T.3.2b.i: sapling_outputs_compact_digest (32-byte hash) + T.3.2b.ii: sapling_outputs_memos_digest (32-byte hash) + T.3.2b.iii: sapling_outputs_noncompact_digest (32-byte hash) + +The personalization field of this hash is set to:: + + "ZTxIdSOutputHash" + +In the case that the transaction has Sapling spends but no Sapling outputs, +``sapling_outputs_digest`` is:: + + BLAKE2b-256("ZTxIdSOutputHash", []) + +T.3.2b.i: sapling_outputs_compact_digest +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A BLAKE2b-256 hash of the subset of Sapling output information included in the +ZIP 307 [#zip-0307]_ ``CompactBlock`` format for all Sapling outputs belonging +to the transaction. For each output, the following elements are included:: + + T.3.2b.i.1: cmu (32 bytes) + T.3.2b.i.2: ephemeralKey (32 bytes) + T.3.2b.i.3: encCiphertext[..52] (first 52 bytes) + +The personalization field of this hash is set to:: + + "ZTxIdSOutC__Hash" (2 underscore characters) + +T.3.2b.ii: sapling_outputs_memos_digest +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A BLAKE2b-256 hash of the memo field data for all Sapling outputs belonging to +the transaction. For each output:: + + T.3.2b.ii.1: encCiphertext[52..564] (512 bytes, encrypted memo) + +The personalization field of this hash is set to:: + + "ZTxIdSOutM__Hash" (2 underscore characters) + +T.3.2b.iii: sapling_outputs_noncompact_digest +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A BLAKE2b-256 hash of the remaining Sapling output information not included in +the ``CompactBlock`` format. For each output:: + + T.3.2b.iii.1: cv (32 bytes) + T.3.2b.iii.2: encCiphertext[564..] (post-memo AEAD tag, 16 bytes) + T.3.2b.iii.3: outCiphertext (80 bytes) + +The personalization field of this hash is set to:: + + "ZTxIdSOutN__Hash" (2 underscore characters) + +T.3.3: orchard_effects_digest +''''''''''''''''''''''''''''' + +In the case that Orchard actions are present, the Orchard effects digest is a +BLAKE2b-256 hash of the following values:: + + T.3.3a: orchard_actions_compact_digest (32-byte hash) + T.3.3b: orchard_actions_memos_digest (32-byte hash) + T.3.3c: orchard_actions_noncompact_digest (32-byte hash) + T.3.3d: flagsOrchard (1 byte) + T.3.3e: anchorOrchard (32 bytes) + +The personalization field of this hash is set to:: + + "ZTxIdOrchardHash" + +Note that unlike ZIP 244, the value balance is not included here; it is committed +via ``value_pool_deltas_digest`` instead. + +In the case that the transaction has no Orchard actions, ``orchard_effects_digest`` +is:: + + BLAKE2b-256("ZTxIdOrchardHash", []) + +T.3.3a: orchard_actions_compact_digest +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A BLAKE2b-256 hash of the subset of Orchard action information intended for +inclusion in the ``CompactBlock`` format. For each action:: + + T.3.3a.i: nullifier (32 bytes) + T.3.3a.ii: cmx (32 bytes) + T.3.3a.iii: ephemeralKey (32 bytes) + T.3.3a.iv: encCiphertext[..52] (first 52 bytes) + +The personalization field of this hash is set to:: + + "ZTxIdOrcActCHash" + +T.3.3b: orchard_actions_memos_digest +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A BLAKE2b-256 hash of the memo field data for all Orchard actions. For each +action:: + + T.3.3b.i: encCiphertext[52..564] (512 bytes, encrypted memo) + +The personalization field of this hash is set to:: + + "ZTxIdOrcActMHash" + +T.3.3c: orchard_actions_noncompact_digest +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A BLAKE2b-256 hash of the remaining Orchard action information not intended for +inclusion in the ``CompactBlock`` format. For each action:: + + T.3.3c.i: cv (32 bytes) + T.3.3c.ii: rk (32 bytes) + T.3.3c.iii: encCiphertext[564..] (post-memo AEAD tag, 16 bytes) + T.3.3c.iv: outCiphertext (80 bytes) + +The personalization field of this hash is set to:: + + "ZTxIdOrcActNHash" + +Signature Digest +```````````````` + +A new per-input transaction digest algorithm is defined that constructs a hash +that may be signed by a transaction creator to commit to the effects of the +transaction. This follows closely the algorithm from ZIP 244 [#zip-0244]_. + +For transactions that have no transparent inputs, the signature digest is +identical to the transaction identifier digest. + +For transactions with transparent inputs, the signature digest replaces +``effects_bundles_digest`` with a ``signature_bundles_digest`` that incorporates +``hash_type``-dependent transparent signing data:: + + signature_digest + ├── header_digest + ├── value_pool_deltas_digest + └── signature_bundles_digest + +signature_digest +................ + +A BLAKE2b-256 hash of the following values:: + + S.1: header_digest (32-byte hash output) + S.2: value_pool_deltas_digest (32-byte hash output) + S.3: signature_bundles_digest (32-byte hash output) + +The personalization field of this hash is set to:: + + "ZcashTxHash_" || CONSENSUS_BRANCH_ID + +This value has the same personalization as the transaction identifier digest, +so that what is being signed in the case that there are no transparent inputs +is exactly the transaction id. + +S.3: signature_bundles_digest +............................. + +If the transaction has no transparent inputs, ``signature_bundles_digest`` is +identical to ``effects_bundles_digest``. + +Otherwise, ``signature_bundles_digest`` is constructed the same as +``effects_bundles_digest``, except that ``transparent_effects_digest`` is +replaced with ``transparent_sig_digest``. + +S.3.0: transparent_sig_digest +''''''''''''''''''''''''''''' + +This digest is a BLAKE2b-256 hash of the following values:: + + S.3.0a: hash_type (1 byte) + S.3.0b: prevouts_sig_digest (32-byte hash) + S.3.0c: amounts_sig_digest (32-byte hash) + S.3.0d: scriptpubkeys_sig_digest (32-byte hash) + S.3.0e: sequence_sig_digest (32-byte hash) + S.3.0f: outputs_sig_digest (32-byte hash) + S.3.0g: txin_sig_digest (32-byte hash) + +The personalization field of this hash is set to:: + + "ZTxIdTranspaHash" + +S.3.0a: hash_type +~~~~~~~~~~~~~~~~~ + +An 8-bit unsigned value. The ``SIGHASH`` encodings from the legacy script system +are used: one of ``SIGHASH_ALL`` (0x01), ``SIGHASH_NONE`` (0x02), or +``SIGHASH_SINGLE`` (0x03), optionally combined with ``SIGHASH_ANYONECANPAY`` (0x80). + +The following restrictions apply: + +- Using any undefined ``hash_type`` (not 0x01, 0x02, 0x03, 0x81, 0x82, or 0x83) + causes validation failure. +- Using ``SIGHASH_SINGLE`` without a corresponding output at the same index + causes validation failure. + +For signatures over Sapling Spends or Orchard Actions, ``hash_type`` is set to +``SIGHASH_ALL`` (0x01). + +S.3.0b: prevouts_sig_digest +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If the ``SIGHASH_ANYONECANPAY`` flag is not set, identical to ``prevouts_digest`` +(T.3.0a). + +Otherwise:: + + BLAKE2b-256("ZTxIdPrevoutHash", []) + +S.3.0c: amounts_sig_digest +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If the ``SIGHASH_ANYONECANPAY`` flag is not set, a BLAKE2b-256 hash of the +concatenation of the 8-byte signed little-endian representations of all ``value`` +fields for the coins spent by the transparent inputs to the transaction. + +The personalization field of this hash is set to:: + + "ZTxTrAmountsHash" + +If the ``SIGHASH_ANYONECANPAY`` flag is set:: + + BLAKE2b-256("ZTxTrAmountsHash", []) + +S.3.0d: scriptpubkeys_sig_digest +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If the ``SIGHASH_ANYONECANPAY`` flag is not set, a BLAKE2b-256 hash of the +concatenation of the field encodings (each including a leading ``compactSize``) +of all ``scriptPubKey`` fields for the coins spent by the transparent inputs. + +The personalization field of this hash is set to:: + + "ZTxTrScriptsHash" + +If the ``SIGHASH_ANYONECANPAY`` flag is set:: + + BLAKE2b-256("ZTxTrScriptsHash", []) + +S.3.0e: sequence_sig_digest +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Identical to ``sequence_digest`` (T.3.0b) regardless of ``hash_type``. + +S.3.0f: outputs_sig_digest +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If the sighash type is neither ``SIGHASH_SINGLE`` nor ``SIGHASH_NONE``, identical +to ``outputs_digest`` (T.3.0c). + +If the sighash type is ``SIGHASH_SINGLE`` and a transparent output exists at the +same index as the input being signed, a hash of that output's encoding. + +Otherwise:: + + BLAKE2b-256("ZTxIdOutputsHash", []) + +S.3.0g: txin_sig_digest +~~~~~~~~~~~~~~~~~~~~~~~ + +For signatures over a transparent input, a BLAKE2b-256 hash of:: + + S.3.0g.i: prevout (36 bytes: 32-byte hash + 4-byte index) + S.3.0g.ii: value (8-byte signed little-endian) + S.3.0g.iii: scriptPubKey (with compactSize length prefix) + S.3.0g.iv: nSequence (4-byte unsigned little-endian) + +The personalization field of this hash is set to:: + + "Zcash___TxInHash" (3 underscores) + +For signatures over a Sapling Spend or Orchard Action:: + + BLAKE2b-256("Zcash___TxInHash", []) + +Authorizing Data Commitment +``````````````````````````` + +A transaction digest algorithm is defined that constructs a digest committing to +the authorizing data of a transaction. The overall structure is:: + + auth_digest + └── auth_bundles_digest + ├─ (bundle_type_id || transparent_auth_digest) + ├─ (bundle_type_id || sapling_auth_digest) + ├─ (bundle_type_id || orchard_auth_digest) + └─ (bundle_type_id || unknown_bundle_auth_digest) ... + +auth_digest +........... + +A BLAKE2b-256 hash of the following value:: + + A.1: auth_bundles_digest (32-byte hash output) + +The personalization field of this hash is set to:: + + "ZTxAuthHash_" || CONSENSUS_BRANCH_ID + +For transaction versions before V6, a placeholder value consisting of 32 bytes +of ``0xFF`` is used in place of the authorizing data commitment. + +A.1: auth_bundles_digest +........................ + +A BLAKE2b-256 hash of the concatenated tagged bundle auth digests for all +bundles present in ``mAuthBundles``, ordered by ``bundleType``. For each +bundle, the following values are concatenated:: + + A.1a: bundleType (compactSize encoding) + A.1b: bundle_auth_digest (32-byte hash output) + +The personalization field of this hash is set to:: + + "ZTxAuthBndHash" + +In the case that the transaction has no auth bundles, ``auth_bundles_digest`` is:: + + BLAKE2b-256("ZTxAuthBndHash", []) + +A.1.0: transparent_auth_digest +'''''''''''''''''''''''''''''' + +In the case that the transaction contains transparent inputs, this is a +BLAKE2b-256 hash of the concatenated ``scriptSig`` values (each with leading +``compactSize`` length) for all transparent inputs. + +The personalization field of this hash is set to:: + + "ZTxAuthTransHash" + +In the case that the transaction has no transparent inputs:: + + BLAKE2b-256("ZTxAuthTransHash", []) + +A.1.2: sapling_auth_digest +'''''''''''''''''''''''''' + +In the case that Sapling spends or outputs are present, this is a BLAKE2b-256 +hash of the following concatenated values:: + + A.1.2a: vSpendProofsSapling (192 bytes per spend) + A.1.2b: vSpendAuthSigsSapling (64 bytes per spend) + A.1.2c: vOutputProofsSapling (192 bytes per output) + A.1.2d: bindingSigSapling (64 bytes) + +The personalization field of this hash is set to:: + + "ZTxAuthSapliHash" + +In the case that the transaction has no Sapling spends or outputs:: + + BLAKE2b-256("ZTxAuthSapliHash", []) + +A.1.3: orchard_auth_digest +'''''''''''''''''''''''''' + +In the case that Orchard actions are present, this is a BLAKE2b-256 hash of the +following concatenated values:: + + A.1.3a: proofsOrchard (aggregated proofs) + A.1.3b: vSpendAuthSigsOrchard (64 bytes per action) + A.1.3c: bindingSigOrchard (64 bytes) + +The personalization field of this hash is set to:: + + "ZTxAuthOrchaHash" + +In the case that the transaction has no Orchard actions:: + + BLAKE2b-256("ZTxAuthOrchaHash", []) + Rationale ========= @@ -858,8 +1494,11 @@ References .. [#protocol-blockchain] `Zcash Protocol Specification, Version 2025.6.3 [NU6.1]. Section 3.3: The Block Chain `_ .. [#protocol-networks] `Zcash Protocol Specification, Version 2025.6.3 [NU6.1]. Section 3.12: Mainnet and Testnet `_ .. [#protocol-subsidies] `Zcash Protocol Specification, Version 2025.6.3 [NU6.1]. Section 7.8: Block Subsidy and Founders' Reward `_ +.. [#zip-0143] `ZIP 143: Transaction Signature Validation for Overwinter `_ .. [#zip-0203] `ZIP 203: Transaction Expiry `_ .. [#zip-0212] `ZIP 212: Allow Recipient to Derive Ephemeral Secret from Note Plaintext `_ .. [#zip-0225] `ZIP 225: Version 5 Transaction Format `_ .. [#zip-0239] `ZIP 239: Relay of Version 5 Transactions `_ +.. [#zip-0244] `ZIP 244: Transaction Identifier Non-Malleability `_ +.. [#zip-0307] `ZIP 307: Light Client Protocol for Payment Detection `_ From 042c6fdc5f0479a8a46358539f9992ce5f559514 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Wed, 28 Jan 2026 10:59:59 -0700 Subject: [PATCH 11/51] [ZIP 248]: Add protocol bundles introduction and bundle type registration process. Restructure the specification to begin with a comprehensive introduction to protocol bundles, explaining effecting data, authorizing data, and the transparent transaction value pool concepts. Define the bundle type registration process that ZIPs must follow when introducing new bundle types. Move the bundle type registry to appear before the transaction format specification for better readability. Co-Authored-By: Claude Opus 4.5 --- zips/zip-0248.rst | 253 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 179 insertions(+), 74 deletions(-) diff --git a/zips/zip-0248.rst b/zips/zip-0248.rst index 6b2c570c0..e92c81db4 100644 --- a/zips/zip-0248.rst +++ b/zips/zip-0248.rst @@ -143,6 +143,185 @@ Non-requirements Specification ============= +Protocol Bundles +---------------- + +This ZIP refines and codifies the concept of "protocol bundles" that emerged +from the implementation of the ZIP 225 [#zip-0225]_ transaction format. It +makes bundles first-class objects and defines a registry of bundle type +identifiers. Within the period that a given transaction format version is used +on the Zcash network, the semantics of the bundle associated with a given +bundle type identifier are fixed. + +A **protocol bundle** is a self-contained component of a transaction that +implements a specific piece of protocol functionality. Each bundle type +defines: + +* What **effecting data** the bundle contains — the data that determines what + state changes the bundle produces (e.g., which notes are spent, which outputs + are created, which transparent UTXOs are consumed or produced). + +* What **authorizing data** the bundle contains — the proofs and signatures + that authorize the state changes specified by the effecting data. + +* How the bundle affects the **transparent transaction value pool** — whether + the bundle adds value to, removes value from, or has no effect on this + ephemeral pool that balances value flows within a transaction. + +Effecting Data and Authorizing Data +``````````````````````````````````` + +The separation of effecting data from authorizing data serves several purposes: + +1. **Transaction identifier stability**: The transaction identifier (txid) is + computed only from the effecting data. This means that the txid is + determined by *what* the transaction does, not by *how* it is authorized. + Third parties cannot change a transaction's identifier by modifying + signatures or proofs. + +2. **Efficient pruning**: Full nodes that have validated a transaction may + prune the authorizing data while retaining the effecting data. Since + authorizing data appears at the end of the encoded transaction, pruning + is simply truncation. + +3. **Partial validation**: A wallet that does not understand a particular + bundle type can still compute the transaction identifier by hashing the + effecting data opaquely, without needing to parse its internal structure. + +The Transparent Transaction Value Pool +`````````````````````````````````````` + +The transparent transaction value pool is an ephemeral concept that exists only +within the scope of processing a single transaction. It serves as a balancing +mechanism through which value flows between bundles. + +Each bundle may contribute a **value pool delta** — a signed value indicating +how much the bundle adds to or removes from the transparent transaction value +pool for a given asset. A positive delta means the bundle is adding value to +the pool (e.g., a shielded spend releasing value), while a negative delta means +the bundle is consuming value from the pool (e.g., a shielded output absorbing +value, or a transaction fee). + +For a valid non-coinbase transaction, the sum of all value pool deltas for each +asset MUST equal zero. This ensures that value is neither created nor destroyed +— it is only transferred between bundles within the transaction. + +For a coinbase transaction, the sum of value pool deltas for ZEC equals the +negative of the block subsidy, reflecting that the block subsidy implicitly +adds value to the transparent transaction value pool. + +Bundle Type Registration +```````````````````````` + +When a ZIP introduces a new bundle type, it MUST: + +1. Request allocation of a bundle type identifier from the registry defined + below. The identifier is a non-negative integer encoded as a ``compactSize`` + value. + +2. Specify whether entries for this bundle type are permitted in + ``mValuePoolDeltas`` (the value pool delta map). + +3. Specify whether entries for this bundle type are permitted in + ``mEffectBundles`` (the effecting data map). + +4. Specify whether entries for this bundle type are permitted in + ``mAuthBundles`` (the authorizing data map). + +5. If effecting data is permitted, define the encoding of that data. + +6. If authorizing data is permitted, define the encoding of that data. + +7. Define the digest algorithm for the bundle's contribution to the transaction + identifier, if effecting data is present. + +8. Define the digest algorithm for the bundle's contribution to the authorizing + data commitment, if authorizing data is present. + +A bundle type MUST NOT permit entries in ``mAuthBundles`` unless it also permits +entries in ``mEffectBundles``. That is, authorizing data cannot exist without +corresponding effecting data for a given bundle type. + +Once a bundle type identifier is assigned for a given transaction version, its +semantics are fixed for the lifetime of that transaction version. A subsequent +network upgrade may define a new transaction version that reassigns identifiers +or changes bundle semantics, but within a single transaction version, bundle +type identifiers have stable, unchanging meanings. + +V6 Transaction Bundle Type Registry +``````````````````````````````````` + +The following integers are registered as bundle type identifiers for the V6 +transaction format. All currently-defined IDs are encoded as single-byte +``compactSize`` values where they appear in the transaction format. + +The ``mValuePoolDeltas`` column indicates whether or not an entry for this +bundle type is permitted in ``mValuePoolDeltas``. For rows where an ❌ +is present, the value pool delta for every pool is guaranteed to be zero, and +so entries in ``mValuePoolDeltas`` are disallowed. + +The ``mEffectBundles`` column indicates whether or not an entry for this bundle +type is permitted in ``mEffectBundles``. For rows where an ❌ is present, the +bundle has no effecting data, and so no entry in ``mEffectBundles`` is +permitted. + +The ``mAuthBundles`` column indicates whether or not an entry for this bundle +type is permitted in ``mAuthBundles``. For rows where an ❌ is present, the +bundle has no authorizing data, and so no entry in ``mAuthBundles`` is +permitted. + ++------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ +| BundleType | ``mValuePoolDeltas`` | ``mEffectBundles`` | ``mAuthBundles`` | Bundle kind | ++============+======================+====================+==================+=============================================================+ +| 0 |✅ |✅ |✅ | Transparent | ++------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ +| 1 | | | | Reserved | ++------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ +| 2 |✅ |✅ |✅ | Sapling | ++------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ +| 3 |✅ |✅ |✅ | Orchard | ++------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ +| 4\* |✅ |❌ |❌ | Transaction fee (\*if ZIP 2002 activated) | ++------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ +| 5\* |✅ |❌ |❌ | ZIP 233 NSM field (\*if ZIP 233 activated) | ++------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ +| 6\* |❌ |✅ |✅ | ZIP 270 Key rotation (\*if ZIP 270 activated) | ++------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ +| 7\* |✅ |✅ |✅ | Lockbox disbursement / "Consensus accounts" | +| | | | | (\*for miner payouts, lockbox, etc if ZIP activated) | ++------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ +| |❌ |✅ |❌ | ZIP 231 Memos | ++------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ +| |✅ |✅ |✅ | Sapling-post-ZIP 231 (if ZIP 231 activated after this ZIP) | ++------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ +| |✅ |✅ |✅ | Orchard-post-ZIP 231 (if ZIP 231 activated after this ZIP) | ++------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ +| |✅ |✅ |✅ | ZSA Issuance | ++------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ +| |✅ |✅ |✅ | OrchardZSA | ++------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ + +The following entries are provided to illustrate how potential future upgrades +might affect the bundle registry: + ++------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ +| BundleType | ``mValuePoolDeltas`` | ``mEffectBundles`` | ``mAuthBundles`` | Bundle kind | ++============+======================+====================+==================+=============================================================+ +| |✅ |✅ |✅ | TZEs | ++------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ +| |✅ |✅ |✅ | Pool that only has a long-term storage protocol (PQ, very | +| | | | | simple thus insulated from counterfeiting fears, can be | +| | | | | used for payments but higher latency for that purpose) | ++------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ +| |✅ |✅ |✅ | Tachyon | ++------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ +| |✅ |✅ |❌ | Staking | ++------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ +| |✅ |✅ |✅ | Unstaking (if it can't be combined with the Staking bundle) | ++------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ +| |✅ |✅ |✅ | Post-quantum fast payment protocol | ++------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ + Transaction Format ------------------ @@ -502,80 +681,6 @@ that authorize the actions. ``OrchardActionEffecting`` at the same index. -Bundle type identifier ID Registry ----------------------------------- - -The following integers are registered as bundle type identifiers for the V6 -transaction format. All currently-defined IDs are encoded as single-byte -``CompactSize`` values where they appear in the transaction format. - -The ``mValuePoolDeltas`` column indicates whether or not an entry for this -value type is allowed to appear in ``mValuePoolDeltas``. For rows where an ❌ -is present, the value pool delta for every pool is guaranteed to be zero, and -so entries in ``mValuePoolDeltas`` are disallowed. - -The ``mEffectBundles`` column indicates whether or not an entry for this value -type is allowed to appear in ``mEffectBundles``. For rows where an ❌ is -present, the bundle is guaranteed to have no effecting or authorizing data, and -so no entry in ``mEffectBundles`` is permitted. - -The ``mAuthBundles`` column indicates whether or not an entry for this value -type is allowed to appear in ``mAuthBundles``. For rows where an ❌ is present, -the bundle is guaranteed to have no authorizing data, and so no entry in -``mAuthBundles`` is permitted. - -+------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ -| BundleType | ``mValuePoolDeltas`` | ``mEffectBundles`` | ``mAuthBundles`` | Bundle kind | -+============+======================+====================+==================+=============================================================+ -| 0 |✅ |✅ |✅ | Transparent | -+------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ -| 1 | | | | Reserved | -+------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ -| 2 |✅ |✅ |✅ | Sapling | -+------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ -| 3 |✅ |✅ |✅ | Orchard | -+------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ -| 4\* |✅ |❌ |❌ | Transaction fee (\*if ZIP 2002 activated) | -+------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ -| 5\* |✅ |❌ |❌ | ZIP 233 NSM field (\*if ZIP 233 activated) | -+------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ -| 6\* |❌ |✅ |✅ | ZIP 270 Key rotation (\*if ZIP 270 activated) | -+------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ -| 7\* |✅ |✅ |✅ | Lockbox disbursement / "Consensus accounts" | -| | | | | (\*for miner payouts, lockbox, etc if ZIP activated) | -+------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ -| |❌ |✅ |❌ | ZIP 231 Memos | -+------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ -| |✅ |✅ |✅ | Sapling-post-ZIP 231 (if ZIP 231 activated after this ZIP) | -+------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ -| |✅ |✅ |✅ | Orchard-post-ZIP 231 (if ZIP 231 activated after this ZIP) | -+------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ -| |✅ |✅ |✅ | ZSA Issuance | -+------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ -| |✅ |✅ |✅ | OrchardZSA | -+------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ - -The following entries are provided to illustrate how potential future upgrades -might affect the value pool delta map. - -+------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ -| BundleType | ``mValuePoolDeltas`` | ``mEffectBundles`` | ``mAuthBundles`` | Bundle kind | -+============+======================+====================+==================+=============================================================+ -| |✅ |✅ |✅ | TZEs | -+------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ -| |✅ |✅ |✅ | Pool that only has a long-term storage protocol (PQ, very | -| | | | | simple thus insulated from counterfeiting fears, can be | -| | | | | used for payments but higher latency for that purpose) | -+------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ -| |✅ |✅ |✅ | Tachyon | -+------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ -| |✅ |✅ |❌ | Staking | -+------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ -| |✅ |✅ |✅ | Unstaking (if it can't be combined with the Staking bundle) | -+------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ -| |✅ |✅ |✅ | Post-quantum fast payment protocol | -+------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ - Consensus Rules --------------- From a26f96c00220588870fb60cb10ae98dba8eb3d4b Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Wed, 28 Jan 2026 15:13:54 -0700 Subject: [PATCH 12/51] [ZIP 248]: Fix table rendering --- zips/zip-0248.rst | 127 +++++++++++++++++++++++++--------------------- 1 file changed, 68 insertions(+), 59 deletions(-) diff --git a/zips/zip-0248.rst b/zips/zip-0248.rst index e92c81db4..ca35ae395 100644 --- a/zips/zip-0248.rst +++ b/zips/zip-0248.rst @@ -434,17 +434,17 @@ Transparent Effecting Data The effecting data for the transparent bundle describes the transparent inputs being spent and the transparent outputs being created. -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -| Bytes | Name | Data Type | Description | -+=============================+==========================+========================================+=====================================================================+ -|``varies`` |``tx_in_count`` |``compactSize`` |Number of transparent inputs. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -|``varies`` |``tx_in_effecting`` |``TransparentInputEffecting[tx_in_count]``|Effecting data for each transparent input. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -|``varies`` |``tx_out_count`` |``compactSize`` |Number of transparent outputs. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -|``varies`` |``tx_out`` |``TransparentOutput[tx_out_count]`` |Transparent outputs. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ ++-----------------------------+--------------------------+------------------------------------------+---------------------------------------------------------------------+ +| Bytes | Name | Data Type | Description | ++=============================+==========================+==========================================+=====================================================================+ +|``varies`` |``tx_in_count`` |``compactSize`` |Number of transparent inputs. | ++-----------------------------+--------------------------+------------------------------------------+---------------------------------------------------------------------+ +|``varies`` |``tx_in_effecting`` |``TransparentInputEffecting[tx_in_count]``|Effecting data for each transparent input. | ++-----------------------------+--------------------------+------------------------------------------+---------------------------------------------------------------------+ +|``varies`` |``tx_out_count`` |``compactSize`` |Number of transparent outputs. | ++-----------------------------+--------------------------+------------------------------------------+---------------------------------------------------------------------+ +|``varies`` |``tx_out`` |``TransparentOutput[tx_out_count]`` |Transparent outputs. | ++-----------------------------+--------------------------+------------------------------------------+---------------------------------------------------------------------+ TransparentInputEffecting ''''''''''''''''''''''''' @@ -509,20 +509,20 @@ outputs. Unlike the V5 transaction format defined in ZIP 225 [#zip-0225]_, the value balance is not included here; it appears in ``mValuePoolDeltas`` instead. -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -| Bytes | Name | Data Type | Description | -+=============================+==========================+========================================+=====================================================================+ -|``varies`` |``nSpendsSapling`` |``compactSize`` |Number of Sapling Spend descriptions. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -|``96 * nSpendsSapling`` |``vSpendsSapling`` |``SaplingSpendEffecting[nSpendsSapling]``|Effecting data for each Sapling Spend. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -|``varies`` |``nOutputsSapling`` |``compactSize`` |Number of Sapling Output descriptions. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -|``756 * nOutputsSapling`` |``vOutputsSapling`` |``SaplingOutput[nOutputsSapling]`` |Sapling Output descriptions. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -|``32`` |``anchorSapling`` |``byte[32]`` |A root of the Sapling note commitment tree at some block height | -| | | |in the past. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ ++-----------------------------+--------------------------+-----------------------------------------+---------------------------------------------------------------------+ +| Bytes | Name | Data Type | Description | ++=============================+==========================+=========================================+=====================================================================+ +|``varies`` |``nSpendsSapling`` |``compactSize`` |Number of Sapling Spend descriptions. | ++-----------------------------+--------------------------+-----------------------------------------+---------------------------------------------------------------------+ +|``96 * nSpendsSapling`` |``vSpendsSapling`` |``SaplingSpendEffecting[nSpendsSapling]``|Effecting data for each Sapling Spend. | ++-----------------------------+--------------------------+-----------------------------------------+---------------------------------------------------------------------+ +|``varies`` |``nOutputsSapling`` |``compactSize`` |Number of Sapling Output descriptions. | ++-----------------------------+--------------------------+-----------------------------------------+---------------------------------------------------------------------+ +|``756 * nOutputsSapling`` |``vOutputsSapling`` |``SaplingOutput[nOutputsSapling]`` |Sapling Output descriptions. | ++-----------------------------+--------------------------+-----------------------------------------+---------------------------------------------------------------------+ +|``32`` |``anchorSapling`` |``byte[32]`` |A root of the Sapling note commitment tree at some block height | +| | | |in the past. | ++-----------------------------+--------------------------+-----------------------------------------+---------------------------------------------------------------------+ * The field ``anchorSapling`` is present if and only if $\mathtt{nSpendsSapling} > 0$. @@ -549,7 +549,8 @@ This is identical to ``OutputDescriptionV5`` as defined in ZIP 225 [#zip-0225]_. +=============================+==========================+========================================+=====================================================================+ |``32`` |``cv`` |``byte[32]`` |A value commitment to the net value of the output note. | +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -|``32`` |``cmu`` |``byte[32]`` |The $u$-coordinate of the note commitment for the output note. | +|``32`` |``cmu`` |``byte[32]`` |The :math:`u\!`-coordinate of the note commitment for the output | +| | | |note. | +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ |``32`` |``ephemeralKey`` |``byte[32]`` |An encoding of an ephemeral Jubjub public key. | +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ @@ -604,22 +605,22 @@ The effecting data for the Orchard bundle describes the Orchard actions. Unlike the V5 transaction format defined in ZIP 225 [#zip-0225]_, the value balance is not included here; it appears in ``mValuePoolDeltas`` instead. -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -| Bytes | Name | Data Type | Description | -+=============================+==========================+========================================+=====================================================================+ -|``varies`` |``nActionsOrchard`` |``compactSize`` |The number of Orchard Action descriptions. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -|``820 * nActionsOrchard`` |``vActionsOrchard`` |``OrchardActionEffecting[nActionsOrchard]``|Effecting data for each Orchard Action. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -|``1`` |``flagsOrchard`` |``byte`` |An 8-bit value representing a set of flags. Ordered from LSB to MSB: | -| | | | | -| | | |* ``enableSpendsOrchard`` | -| | | |* ``enableOutputsOrchard`` | -| | | |* The remaining bits are set to $0$. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -|``32`` |``anchorOrchard`` |``byte[32]`` |A root of the Orchard note commitment tree at some block height | -| | | |in the past. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ ++-----------------------------+--------------------------+-------------------------------------------+---------------------------------------------------------------------+ +| Bytes | Name | Data Type | Description | ++=============================+==========================+===========================================+=====================================================================+ +|``varies`` |``nActionsOrchard`` |``compactSize`` |The number of Orchard Action descriptions. | ++-----------------------------+--------------------------+-------------------------------------------+---------------------------------------------------------------------+ +|``820 * nActionsOrchard`` |``vActionsOrchard`` |``OrchardActionEffecting[nActionsOrchard]``|Effecting data for each Orchard Action. | ++-----------------------------+--------------------------+-------------------------------------------+---------------------------------------------------------------------+ +|``1`` |``flagsOrchard`` |``byte`` |An 8-bit value representing a set of flags. Ordered from LSB to MSB: | +| | | | | +| | | |* ``enableSpendsOrchard`` | +| | | |* ``enableOutputsOrchard`` | +| | | |* The remaining bits are set to :math:`0\!`. | ++-----------------------------+--------------------------+-------------------------------------------+---------------------------------------------------------------------+ +|``32`` |``anchorOrchard`` |``byte[32]`` |A root of the Orchard note commitment tree at some block height | +| | | |in the past. | ++-----------------------------+--------------------------+-------------------------------------------+---------------------------------------------------------------------+ * The fields ``flagsOrchard`` and ``anchorOrchard`` are present if and only if $\mathtt{nActionsOrchard} > 0$. @@ -639,7 +640,8 @@ OrchardActionEffecting +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ |``32`` |``rk`` |``byte[32]`` |The randomized validating key for this Action. | +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -|``32`` |``cmx`` |``byte[32]`` |The $x$-coordinate of the note commitment for the output note. | +|``32`` |``cmx`` |``byte[32]`` |The :math:`x\!`-coordinate of the note commitment for the output | +| | | |note. | +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ |``32`` |``ephemeralKey`` |``byte[32]`` |An encoding of an ephemeral Pallas public key. | +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ @@ -659,7 +661,7 @@ that authorize the actions. | Bytes | Name | Data Type | Description | +=============================+==========================+========================================+=====================================================================+ |``varies`` |``sizeProofsOrchard`` |``compactSize`` |Length in bytes of ``proofsOrchard``. Value is | -| | | |$2720 + 2272 \cdot \mathtt{nActionsOrchard}$. | +| | | |:math:`2720 + 2272 \cdot \mathtt{nActionsOrchard}\!`. | +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ |``sizeProofsOrchard`` |``proofsOrchard`` |``byte[sizeProofsOrchard]`` |Encoding of aggregated zk-SNARK proofs for Orchard Actions. | +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ @@ -762,7 +764,7 @@ of the tree. Nodes that are not themselves digests are written in ``camelCase``. In the specification below, nodes of the tree are presented in depth-first order. txid_digest -........... +''''''''''' A BLAKE2b-256 hash of the following values:: @@ -781,7 +783,7 @@ encoding of the consensus branch ID for the epoch of the block containing the transaction. T.1: header_digest -.................. +'''''''''''''''''' A BLAKE2b-256 hash of the following values:: @@ -796,7 +798,7 @@ The personalization field of this hash is set to:: "ZTxIdHeadersHash" T.2: value_pool_deltas_digest -............................. +''''''''''''''''''''''''''''' A BLAKE2b-256 hash of the concatenated encodings of all entries in ``mValuePoolDeltas``, ordered by ``(bundleType, assetClass, assetUuid)``. @@ -818,7 +820,7 @@ only occur for transactions that have no effect on any value pool), BLAKE2b-256("ZTxIdVPDeltaHash", []) T.3: effects_bundles_digest -........................... +''''''''''''''''''''''''''' A BLAKE2b-256 hash of the concatenated tagged bundle effect digests for all bundles present in ``mEffectBundles``, ordered by ``bundleType``. For each @@ -845,7 +847,7 @@ identifier. This enables partial verification of transactions containing unknown bundle types. T.3.0: transparent_effects_digest -''''''''''''''''''''''''''''''''' +................................. In the case that transparent inputs or outputs are present, the transparent effects digest is a BLAKE2b-256 hash of the following values:: @@ -911,7 +913,7 @@ outputs, ``outputs_digest`` is:: BLAKE2b-256("ZTxIdOutputsHash", []) T.3.2: sapling_effects_digest -''''''''''''''''''''''''''''' +............................. In the case that Sapling spends or outputs are present, the Sapling effects digest is a BLAKE2b-256 hash of the following values:: @@ -1038,7 +1040,7 @@ The personalization field of this hash is set to:: "ZTxIdSOutN__Hash" (2 underscore characters) T.3.3: orchard_effects_digest -''''''''''''''''''''''''''''' +............................. In the case that Orchard actions are present, the Orchard effects digest is a BLAKE2b-256 hash of the following values:: @@ -1123,7 +1125,7 @@ For transactions with transparent inputs, the signature digest replaces └── signature_bundles_digest signature_digest -................ +'''''''''''''''' A BLAKE2b-256 hash of the following values:: @@ -1140,7 +1142,7 @@ so that what is being signed in the case that there are no transparent inputs is exactly the transaction id. S.3: signature_bundles_digest -............................. +''''''''''''''''''''''''''''' If the transaction has no transparent inputs, ``signature_bundles_digest`` is identical to ``effects_bundles_digest``. @@ -1150,7 +1152,7 @@ Otherwise, ``signature_bundles_digest`` is constructed the same as replaced with ``transparent_sig_digest``. S.3.0: transparent_sig_digest -''''''''''''''''''''''''''''' +............................. This digest is a BLAKE2b-256 hash of the following values:: @@ -1273,7 +1275,7 @@ the authorizing data of a transaction. The overall structure is:: └─ (bundle_type_id || unknown_bundle_auth_digest) ... auth_digest -........... +''''''''''' A BLAKE2b-256 hash of the following value:: @@ -1287,7 +1289,7 @@ For transaction versions before V6, a placeholder value consisting of 32 bytes of ``0xFF`` is used in place of the authorizing data commitment. A.1: auth_bundles_digest -........................ +'''''''''''''''''''''''' A BLAKE2b-256 hash of the concatenated tagged bundle auth digests for all bundles present in ``mAuthBundles``, ordered by ``bundleType``. For each @@ -1305,7 +1307,7 @@ In the case that the transaction has no auth bundles, ``auth_bundles_digest`` is BLAKE2b-256("ZTxAuthBndHash", []) A.1.0: transparent_auth_digest -'''''''''''''''''''''''''''''' +.............................. In the case that the transaction contains transparent inputs, this is a BLAKE2b-256 hash of the concatenated ``scriptSig`` values (each with leading @@ -1320,7 +1322,7 @@ In the case that the transaction has no transparent inputs:: BLAKE2b-256("ZTxAuthTransHash", []) A.1.2: sapling_auth_digest -'''''''''''''''''''''''''' +.......................... In the case that Sapling spends or outputs are present, this is a BLAKE2b-256 hash of the following concatenated values:: @@ -1339,7 +1341,7 @@ In the case that the transaction has no Sapling spends or outputs:: BLAKE2b-256("ZTxAuthSapliHash", []) A.1.3: orchard_auth_digest -'''''''''''''''''''''''''' +.......................... In the case that Orchard actions are present, this is a BLAKE2b-256 hash of the following concatenated values:: @@ -1584,6 +1586,13 @@ Questions and encoded at the end of the transaction in a batch, so that pruning is simply truncation? +* The light wallet protocol will be updated to allow the client to specify the + set of bundle types that the client understands. In the case that this + information is provided, the light client server will then send the root + hashes for each bundle type that the client **does not** understand when + returning raw transaction data, so that the light client can correctly + recompute and validate the txid; also, the compact transactions can be pruned + to exclude bundles of bundle types. that the client will not understand. TODO ==== From 4399afa217b3a698ce5018fa078aecb6f40c1016 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Wed, 28 Jan 2026 15:37:56 -0700 Subject: [PATCH 13/51] [ZIP 248]: Fold away rationale & potental future bundle types spec. --- zips/zip-0248.rst | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/zips/zip-0248.rst b/zips/zip-0248.rst index ca35ae395..fde6cc129 100644 --- a/zips/zip-0248.rst +++ b/zips/zip-0248.rst @@ -168,8 +168,13 @@ defines: the bundle adds value to, removes value from, or has no effect on this ephemeral pool that balances value flows within a transaction. -Effecting Data and Authorizing Data -``````````````````````````````````` +Rationale for Effecting Data and Authorizing Data +````````````````````````````````````````````````` + +.. raw:: html + +
+ Click to show/hide The separation of effecting data from authorizing data serves several purposes: @@ -188,6 +193,10 @@ The separation of effecting data from authorizing data serves several purposes: bundle type can still compute the transaction identifier by hashing the effecting data opaquely, without needing to parse its internal structure. +.. raw:: html + +
+ The Transparent Transaction Value Pool `````````````````````````````````````` @@ -215,9 +224,8 @@ Bundle Type Registration When a ZIP introduces a new bundle type, it MUST: -1. Request allocation of a bundle type identifier from the registry defined - below. The identifier is a non-negative integer encoded as a ``compactSize`` - value. +1. Request allocation of a bundle type identifier in the registry defined + below. The identifier must be a non-negative integer. 2. Specify whether entries for this bundle type are permitted in ``mValuePoolDeltas`` (the value pool delta map). @@ -301,6 +309,14 @@ permitted. | |✅ |✅ |✅ | OrchardZSA | +------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ +Potential Future Bundle Types +````````````````````````````` + +.. raw:: html + +
+ Click to show/hide + The following entries are provided to illustrate how potential future upgrades might affect the bundle registry: @@ -322,6 +338,10 @@ might affect the bundle registry: | |✅ |✅ |✅ | Post-quantum fast payment protocol | +------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ +.. raw:: html + +
+ Transaction Format ------------------ @@ -717,7 +737,7 @@ Full node implementations MUST verify that: asset equals 0. .. math:: - + \forall \mathsf{a}. \sum_{\mathsf{d} \in \mathsf{mValuePoolDeltas} | \mathsf{AssetUuid}_\mathsf{d} = \mathsf{a}} \mathsf{d.value} = 0 Digest Algorithms From a69ea19a74545ac93c48d82a7f9a84f2d4b87a04 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Fri, 30 Jan 2026 14:05:34 -0700 Subject: [PATCH 14/51] [ZIP 248]: Address PR review comments. - Update PR URL to 1156 and fix email addresses - Use conformance language (MAY/MUST NOT) for registry column descriptions - Add constraint that map keys must be in increasing order - Change "ordered by" to "in increasing order of" throughout - Fix "transparent transaction value pool" terminology - Change AssetUuid subscript notation to function notation - Add registry update mechanism language - Add "Defining ZIP" column to bundle type registry table - Rephrase consensus rules section to clarify modifications to protocol spec - Add clarifying text for fee bundle semantics (coinbase collects, others pay) - Add mutual exclusion consensus rule for Sapling/Orchard bundle variants Co-Authored-By: Claude Opus 4.5 --- zips/zip-0248.rst | 132 ++++++++++++++++++++++++++-------------------- 1 file changed, 76 insertions(+), 56 deletions(-) diff --git a/zips/zip-0248.rst b/zips/zip-0248.rst index fde6cc129..edec266bf 100644 --- a/zips/zip-0248.rst +++ b/zips/zip-0248.rst @@ -264,50 +264,53 @@ transaction format. All currently-defined IDs are encoded as single-byte ``compactSize`` values where they appear in the transaction format. The ``mValuePoolDeltas`` column indicates whether or not an entry for this -bundle type is permitted in ``mValuePoolDeltas``. For rows where an ❌ +bundle type MAY appear in ``mValuePoolDeltas``. For rows where an ❌ is present, the value pool delta for every pool is guaranteed to be zero, and -so entries in ``mValuePoolDeltas`` are disallowed. +so entries in ``mValuePoolDeltas`` MUST NOT be present. The ``mEffectBundles`` column indicates whether or not an entry for this bundle -type is permitted in ``mEffectBundles``. For rows where an ❌ is present, the -bundle has no effecting data, and so no entry in ``mEffectBundles`` is -permitted. +type MAY appear in ``mEffectBundles``. For rows where an ❌ is present, the +bundle has no effecting data, and so an entry in ``mEffectBundles`` MUST NOT +be present. The ``mAuthBundles`` column indicates whether or not an entry for this bundle -type is permitted in ``mAuthBundles``. For rows where an ❌ is present, the -bundle has no authorizing data, and so no entry in ``mAuthBundles`` is -permitted. - -+------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ -| BundleType | ``mValuePoolDeltas`` | ``mEffectBundles`` | ``mAuthBundles`` | Bundle kind | -+============+======================+====================+==================+=============================================================+ -| 0 |✅ |✅ |✅ | Transparent | -+------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ -| 1 | | | | Reserved | -+------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ -| 2 |✅ |✅ |✅ | Sapling | -+------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ -| 3 |✅ |✅ |✅ | Orchard | -+------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ -| 4\* |✅ |❌ |❌ | Transaction fee (\*if ZIP 2002 activated) | -+------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ -| 5\* |✅ |❌ |❌ | ZIP 233 NSM field (\*if ZIP 233 activated) | -+------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ -| 6\* |❌ |✅ |✅ | ZIP 270 Key rotation (\*if ZIP 270 activated) | -+------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ -| 7\* |✅ |✅ |✅ | Lockbox disbursement / "Consensus accounts" | -| | | | | (\*for miner payouts, lockbox, etc if ZIP activated) | -+------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ -| |❌ |✅ |❌ | ZIP 231 Memos | -+------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ -| |✅ |✅ |✅ | Sapling-post-ZIP 231 (if ZIP 231 activated after this ZIP) | -+------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ -| |✅ |✅ |✅ | Orchard-post-ZIP 231 (if ZIP 231 activated after this ZIP) | -+------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ -| |✅ |✅ |✅ | ZSA Issuance | -+------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ -| |✅ |✅ |✅ | OrchardZSA | -+------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ +type MAY appear in ``mAuthBundles``. For rows where an ❌ is present, the +bundle has no authorizing data, and so an entry in ``mAuthBundles`` MUST NOT +be present. + ++------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ +| BundleType | ``mValuePoolDeltas`` | ``mEffectBundles`` | ``mAuthBundles`` | Defining ZIP | Bundle kind | ++============+======================+====================+==================+==============+==============================================+ +| 0 |✅ |✅ |✅ | This ZIP | Transparent | ++------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ +| 1 | | | | | Reserved | ++------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ +| 2 |✅ |✅ |✅ | This ZIP | Sapling | ++------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ +| 3 |✅ |✅ |✅ | This ZIP | Orchard | ++------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ +| 4 |✅ |❌ |❌ | ZIP 2002 | Transaction fee | ++------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ +| 5 |✅ |❌ |❌ | ZIP 233 | ZIP 233 NSM field | ++------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ +| 6 |❌ |✅ |✅ | ZIP 270 | Key rotation | ++------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ +| 7 |✅ |✅ |✅ | TBD | Lockbox disbursement | ++------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ +| |❌ |✅ |❌ | ZIP 231 | Memos | ++------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ +| |✅ |✅ |✅ | ZIP 231 | Sapling-post-ZIP 231 | ++------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ +| |✅ |✅ |✅ | ZIP 231 | Orchard-post-ZIP 231 | ++------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ +| |✅ |✅ |✅ | ZIP 227 | ZSA Issuance | ++------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ +| |✅ |✅ |✅ | ZIP 226 | OrchardZSA | ++------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ + +Additional bundle types MAY be added to this registry via modifications to this +ZIP specified in other ZIPs. Such modifications MUST specify all of the +information required by the `Bundle Type Registration`_ section above. Potential Future Bundle Types ````````````````````````````` @@ -386,10 +389,11 @@ Transaction Format | varies |``mAuthBundles`` |``BundleData[nAuthBundles]`` |A map from bundle identifier to the authorizing data of a bundle. | +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ -``mEffectBundles`` and ``mAuthBundles`` are interpreted as a maps keyed by -bundle type. Each map MUST NOT contain more than a single entry for a given -key. For each key that exists in ``mAuthBundles``, a corresponding entry -must exist in ``mEffectBundles``. +``mEffectBundles`` and ``mAuthBundles`` are interpreted as maps keyed by +bundle type. The entries in each map MUST be in increasing order of key. +Each map MUST NOT contain more than a single entry for a given key. For each +key that exists in ``mAuthBundles``, a corresponding entry must exist in +``mEffectBundles``. ValuePoolDelta -------------- @@ -406,8 +410,8 @@ ValuePoolDelta | | | |array containing a universally unique 64-byte identifier for the | | | | |asset. | +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ -| 8 |``value`` |``nonzero int64`` |The net change to the transparent value pool of the given asset | -| | | |produced by the bundle corresponding to the bundle type identifier. | +| 8 |``value`` |``nonzero int64`` |The net change to the transparent transaction value pool for the | +| | | |given asset, produced by the bundle with this bundle type identifier.| | | | |This value MUST be nonzero; if a ``ValuePoolDelta`` record would | | | | |have zero value, it MUST be elided from the encoding | | | | |of ``mValuePoolDeltas`` instead. | @@ -418,15 +422,15 @@ $(\mathsf{BundleType}, \mathsf{AssetUuid}).$ The map MUST NOT contain more than a single entry for a given key. Lookups in this map are denoted with the syntax $\mathsf{mValuePoolDeltas}[(\mathsf{BundleType}, \mathsf{AssetUuid})].$ -Let $\mathsf{AssetUuid}_\mathsf{d}$ be the asset indicated by the ``mValuePoolDeltas`` entry $\mathsf{d}.$ +Let $\mathsf{AssetUuid}(\mathsf{d})$ be the asset indicated by the ``mValuePoolDeltas`` entry $\mathsf{d}.$ .. math:: - \mathsf{AssetUuid} = + \mathsf{AssetUuid}(\mathsf{d}) = \begin{cases} \mathsf{Zec} & \text{if } \mathsf{d}.\mathsf{assetClass} = 0 \\ \mathsf{d}.\mathsf{assetUuid} & \text{if } \mathsf{d}.\mathsf{assetClass} = 1 \\ - \bot \text{otherwise} + \bot & \text{otherwise} \end{cases} BundleData @@ -706,20 +710,36 @@ that authorize the actions. Consensus Rules --------------- +This ZIP requires the following modifications to the consensus rules in the +Zcash Protocol Specification. + Let ``FeeBundleId`` be the identifier of the fee bundle. In V6 transactions, $\mathsf{FeeBundleId} = 4$ as defined in the table above. -Full node implementations MUST verify that: +The following transaction validity rules are added: * The ``assetClass`` value for any entry in ``mValuePoolDeltas`` having ``bundleType = FeeBundleId`` is 0 (fee amounts are denominated in ZEC and no other asset.) -* For coinbase transaction, the value of $\mathsf{mValuePoolDeltas}[(\mathsf{FeeBundleId}, \mathsf{Zec})]$ must be nonnegative. +* For coinbase transactions, the value of $\mathsf{mValuePoolDeltas}[(\mathsf{FeeBundleId}, \mathsf{Zec})]$ + must be nonnegative. This represents the total transaction fees collected from + all other transactions in the block. -* For non-coinbase transactions, the value of $\mathsf{mValuePoolDeltas}[(\mathsf{FeeBundleId}, \mathsf{Zec})]$ must be nonpositive. +* For non-coinbase transactions, the value of $\mathsf{mValuePoolDeltas}[(\mathsf{FeeBundleId}, \mathsf{Zec})]$ + must be nonpositive. This represents the transaction fee paid by the + transaction (expressed as a negative value, since it is removed from the + transparent transaction value pool). * Within the scope of a block, the sum of the fee bundle values must equal 0. + That is, the fees collected by the coinbase transaction must equal the sum of + fees paid by all other transactions in the block. + +* Certain bundle types are mutually exclusive: a transaction MUST NOT contain + more than one bundle from each of the following sets: + + * {Sapling, Sapling-post-ZIP-231} + * {Orchard, Orchard-post-ZIP-231, OrchardZSA} * For the coinbase transaction, the sum of value pool deltas in the ZEC asset is equal to the negative of the block subsidy for that block; the block @@ -728,7 +748,7 @@ Full node implementations MUST verify that: .. math:: - \sum_{\mathsf{d} \in \mathsf{mValuePoolDeltas} | \mathsf{AssetUuid}_\mathsf{d} = \mathsf{Zec}} \mathsf{d.value} = -\mathsf{BlockSubsidy}(\mathsf{height}) + \sum_{\mathsf{d} \in \mathsf{mValuePoolDeltas} | \mathsf{AssetUuid}(\mathsf{d}) = \mathsf{Zec}} \mathsf{d.value} = -\mathsf{BlockSubsidy}(\mathsf{height}) where $\mathsf{BlockSubsidy}$ is defined in § 7.8 'Block Subsidy and Founders' Reward'. [#protocol-subsidies]_ @@ -738,7 +758,7 @@ Full node implementations MUST verify that: .. math:: - \forall \mathsf{a}. \sum_{\mathsf{d} \in \mathsf{mValuePoolDeltas} | \mathsf{AssetUuid}_\mathsf{d} = \mathsf{a}} \mathsf{d.value} = 0 + \forall \mathsf{a}. \sum_{\mathsf{d} \in \mathsf{mValuePoolDeltas} | \mathsf{AssetUuid}(\mathsf{d}) = \mathsf{a}} \mathsf{d.value} = 0 Digest Algorithms ----------------- @@ -821,7 +841,7 @@ T.2: value_pool_deltas_digest ''''''''''''''''''''''''''''' A BLAKE2b-256 hash of the concatenated encodings of all entries in -``mValuePoolDeltas``, ordered by ``(bundleType, assetClass, assetUuid)``. +``mValuePoolDeltas``, in increasing order of ``(bundleType, assetClass, assetUuid)``. For each entry, the following values are concatenated:: T.2a: bundleType (compactSize encoding) @@ -843,7 +863,7 @@ T.3: effects_bundles_digest ''''''''''''''''''''''''''' A BLAKE2b-256 hash of the concatenated tagged bundle effect digests for all -bundles present in ``mEffectBundles``, ordered by ``bundleType``. For each +bundles present in ``mEffectBundles``, in increasing order of ``bundleType``. For each bundle, the following values are concatenated:: T.3a: bundleType (compactSize encoding) @@ -1312,7 +1332,7 @@ A.1: auth_bundles_digest '''''''''''''''''''''''' A BLAKE2b-256 hash of the concatenated tagged bundle auth digests for all -bundles present in ``mAuthBundles``, ordered by ``bundleType``. For each +bundles present in ``mAuthBundles``, in increasing order of ``bundleType``. For each bundle, the following values are concatenated:: A.1a: bundleType (compactSize encoding) From f75111b70399d222fd8dd5ef1be6295f4a74901e Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Wed, 4 Feb 2026 14:18:10 -0700 Subject: [PATCH 15/51] [ZIP 2002]: Propose to register ZIP 248 bundle type 4. - Register bundle type 4 (Transaction fee) in the V6 bundle registry - Update consensus rules to use mValuePoolDeltas terminology - Replace header_digest modification with value_pool_deltas_digest reference - Add reference to extensible transaction format ZIP Co-Authored-By: Claude Opus 4.5 --- zips/zip-0248.rst | 3 ++ zips/zip-2002.rst | 91 ++++++++++++++++++++++++++--------------------- 2 files changed, 54 insertions(+), 40 deletions(-) diff --git a/zips/zip-0248.rst b/zips/zip-0248.rst index edec266bf..bcc2f6536 100644 --- a/zips/zip-0248.rst +++ b/zips/zip-0248.rst @@ -422,6 +422,9 @@ $(\mathsf{BundleType}, \mathsf{AssetUuid}).$ The map MUST NOT contain more than a single entry for a given key. Lookups in this map are denoted with the syntax $\mathsf{mValuePoolDeltas}[(\mathsf{BundleType}, \mathsf{AssetUuid})].$ +Let $\mathsf{Zec}$ be a distinguished value representing the ZEC asset. It is +used as the asset identifier when $\mathsf{assetClass} = 0$. + Let $\mathsf{AssetUuid}(\mathsf{d})$ be the asset indicated by the ``mValuePoolDeltas`` entry $\mathsf{d}.$ .. math:: diff --git a/zips/zip-2002.rst b/zips/zip-2002.rst index 0abbda89e..083a22679 100644 --- a/zips/zip-2002.rst +++ b/zips/zip-2002.rst @@ -32,10 +32,12 @@ The terms "Mainnet" and "Testnet" are to be interpreted as described in Abstract ======== -This proposal adds an explicit ``fee`` field to the v6 transaction format. -Instead of fees being implicit in the difference between the input value and -output value of the transaction, all value transfers, including fee transfers to -miners, will be explicit and committed to via the txid. +This proposal makes the transaction fee explicit in the v6 transaction format, +as an entry in the transparent transaction value pool balance map defined in +ZIP 248 [#zip-0248]_. Instead of fees being implicit in the difference between +the input value and output value of the transaction, all value transfers, +including fee transfers to miners, will be explicit and committed to via the +txid. Motivation @@ -68,53 +70,65 @@ needed to compute it. Specification ============= -Changes to ZIP 230 [#zip-0230]_ -------------------------------- +Changes to ZIP 248 +------------------ -The following field is appended to the Common Transaction Fields of the v6 -transaction format after ``nExpiryHeight`` [#zip-0230-transaction-format]_: +This ZIP proposes to register bundle type 4 ("Transaction fee") in the V6 +transaction bundle type registry defined in ZIP 248 [#zip-0248]_. -+-------+---------+------------+------------------------------------------------------+ -| Bytes | Name | Data Type | Description | -+=======+=========+============+======================================================+ -| 8 | ``fee`` | ``uint64`` | The fee to be paid by this transaction, in zatoshis. | -+-------+---------+------------+------------------------------------------------------+ ++------------+----------------------+--------------------+------------------+ +| BundleType | ``mValuePoolDeltas`` | ``mEffectBundles`` | ``mAuthBundles`` | ++============+======================+====================+==================+ +| 4 |✅ |❌ |❌ | ++------------+----------------------+--------------------+------------------+ -Note: If both this ZIP and ZIP 233 are selected for inclusion in the same -Network Upgrade, then the ordering of fields in the transaction format will -be ``fee`` and then ``zip233Amount``. +The fee bundle has no effecting data and no authorizing data. The transaction +fee is represented solely as an entry in ``mValuePoolDeltas`` with +``bundleType = 4`` and ``assetClass = 0`` (ZEC). + +For non-coinbase transactions, the ``value`` field of this entry MUST be +nonpositive, representing the fee being removed from the transparent +transaction value pool. For coinbase transactions, the ``value`` field MUST be +nonnegative, representing the total fees collected from other transactions in +the block being added to the ZEC transparent transaction value pool. Changes to the Zcash Protocol Specification ------------------------------------------- -In § 3.4 ‘Transactions and Treestates’ [#protocol-transactions]_ (last modified by -ZIP 236 [#zip-0236]_), add the following consensus rule and note: +Let $\mathsf{FeeBundleId} = 4.$ + +Let $\mathsf{Zec}$ be the asset UUID for ZEC as defined in ZIP 248 [#zip-0248]_. + +In § 3.4 'Transactions and Treestates' [#protocol-transactions]_ (last modified by +ZIP 236 [#zip-0236]_), add the following consensus rules: - * [NU7 onward] For v6 and later transactions, the remaining value in the - transparent transaction value pool, in zatoshis, MUST be equal to the value - of the transaction’s ``fee`` field. - - Non-normative note: The effect of these rules is that the ``fee`` field of - v6 and later coinbase transactions will always be zero. + * [NU7 onward] The ``assetClass`` for any entry in ``mValuePoolDeltas`` having + ``bundleType`` $= \mathsf{FeeBundleId}$ MUST be 0. That is, fee amounts MUST + be denominated in ZEC. -In § 7.1 ‘Transaction Encoding and Consensus’ [#protocol-txnconsensus]_, add: + * [NU7 onward] For v6 and later non-coinbase transactions, the value of + $\mathsf{mValuePoolDeltas}[(\mathsf{FeeBundleId}, \mathsf{Zec})]$ MUST be + nonpositive. Its absolute value represents the transaction fee in zatoshis. - [NU7 onward] ``fee`` MUST be in the range $\{ 0 .. \mathsf{MAX\_MONEY} \}$. + * [NU7 onward] For v6 and later coinbase transactions, the value of + $\mathsf{mValuePoolDeltas}[(\mathsf{FeeBundleId}, \mathsf{Zec})]$ MUST be + nonnegative. It represents the total transaction fees collected from all + other transactions in the block. +In § 7.1 'Transaction Encoding and Consensus' [#protocol-txnconsensus]_, add: -Modifications relative to ZIP 244 [#zip-0244]_ ----------------------------------------------- + [NU7 onward] The absolute value of the fee bundle's value pool delta MUST + be in the range $\{ 0 .. \mathsf{MAX\_MONEY} \}$. -Relative to the sighash algorithm defined in ZIP 244, the sighash algorithm -that applies to v6 transactions differs by appending the ``fee`` field to -the Common Transaction Fields that are the input to the digest in -T.1: header_digest [#zip-0244-header-digest]_:: - T.1f: fee (8-byte little-endian fee amount) +Modifications to Digest Algorithms +---------------------------------- -Note: If both this ZIP and ZIP 233 are selected for inclusion in the same -Network Upgrade, then the ambiguity in ordering of the fields added by these -ZIPs would need to be resolved. +The fee amount is committed to the transaction identifier and signature +digest via the ``value_pool_deltas_digest`` defined in ZIP 248 [#zip-0248]_. +Since the fee bundle (bundle type 4) has no effecting data and no authorizing +data, its only contribution to the transaction digest is through its entry +in ``mValuePoolDeltas``. Applicability @@ -147,8 +161,5 @@ References .. [#bitcointalk-fee-error] `Bitcoin Forum post by @Voiceeeeee, March 8, 2017. "PLEASE HELP.. I sent a transaction with a 2.5 BTC transaction fee" `_ .. [#zip-0200] `ZIP 200: Network Upgrade Mechanism `_ .. [#zip-0230] `ZIP 230: Version 6 Transaction Format `_ -.. [#zip-0230-transaction-format] `ZIP 230: Version 6 Transaction Format — Specification: Transaction Format `_ .. [#zip-0236] `ZIP 236: Blocks should balance exactly `_ -.. [#zip-0244] `ZIP 244: Transaction Identifier Non-Malleability `_ -.. [#zip-0244-header-digest] `ZIP 244: Transaction Identifier Non-Malleability. Section T.1: Header Digest `_ -.. [#zip-0246] `ZIP 246: Digests for the Version 6 Transaction Format `_ +.. [#zip-0248] `ZIP 248: Extensible Transaction Format `_ From d9b1be5767e3c40c809b86a68de88f3b90c0af1e Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Wed, 4 Feb 2026 14:21:02 -0700 Subject: [PATCH 16/51] [ZIP 233]: Propose to register ZIP 248 bundle type 5. - Register bundle type 5 (NSM field) in the V6 bundle registry - Update consensus rules to use mValuePoolDeltas terminology - Replace header_digest modification with value_pool_deltas_digest reference - Add reference to extensible transaction format ZIP Co-Authored-By: Claude Opus 4.5 --- zips/zip-0233.md | 109 +++++++++++++++++++++++++---------------------- 1 file changed, 57 insertions(+), 52 deletions(-) diff --git a/zips/zip-0233.md b/zips/zip-0233.md index 54ed1bc6a..85abd8f7f 100644 --- a/zips/zip-0233.md +++ b/zips/zip-0233.md @@ -81,25 +81,31 @@ design shared by Bitcoin-like systems: # Privacy Implications -ZIP 233 adds a new type of transparent transaction event that is fully visible to chain -observers, and linked to other events performed in the transaction. The removal of -funds from circulation does not affect shielded outputs, and therefore does not alter -the privacy properties of shielded funds. +ZIP 233 adds a new type of transparent transaction event that is fully visible +to chain observers, and linked to other events performed in the transaction. +The removal of funds from circulation does represent a potential distinguisher; +transactions that intentionally remove funds from circulation are likely to +represent a small fraction of Zcash transactions, and so this will provide +another tool that adversaries may use to be able to segment users of the +network. # Requirements -- The mechanism enables users to remove funds from the circulating supply, and each removal event is explicitly specified in the corresponding transaction. -- The process is publicly auditable, allowing network participants to verify the amount and occurrence of funds removed from circulation. +- The mechanism enables users to remove funds from the circulating supply, and + each removal event is explicitly specified in the corresponding transaction. +- The process is publicly auditable, allowing network participants to verify + the amount and occurrence of funds removed from circulation. # Specification -## Transaction Field +## Changes to ZIP 248 -Each transaction gains a $\mathsf{zip233\_amount}$ property, specifying the -value in zatoshis that is removed from circulation when the transaction is -mined. The value removed from circulation subtracts from the remaining value in -the "transparent transaction value pool" as described in § 3.4 ‘Transactions and -Treestates’ [^protocol-transactions]. +This ZIP proposes to register bundle type 5 ("ZIP 233 NSM field") in the V6 +transaction bundle type registry defined in ZIP 248 [^zip-0248]. + +| BundleType | `mValuePoolDeltas` | `mEffectBundles` | `mAuthBundles` | +|------------|--------------------| -----------------|----------------| +| 5 |✅ |❌ |❌ | $\mathsf{zip233\_amount}$ does not result in an output being produced in any chain value pool, and therefore from the point at which the transaction is @@ -109,54 +115,57 @@ through to the end of the block in which the transaction is mined. ZIP 234 [^zip-0234] specifies a mechanism by which the funds removed from circulation may be reissued through future block subsidies. -## Changes to ZIP 230 [^zip-0230] - -The following field is appended to the Common Transaction Fields of the v6 -transaction format after `nExpiryHeight` [^zip-0230-transaction-format]: +The NSM bundle has no effecting data and no authorizing data. The amount to be +removed from circulation is represented solely as an entry in `mValuePoolDeltas` +with `bundleType = 5` and `assetClass = 0` (ZEC). -| Bytes | Name | Data Type | Description | -|-------|----------------|-----------|----------------------------------------------------------------------------| -| 8 | `zip233Amount` | `uint64` | The value to be removed from circulation in this transaction, in zatoshis. | +## NSM Amount -The $\mathsf{zip233\_amount}$ of a transaction is defined to be the value of the -`zip233Amount` field if present, and otherwise 0. +When the `mValuePoolDeltas` map contains an entry with `bundleType = 5`, the +transaction removes funds from circulation. The entry's `value` field MUST BE +nonpositive; its negation is denoted $\mathsf{zip233\_amount}$ and represents +the value in zatoshis removed from circulation when the transaction is mined. +If no such entry is present, $\mathsf{zip233\_amount}$ is defined to be 0. -Notes: - -* If both this ZIP and ZIP 2002 are selected for inclusion in the same Network - Upgrade, then the ordering of fields in the transaction format will be ``fee`` - and then ``zip233Amount``. -* Older transaction versions can continue to be supported after a network - upgrade, but removing funds from circulation is not possible for these - transactions. For example, NU5 supports both v4 and v5 transaction formats, - for both coinbase and non-coinbase transactions. +The NSM bundle's effect on the transparent transaction value pool does not +reflect an output being produced in any chain value pool. At the point at which +the transaction is applied to the global chain state, $\mathsf{zip233\_amount}$ +is subtracted from the issued supply. It is unavailable for circulation on the +network at least through to the end of the block in which the transaction is +mined. ZIP 234 [^zip-0234] specifies a potential mechanism by which the funds +removed from circulation would become available for reintroduction into the +issued supply in subsequent blocks. ## Changes to the Zcash Protocol Specification -Make a change to § 3.4 ‘Transactions and Treestates’ [^protocol-transactions] -implementing the specification in [ZIP-233 Amount]. - -In § 7.1 ‘Transaction Encoding and Consensus’ [^protocol-txnconsensus], add: +Let $\mathsf{NSMBundleId} = 5.$ -> [NU7 onward] $\mathsf{zip233\_amount}$ MUST be in the range $\{ 0 .. \mathsf{MAX\_MONEY} \}$. +Let $\mathsf{Zec}$ be the asset UUID for ZEC as defined in ZIP 248 [^zip-0248]. -In § 7.1.2 ‘Transaction Consensus Rules’ [^protocol-txnconsensus], add a note: +Make a change to § 3.4 'Transactions and Treestates' [^protocol-transactions] +adding the following consensus rules: -> [NU7 onward] $\mathsf{zip233\_amount}$ does not result in an output being produced in any -chain value pool. +> * [NU7 onward] The `assetClass` for any entry in `mValuePoolDeltas` having +> `bundleType` $= \mathsf{NSMBundleId}$ MUST be 0. That is, amounts to remove +> from circulation MUST be denominated in ZEC. +> +> * [NU7 onward] The value of $\mathsf{mValuePoolDeltas}[(\mathsf{NSMBundleId}, \mathsf{Zec})]$, +> if present, MUST be nonpositive. Its absolute value is $\mathsf{zip233\_amount}$. +> +> * [NU7 onward] $\mathsf{zip233\_amount}$ does not result in an output being +> produced in any chain value pool. -## Modifications relative to ZIP 244 [^zip-0244] +In § 7.1 'Transaction Encoding and Consensus' [^protocol-txnconsensus], add: -Relative to the sighash algorithm defined in ZIP 244, the sighash algorithm -that applies to v6 transactions differs by appending the encoding of -$\mathsf{zip233\_amount}$ to the Common Transaction Fields that are the input -to the digest in T.1: `header_digest` [^zip-0244-t-1-header-digest]: +> [NU7 onward] $\mathsf{zip233\_amount}$ MUST be in the range $\{ 0 .. \mathsf{MAX\_MONEY} \}$. -> T.1f: zip233_amount (8-byte little-endian amount to remove from circulation) +## Modifications to Digest Algorithms -Note: If both this ZIP and ZIP 2002 are selected for inclusion in the same -Network Upgrade, then the ambiguity in ordering of the fields added by these -ZIPs would need to be resolved. +The $\mathsf{zip233\_amount}$ is committed to the transaction identifier and +signature digest via the `value_pool_deltas_digest` defined in ZIP 248 [^zip-0248]. +Since the NSM bundle (bundle type 5) has no effecting data and no authorizing +data, its only contribution to the transaction digest is through its entry +in `mValuePoolDeltas`. ## Applicability @@ -198,14 +207,10 @@ This ZIP is proposed to activate with Network Upgrade 7. [^draft-arya-deploy-nu7 [^zip-0230]: [ZIP 230: Version 6 Transaction Format](zip-0230.rst) -[^zip-0230-transaction-format]: [ZIP 230: Version 6 Transaction Format. Section 'Transaction Format'](zip-0230.rst#transaction-format) - [^zip-0234]: [ZIP 234: Network Sustainability Mechanism: Issuance Smoothing](zip-0234.rst) [^zip-0235]: [ZIP 235: Remove 60% of Transaction Fees From Circulation](zip-0235.rst) -[^zip-0244]: [ZIP 244: Transaction Identifier Non-Malleability](zip-0244.rst) - -[^zip-0244-t-1-header-digest]: [ZIP 244: Transaction Identifier Non-Malleability. Section T.1: header_digest](zip-0244.rst#t-1-header-digest) +[^zip-0248]: [ZIP 248: Extensible Transaction Format](zip-0248.rst) [^draft-arya-deploy-nu7]: [draft-arya-deploy-nu7: Deployment of the NU7 Network Upgrade](draft-arya-deploy-nu7.md) From 312c7b1929a3771dfeb19b19cea7d3607908fa5b Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Wed, 4 Feb 2026 14:24:15 -0700 Subject: [PATCH 17/51] [ZIP 231]: Propose to register ZIP 248 bundle types. - Register Memos, Sapling-post-ZIP 231, and Orchard-post-ZIP 231 bundle types - Update encoding section to clarify it describes effecting data - Replace Transaction sighash section with Transaction Digest referencing ZIP XXX - Specify BLAKE2b-256 personalization strings for memo digest computation - Add reference to extensible transaction format ZIP - Fix zip-0230-note-plaintexts reference Co-Authored-By: Claude Opus 4.5 --- zips/zip-0231.md | 166 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 161 insertions(+), 5 deletions(-) diff --git a/zips/zip-0231.md b/zips/zip-0231.md index f5b05b61f..8a4190ce0 100644 --- a/zips/zip-0231.md +++ b/zips/zip-0231.md @@ -204,6 +204,149 @@ Since this proposal is defined only for v6 and later transactions, it is not necessary to consider Sprout JoinSplit outputs. The following sections apply to both Sapling and Orchard outputs in v6-onward transactions. +## Changes to ZIP 248 + +This ZIP proposes to register the following bundle types in the V6 transaction +bundle type registry defined in ZIP 248 [^zip-0248]: + +| BundleType | `mValuePoolDeltas` | `mEffectBundles` | `mAuthBundles` | Bundle kind | +|------------|--------------------| -----------------|----------------|----------------------| +| TBD |❌ |✅ |❌ | Memos | +| TBD |✅ |✅ |✅ | Sapling-post-ZIP 231 | +| TBD |✅ |✅ |✅ | Orchard-post-ZIP 231 | + +The Memos bundle has no value pool deltas (memo data does not involve value +transfers) and no authorizing data. The effecting data consists of the encoded +memo bundle as defined in [Encoding in transactions]. + +If this ZIP is activated in the same network upgrade as ZIP 248, the encoding +of the Sapling and Orchard bundles described in this ZIP will be used for +bundle types 2 and 3, respectively, and ZIP 248's definition of the Sapling and +Orchard bundles must be updated accordingly. If this ZIP is activated in a +network upgrade AFTER the network upgrade in which ZIP 248 is activated, the +encodings it describes will be assigned distinct bundle identifiers. In this +latter case, a transaction MUST NOT contain both a Sapling-pre-ZIP 231 bundle +and a Sapling-post-ZIP 231 bundle, or both an Orchard-pre-ZIP 231 bundle and an +Orchard-post-ZIP 231 bundle. + +## Sapling-post-ZIP 231 Bundle + +The Sapling-post-ZIP 231 bundle replaces the Sapling bundle defined in +ZIP 248 [^zip-0248]. The only change is that the note plaintext in each +Sapling output is shortened: the 512-byte memo field is replaced by a +32-byte $\mathsf{K^{memo}}$, reducing `encCiphertext` from 580 bytes to +100 bytes. + +### Sapling-post-ZIP 231 Effecting Data + +The effecting data for the Sapling-post-ZIP 231 bundle describes the Sapling +spends and outputs. + +| Bytes | Name | Data Type | Description | +|--------------------------|--------------------|---------------------------------------------|------------------------------------------------------------------------------| +| varies | `nSpendsSapling` | `compactSize` | Number of Sapling Spend descriptions. | +| 96 \* nSpendsSapling | `vSpendsSapling` | `SaplingSpendEffecting[nSpendsSapling]` | Effecting data for each Sapling Spend. | +| varies | `nOutputsSapling` | `compactSize` | Number of Sapling Output descriptions. | +| 276 \* nOutputsSapling | `vOutputsSapling` | `SaplingOutputPostZIP231[nOutputsSapling]` | Sapling Output descriptions. | +| 32 | `anchorSapling` | `byte[32]` | A root of the Sapling note commitment tree at some block height in the past. | + +* The field `anchorSapling` is present if and only if $\mathtt{nSpendsSapling} > 0$. + +`SaplingSpendEffecting` is unchanged from ZIP 248 [^zip-0248]. + +#### SaplingOutputPostZIP231 + +| Bytes | Name | Data Type | Description | +|-------|-----------------|-------------|---------------------------------------------------------------------------------------------------------------------------| +| 32 | `cv` | `byte[32]` | A value commitment to the net value of the output note. | +| 32 | `cmu` | `byte[32]` | The $u$-coordinate of the note commitment for the output note. | +| 32 | `ephemeralKey` | `byte[32]` | An encoding of an ephemeral Jubjub public key. | +| 100 | `encCiphertext` | `byte[100]` | The encrypted contents of the note plaintext, which contains $\mathsf{K^{memo}}$ in place of the 512-byte memo field. | +| 80 | `outCiphertext` | `byte[80]` | The encrypted contents of the byte string created by concatenation of the transmission key with the ephemeral secret key. | + +### Sapling-post-ZIP 231 Authorizing Data + +The authorizing data is unchanged from the Sapling bundle defined in +ZIP 248 [^zip-0248]. + +| Bytes | Name | Data Type | Description | +|--------------------------|--------------------------|-----------------------------------|--------------------------------------------------------------| +| 192 \* nSpendsSapling | `vSpendProofsSapling` | `byte[192 * nSpendsSapling]` | Encodings of the zk-SNARK proofs for each Sapling Spend. | +| 64 \* nSpendsSapling | `vSpendAuthSigsSapling` | `byte[64 * nSpendsSapling]` | Authorizing signatures for each Sapling Spend. | +| 192 \* nOutputsSapling | `vOutputProofsSapling` | `byte[192 * nOutputsSapling]` | Encodings of the zk-SNARK proofs for each Sapling Output. | +| 64 | `bindingSigSapling` | `byte[64]` | A Sapling binding signature on the SIGHASH transaction hash. | + +* The values of `nSpendsSapling` and `nOutputsSapling` are not re-encoded in + the authorizing data; they are taken from the corresponding effecting data. +* The field `bindingSigSapling` is present if and only if + $\mathtt{nSpendsSapling} + \mathtt{nOutputsSapling} > 0$. +* The elements of `vSpendProofsSapling` and `vSpendAuthSigsSapling` have a + 1:1 correspondence to the elements of `vSpendsSapling` in the effecting data + and MUST be ordered such that the element at a given index corresponds to the + `SaplingSpendEffecting` at the same index. +* The elements of `vOutputProofsSapling` have a 1:1 correspondence to the + elements of `vOutputsSapling` in the effecting data and MUST be ordered such + that the proof at a given index corresponds to the `SaplingOutputPostZIP231` + at the same index. + +## Orchard-post-ZIP 231 Bundle + +The Orchard-post-ZIP 231 bundle replaces the Orchard bundle defined in +ZIP 248 [^zip-0248]. As with Sapling, the only change is that the note +plaintext in each Orchard action is shortened: the 512-byte memo field is +replaced by a 32-byte $\mathsf{K^{memo}}$, reducing `encCiphertext` from +580 bytes to 100 bytes. + +### Orchard-post-ZIP 231 Effecting Data + +The effecting data for the Orchard-post-ZIP 231 bundle describes the Orchard +actions. + +| Bytes | Name | Data Type | Description | +|--------------------------|--------------------|-------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------| +| varies | `nActionsOrchard` | `compactSize` | The number of Orchard Action descriptions. | +| 340 \* nActionsOrchard | `vActionsOrchard` | `OrchardActionPostZIP231[nActionsOrchard]` | Effecting data for each Orchard Action. | +| 1 | `flagsOrchard` | `byte` | An 8-bit value representing a set of flags. Ordered from LSB to MSB: `enableSpendsOrchard`, `enableOutputsOrchard`. The remaining bits are set to $0$. | +| 32 | `anchorOrchard` | `byte[32]` | A root of the Orchard note commitment tree at some block height in the past. | + +* The fields `flagsOrchard` and `anchorOrchard` are present if and only if + $\mathtt{nActionsOrchard} > 0$. +* For coinbase transactions, the `enableSpendsOrchard` bit MUST be set to $0$. + +#### OrchardActionPostZIP231 + +| Bytes | Name | Data Type | Description | +|-------|-----------------|-------------|---------------------------------------------------------------------------------------------------------------------------| +| 32 | `cv` | `byte[32]` | A value commitment to the net value of the input note minus the output note. | +| 32 | `nullifier` | `byte[32]` | The nullifier of the input note. | +| 32 | `rk` | `byte[32]` | The randomized validating key for this Action. | +| 32 | `cmx` | `byte[32]` | The $x$-coordinate of the note commitment for the output note. | +| 32 | `ephemeralKey` | `byte[32]` | An encoding of an ephemeral Pallas public key. | +| 100 | `encCiphertext` | `byte[100]` | The encrypted contents of the note plaintext, which contains $\mathsf{K^{memo}}$ in place of the 512-byte memo field. | +| 80 | `outCiphertext` | `byte[80]` | The encrypted contents of the byte string created by concatenation of the transmission key with the ephemeral secret key. | + +### Orchard-post-ZIP 231 Authorizing Data + +The authorizing data is unchanged from the Orchard bundle defined in +ZIP 248 [^zip-0248]. + +| Bytes | Name | Data Type | Description | +|--------------------------|--------------------------|-----------------------------------|--------------------------------------------------------------------------------------------| +| varies | `sizeProofsOrchard` | `compactSize` | Length in bytes of `proofsOrchard`. Value is $2720 + 2272 \cdot \mathtt{nActionsOrchard}$. | +| sizeProofsOrchard | `proofsOrchard` | `byte[sizeProofsOrchard]` | Encoding of aggregated zk-SNARK proofs for Orchard Actions. | +| 64 \* nActionsOrchard | `vSpendAuthSigsOrchard` | `byte[64 * nActionsOrchard]` | Authorizing signatures for each Orchard Action. | +| 64 | `bindingSigOrchard` | `byte[64]` | An Orchard binding signature on the SIGHASH transaction hash. | + +* The value of `nActionsOrchard` is not re-encoded in the authorizing data; it + is taken from the corresponding effecting data. +* The fields `sizeProofsOrchard`, `proofsOrchard`, and `bindingSigOrchard` are + present if and only if $\mathtt{nActionsOrchard} > 0$. +* The proofs aggregated in `proofsOrchard`, and the elements of + `vSpendAuthSigsOrchard`, each have a 1:1 correspondence to the elements of + `vActionsOrchard` in the effecting data and MUST be ordered such that the + proof or signature at a given index corresponds to the + `OrchardActionPostZIP231` at the same index. + ## Memo bundle A memo bundle consists of a sequence of 272-byte memo chunks, each encrypting @@ -386,6 +529,9 @@ transaction. ## Encoding in transactions +The following describes the effecting data for the memo bundle. This data +appears in `mEffectBundles` with the memo bundle type identifier. + | Bytes | Name | Data Type | Description | |----------|------------------------|---------------------------------------------------|------------------------------------------------------------------------| | 1 | $\mathtt{fAllPruned}$ | $\mathtt{uint8}$ | 1 if the memo bundle has been pruned, otherwise 0. | @@ -403,13 +549,21 @@ If $\mathtt{fAllPruned} = 0$, then: If $\mathtt{fAllPruned} = 1$, then: - $\mathtt{saltOrHash}$ contains the $\mathsf{memo\_bundle\_digest}$ as defined in - [Transaction sighash]. + [Transaction Digest]. - The $\mathtt{nMemoChunks}$ and $\mathtt{vMemoChunks}$ fields will be absent. -## Transaction sighash +## Transaction Digest + +The memo bundle contributes to the transaction identifier via the +`effects_bundles_digest` defined in ZIP 248 [^zip-0248]. -$\mathsf{memo\_chunk\_digest}[i] = H(\mathtt{vMemoChunks}[i]) \\$ -$\mathsf{memo\_bundle\_digest} = H(\mathsf{concat}(\mathsf{memo\_chunk\_digests}))$ +The memo bundle's effect digest is computed as follows: + +$\mathsf{memo\_chunk\_digest}[i] = \mathsf{BLAKE2b\text{-}256}(\texttt{"ZTxIdMemoChunkHs"}, \mathtt{vMemoChunks}[i]) \\$ +$\mathsf{memo\_bundle\_digest} = \mathsf{BLAKE2b\text{-}256}(\texttt{"ZTxIdMemoBundHsh"}, \mathsf{concat}(\mathsf{memo\_chunk\_digests}))$ + +For pruned chunks, the $\mathsf{memo\_chunk\_digest}$ stored in the transaction +encoding is used directly. The memo bundle digest is used in place of the full memo bundle when the bundle has been pruned. @@ -789,9 +943,11 @@ TBD [^zip-0200]: [ZIP 200: Network Upgrade Mechanism](zip-0200.rst) +[^zip-0248]: [ZIP 248: Extensible Transaction Format](zip-0248.rst) + [^draft-arya-deploy-nu7]: [draft-arya-deploy-nu7: Deployment of the NU7 Network Upgrade](draft-arya-deploy-nu7.md) -[^zip-0230-orchard-note-plaintext]: [ZIP 230: Version 6 Transaction Format — Orchard Note Plaintext](zip-0230.rst#orchard-note-plaintext) +[^zip-0230-note-plaintexts]: [ZIP 230: Version 6 Transaction Format — Note Plaintexts](zip-0230.rst#note-plaintexts) [^zip-0248]: [ZIP 248: Extensible Transaction Format (PR: zcash/zips#1156)](https://github.com/zcash/zips/pull/1156) From 576fe3f67d98551c93e950445e66b06ae4425dc8 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Thu, 5 Mar 2026 19:11:42 -0700 Subject: [PATCH 18/51] [ZIP 248]: Change bundle identifiers to (bundleType, bundleVersion) tuples. This makes the mutual exclusivity of bundle variants (e.g. Orchard vs OrchardZSA) implicit in the map structure, and allows clients that do not recognize a specific bundleVersion to still identify which pool is affected. Co-Authored-By: Claude Opus 4.6 --- zips/zip-0231.md | 33 ++++--- zips/zip-0233.md | 10 +-- zips/zip-0248.rst | 214 +++++++++++++++++++++++++++------------------- zips/zip-2002.rst | 16 ++-- 4 files changed, 158 insertions(+), 115 deletions(-) diff --git a/zips/zip-0231.md b/zips/zip-0231.md index 8a4190ce0..d3460cdce 100644 --- a/zips/zip-0231.md +++ b/zips/zip-0231.md @@ -206,28 +206,33 @@ to both Sapling and Orchard outputs in v6-onward transactions. ## Changes to ZIP 248 -This ZIP proposes to register the following bundle types in the V6 transaction -bundle type registry defined in ZIP 248 [^zip-0248]: +This ZIP proposes to register a new bundle type for Memos and new versions of +the Sapling and Orchard bundle types in the V6 transaction bundle type registry +defined in ZIP 248 [^zip-0248]: -| BundleType | `mValuePoolDeltas` | `mEffectBundles` | `mAuthBundles` | Bundle kind | -|------------|--------------------| -----------------|----------------|----------------------| -| TBD |❌ |✅ |❌ | Memos | -| TBD |✅ |✅ |✅ | Sapling-post-ZIP 231 | -| TBD |✅ |✅ |✅ | Orchard-post-ZIP 231 | +| BundleType | BundleVersion | `mValuePoolDeltas` | `mEffectBundles` | `mAuthBundles` | Bundle kind | +|------------|---------------|--------------------|------------------|----------------|----------------------| +| TBD | 0 |❌ |✅ |❌ | Memos | +| 2 | TBD |✅ |✅ |✅ | Sapling-post-ZIP 231 | +| 3 | TBD |✅ |✅ |✅ | Orchard-post-ZIP 231 | The Memos bundle has no value pool deltas (memo data does not involve value transfers) and no authorizing data. The effecting data consists of the encoded memo bundle as defined in [Encoding in transactions]. +The Sapling-post-ZIP 231 and Orchard-post-ZIP 231 entries are new versions of +the existing Sapling (``bundleType`` 2) and Orchard (``bundleType`` 3) bundle +types respectively. Because ZIP 248 requires that each bundle map is keyed by +``bundleType`` alone, a transaction that includes a Sapling-post-ZIP 231 bundle +cannot also include a pre-ZIP 231 Sapling bundle, and similarly for Orchard. + If this ZIP is activated in the same network upgrade as ZIP 248, the encoding of the Sapling and Orchard bundles described in this ZIP will be used for -bundle types 2 and 3, respectively, and ZIP 248's definition of the Sapling and -Orchard bundles must be updated accordingly. If this ZIP is activated in a -network upgrade AFTER the network upgrade in which ZIP 248 is activated, the -encodings it describes will be assigned distinct bundle identifiers. In this -latter case, a transaction MUST NOT contain both a Sapling-pre-ZIP 231 bundle -and a Sapling-post-ZIP 231 bundle, or both an Orchard-pre-ZIP 231 bundle and an -Orchard-post-ZIP 231 bundle. +bundle type 2 version 0 and bundle type 3 version 0, respectively, and +ZIP 248's definition of the Sapling and Orchard bundles must be updated +accordingly. If this ZIP is activated in a network upgrade AFTER the network +upgrade in which ZIP 248 is activated, the encodings it describes will be +assigned distinct bundle version identifiers for their respective bundle types. ## Sapling-post-ZIP 231 Bundle diff --git a/zips/zip-0233.md b/zips/zip-0233.md index 85abd8f7f..c8e10f570 100644 --- a/zips/zip-0233.md +++ b/zips/zip-0233.md @@ -100,12 +100,12 @@ network. ## Changes to ZIP 248 -This ZIP proposes to register bundle type 5 ("ZIP 233 NSM field") in the V6 -transaction bundle type registry defined in ZIP 248 [^zip-0248]. +This ZIP proposes to register bundle type 5 version 0 ("ZIP 233 NSM field") in +the V6 transaction bundle type registry defined in ZIP 248 [^zip-0248]. -| BundleType | `mValuePoolDeltas` | `mEffectBundles` | `mAuthBundles` | -|------------|--------------------| -----------------|----------------| -| 5 |✅ |❌ |❌ | +| BundleType | BundleVersion | `mValuePoolDeltas` | `mEffectBundles` | `mAuthBundles` | +|------------|---------------|--------------------|------------------|----------------| +| 5 | 0 |✅ |❌ |❌ | $\mathsf{zip233\_amount}$ does not result in an output being produced in any chain value pool, and therefore from the point at which the transaction is diff --git a/zips/zip-0248.rst b/zips/zip-0248.rst index bcc2f6536..03f435825 100644 --- a/zips/zip-0248.rst +++ b/zips/zip-0248.rst @@ -148,14 +148,29 @@ Protocol Bundles This ZIP refines and codifies the concept of "protocol bundles" that emerged from the implementation of the ZIP 225 [#zip-0225]_ transaction format. It -makes bundles first-class objects and defines a registry of bundle type -identifiers. Within the period that a given transaction format version is used -on the Zcash network, the semantics of the bundle associated with a given -bundle type identifier are fixed. +makes bundles first-class objects and defines a registry of bundle type and +version identifiers. Within the period that a given transaction format version +is used on the Zcash network, the semantics of the bundle associated with a +given ``(bundleType, bundleVersion)`` pair are fixed. A **protocol bundle** is a self-contained component of a transaction that -implements a specific piece of protocol functionality. Each bundle type -defines: +implements a specific piece of protocol functionality. Each bundle is +identified by a ``(bundleType, bundleVersion)`` pair, where: + +* The **bundle type** identifies the protocol or value pool that the bundle + operates on (e.g., Transparent, Sapling, Orchard). + +* The **bundle version** identifies a specific variant of that protocol. New + versions of an existing bundle type may be introduced by subsequent ZIPs + to evolve a protocol's functionality while preserving the association with + the same value pool. + +A transaction MUST NOT contain more than one version of any given bundle type. +This constraint is enforced by the map structure of the transaction encoding: +the maps ``mValuePoolDeltas``, ``mEffectBundles``, and ``mAuthBundles`` are +each keyed by ``bundleType`` alone. + +Each bundle type/version pair defines: * What **effecting data** the bundle contains — the data that determines what state changes the bundle produces (e.g., which notes are spent, which outputs @@ -222,10 +237,15 @@ adds value to the transparent transaction value pool. Bundle Type Registration ```````````````````````` -When a ZIP introduces a new bundle type, it MUST: +When a ZIP introduces a new bundle type or a new version of an existing bundle +type, it MUST: -1. Request allocation of a bundle type identifier in the registry defined - below. The identifier must be a non-negative integer. +1. Request allocation of a ``(bundleType, bundleVersion)`` pair in the registry + defined below. The ``bundleType`` and ``bundleVersion`` are each + non-negative integers. If the ZIP introduces a new bundle type, it requests + a new ``bundleType`` value with ``bundleVersion`` 0. If it introduces a new + version of an existing bundle type, it requests a new ``bundleVersion`` + value for the existing ``bundleType``. 2. Specify whether entries for this bundle type are permitted in ``mValuePoolDeltas`` (the value pool delta map). @@ -250,17 +270,23 @@ A bundle type MUST NOT permit entries in ``mAuthBundles`` unless it also permits entries in ``mEffectBundles``. That is, authorizing data cannot exist without corresponding effecting data for a given bundle type. -Once a bundle type identifier is assigned for a given transaction version, its -semantics are fixed for the lifetime of that transaction version. A subsequent -network upgrade may define a new transaction version that reassigns identifiers -or changes bundle semantics, but within a single transaction version, bundle -type identifiers have stable, unchanging meanings. +Once a ``(bundleType, bundleVersion)`` pair is assigned for a given transaction +version, its semantics are fixed for the lifetime of that transaction version. +A subsequent network upgrade may define a new transaction version that +reassigns identifiers or changes bundle semantics, but within a single +transaction version, bundle type and version identifiers have stable, +unchanging meanings. + +A new version of an existing bundle type MUST affect the same value pool(s) as +the original bundle type. This ensures that a client that does not recognize a +particular ``bundleVersion`` can still determine which pool(s) are affected by +the bundle and inform its user accordingly. V6 Transaction Bundle Type Registry ``````````````````````````````````` -The following integers are registered as bundle type identifiers for the V6 -transaction format. All currently-defined IDs are encoded as single-byte +The following ``(bundleType, bundleVersion)`` pairs are registered for the V6 +transaction format. All currently-defined values are encoded as single-byte ``compactSize`` values where they appear in the transaction format. The ``mValuePoolDeltas`` column indicates whether or not an entry for this @@ -278,39 +304,40 @@ type MAY appear in ``mAuthBundles``. For rows where an ❌ is present, the bundle has no authorizing data, and so an entry in ``mAuthBundles`` MUST NOT be present. -+------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ -| BundleType | ``mValuePoolDeltas`` | ``mEffectBundles`` | ``mAuthBundles`` | Defining ZIP | Bundle kind | -+============+======================+====================+==================+==============+==============================================+ -| 0 |✅ |✅ |✅ | This ZIP | Transparent | -+------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ -| 1 | | | | | Reserved | -+------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ -| 2 |✅ |✅ |✅ | This ZIP | Sapling | -+------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ -| 3 |✅ |✅ |✅ | This ZIP | Orchard | -+------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ -| 4 |✅ |❌ |❌ | ZIP 2002 | Transaction fee | -+------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ -| 5 |✅ |❌ |❌ | ZIP 233 | ZIP 233 NSM field | -+------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ -| 6 |❌ |✅ |✅ | ZIP 270 | Key rotation | -+------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ -| 7 |✅ |✅ |✅ | TBD | Lockbox disbursement | -+------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ -| |❌ |✅ |❌ | ZIP 231 | Memos | -+------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ -| |✅ |✅ |✅ | ZIP 231 | Sapling-post-ZIP 231 | -+------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ -| |✅ |✅ |✅ | ZIP 231 | Orchard-post-ZIP 231 | -+------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ -| |✅ |✅ |✅ | ZIP 227 | ZSA Issuance | -+------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ -| |✅ |✅ |✅ | ZIP 226 | OrchardZSA | -+------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ - -Additional bundle types MAY be added to this registry via modifications to this -ZIP specified in other ZIPs. Such modifications MUST specify all of the -information required by the `Bundle Type Registration`_ section above. ++------------+---------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ +| BundleType | BundleVersion | ``mValuePoolDeltas`` | ``mEffectBundles`` | ``mAuthBundles`` | Defining ZIP | Bundle kind | ++============+===============+======================+====================+==================+==============+==============================================+ +| 0 | 0 |✅ |✅ |✅ | This ZIP | Transparent | ++------------+---------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ +| 1 | | | | | | Reserved | ++------------+---------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ +| 2 | 0 |✅ |✅ |✅ | This ZIP | Sapling | ++------------+---------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ +| 2 | |✅ |✅ |✅ | ZIP 231 | Sapling-post-ZIP 231 | ++------------+---------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ +| 3 | 0 |✅ |✅ |✅ | This ZIP | Orchard | ++------------+---------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ +| 3 | |✅ |✅ |✅ | ZIP 231 | Orchard-post-ZIP 231 | ++------------+---------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ +| 3 | |✅ |✅ |✅ | ZIP 226 | OrchardZSA | ++------------+---------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ +| 4 | 0 |✅ |❌ |❌ | ZIP 2002 | Transaction fee | ++------------+---------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ +| 5 | 0 |✅ |❌ |❌ | ZIP 233 | ZIP 233 NSM field | ++------------+---------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ +| 6 | 0 |❌ |✅ |✅ | ZIP 270 | Key rotation | ++------------+---------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ +| 7 | 0 |✅ |✅ |✅ | TBD | Lockbox disbursement | ++------------+---------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ +| | 0 |❌ |✅ |❌ | ZIP 231 | Memos | ++------------+---------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ +| | 0 |✅ |✅ |✅ | ZIP 227 | ZSA Issuance | ++------------+---------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ + +Additional bundle types or versions MAY be added to this registry via +modifications to this ZIP specified in other ZIPs. Such modifications MUST +specify all of the information required by the `Bundle Type Registration`_ +section above. Potential Future Bundle Types ````````````````````````````` @@ -323,23 +350,23 @@ Potential Future Bundle Types The following entries are provided to illustrate how potential future upgrades might affect the bundle registry: -+------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ -| BundleType | ``mValuePoolDeltas`` | ``mEffectBundles`` | ``mAuthBundles`` | Bundle kind | -+============+======================+====================+==================+=============================================================+ -| |✅ |✅ |✅ | TZEs | -+------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ -| |✅ |✅ |✅ | Pool that only has a long-term storage protocol (PQ, very | -| | | | | simple thus insulated from counterfeiting fears, can be | -| | | | | used for payments but higher latency for that purpose) | -+------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ -| |✅ |✅ |✅ | Tachyon | -+------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ -| |✅ |✅ |❌ | Staking | -+------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ -| |✅ |✅ |✅ | Unstaking (if it can't be combined with the Staking bundle) | -+------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ -| |✅ |✅ |✅ | Post-quantum fast payment protocol | -+------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ ++------------+---------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ +| BundleType | BundleVersion | ``mValuePoolDeltas`` | ``mEffectBundles`` | ``mAuthBundles`` | Bundle kind | ++============+===============+======================+====================+==================+=============================================================+ +| | 0 |✅ |✅ |✅ | TZEs | ++------------+---------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ +| | 0 |✅ |✅ |✅ | Pool that only has a long-term storage protocol (PQ, very | +| | | | | | simple thus insulated from counterfeiting fears, can be | +| | | | | | used for payments but higher latency for that purpose) | ++------------+---------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ +| | 0 |✅ |✅ |✅ | Tachyon | ++------------+---------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ +| | 0 |✅ |✅ |❌ | Staking | ++------------+---------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ +| | 0 |✅ |✅ |✅ | Unstaking (if it can't be combined with the Staking bundle) | ++------------+---------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ +| | 0 |✅ |✅ |✅ | Post-quantum fast payment protocol | ++------------+---------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ .. raw:: html @@ -390,9 +417,10 @@ Transaction Format +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ ``mEffectBundles`` and ``mAuthBundles`` are interpreted as maps keyed by -bundle type. The entries in each map MUST be in increasing order of key. -Each map MUST NOT contain more than a single entry for a given key. For each -key that exists in ``mAuthBundles``, a corresponding entry must exist in +``bundleType``. The entries in each map MUST be in increasing order of +``bundleType``. Each map MUST NOT contain more than a single entry for a given +``bundleType``. For each ``bundleType`` that exists in ``mAuthBundles``, a +corresponding entry with the same ``bundleVersion`` must exist in ``mEffectBundles``. ValuePoolDelta @@ -403,6 +431,8 @@ ValuePoolDelta +=============================+==============================+================================================+=====================================================================+ | varies |``bundleType`` |``compactSize`` |An encoding of the bundle type identifier. | +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| varies |``bundleVersion`` |``compactSize`` |An encoding of the bundle version identifier. | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ | 1 |``assetClass`` |``uint8`` |An asset class identifier. 0x00 for the ZEC asset, 0x01 for other | | | | |assets. | +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ @@ -422,6 +452,9 @@ $(\mathsf{BundleType}, \mathsf{AssetUuid}).$ The map MUST NOT contain more than a single entry for a given key. Lookups in this map are denoted with the syntax $\mathsf{mValuePoolDeltas}[(\mathsf{BundleType}, \mathsf{AssetUuid})].$ +All entries in ``mValuePoolDeltas`` having the same ``bundleType`` MUST have +the same ``bundleVersion``. + Let $\mathsf{Zec}$ be a distinguished value representing the ZEC asset. It is used as the asset identifier when $\mathsf{assetClass} = 0$. @@ -444,6 +477,8 @@ BundleData +=============================+==============================+================================================+=====================================================================+ | varies |``bundleType`` |``compactSize`` |An encoding of the bundle type identifier. | +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| varies |``bundleVersion`` |``compactSize`` |An encoding of the bundle version identifier. | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ | varies |``nBundleDataLen`` |``compactSize`` |The length of the ``vBundleData`` byte array. | +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ | varies |``vBundleData`` |``byte[nBundleDataLen]`` |The effecting or authorizing data for the bundle, dependent upon | @@ -738,11 +773,11 @@ The following transaction validity rules are added: That is, the fees collected by the coinbase transaction must equal the sum of fees paid by all other transactions in the block. -* Certain bundle types are mutually exclusive: a transaction MUST NOT contain - more than one bundle from each of the following sets: - - * {Sapling, Sapling-post-ZIP-231} - * {Orchard, Orchard-post-ZIP-231, OrchardZSA} +* For each ``bundleType`` that appears in any of ``mValuePoolDeltas``, + ``mEffectBundles``, or ``mAuthBundles``, all entries for that ``bundleType`` + across all three maps MUST have the same ``bundleVersion``. (This, combined + with the constraint that each map is keyed by ``bundleType``, ensures that a + transaction uses at most one version of any given bundle type.) * For the coinbase transaction, the sum of value pool deltas in the ZEC asset is equal to the negative of the block subsidy for that block; the block @@ -786,8 +821,8 @@ follows:: ├── header_digest ├── value_pool_deltas_digest └── effects_bundles_digest - ├─ (bundle_type_id || transparent_effects_digest) - ├─ (bundle_type_id || sapling_effects_digest) + ├─ (bundle_type_id || bundle_version || transparent_effects_digest) + ├─ (bundle_type_id || bundle_version || sapling_effects_digest) │ ├── sapling_spends_digest │ │ ├── sapling_spends_compact_digest │ │ └── sapling_spends_noncompact_digest @@ -795,11 +830,11 @@ follows:: │ ├── sapling_outputs_compact_digest │ ├── sapling_outputs_memos_digest │ └── sapling_outputs_noncompact_digest - ├─ (bundle_type_id || orchard_effects_digest) + ├─ (bundle_type_id || bundle_version || orchard_effects_digest) │ ├── orchard_actions_compact_digest │ ├── orchard_actions_memos_digest │ └── orchard_actions_noncompact_digest - └─ (bundle_type_id || unknown_bundle_effects_digest) ... + └─ (bundle_type_id || bundle_version || unknown_bundle_effects_digest) ... Each node written as ``snake_case`` in this tree is a BLAKE2b-256 hash of its children, initialized with a personalization string specific to that branch @@ -847,10 +882,11 @@ A BLAKE2b-256 hash of the concatenated encodings of all entries in ``mValuePoolDeltas``, in increasing order of ``(bundleType, assetClass, assetUuid)``. For each entry, the following values are concatenated:: - T.2a: bundleType (compactSize encoding) - T.2b: assetClass (1 byte) - T.2c: assetUuid (0 or 64 bytes, depending on assetClass) - T.2d: value (8-byte signed little-endian) + T.2a: bundleType (compactSize encoding) + T.2b: bundleVersion (compactSize encoding) + T.2c: assetClass (1 byte) + T.2d: assetUuid (0 or 64 bytes, depending on assetClass) + T.2e: value (8-byte signed little-endian) The personalization field of this hash is set to:: @@ -870,7 +906,8 @@ bundles present in ``mEffectBundles``, in increasing order of ``bundleType``. Fo bundle, the following values are concatenated:: T.3a: bundleType (compactSize encoding) - T.3b: bundle_effects_digest (32-byte hash output) + T.3b: bundleVersion (compactSize encoding) + T.3c: bundle_effects_digest (32-byte hash output) where ``bundle_effects_digest`` is the root hash of the bundle's effecting data tree, as defined below for each known bundle type. @@ -1312,10 +1349,10 @@ the authorizing data of a transaction. The overall structure is:: auth_digest └── auth_bundles_digest - ├─ (bundle_type_id || transparent_auth_digest) - ├─ (bundle_type_id || sapling_auth_digest) - ├─ (bundle_type_id || orchard_auth_digest) - └─ (bundle_type_id || unknown_bundle_auth_digest) ... + ├─ (bundle_type_id || bundle_version || transparent_auth_digest) + ├─ (bundle_type_id || bundle_version || sapling_auth_digest) + ├─ (bundle_type_id || bundle_version || orchard_auth_digest) + └─ (bundle_type_id || bundle_version || unknown_bundle_auth_digest) ... auth_digest ''''''''''' @@ -1339,7 +1376,8 @@ bundles present in ``mAuthBundles``, in increasing order of ``bundleType``. For bundle, the following values are concatenated:: A.1a: bundleType (compactSize encoding) - A.1b: bundle_auth_digest (32-byte hash output) + A.1b: bundleVersion (compactSize encoding) + A.1c: bundle_auth_digest (32-byte hash output) The personalization field of this hash is set to:: diff --git a/zips/zip-2002.rst b/zips/zip-2002.rst index 083a22679..c5e0cde26 100644 --- a/zips/zip-2002.rst +++ b/zips/zip-2002.rst @@ -73,14 +73,14 @@ Specification Changes to ZIP 248 ------------------ -This ZIP proposes to register bundle type 4 ("Transaction fee") in the V6 -transaction bundle type registry defined in ZIP 248 [#zip-0248]_. - -+------------+----------------------+--------------------+------------------+ -| BundleType | ``mValuePoolDeltas`` | ``mEffectBundles`` | ``mAuthBundles`` | -+============+======================+====================+==================+ -| 4 |✅ |❌ |❌ | -+------------+----------------------+--------------------+------------------+ +This ZIP proposes to register bundle type 4 version 0 ("Transaction fee") in +the V6 transaction bundle type registry defined in ZIP 248 [#zip-0248]_. + ++------------+---------------+----------------------+--------------------+------------------+ +| BundleType | BundleVersion | ``mValuePoolDeltas`` | ``mEffectBundles`` | ``mAuthBundles`` | ++============+===============+======================+====================+==================+ +| 4 | 0 |✅ |❌ |❌ | ++------------+---------------+----------------------+--------------------+------------------+ The fee bundle has no effecting data and no authorizing data. The transaction fee is represented solely as an entry in ``mValuePoolDeltas`` with From ced3ce453781557620e820e73552aae19a4f0b48 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Thu, 5 Mar 2026 19:31:48 -0700 Subject: [PATCH 19/51] [ZIP 248]: Add wallet implications section Add a section to ZIP 248 describing wallet requirements for handling unknown bundle types and versions. Co-Authored-By: Claude Opus 4.6 --- zips/zip-0248.rst | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/zips/zip-0248.rst b/zips/zip-0248.rst index 03f435825..17a6ede9e 100644 --- a/zips/zip-0248.rst +++ b/zips/zip-0248.rst @@ -1440,13 +1440,41 @@ In the case that the transaction has no Orchard actions:: BLAKE2b-256("ZTxAuthOrchaHash", []) +Implications for Wallets +----------------------- + +Sending v6 transactions +``````````````````````` + +*All* Zcash wallets SHOULD, without undue delay, switch to sending only v6 +transactions once they are allowed on the network. This applies to all +transactions regardless of whether they use new v6 features. + +Support for receiving funds in v6 transactions +`````````````````````````````````````````````` + +Zcash wallets MUST support parsing v6 transactions by the time they are allowed +on the network. + +Because the v6 transaction format uses a type-length-value encoding for +bundles, a wallet is not required to understand the internal encoding of every +bundle type in order to parse a transaction. However, a wallet that encounters +a bundle with an unrecognized ``bundleType`` SHOULD alert the user that the +transaction contains components it does not understand. A wallet that +encounters a bundle with a recognized ``bundleType`` but unrecognized +``bundleVersion`` SHOULD alert the user that the transaction affects a pool the +wallet is aware of, but in a way the wallet does not fully understand. + +A wallet MUST NOT construct or sign a transaction containing a bundle type or +version that it does not fully understand. It MAY, however, correctly compute +the transaction identifier or authorizing data commitment of any well-formed +v6 transaction by hashing the effecting or authorizing data of unrecognized +bundles opaquely (see `Digest Algorithms`_). + + Rationale ========= -TODO: Document why we take the specific approach we do on what the format -constrains vs what wallets are expected (required?) to notify users of (once we -decide on the approach). - Effecting data bundles and authorizing data bundles are stored separately in the transaction format so that the authorizing data may be pruned by straightforward truncation of the encoded representation of the transaction. From 69c32512db68349e4d3f1f0b61c7398588ac1007 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Tue, 24 Mar 2026 14:16:43 -0600 Subject: [PATCH 20/51] [ZIP 248]: Rename `bundleVersion` to `bundleVariant` --- zips/zip-0231.md | 8 ++-- zips/zip-0233.md | 4 +- zips/zip-0248.rst | 94 +++++++++++++++++++++++------------------------ zips/zip-2002.rst | 4 +- 4 files changed, 55 insertions(+), 55 deletions(-) diff --git a/zips/zip-0231.md b/zips/zip-0231.md index d3460cdce..1e7f8cfbc 100644 --- a/zips/zip-0231.md +++ b/zips/zip-0231.md @@ -210,7 +210,7 @@ This ZIP proposes to register a new bundle type for Memos and new versions of the Sapling and Orchard bundle types in the V6 transaction bundle type registry defined in ZIP 248 [^zip-0248]: -| BundleType | BundleVersion | `mValuePoolDeltas` | `mEffectBundles` | `mAuthBundles` | Bundle kind | +| BundleType | BundleVariant | `mValuePoolDeltas` | `mEffectBundles` | `mAuthBundles` | Bundle kind | |------------|---------------|--------------------|------------------|----------------|----------------------| | TBD | 0 |❌ |✅ |❌ | Memos | | 2 | TBD |✅ |✅ |✅ | Sapling-post-ZIP 231 | @@ -220,7 +220,7 @@ The Memos bundle has no value pool deltas (memo data does not involve value transfers) and no authorizing data. The effecting data consists of the encoded memo bundle as defined in [Encoding in transactions]. -The Sapling-post-ZIP 231 and Orchard-post-ZIP 231 entries are new versions of +The Sapling-post-ZIP 231 and Orchard-post-ZIP 231 entries are new variants of the existing Sapling (``bundleType`` 2) and Orchard (``bundleType`` 3) bundle types respectively. Because ZIP 248 requires that each bundle map is keyed by ``bundleType`` alone, a transaction that includes a Sapling-post-ZIP 231 bundle @@ -228,11 +228,11 @@ cannot also include a pre-ZIP 231 Sapling bundle, and similarly for Orchard. If this ZIP is activated in the same network upgrade as ZIP 248, the encoding of the Sapling and Orchard bundles described in this ZIP will be used for -bundle type 2 version 0 and bundle type 3 version 0, respectively, and +bundle type 2 variant 0 and bundle type 3 variant 0, respectively, and ZIP 248's definition of the Sapling and Orchard bundles must be updated accordingly. If this ZIP is activated in a network upgrade AFTER the network upgrade in which ZIP 248 is activated, the encodings it describes will be -assigned distinct bundle version identifiers for their respective bundle types. +assigned distinct bundle variant identifiers for their respective bundle types. ## Sapling-post-ZIP 231 Bundle diff --git a/zips/zip-0233.md b/zips/zip-0233.md index c8e10f570..002bd60f3 100644 --- a/zips/zip-0233.md +++ b/zips/zip-0233.md @@ -100,10 +100,10 @@ network. ## Changes to ZIP 248 -This ZIP proposes to register bundle type 5 version 0 ("ZIP 233 NSM field") in +This ZIP proposes to register bundle type 5 variant 0 ("ZIP 233 NSM field") in the V6 transaction bundle type registry defined in ZIP 248 [^zip-0248]. -| BundleType | BundleVersion | `mValuePoolDeltas` | `mEffectBundles` | `mAuthBundles` | +| BundleType | BundleVariant | `mValuePoolDeltas` | `mEffectBundles` | `mAuthBundles` | |------------|---------------|--------------------|------------------|----------------| | 5 | 0 |✅ |❌ |❌ | diff --git a/zips/zip-0248.rst b/zips/zip-0248.rst index 17a6ede9e..d5207e229 100644 --- a/zips/zip-0248.rst +++ b/zips/zip-0248.rst @@ -149,28 +149,28 @@ Protocol Bundles This ZIP refines and codifies the concept of "protocol bundles" that emerged from the implementation of the ZIP 225 [#zip-0225]_ transaction format. It makes bundles first-class objects and defines a registry of bundle type and -version identifiers. Within the period that a given transaction format version +variant identifiers. Within the period that a given transaction format version is used on the Zcash network, the semantics of the bundle associated with a -given ``(bundleType, bundleVersion)`` pair are fixed. +given ``(bundleType, bundleVariant)`` pair are fixed. A **protocol bundle** is a self-contained component of a transaction that implements a specific piece of protocol functionality. Each bundle is -identified by a ``(bundleType, bundleVersion)`` pair, where: +identified by a ``(bundleType, bundleVariant)`` pair, where: * The **bundle type** identifies the protocol or value pool that the bundle operates on (e.g., Transparent, Sapling, Orchard). -* The **bundle version** identifies a specific variant of that protocol. New - versions of an existing bundle type may be introduced by subsequent ZIPs +* The **bundle variant** identifies a specific variant of that protocol. New + variants of an existing bundle type may be introduced by subsequent ZIPs to evolve a protocol's functionality while preserving the association with the same value pool. -A transaction MUST NOT contain more than one version of any given bundle type. +A transaction MUST NOT contain more than one variant of any given bundle type. This constraint is enforced by the map structure of the transaction encoding: the maps ``mValuePoolDeltas``, ``mEffectBundles``, and ``mAuthBundles`` are each keyed by ``bundleType`` alone. -Each bundle type/version pair defines: +Each bundle type/variant pair defines: * What **effecting data** the bundle contains — the data that determines what state changes the bundle produces (e.g., which notes are spent, which outputs @@ -237,14 +237,14 @@ adds value to the transparent transaction value pool. Bundle Type Registration ```````````````````````` -When a ZIP introduces a new bundle type or a new version of an existing bundle +When a ZIP introduces a new bundle type or a new variant of an existing bundle type, it MUST: -1. Request allocation of a ``(bundleType, bundleVersion)`` pair in the registry - defined below. The ``bundleType`` and ``bundleVersion`` are each +1. Request allocation of a ``(bundleType, bundleVariant)`` pair in the registry + defined below. The ``bundleType`` and ``bundleVariant`` are each non-negative integers. If the ZIP introduces a new bundle type, it requests - a new ``bundleType`` value with ``bundleVersion`` 0. If it introduces a new - version of an existing bundle type, it requests a new ``bundleVersion`` + a new ``bundleType`` value with ``bundleVariant`` 0. If it introduces a new + variant of an existing bundle type, it requests a new ``bundleVariant`` value for the existing ``bundleType``. 2. Specify whether entries for this bundle type are permitted in @@ -270,22 +270,22 @@ A bundle type MUST NOT permit entries in ``mAuthBundles`` unless it also permits entries in ``mEffectBundles``. That is, authorizing data cannot exist without corresponding effecting data for a given bundle type. -Once a ``(bundleType, bundleVersion)`` pair is assigned for a given transaction +Once a ``(bundleType, bundleVariant)`` pair is assigned for a given transaction version, its semantics are fixed for the lifetime of that transaction version. A subsequent network upgrade may define a new transaction version that reassigns identifiers or changes bundle semantics, but within a single -transaction version, bundle type and version identifiers have stable, +transaction version, bundle type and variant identifiers have stable, unchanging meanings. -A new version of an existing bundle type MUST affect the same value pool(s) as +A new variant of an existing bundle type MUST affect the same value pool(s) as the original bundle type. This ensures that a client that does not recognize a -particular ``bundleVersion`` can still determine which pool(s) are affected by +particular ``bundleVariant`` can still determine which pool(s) are affected by the bundle and inform its user accordingly. V6 Transaction Bundle Type Registry ``````````````````````````````````` -The following ``(bundleType, bundleVersion)`` pairs are registered for the V6 +The following ``(bundleType, bundleVariant)`` pairs are registered for the V6 transaction format. All currently-defined values are encoded as single-byte ``compactSize`` values where they appear in the transaction format. @@ -305,7 +305,7 @@ bundle has no authorizing data, and so an entry in ``mAuthBundles`` MUST NOT be present. +------------+---------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ -| BundleType | BundleVersion | ``mValuePoolDeltas`` | ``mEffectBundles`` | ``mAuthBundles`` | Defining ZIP | Bundle kind | +| BundleType | BundleVariant | ``mValuePoolDeltas`` | ``mEffectBundles`` | ``mAuthBundles`` | Defining ZIP | Bundle kind | +============+===============+======================+====================+==================+==============+==============================================+ | 0 | 0 |✅ |✅ |✅ | This ZIP | Transparent | +------------+---------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ @@ -334,7 +334,7 @@ be present. | | 0 |✅ |✅ |✅ | ZIP 227 | ZSA Issuance | +------------+---------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ -Additional bundle types or versions MAY be added to this registry via +Additional bundle types or variants MAY be added to this registry via modifications to this ZIP specified in other ZIPs. Such modifications MUST specify all of the information required by the `Bundle Type Registration`_ section above. @@ -351,7 +351,7 @@ The following entries are provided to illustrate how potential future upgrades might affect the bundle registry: +------------+---------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ -| BundleType | BundleVersion | ``mValuePoolDeltas`` | ``mEffectBundles`` | ``mAuthBundles`` | Bundle kind | +| BundleType | BundleVariant | ``mValuePoolDeltas`` | ``mEffectBundles`` | ``mAuthBundles`` | Bundle kind | +============+===============+======================+====================+==================+=============================================================+ | | 0 |✅ |✅ |✅ | TZEs | +------------+---------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ @@ -420,7 +420,7 @@ Transaction Format ``bundleType``. The entries in each map MUST be in increasing order of ``bundleType``. Each map MUST NOT contain more than a single entry for a given ``bundleType``. For each ``bundleType`` that exists in ``mAuthBundles``, a -corresponding entry with the same ``bundleVersion`` must exist in +corresponding entry with the same ``bundleVariant`` must exist in ``mEffectBundles``. ValuePoolDelta @@ -431,7 +431,7 @@ ValuePoolDelta +=============================+==============================+================================================+=====================================================================+ | varies |``bundleType`` |``compactSize`` |An encoding of the bundle type identifier. | +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ -| varies |``bundleVersion`` |``compactSize`` |An encoding of the bundle version identifier. | +| varies |``bundleVariant`` |``compactSize`` |An encoding of the bundle variant identifier. | +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ | 1 |``assetClass`` |``uint8`` |An asset class identifier. 0x00 for the ZEC asset, 0x01 for other | | | | |assets. | @@ -453,7 +453,7 @@ a single entry for a given key. Lookups in this map are denoted with the syntax $\mathsf{mValuePoolDeltas}[(\mathsf{BundleType}, \mathsf{AssetUuid})].$ All entries in ``mValuePoolDeltas`` having the same ``bundleType`` MUST have -the same ``bundleVersion``. +the same ``bundleVariant``. Let $\mathsf{Zec}$ be a distinguished value representing the ZEC asset. It is used as the asset identifier when $\mathsf{assetClass} = 0$. @@ -477,7 +477,7 @@ BundleData +=============================+==============================+================================================+=====================================================================+ | varies |``bundleType`` |``compactSize`` |An encoding of the bundle type identifier. | +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ -| varies |``bundleVersion`` |``compactSize`` |An encoding of the bundle version identifier. | +| varies |``bundleVariant`` |``compactSize`` |An encoding of the bundle variant identifier. | +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ | varies |``nBundleDataLen`` |``compactSize`` |The length of the ``vBundleData`` byte array. | +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ @@ -775,9 +775,9 @@ The following transaction validity rules are added: * For each ``bundleType`` that appears in any of ``mValuePoolDeltas``, ``mEffectBundles``, or ``mAuthBundles``, all entries for that ``bundleType`` - across all three maps MUST have the same ``bundleVersion``. (This, combined + across all three maps MUST have the same ``bundleVariant``. (This, combined with the constraint that each map is keyed by ``bundleType``, ensures that a - transaction uses at most one version of any given bundle type.) + transaction uses at most one variant of any given bundle type.) * For the coinbase transaction, the sum of value pool deltas in the ZEC asset is equal to the negative of the block subsidy for that block; the block @@ -821,8 +821,8 @@ follows:: ├── header_digest ├── value_pool_deltas_digest └── effects_bundles_digest - ├─ (bundle_type_id || bundle_version || transparent_effects_digest) - ├─ (bundle_type_id || bundle_version || sapling_effects_digest) + ├─ (bundle_type_id || bundle_variant || transparent_effects_digest) + ├─ (bundle_type_id || bundle_variant || sapling_effects_digest) │ ├── sapling_spends_digest │ │ ├── sapling_spends_compact_digest │ │ └── sapling_spends_noncompact_digest @@ -830,11 +830,11 @@ follows:: │ ├── sapling_outputs_compact_digest │ ├── sapling_outputs_memos_digest │ └── sapling_outputs_noncompact_digest - ├─ (bundle_type_id || bundle_version || orchard_effects_digest) + ├─ (bundle_type_id || bundle_variant || orchard_effects_digest) │ ├── orchard_actions_compact_digest │ ├── orchard_actions_memos_digest │ └── orchard_actions_noncompact_digest - └─ (bundle_type_id || bundle_version || unknown_bundle_effects_digest) ... + └─ (bundle_type_id || bundle_variant || unknown_bundle_effects_digest) ... Each node written as ``snake_case`` in this tree is a BLAKE2b-256 hash of its children, initialized with a personalization string specific to that branch @@ -883,7 +883,7 @@ A BLAKE2b-256 hash of the concatenated encodings of all entries in For each entry, the following values are concatenated:: T.2a: bundleType (compactSize encoding) - T.2b: bundleVersion (compactSize encoding) + T.2b: bundleVariant (compactSize encoding) T.2c: assetClass (1 byte) T.2d: assetUuid (0 or 64 bytes, depending on assetClass) T.2e: value (8-byte signed little-endian) @@ -906,7 +906,7 @@ bundles present in ``mEffectBundles``, in increasing order of ``bundleType``. Fo bundle, the following values are concatenated:: T.3a: bundleType (compactSize encoding) - T.3b: bundleVersion (compactSize encoding) + T.3b: bundleVariant (compactSize encoding) T.3c: bundle_effects_digest (32-byte hash output) where ``bundle_effects_digest`` is the root hash of the bundle's effecting data @@ -1349,10 +1349,10 @@ the authorizing data of a transaction. The overall structure is:: auth_digest └── auth_bundles_digest - ├─ (bundle_type_id || bundle_version || transparent_auth_digest) - ├─ (bundle_type_id || bundle_version || sapling_auth_digest) - ├─ (bundle_type_id || bundle_version || orchard_auth_digest) - └─ (bundle_type_id || bundle_version || unknown_bundle_auth_digest) ... + ├─ (bundle_type_id || bundle_variant || transparent_auth_digest) + ├─ (bundle_type_id || bundle_variant || sapling_auth_digest) + ├─ (bundle_type_id || bundle_variant || orchard_auth_digest) + └─ (bundle_type_id || bundle_variant || unknown_bundle_auth_digest) ... auth_digest ''''''''''' @@ -1376,7 +1376,7 @@ bundles present in ``mAuthBundles``, in increasing order of ``bundleType``. For bundle, the following values are concatenated:: A.1a: bundleType (compactSize encoding) - A.1b: bundleVersion (compactSize encoding) + A.1b: bundleVariant (compactSize encoding) A.1c: bundle_auth_digest (32-byte hash output) The personalization field of this hash is set to:: @@ -1462,11 +1462,11 @@ bundle type in order to parse a transaction. However, a wallet that encounters a bundle with an unrecognized ``bundleType`` SHOULD alert the user that the transaction contains components it does not understand. A wallet that encounters a bundle with a recognized ``bundleType`` but unrecognized -``bundleVersion`` SHOULD alert the user that the transaction affects a pool the +``bundleVariant`` SHOULD alert the user that the transaction affects a pool the wallet is aware of, but in a way the wallet does not fully understand. A wallet MUST NOT construct or sign a transaction containing a bundle type or -version that it does not fully understand. It MAY, however, correctly compute +variant that it does not fully understand. It MAY, however, correctly compute the transaction identifier or authorizing data commitment of any well-formed v6 transaction by hashing the effecting or authorizing data of unrecognized bundles opaquely (see `Digest Algorithms`_). @@ -1595,9 +1595,9 @@ Sketch of the format: * Transparent transaction value pool "traffic map" - * Option 1: BundleVersionID -> (valueBalance, AssetId -> valueBalance) + * Option 1: BundleVariantID -> (valueBalance, AssetId -> valueBalance) - * Key: Bundle version ID + * Key: Bundle variant ID * Value: * ZEC `valueBalance` @@ -1609,14 +1609,14 @@ Sketch of the format: be understandable independently of protocol changes) * `valueBalance` - * Option 2: (BundleVersionID, Option[AssetId]) -> valueBalance + * Option 2: (BundleVariantID, Option[AssetId]) -> valueBalance - * Key: Bundle version ID encoded as u8 || { Option[AssetId] } + * Key: Bundle variant ID encoded as u8 || { Option[AssetId] } * Value: `valueBalance` - * Option 3: BundleVersionID -> Option[AssetId] -> valueBalance + * Option 3: BundleVariantID -> Option[AssetId] -> valueBalance - * Key: Bundle version ID + * Key: Bundle variant ID * Value: * Map containing one or more generalized value balances @@ -1625,9 +1625,9 @@ Sketch of the format: * `valueBalance` * Sequence of bundles (maybe with a length prefix?) - * Bundle version ID + * Bundle variant ID - * Maybe flag bits, either in the version ID or next to it, that + * Maybe flag bits, either in the variant ID or next to it, that indicate how an opaquely-parsing wallet should interpret the bundle, e.g.: diff --git a/zips/zip-2002.rst b/zips/zip-2002.rst index c5e0cde26..bdb9fc398 100644 --- a/zips/zip-2002.rst +++ b/zips/zip-2002.rst @@ -73,11 +73,11 @@ Specification Changes to ZIP 248 ------------------ -This ZIP proposes to register bundle type 4 version 0 ("Transaction fee") in +This ZIP proposes to register bundle type 4 variant 0 ("Transaction fee") in the V6 transaction bundle type registry defined in ZIP 248 [#zip-0248]_. +------------+---------------+----------------------+--------------------+------------------+ -| BundleType | BundleVersion | ``mValuePoolDeltas`` | ``mEffectBundles`` | ``mAuthBundles`` | +| BundleType | BundleVariant | ``mValuePoolDeltas`` | ``mEffectBundles`` | ``mAuthBundles`` | +============+===============+======================+====================+==================+ | 4 | 0 |✅ |❌ |❌ | +------------+---------------+----------------------+--------------------+------------------+ From 5144996e1f52776dcce1f898914864a52279fec3 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Tue, 24 Mar 2026 14:41:12 -0600 Subject: [PATCH 21/51] [ZIP 248]: Specify `mValuePoolDeltas` encoding order. --- zips/zip-0248.rst | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/zips/zip-0248.rst b/zips/zip-0248.rst index d5207e229..4633d5460 100644 --- a/zips/zip-0248.rst +++ b/zips/zip-0248.rst @@ -416,12 +416,19 @@ Transaction Format | varies |``mAuthBundles`` |``BundleData[nAuthBundles]`` |A map from bundle identifier to the authorizing data of a bundle. | +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +``mValuePoolDeltas`` is interpreted as a map keyed by the tuple +$(\mathsf{BundleType}, \mathsf{AssetUuid})$; this logical map MUST NOT contain +more than a single entry for a given key. The `ValuePoolDelta`_ records that +represent the entries this map MUST be encoded in increasing order of +`(bundleType, assetClass, assetUuid)` Lookups in this map are denoted with the +syntax $\mathsf{mValuePoolDeltas}[(\mathsf{BundleType}, \mathsf{AssetUuid})].$ + ``mEffectBundles`` and ``mAuthBundles`` are interpreted as maps keyed by -``bundleType``. The entries in each map MUST be in increasing order of -``bundleType``. Each map MUST NOT contain more than a single entry for a given -``bundleType``. For each ``bundleType`` that exists in ``mAuthBundles``, a -corresponding entry with the same ``bundleVariant`` must exist in -``mEffectBundles``. +``bundleType``. The records that represent each map entry map MUST be encoded +in increasing order of ``bundleType``. Each map MUST NOT contain more than a +single entry for a given ``bundleType``. For each ``bundleType`` that exists in +``mAuthBundles``, a corresponding entry with the same ``bundleVariant`` must +exist in ``mEffectBundles``. ValuePoolDelta -------------- @@ -1441,7 +1448,7 @@ In the case that the transaction has no Orchard actions:: Implications for Wallets ------------------------ +------------------------ Sending v6 transactions ``````````````````````` From 0db337dcfa0708386e08ffa44d0670230917dc47 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Tue, 24 Mar 2026 14:50:17 -0600 Subject: [PATCH 22/51] [ZIP 248]: Fix ordering constraint in signature hashing. --- zips/zip-0248.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/zips/zip-0248.rst b/zips/zip-0248.rst index 4633d5460..84a07329e 100644 --- a/zips/zip-0248.rst +++ b/zips/zip-0248.rst @@ -886,8 +886,8 @@ T.2: value_pool_deltas_digest ''''''''''''''''''''''''''''' A BLAKE2b-256 hash of the concatenated encodings of all entries in -``mValuePoolDeltas``, in increasing order of ``(bundleType, assetClass, assetUuid)``. -For each entry, the following values are concatenated:: +``mValuePoolDeltas``, in transaction order. For each entry, the following +values are concatenated:: T.2a: bundleType (compactSize encoding) T.2b: bundleVariant (compactSize encoding) @@ -909,8 +909,8 @@ T.3: effects_bundles_digest ''''''''''''''''''''''''''' A BLAKE2b-256 hash of the concatenated tagged bundle effect digests for all -bundles present in ``mEffectBundles``, in increasing order of ``bundleType``. For each -bundle, the following values are concatenated:: +bundles present in ``mEffectBundles``, in transaction order. For each bundle, +the following values are concatenated:: T.3a: bundleType (compactSize encoding) T.3b: bundleVariant (compactSize encoding) @@ -1379,8 +1379,8 @@ A.1: auth_bundles_digest '''''''''''''''''''''''' A BLAKE2b-256 hash of the concatenated tagged bundle auth digests for all -bundles present in ``mAuthBundles``, in increasing order of ``bundleType``. For each -bundle, the following values are concatenated:: +bundles present in ``mAuthBundles``, in transaction order. For each bundle, +the following values are concatenated:: A.1a: bundleType (compactSize encoding) A.1b: bundleVariant (compactSize encoding) From 0f0ffe1a267298d5c7bd89df6cc5c9efdd243a5c Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Tue, 24 Mar 2026 14:56:01 -0600 Subject: [PATCH 23/51] [ZIP 248]: Address comments from code review. --- zips/zip-0248.rst | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/zips/zip-0248.rst b/zips/zip-0248.rst index 84a07329e..b9246db36 100644 --- a/zips/zip-0248.rst +++ b/zips/zip-0248.rst @@ -167,8 +167,9 @@ identified by a ``(bundleType, bundleVariant)`` pair, where: A transaction MUST NOT contain more than one variant of any given bundle type. This constraint is enforced by the map structure of the transaction encoding: -the maps ``mValuePoolDeltas``, ``mEffectBundles``, and ``mAuthBundles`` are -each keyed by ``bundleType`` alone. +the maps ``mEffectBundles``, and ``mAuthBundles`` are each keyed by +``bundleType`` alone; ``mValuePoolDeltas`` is keyed by bundle type and asset +ID. Each bundle type/variant pair defines: @@ -928,11 +929,6 @@ is:: BLAKE2b-256("ZTxIdEffBndHash", []) -For bundle types not recognized by a wallet, the wallet MUST be provided with the -32-byte ``bundle_effects_digest`` value in order to compute the transaction -identifier. This enables partial verification of transactions containing unknown -bundle types. - T.3.0: transparent_effects_digest ................................. @@ -1465,19 +1461,21 @@ on the network. Because the v6 transaction format uses a type-length-value encoding for bundles, a wallet is not required to understand the internal encoding of every -bundle type in order to parse a transaction. However, a wallet that encounters -a bundle with an unrecognized ``bundleType`` SHOULD alert the user that the +bundle in order to parse a transaction. However, a wallet that encounters a +bundle with an unrecognized ``bundleType`` SHOULD alert the user that the transaction contains components it does not understand. A wallet that encounters a bundle with a recognized ``bundleType`` but unrecognized ``bundleVariant`` SHOULD alert the user that the transaction affects a pool the wallet is aware of, but in a way the wallet does not fully understand. -A wallet MUST NOT construct or sign a transaction containing a bundle type or -variant that it does not fully understand. It MAY, however, correctly compute -the transaction identifier or authorizing data commitment of any well-formed -v6 transaction by hashing the effecting or authorizing data of unrecognized -bundles opaquely (see `Digest Algorithms`_). +For bundle types not understood by a wallet, the wallet can compute the +transaction identifier so long as it has been provided with the 32-byte +``bundle_effects_digest`` value for each bundle that it does not understand. +This enables partial verification of transactions containing unknown bundle +types. +A wallet MUST NOT construct or sign a transaction containing a bundle type or +variant that it does not fully understand. Rationale ========= From c5f0607a6669ef6a2b83be3868624dda43411bf0 Mon Sep 17 00:00:00 2001 From: arya2 Date: Fri, 3 Apr 2026 21:43:41 -0400 Subject: [PATCH 24/51] Add sighash versioning and associated data definitions for V6 transactions Co-Authored-By: Claude (unknown version) --- zips/zip-0248.rst | 102 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 88 insertions(+), 14 deletions(-) diff --git a/zips/zip-0248.rst b/zips/zip-0248.rst index b9246db36..5eeae851c 100644 --- a/zips/zip-0248.rst +++ b/zips/zip-0248.rst @@ -561,12 +561,20 @@ TransparentInputAuth +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ | Bytes | Name | Data Type | Description | +=============================+==========================+========================================+=====================================================================+ +|``varies`` |``sighashInfo`` |``TransparentSighashInfo`` |The sighash version and associated information for this input. | +| | | |[#zip-0230-transparent-sighash-info]_ [#zip-0246-sighash-versioning]_| ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ |``varies`` |``scriptSigLen`` |``compactSize`` |Length of the scriptSig. | +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ |``scriptSigLen`` |``scriptSig`` |``byte[scriptSigLen]`` |The script satisfying the conditions of the referenced output's | | | | |scriptPubKey. | +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +The ``TransparentSighashInfo`` type is defined in ZIP 230 +[#zip-0230-transparent-sighash-info]_. It consists of a ``compactSize``-prefixed +byte array containing the sighash version and any associated data required by +that version, as specified in ZIP 246 [#zip-0246-sighash-versioning]_. + Sapling Bundle -------------- @@ -641,11 +649,13 @@ that authorize the spends and validate the outputs. +=============================+==========================+========================================+=====================================================================+ |``192 * nSpendsSapling`` |``vSpendProofsSapling`` |``byte[192 * nSpendsSapling]`` |Encodings of the zk-SNARK proofs for each Sapling Spend. | +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -|``64 * nSpendsSapling`` |``vSpendAuthSigsSapling`` |``byte[64 * nSpendsSapling]`` |Authorizing signatures for each Sapling Spend. | +|``varies`` |``vSpendAuthSigsSapling`` |``SaplingSignature[nSpendsSapling]`` |Authorizing signatures for each Sapling Spend. | +| | | |[#zip-0230-sapling-signature]_ | +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ |``192 * nOutputsSapling`` |``vOutputProofsSapling`` |``byte[192 * nOutputsSapling]`` |Encodings of the zk-SNARK proofs for each Sapling Output. | +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -|``64`` |``bindingSigSapling`` |``byte[64]`` |A Sapling binding signature on the SIGHASH transaction hash. | +|``varies`` |``bindingSigSapling`` |``SaplingSignature`` |A Sapling binding signature on the SIGHASH transaction hash. | +| | | |[#zip-0230-sapling-signature]_ | +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ * The values of ``nSpendsSapling`` and ``nOutputsSapling`` are not re-encoded in @@ -735,9 +745,11 @@ that authorize the actions. +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ |``sizeProofsOrchard`` |``proofsOrchard`` |``byte[sizeProofsOrchard]`` |Encoding of aggregated zk-SNARK proofs for Orchard Actions. | +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -|``64 * nActionsOrchard`` |``vSpendAuthSigsOrchard`` |``byte[64 * nActionsOrchard]`` |Authorizing signatures for each Orchard Action. | +|``varies`` |``vSpendAuthSigsOrchard`` |``OrchardSignature[nActionsOrchard]`` |Authorizing signatures for each Orchard Action. | +| | | |[#zip-0230-orchard-signature]_ | +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -|``64`` |``bindingSigOrchard`` |``byte[64]`` |An Orchard binding signature on the SIGHASH transaction hash. | +|``varies`` |``bindingSigOrchard`` |``OrchardSignature`` |An Orchard binding signature on the SIGHASH transaction hash. | +| | | |[#zip-0230-orchard-signature]_ | +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ * The value of ``nActionsOrchard`` is not re-encoded in the authorizing data; it @@ -806,6 +818,44 @@ The following transaction validity rules are added: \forall \mathsf{a}. \sum_{\mathsf{d} \in \mathsf{mValuePoolDeltas} | \mathsf{AssetUuid}(\mathsf{d}) = \mathsf{a}} \mathsf{d.value} = 0 +Sighash Versioning +------------------- + +This ZIP adopts the sighash algorithm versioning defined in ZIP 246 +[#zip-0246-sighash-versioning]_. Where previously each transaction version had a +single associated sighash algorithm, going forward it is possible for signers to +use any sighash algorithm within the closed set specified for a given transaction +version (and made available in consensus via network upgrades). + +The sighash version is encoded as a single byte alongside any associated data +that the sighash algorithm version requires (for deterministically computing the +digest): + +``sighashInfo = [sighashVersion] || associatedData`` + +where ``associatedData`` is specific to the bundle it appears in. + +The following sighash algorithm versions are defined for V6 transactions: + ++--------------------+-------------------------------------------------------+ +| |:math:`\hspace{4.5em}` ``associatedData`` | ++--------------------+-------------+-------------+-------------+-------------+ +| ``sighashVersion`` | Transparent | Sapling | Orchard | Issuance | ++--------------------+-------------+-------------+-------------+-------------+ +| 0 |``[]`` |``[]`` |``[]`` |``[]`` | ++--------------------+-------------+-------------+-------------+-------------+ + +Version 0 is by convention the "commit to all effecting data" sighash algorithm. +Other versions can commit to whatever makes sense for desired functionality +within a given transaction version. Consensus rules choose the digest algorithm +for each signer based on ``sighashVersion``. + +Sighash version information is present alongside each signature in the +authorizing data of the transaction, via the per-signature structures defined in +ZIP 230 [#zip-0230]_ (``TransparentSighashInfo``, ``SaplingSignature``, +``OrchardSignature``). See ZIP 246 [#zip-0246]_ for the full specification of +sighash versioning. + Digest Algorithms ----------------- @@ -864,7 +914,7 @@ The personalization field of this hash is set to:: ``ZcashTxHash_`` has 1 underscore character. -As in ZIP 143 [#zip-0143]_, CONSENSUS_BRANCH_ID is the 4-byte little-endian +As in ZIP 244 [#zip-0244]_, CONSENSUS_BRANCH_ID is the 4-byte little-endian encoding of the consensus branch ID for the epoch of the block containing the transaction. @@ -1195,6 +1245,13 @@ A new per-input transaction digest algorithm is defined that constructs a hash that may be signed by a transaction creator to commit to the effects of the transaction. This follows closely the algorithm from ZIP 244 [#zip-0244]_. +The digest algorithm used for a given signature is determined by the +``sighashVersion`` from the signer's ``sighashInfo``, as specified in the +`Sighash Versioning`_ section. For sighash version 0 (the only version +currently defined for V6 transactions), the digest algorithm is as specified +below. Future sighash versions, defined via updates to ZIP 246 +[#zip-0246]_, may specify different digest algorithms. + For transactions that have no transparent inputs, the signature digest is identical to the transaction identifier digest. @@ -1265,8 +1322,8 @@ The following restrictions apply: - Using ``SIGHASH_SINGLE`` without a corresponding output at the same index causes validation failure. -For signatures over Sapling Spends or Orchard Actions, ``hash_type`` is set to -``SIGHASH_ALL`` (0x01). +For sighash version 0, signatures over Sapling Spends or Orchard Actions use +``hash_type = SIGHASH_ALL`` (0x01). S.3.0b: prevouts_sig_digest ~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1394,8 +1451,14 @@ A.1.0: transparent_auth_digest .............................. In the case that the transaction contains transparent inputs, this is a -BLAKE2b-256 hash of the concatenated ``scriptSig`` values (each with leading -``compactSize`` length) for all transparent inputs. +BLAKE2b-256 hash of the following concatenated values for each transparent +input:: + + A.1.0a: TransparentSighashInfo (field encoding bytes) + A.1.0b: scriptSig (field encoding bytes, with compactSize length prefix) + +The field encoding of ``TransparentSighashInfo`` is specified in ZIP 230 +[#zip-0230-transparent-sighash-info]_. The personalization field of this hash is set to:: @@ -1412,9 +1475,12 @@ In the case that Sapling spends or outputs are present, this is a BLAKE2b-256 hash of the following concatenated values:: A.1.2a: vSpendProofsSapling (192 bytes per spend) - A.1.2b: vSpendAuthSigsSapling (64 bytes per spend) + A.1.2b: vSpendAuthSigsSapling (SaplingSignature field encoding per spend) A.1.2c: vOutputProofsSapling (192 bytes per output) - A.1.2d: bindingSigSapling (64 bytes) + A.1.2d: bindingSigSapling (SaplingSignature field encoding) + +The ``SaplingSignature`` field encoding includes ``sighashInfo``, as specified in +ZIP 230 [#zip-0230-sapling-signature]_. The personalization field of this hash is set to:: @@ -1431,8 +1497,11 @@ In the case that Orchard actions are present, this is a BLAKE2b-256 hash of the following concatenated values:: A.1.3a: proofsOrchard (aggregated proofs) - A.1.3b: vSpendAuthSigsOrchard (64 bytes per action) - A.1.3c: bindingSigOrchard (64 bytes) + A.1.3b: vSpendAuthSigsOrchard (OrchardSignature field encoding per action) + A.1.3c: bindingSigOrchard (OrchardSignature field encoding) + +The ``OrchardSignature`` field encoding includes ``sighashInfo``, as specified in +ZIP 230 [#zip-0230-orchard-signature]_. The personalization field of this hash is set to:: @@ -1722,11 +1791,16 @@ References .. [#protocol-blockchain] `Zcash Protocol Specification, Version 2025.6.3 [NU6.1]. Section 3.3: The Block Chain `_ .. [#protocol-networks] `Zcash Protocol Specification, Version 2025.6.3 [NU6.1]. Section 3.12: Mainnet and Testnet `_ .. [#protocol-subsidies] `Zcash Protocol Specification, Version 2025.6.3 [NU6.1]. Section 7.8: Block Subsidy and Founders' Reward `_ -.. [#zip-0143] `ZIP 143: Transaction Signature Validation for Overwinter `_ .. [#zip-0203] `ZIP 203: Transaction Expiry `_ .. [#zip-0212] `ZIP 212: Allow Recipient to Derive Ephemeral Secret from Note Plaintext `_ .. [#zip-0225] `ZIP 225: Version 5 Transaction Format `_ +.. [#zip-0230] `ZIP 230: Version 6 Transaction Format `_ +.. [#zip-0230-transparent-sighash-info] `ZIP 230: Version 6 Transaction Format — Transparent Sighash Information `_ +.. [#zip-0230-sapling-signature] `ZIP 230: Version 6 Transaction Format — Sapling Signature `_ +.. [#zip-0230-orchard-signature] `ZIP 230: Version 6 Transaction Format — Orchard Signature `_ .. [#zip-0239] `ZIP 239: Relay of Version 5 Transactions `_ .. [#zip-0244] `ZIP 244: Transaction Identifier Non-Malleability `_ +.. [#zip-0246] `ZIP 246: Digests for the Version 6 Transaction Format `_ +.. [#zip-0246-sighash-versioning] `ZIP 246: Digests for the Version 6 Transaction Format — Sighash Versioning `_ .. [#zip-0307] `ZIP 307: Light Client Protocol for Payment Detection `_ From 6a021cc3bf434853b97f3946ecde03fa59fd9ccc Mon Sep 17 00:00:00 2001 From: arya2 Date: Tue, 7 Apr 2026 16:27:16 -0400 Subject: [PATCH 25/51] Remove references to ZIP 230 and ZIP 246 Co-Authored-By: Claude (unknown version) --- zips/zip-0248.rst | 103 +++++++++++++++++++++++++++++++--------------- 1 file changed, 70 insertions(+), 33 deletions(-) diff --git a/zips/zip-0248.rst b/zips/zip-0248.rst index 5eeae851c..f511e117e 100644 --- a/zips/zip-0248.rst +++ b/zips/zip-0248.rst @@ -561,8 +561,8 @@ TransparentInputAuth +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ | Bytes | Name | Data Type | Description | +=============================+==========================+========================================+=====================================================================+ -|``varies`` |``sighashInfo`` |``TransparentSighashInfo`` |The sighash version and associated information for this input. | -| | | |[#zip-0230-transparent-sighash-info]_ [#zip-0246-sighash-versioning]_| +|``varies`` |``sighashInfo`` |``TransparentSighashInfo`` |The sighash version and associated information for this input, | +| | | |as defined in `Per-Signature Structures`_. | +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ |``varies`` |``scriptSigLen`` |``compactSize`` |Length of the scriptSig. | +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ @@ -570,10 +570,9 @@ TransparentInputAuth | | | |scriptPubKey. | +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -The ``TransparentSighashInfo`` type is defined in ZIP 230 -[#zip-0230-transparent-sighash-info]_. It consists of a ``compactSize``-prefixed -byte array containing the sighash version and any associated data required by -that version, as specified in ZIP 246 [#zip-0246-sighash-versioning]_. +The ``TransparentSighashInfo`` type is defined in `Per-Signature Structures`_. +It consists of a ``compactSize``-prefixed byte array containing the sighash +version and any associated data required by that version. Sapling Bundle @@ -650,12 +649,10 @@ that authorize the spends and validate the outputs. |``192 * nSpendsSapling`` |``vSpendProofsSapling`` |``byte[192 * nSpendsSapling]`` |Encodings of the zk-SNARK proofs for each Sapling Spend. | +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ |``varies`` |``vSpendAuthSigsSapling`` |``SaplingSignature[nSpendsSapling]`` |Authorizing signatures for each Sapling Spend. | -| | | |[#zip-0230-sapling-signature]_ | +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ |``192 * nOutputsSapling`` |``vOutputProofsSapling`` |``byte[192 * nOutputsSapling]`` |Encodings of the zk-SNARK proofs for each Sapling Output. | +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ |``varies`` |``bindingSigSapling`` |``SaplingSignature`` |A Sapling binding signature on the SIGHASH transaction hash. | -| | | |[#zip-0230-sapling-signature]_ | +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ * The values of ``nSpendsSapling`` and ``nOutputsSapling`` are not re-encoded in @@ -746,10 +743,8 @@ that authorize the actions. |``sizeProofsOrchard`` |``proofsOrchard`` |``byte[sizeProofsOrchard]`` |Encoding of aggregated zk-SNARK proofs for Orchard Actions. | +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ |``varies`` |``vSpendAuthSigsOrchard`` |``OrchardSignature[nActionsOrchard]`` |Authorizing signatures for each Orchard Action. | -| | | |[#zip-0230-orchard-signature]_ | +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ |``varies`` |``bindingSigOrchard`` |``OrchardSignature`` |An Orchard binding signature on the SIGHASH transaction hash. | -| | | |[#zip-0230-orchard-signature]_ | +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ * The value of ``nActionsOrchard`` is not re-encoded in the authorizing data; it @@ -821,11 +816,11 @@ The following transaction validity rules are added: Sighash Versioning ------------------- -This ZIP adopts the sighash algorithm versioning defined in ZIP 246 -[#zip-0246-sighash-versioning]_. Where previously each transaction version had a -single associated sighash algorithm, going forward it is possible for signers to -use any sighash algorithm within the closed set specified for a given transaction -version (and made available in consensus via network upgrades). +This ZIP introduces sighash algorithm versioning. Where previously each +transaction version had a single associated sighash algorithm, going forward it +is possible for signers to use any sighash algorithm within the closed set +specified for a given transaction version (and made available in consensus via +network upgrades). The sighash version is encoded as a single byte alongside any associated data that the sighash algorithm version requires (for deterministically computing the @@ -851,10 +846,58 @@ within a given transaction version. Consensus rules choose the digest algorithm for each signer based on ``sighashVersion``. Sighash version information is present alongside each signature in the -authorizing data of the transaction, via the per-signature structures defined in -ZIP 230 [#zip-0230]_ (``TransparentSighashInfo``, ``SaplingSignature``, -``OrchardSignature``). See ZIP 246 [#zip-0246]_ for the full specification of -sighash versioning. +authorizing data of the transaction, via the per-signature structures defined +below. + +Per-Signature Structures +```````````````````````` + +The following structures carry sighash version information alongside each +signature in the authorizing data of a V6 transaction. + +Transparent Sighash Information (``TransparentSighashInfo``) +............................................................ + ++-----------------------------+------------------------------+----------------------------------+---------------------------------------------------+ +| Bytes | Name | Data Type | Description | ++=============================+==============================+==================================+===================================================+ +| varies |``sizeSighashInfo`` |``compactSize`` |The size in bytes of ``sighashInfo``. | ++-----------------------------+------------------------------+----------------------------------+---------------------------------------------------+ +| ``sizeSighashInfo`` |``sighashInfo`` |``byte[sizeSighashInfo]`` |The sighash version and associated information, | +| | | |as defined in `Sighash Versioning`_. | ++-----------------------------+------------------------------+----------------------------------+---------------------------------------------------+ + +Sapling Signature (``SaplingSignature``) +........................................ + ++-----------------------------+------------------------------+----------------------------------+---------------------------------------------------+ +| Bytes | Name | Data Type | Description | ++=============================+==============================+==================================+===================================================+ +| varies |``sizeSighashInfo`` |``compactSize`` |The size in bytes of ``sighashInfo``. | ++-----------------------------+------------------------------+----------------------------------+---------------------------------------------------+ +| ``sizeSighashInfo`` |``sighashInfo`` |``byte[sizeSighashInfo]`` |The sighash version and associated information, | +| | | |as defined in `Sighash Versioning`_. | ++-----------------------------+------------------------------+----------------------------------+---------------------------------------------------+ +| 64 |``signature`` |``byte[64]`` |An encoding of a RedJubjub signature, which may be | +| | | |either a ``spendAuthSig`` or ``bindingSig`` | +| | | |depending on context. | ++-----------------------------+------------------------------+----------------------------------+---------------------------------------------------+ + +Orchard Signature (``OrchardSignature``) +........................................ + ++-----------------------------+------------------------------+----------------------------------+---------------------------------------------------+ +| Bytes | Name | Data Type | Description | ++=============================+==============================+==================================+===================================================+ +| varies |``sizeSighashInfo`` |``compactSize`` |The size in bytes of ``sighashInfo``. | ++-----------------------------+------------------------------+----------------------------------+---------------------------------------------------+ +| ``sizeSighashInfo`` |``sighashInfo`` |``byte[sizeSighashInfo]`` |The sighash version and associated information, | +| | | |as defined in `Sighash Versioning`_. | ++-----------------------------+------------------------------+----------------------------------+---------------------------------------------------+ +| 64 |``signature`` |``byte[64]`` |An encoding of a RedPallas signature, which may be | +| | | |either a ``spendAuthSig`` or ``bindingSig`` | +| | | |depending on context. | ++-----------------------------+------------------------------+----------------------------------+---------------------------------------------------+ Digest Algorithms ----------------- @@ -1249,8 +1292,8 @@ The digest algorithm used for a given signature is determined by the ``sighashVersion`` from the signer's ``sighashInfo``, as specified in the `Sighash Versioning`_ section. For sighash version 0 (the only version currently defined for V6 transactions), the digest algorithm is as specified -below. Future sighash versions, defined via updates to ZIP 246 -[#zip-0246]_, may specify different digest algorithms. +below. Future network upgrades may define additional sighash algorithm versions +with divergent behavior. For transactions that have no transparent inputs, the signature digest is identical to the transaction identifier digest. @@ -1457,8 +1500,8 @@ input:: A.1.0a: TransparentSighashInfo (field encoding bytes) A.1.0b: scriptSig (field encoding bytes, with compactSize length prefix) -The field encoding of ``TransparentSighashInfo`` is specified in ZIP 230 -[#zip-0230-transparent-sighash-info]_. +The field encoding of ``TransparentSighashInfo`` is defined in +`Per-Signature Structures`_. The personalization field of this hash is set to:: @@ -1479,8 +1522,8 @@ hash of the following concatenated values:: A.1.2c: vOutputProofsSapling (192 bytes per output) A.1.2d: bindingSigSapling (SaplingSignature field encoding) -The ``SaplingSignature`` field encoding includes ``sighashInfo``, as specified in -ZIP 230 [#zip-0230-sapling-signature]_. +The ``SaplingSignature`` field encoding is defined in `Per-Signature Structures`_ +and includes ``sighashInfo``. The personalization field of this hash is set to:: @@ -1500,8 +1543,8 @@ following concatenated values:: A.1.3b: vSpendAuthSigsOrchard (OrchardSignature field encoding per action) A.1.3c: bindingSigOrchard (OrchardSignature field encoding) -The ``OrchardSignature`` field encoding includes ``sighashInfo``, as specified in -ZIP 230 [#zip-0230-orchard-signature]_. +The ``OrchardSignature`` field encoding is defined in `Per-Signature Structures`_ +and includes ``sighashInfo``. The personalization field of this hash is set to:: @@ -1794,13 +1837,7 @@ References .. [#zip-0203] `ZIP 203: Transaction Expiry `_ .. [#zip-0212] `ZIP 212: Allow Recipient to Derive Ephemeral Secret from Note Plaintext `_ .. [#zip-0225] `ZIP 225: Version 5 Transaction Format `_ -.. [#zip-0230] `ZIP 230: Version 6 Transaction Format `_ -.. [#zip-0230-transparent-sighash-info] `ZIP 230: Version 6 Transaction Format — Transparent Sighash Information `_ -.. [#zip-0230-sapling-signature] `ZIP 230: Version 6 Transaction Format — Sapling Signature `_ -.. [#zip-0230-orchard-signature] `ZIP 230: Version 6 Transaction Format — Orchard Signature `_ .. [#zip-0239] `ZIP 239: Relay of Version 5 Transactions `_ .. [#zip-0244] `ZIP 244: Transaction Identifier Non-Malleability `_ -.. [#zip-0246] `ZIP 246: Digests for the Version 6 Transaction Format `_ -.. [#zip-0246-sighash-versioning] `ZIP 246: Digests for the Version 6 Transaction Format — Sighash Versioning `_ .. [#zip-0307] `ZIP 307: Light Client Protocol for Payment Detection `_ From 79fd00f1387967fd3e322f27f95edda075e316a4 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood Date: Thu, 9 Apr 2026 04:31:22 +0100 Subject: [PATCH 26/51] [ZIP 248]: Add Parsing Rules section. A "Parsing Rules" section, ahead of the per-bundle format definitions and "Consensus Rules", lists the parser-level invariants that any v6 parser must enforce regardless of which bundle types it understands. This makes it explicit that parsing the format is safe even for parsers that don't recognize every bundle type, and gives wallets a single place to look for the constraints they need to check before they can compute the txid or enumerate transparent value flows. Move the cross-map "all entries for the same bundleType across the three maps must encode the same bundleVariant" rule, the per-element 1:1 correspondences in the Sapling authorizing-data section, and the analogous rules in the Orchard authorizing-data section into the new section. Their previous locations are replaced with one-line forward references. Co-Authored-By: Claude Opus 4.6 (1M context) --- zips/zip-0248.rst | 86 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 66 insertions(+), 20 deletions(-) diff --git a/zips/zip-0248.rst b/zips/zip-0248.rst index f511e117e..f8c4abefa 100644 --- a/zips/zip-0248.rst +++ b/zips/zip-0248.rst @@ -495,6 +495,66 @@ BundleData +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +Parsing Rules +------------- + +The rules in this section are requirements on the byte encoding of a V6 +transaction. A byte stream that violates any of these rules is not a +well-formed V6 transaction and MUST be rejected by any parser, regardless +of which bundle types the parser understands. Enforcement of these rules +is what makes it safe for a wallet to parse, identify, and compute the +transaction identifier for a transaction containing bundle types that the +wallet does not itself implement. + +* Each of ``mValuePoolDeltas``, ``mEffectBundles``, and ``mAuthBundles`` MUST + contain at most one entry per key, and the entries MUST be encoded in + strictly increasing key order as defined in `Transaction Format`_. + +* Every ``ValuePoolDelta`` record MUST have a nonzero ``value`` field. A + ``ValuePoolDelta`` record that would have ``value = 0`` MUST be elided from + the encoding of ``mValuePoolDeltas``. + +* In every ``ValuePoolDelta`` record, ``assetUuid`` MUST be the zero-length + byte array if ``assetClass = 0``, and MUST be a 64-byte value if + ``assetClass = 1``. No other value of ``assetClass`` is permitted. + +* For each ``bundleType`` that appears in any of ``mValuePoolDeltas``, + ``mEffectBundles``, or ``mAuthBundles``, all entries for that ``bundleType`` + across all three maps MUST encode the same ``bundleVariant``. (This, + combined with the constraint that each of ``mEffectBundles`` and + ``mAuthBundles`` is keyed by ``bundleType``, ensures that a transaction + uses at most one variant of any given bundle type.) + +* For each ``bundleType`` that appears in ``mAuthBundles``, a corresponding + entry with the same ``bundleVariant`` MUST exist in ``mEffectBundles``. + +* A bundle type MUST NOT appear in any map for which the corresponding column + of the `V6 Transaction Bundle Type Registry`_ is marked ❌, and MUST NOT + appear in any map at all if its row in the registry is marked as Reserved. + +* Within the encoding of any bundle's effecting and authorizing data, every + per-element sequence in the authorizing data that is described as + corresponding to a per-element sequence in the effecting data MUST have + exactly the same length as that effecting-data sequence, and the element at + each index in the authorizing-data sequence corresponds to the element at + the same index in the effecting-data sequence. For the bundle types + defined by this ZIP this requires: + + * ``vSpendProofsSapling`` and ``vSpendAuthSigsSapling`` each have + ``nSpendsSapling`` elements; + * ``vOutputProofsSapling`` has ``nOutputsSapling`` elements; + * ``vSpendAuthSigsOrchard`` has ``nActionsOrchard`` elements, and + ``proofsOrchard`` aggregates exactly ``nActionsOrchard`` per-action + proofs. + +A wallet that successfully parses a V6 transaction under these rules is +guaranteed to be able to compute the transaction identifier (given, for +each bundle type it does not understand, the corresponding 32-byte +``bundle_effects_digest`` value as described in `Implications for Wallets`_), +and to enumerate the transparent value flows of the transaction at the +granularity of bundle types. + + Transparent Bundle ------------------ @@ -661,15 +721,9 @@ that authorize the spends and validate the outputs. * The field ``bindingSigSapling`` is present if and only if $\mathtt{nSpendsSapling} + \mathtt{nOutputsSapling} > 0$. -* The elements of ``vSpendProofsSapling`` and ``vSpendAuthSigsSapling`` have a - 1:1 correspondence to the elements of ``vSpendsSapling`` in the effecting data - and MUST be ordered such that the element at a given index corresponds to the - ``SaplingSpendEffecting`` at the same index. - -* The elements of ``vOutputProofsSapling`` have a 1:1 correspondence to the - elements of ``vOutputsSapling`` in the effecting data and MUST be ordered such - that the proof at a given index corresponds to the ``SaplingOutput`` at the - same index. +The 1:1 correspondences between Sapling authorizing-data elements and the +elements of the corresponding effecting data are required by the parsing +rules in `Parsing Rules`_. Orchard Bundle @@ -753,11 +807,9 @@ that authorize the actions. * The fields ``sizeProofsOrchard``, ``proofsOrchard``, and ``bindingSigOrchard`` are present if and only if $\mathtt{nActionsOrchard} > 0$. -* The proofs aggregated in ``proofsOrchard``, and the elements of - ``vSpendAuthSigsOrchard``, each have a 1:1 correspondence to the elements of - ``vActionsOrchard`` in the effecting data and MUST be ordered such that the - proof or signature at a given index corresponds to the - ``OrchardActionEffecting`` at the same index. +The 1:1 correspondences between Orchard authorizing-data elements and the +elements of the corresponding effecting data are required by the parsing +rules in `Parsing Rules`_. Consensus Rules @@ -788,12 +840,6 @@ The following transaction validity rules are added: That is, the fees collected by the coinbase transaction must equal the sum of fees paid by all other transactions in the block. -* For each ``bundleType`` that appears in any of ``mValuePoolDeltas``, - ``mEffectBundles``, or ``mAuthBundles``, all entries for that ``bundleType`` - across all three maps MUST have the same ``bundleVariant``. (This, combined - with the constraint that each map is keyed by ``bundleType``, ensures that a - transaction uses at most one variant of any given bundle type.) - * For the coinbase transaction, the sum of value pool deltas in the ZEC asset is equal to the negative of the block subsidy for that block; the block subsidy adds an implicit input value to the transparent transaction value From 66a589b71da14c1a44a6db0ab5e6d29d0e213aff Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood Date: Thu, 9 Apr 2026 04:40:17 +0100 Subject: [PATCH 27/51] [ZIP 248]: Restructure Consensus Rules into bundle-local and cross-bundle subsections. The bundle-local rules ("assetClass = 0 for fee bundle entries", and "coinbase transactions must have enableSpendsOrchard = 0") only need to be enforced by parties that understand the bundle type they apply to, while the cross-bundle / chain-context rules (per-block fee sum, coinbase ZEC subsidy sum, non-coinbase per-asset value pool delta sum) require full validators with block context. The "coinbase transactions must have enableSpendsOrchard = 0" rule was previously stated in passing in the prose under the Orchard flagsOrchard field; lift it into the new bundle-local subsection so all consensus rules are in one place. Co-Authored-By: Claude Opus 4.6 (1M context) --- zips/zip-0248.rst | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/zips/zip-0248.rst b/zips/zip-0248.rst index f8c4abefa..7e23bc59f 100644 --- a/zips/zip-0248.rst +++ b/zips/zip-0248.rst @@ -756,8 +756,6 @@ not included here; it appears in ``mValuePoolDeltas`` instead. * The fields ``flagsOrchard`` and ``anchorOrchard`` are present if and only if $\mathtt{nActionsOrchard} > 0$. -* For coinbase transactions, the ``enableSpendsOrchard`` bit MUST be set to $0$. - OrchardActionEffecting '''''''''''''''''''''' @@ -816,17 +814,34 @@ Consensus Rules --------------- This ZIP requires the following modifications to the consensus rules in the -Zcash Protocol Specification. +Zcash Protocol Specification. These rules are additional to the parsing rules +above; a transaction that satisfies the parsing rules but violates any of +these consensus rules is well-formed but invalid. Let ``FeeBundleId`` be the identifier of the fee bundle. In V6 transactions, $\mathsf{FeeBundleId} = 4$ as defined in the table above. -The following transaction validity rules are added: +Bundle-local rules +`````````````````` + +The following rules constrain the contents of individual bundles. A wallet +or full validator only needs to enforce a given rule in this subsection if +it understands the bundle type that the rule applies to. * The ``assetClass`` value for any entry in ``mValuePoolDeltas`` having ``bundleType = FeeBundleId`` is 0 (fee amounts are denominated in ZEC and no other asset.) +* For coinbase transactions, the ``enableSpendsOrchard`` bit of the Orchard + bundle's ``flagsOrchard`` field MUST be 0. + +Cross-bundle and chain-context rules +```````````````````````````````````` + +The following rules relate value pool deltas across bundles within a +transaction, or across transactions within a block. They MUST be enforced by +full validators. + * For coinbase transactions, the value of $\mathsf{mValuePoolDeltas}[(\mathsf{FeeBundleId}, \mathsf{Zec})]$ must be nonnegative. This represents the total transaction fees collected from all other transactions in the block. From 7eb5a0021ecbe8dbc07ab89fe55deef35f958c7a Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood Date: Thu, 9 Apr 2026 04:41:33 +0100 Subject: [PATCH 28/51] [ZIP 248]: Clarify anchorSapling handling at T.3.2c when nSpendsSapling = 0. The wire format for v6 Sapling effecting data omits anchorSapling when there are no Sapling spends, but T.3.2c lists anchorSapling as an unconditional 32-byte component of sapling_effects_digest. State explicitly that the value hashed at T.3.2c is 32 zero bytes in that case, so the digest structure remains fixed for any non-empty Sapling bundle. Co-Authored-By: Claude Opus 4.6 (1M context) --- zips/zip-0248.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/zips/zip-0248.rst b/zips/zip-0248.rst index 7e23bc59f..cd24c588a 100644 --- a/zips/zip-0248.rst +++ b/zips/zip-0248.rst @@ -1163,6 +1163,11 @@ The personalization field of this hash is set to:: "ZTxIdSaplingHash" +If $\mathtt{nSpendsSapling} = 0$ (in which case the ``anchorSapling`` field is +not present in the wire encoding), the value hashed at position T.3.2c is 32 +zero bytes. Otherwise it is the encoding of ``anchorSapling`` as it appears in +the Sapling effecting data. + Note that unlike ZIP 244, the value balance is not included here; it is committed via ``value_pool_deltas_digest`` instead. From cfcbe371901728b0faabfbed160c2d28e2d16256 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood Date: Thu, 9 Apr 2026 04:43:05 +0100 Subject: [PATCH 29/51] [ZIP 248]: Pad ZTxIdEffBndHash and ZTxAuthBndHash personalizations to 16 characters. Every other personalization string in the digest tree is exactly 16 characters, but ZTxIdEffBndHash (15) and ZTxAuthBndHash (14) were shorter, leaving the padding for the trailing bytes ambiguous. Rename them to ZTxIdEffBnd_Hash (1 underscore) and ZTxAuthBnd__Hash (2 underscores), matching the existing underscore-padding convention used elsewhere in this ZIP (e.g. ZTxIdSOutC__Hash) and in ZIP 244. Co-Authored-By: Claude Opus 4.6 (1M context) --- zips/zip-0248.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/zips/zip-0248.rst b/zips/zip-0248.rst index cd24c588a..205f82fce 100644 --- a/zips/zip-0248.rst +++ b/zips/zip-0248.rst @@ -1076,12 +1076,12 @@ tree, as defined below for each known bundle type. The personalization field of this hash is set to:: - "ZTxIdEffBndHash" + "ZTxIdEffBnd_Hash" (1 underscore character) In the case that the transaction has no effect bundles, ``effects_bundles_digest`` is:: - BLAKE2b-256("ZTxIdEffBndHash", []) + BLAKE2b-256("ZTxIdEffBnd_Hash", []) T.3.0: transparent_effects_digest ................................. @@ -1550,11 +1550,11 @@ the following values are concatenated:: The personalization field of this hash is set to:: - "ZTxAuthBndHash" + "ZTxAuthBnd__Hash" (2 underscore characters) In the case that the transaction has no auth bundles, ``auth_bundles_digest`` is:: - BLAKE2b-256("ZTxAuthBndHash", []) + BLAKE2b-256("ZTxAuthBnd__Hash", []) A.1.0: transparent_auth_digest .............................. From 334453a2d4337b2aa0dac65ca830040aad988fd1 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood Date: Thu, 9 Apr 2026 05:01:26 +0100 Subject: [PATCH 30/51] [ZIP 248]: Fix heading underline in Per-Signature Structures. Use "'" instead of "." for the sub-headings, so they're level 4 (matching the rest of the document) instead of level 5. The previous underline triggered a docutils "Title level inconsistent" SEVERE error and the document failed to render. Co-Authored-By: Claude Opus 4.6 (1M context) --- zips/zip-0248.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/zips/zip-0248.rst b/zips/zip-0248.rst index 205f82fce..42a890394 100644 --- a/zips/zip-0248.rst +++ b/zips/zip-0248.rst @@ -917,7 +917,7 @@ The following structures carry sighash version information alongside each signature in the authorizing data of a V6 transaction. Transparent Sighash Information (``TransparentSighashInfo``) -............................................................ +'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' +-----------------------------+------------------------------+----------------------------------+---------------------------------------------------+ | Bytes | Name | Data Type | Description | @@ -929,7 +929,7 @@ Transparent Sighash Information (``TransparentSighashInfo``) +-----------------------------+------------------------------+----------------------------------+---------------------------------------------------+ Sapling Signature (``SaplingSignature``) -........................................ +'''''''''''''''''''''''''''''''''''''''' +-----------------------------+------------------------------+----------------------------------+---------------------------------------------------+ | Bytes | Name | Data Type | Description | @@ -945,7 +945,7 @@ Sapling Signature (``SaplingSignature``) +-----------------------------+------------------------------+----------------------------------+---------------------------------------------------+ Orchard Signature (``OrchardSignature``) -........................................ +'''''''''''''''''''''''''''''''''''''''' +-----------------------------+------------------------------+----------------------------------+---------------------------------------------------+ | Bytes | Name | Data Type | Description | From b6093059b4fdf853091bd8843c8f8963607f8158 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood Date: Wed, 15 Apr 2026 00:42:09 +0100 Subject: [PATCH 31/51] [ZIP 248]: Fix typos and RST syntax. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix "wouild" → "would", "advertizing" → "advertising", "inaccessiblity" → "inaccessibility", "i.e," → "i.e.,", and "[^BCP14]" (Markdown footnote) → "[#BCP14]_" (RST). Co-Authored-By: Claude Opus 4.6 (1M context) --- zips/zip-0248.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/zips/zip-0248.rst b/zips/zip-0248.rst index 42a890394..58c014324 100644 --- a/zips/zip-0248.rst +++ b/zips/zip-0248.rst @@ -18,7 +18,7 @@ Terminology {Edit this to reflect the key words that are actually used.} The key words "MUST", "REQUIRED", "MUST NOT", "SHOULD", and "MAY" in this -document are to be interpreted as described in BCP 14 [^BCP14] when, and only +document are to be interpreted as described in BCP 14 [#BCP14]_ when, and only when, they appear in all capitals. The character § is used when referring to sections of the Zcash Protocol @@ -36,7 +36,7 @@ transparent transaction value pool An ephemeral value for the balance of an asset within the scope of a single transaction, which is modified by additions and subtractions in the processing of the effects of transaction bundles. When all of the effects of - a transaction are accounted for, each such balance is zero; i.e, the total of + a transaction are accounted for, each such balance is zero; i.e., the total of additions to the balance equals the total of subtractions from it. @@ -74,7 +74,7 @@ appropriate. For many new features, however, it is possible for a wallet to continue functioning correctly without having to fully understand a transaction using that feature. -For example, if TZEs were to be added to the protocol, it wouild be possible +For example, if TZEs were to be added to the protocol, it would be possible for wallets to continue operating with transparent/Sapling/Orchard functionality, ignoring TZE parts. There is substantial precedent for this sort of behavior; transparent-only hardware wallets are currently still important in @@ -1696,7 +1696,7 @@ transaction version. Except for certain cases involving severe security flaws, we should avoid doing that again. If a wallet needs to actively do something differently (for example, -advertizing addresses in a new format or creating an output with a TZE +advertising addresses in a new format or creating an output with a TZE precondition) in order to be affected by a new feature, then it is reasonably safe for it to ignore the feature as long as it can still parse transactions and, and create and sign transactions that don't make use of those features. @@ -1705,7 +1705,7 @@ It is okay that such a wallet might not be able to see funds that depend on new features, as long as they do not create such funds themselves. Loss of funds is unacceptable. Temporary inaccessibility of funds in certain -circumstances can be okay -- provided that this potential inaccessiblity and +circumstances can be okay -- provided that this potential inaccessibility and the circumstances where it can occur is documented and an explicit design decision. From ae1ac3baf77c14b7c53a6128050fe0034aa21a1b Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood Date: Wed, 15 Apr 2026 01:00:18 +0100 Subject: [PATCH 32/51] [ZIP 248]: Use MUST for conformance requirements in the Specification section. Consensus Rules and Transaction Format prose use lowercase "must" for requirements that are normative. Per BCP 14, these carry conformance meaning only when in ALL CAPS in the Specification section. Requirements section left as-is per ZIP 0 (must not contain conformance requirements). Co-Authored-By: Claude Opus 4.6 (1M context) --- zips/zip-0248.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/zips/zip-0248.rst b/zips/zip-0248.rst index 58c014324..d22458f44 100644 --- a/zips/zip-0248.rst +++ b/zips/zip-0248.rst @@ -428,7 +428,7 @@ syntax $\mathsf{mValuePoolDeltas}[(\mathsf{BundleType}, \mathsf{AssetUuid})].$ ``bundleType``. The records that represent each map entry map MUST be encoded in increasing order of ``bundleType``. Each map MUST NOT contain more than a single entry for a given ``bundleType``. For each ``bundleType`` that exists in -``mAuthBundles``, a corresponding entry with the same ``bundleVariant`` must +``mAuthBundles``, a corresponding entry with the same ``bundleVariant`` MUST exist in ``mEffectBundles``. ValuePoolDelta @@ -829,8 +829,8 @@ or full validator only needs to enforce a given rule in this subsection if it understands the bundle type that the rule applies to. * The ``assetClass`` value for any entry in ``mValuePoolDeltas`` having - ``bundleType = FeeBundleId`` is 0 (fee amounts are denominated in ZEC - and no other asset.) + ``bundleType = FeeBundleId`` MUST be 0 (fee amounts are denominated in ZEC + and no other asset). * For coinbase transactions, the ``enableSpendsOrchard`` bit of the Orchard bundle's ``flagsOrchard`` field MUST be 0. @@ -843,20 +843,20 @@ transaction, or across transactions within a block. They MUST be enforced by full validators. * For coinbase transactions, the value of $\mathsf{mValuePoolDeltas}[(\mathsf{FeeBundleId}, \mathsf{Zec})]$ - must be nonnegative. This represents the total transaction fees collected from + MUST be nonnegative. This represents the total transaction fees collected from all other transactions in the block. * For non-coinbase transactions, the value of $\mathsf{mValuePoolDeltas}[(\mathsf{FeeBundleId}, \mathsf{Zec})]$ - must be nonpositive. This represents the transaction fee paid by the + MUST be nonpositive. This represents the transaction fee paid by the transaction (expressed as a negative value, since it is removed from the transparent transaction value pool). -* Within the scope of a block, the sum of the fee bundle values must equal 0. - That is, the fees collected by the coinbase transaction must equal the sum of +* Within the scope of a block, the sum of the fee bundle values MUST equal 0. + That is, the fees collected by the coinbase transaction MUST equal the sum of fees paid by all other transactions in the block. * For the coinbase transaction, the sum of value pool deltas in the ZEC asset - is equal to the negative of the block subsidy for that block; the block + MUST be equal to the negative of the block subsidy for that block; the block subsidy adds an implicit input value to the transparent transaction value pool that the coinbase outputs consume. @@ -868,7 +868,7 @@ full validators. Founders' Reward'. [#protocol-subsidies]_ * For all non-coinbase transactions, the sum of value pool delta values in each - asset equals 0. + asset MUST equal 0. .. math:: From c9ef7026dad53617c6a79800d03044dac61a8a07 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood Date: Wed, 15 Apr 2026 01:05:15 +0100 Subject: [PATCH 33/51] [ZIP 248]: Remove redundant normative constraints; cross-reference Parsing Rules. The uniqueness, ordering, and cross-map consistency constraints on mValuePoolDeltas, mEffectBundles, and mAuthBundles were stated in three places: the prose after the Transaction Format table, the prose after the ValuePoolDelta table, and the Parsing Rules section. Keep Parsing Rules as the single normative source and replace the earlier prose with descriptive text and a cross-reference. Co-Authored-By: Claude Opus 4.6 (1M context) --- zips/zip-0248.rst | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/zips/zip-0248.rst b/zips/zip-0248.rst index d22458f44..41b10d842 100644 --- a/zips/zip-0248.rst +++ b/zips/zip-0248.rst @@ -418,18 +418,15 @@ Transaction Format +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ ``mValuePoolDeltas`` is interpreted as a map keyed by the tuple -$(\mathsf{BundleType}, \mathsf{AssetUuid})$; this logical map MUST NOT contain -more than a single entry for a given key. The `ValuePoolDelta`_ records that -represent the entries this map MUST be encoded in increasing order of -`(bundleType, assetClass, assetUuid)` Lookups in this map are denoted with the -syntax $\mathsf{mValuePoolDeltas}[(\mathsf{BundleType}, \mathsf{AssetUuid})].$ +$(\mathsf{BundleType}, \mathsf{AssetUuid})$. Lookups in this map are denoted +with the syntax +$\mathsf{mValuePoolDeltas}[(\mathsf{BundleType}, \mathsf{AssetUuid})].$ ``mEffectBundles`` and ``mAuthBundles`` are interpreted as maps keyed by -``bundleType``. The records that represent each map entry map MUST be encoded -in increasing order of ``bundleType``. Each map MUST NOT contain more than a -single entry for a given ``bundleType``. For each ``bundleType`` that exists in -``mAuthBundles``, a corresponding entry with the same ``bundleVariant`` MUST -exist in ``mEffectBundles``. +``bundleType``. + +Encoding constraints on these maps (uniqueness, ordering, and cross-map +consistency) are specified in `Parsing Rules`_. ValuePoolDelta -------------- @@ -455,14 +452,6 @@ ValuePoolDelta | | | |of ``mValuePoolDeltas`` instead. | +-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ -``mValuePoolDeltas`` is interpreted as a map keyed by the tuple -$(\mathsf{BundleType}, \mathsf{AssetUuid}).$ The map MUST NOT contain more than -a single entry for a given key. Lookups in this map are denoted with the -syntax $\mathsf{mValuePoolDeltas}[(\mathsf{BundleType}, \mathsf{AssetUuid})].$ - -All entries in ``mValuePoolDeltas`` having the same ``bundleType`` MUST have -the same ``bundleVariant``. - Let $\mathsf{Zec}$ be a distinguished value representing the ZEC asset. It is used as the asset identifier when $\mathsf{assetClass} = 0$. From bc75bd3e28fba9cdb2eeaaa7e8cde5300991459e Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood Date: Wed, 15 Apr 2026 01:07:38 +0100 Subject: [PATCH 34/51] [ZIP 248]: Specify key comparison for mValuePoolDeltas ordering. The Parsing Rules required entries in strictly increasing key order but did not specify the comparison operation for the 64-byte assetUuid field. State explicitly that the key tuple (bundleType, assetClass, assetUuid) is compared lexicographically, with assetUuid compared as a byte string. Also fix a circular cross-reference: Parsing Rules said "as defined in Transaction Format" but Transaction Format now cross-references Parsing Rules. Make the Parsing Rules bullet self-contained instead. Co-Authored-By: Claude Opus 4.6 (1M context) --- zips/zip-0248.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/zips/zip-0248.rst b/zips/zip-0248.rst index 41b10d842..8f6e85145 100644 --- a/zips/zip-0248.rst +++ b/zips/zip-0248.rst @@ -497,7 +497,10 @@ wallet does not itself implement. * Each of ``mValuePoolDeltas``, ``mEffectBundles``, and ``mAuthBundles`` MUST contain at most one entry per key, and the entries MUST be encoded in - strictly increasing key order as defined in `Transaction Format`_. + strictly increasing key order. For ``mValuePoolDeltas`` the key order is + ``(bundleType, assetClass, assetUuid)`` compared lexicographically (with + ``assetUuid`` compared as a byte string). For ``mEffectBundles`` and + ``mAuthBundles`` the key order is ``bundleType``. * Every ``ValuePoolDelta`` record MUST have a nonzero ``value`` field. A ``ValuePoolDelta`` record that would have ``value = 0`` MUST be elided from From 500ea78cc11d4ddae29f76fa4cc61a94db971436 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood Date: Wed, 15 Apr 2026 01:23:19 +0100 Subject: [PATCH 35/51] [ZIP 248]: Define transparent bundle value pool delta computation. The transparent bundle has no cryptographic binding between its contents and its mValuePoolDeltas entry (unlike Sapling/Orchard where value commitments and binding signatures enforce the relationship). Specify the consensus rule that full validators MUST verify the transparent delta equals total input value minus total output value, for both non-coinbase and coinbase transactions. Co-Authored-By: Claude Opus 4.6 (1M context) --- zips/zip-0248.rst | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/zips/zip-0248.rst b/zips/zip-0248.rst index 8f6e85145..d05e60248 100644 --- a/zips/zip-0248.rst +++ b/zips/zip-0248.rst @@ -550,6 +550,21 @@ granularity of bundle types. Transparent Bundle ------------------ +The transparent bundle's value pool delta in ``mValuePoolDeltas`` represents +the net value flowing from the transparent inputs to the transparent outputs. + +For a non-coinbase transaction, a full validator MUST verify that the ZEC +value pool delta for ``bundleType = 0`` equals the total value of the +transparent inputs minus the total value of the transparent outputs. (The +input values are not encoded in the transaction itself; they are obtained +from the UTXOs being spent.) + +For a coinbase transaction, the total transparent input value is implicitly +the block subsidy plus the total transaction fees paid by other transactions +in the block. A full validator MUST verify that the ZEC value pool delta for +``bundleType = 0`` equals this implicit input value minus the total value of +the coinbase transparent outputs. + Transparent Effecting Data `````````````````````````` From 4151170654b93ae407cdad43b3ac7a3d70e09750 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Tue, 1 Sep 2026 13:02:32 -0600 Subject: [PATCH 36/51] [ZIP 248]: Propose the V7 transaction format. This ZIP proposes its format as transaction version 7; version 6 is taken by ZIP 229. The formats that precede it are referred to as pre-V7. ZIP 248 defines "V7 transaction format", "V7 transaction", and "pre-V7 transaction format" in its Terminology section; ZIPs 231 and 2002 adopt those terms by reference. ZIP 231 additionally uses "V7-onward" and "pre-V7" to qualify note plaintexts and ciphertexts. ZIP 2002's Deployment section and ZIP 233's reference list also drop their remaining citations of ZIP 230, which the ZIP 248 registry supersedes. Co-Authored-By: Claude Opus 5 --- zips/zip-0231.md | 94 +++++++++++++++++++++++++---------------------- zips/zip-0233.md | 4 +- zips/zip-0248.rst | 49 ++++++++++++++---------- zips/zip-2002.rst | 14 ++++--- 4 files changed, 90 insertions(+), 71 deletions(-) diff --git a/zips/zip-0231.md b/zips/zip-0231.md index 1e7f8cfbc..125f42937 100644 --- a/zips/zip-0231.md +++ b/zips/zip-0231.md @@ -28,6 +28,11 @@ Specification. [^protocol] The terms "Mainnet" and "Testnet" are to be interpreted as described in § 3.12 ‘Mainnet and Testnet’. [^protocol-networks] +The terms "V7 transaction format", "V7 transaction", and "pre-V7 transaction +format" are to be interpreted as defined in ZIP 248. [^zip-0248] A note +plaintext or note ciphertext is described as "V7-onward" or "pre-V7" according +to the format of the transaction that contains it. + # Abstract @@ -94,9 +99,10 @@ not meet the standard IND-CCA2 ∧ INT-CTXT security notion for an authenticated encryption scheme [^BN2000]. By decoupling memo data from note ciphertexts, this proposal reduces the -v6-onward note ciphertext to 100 bytes (excluding any other changes to the note -plaintext proposed by other ZIPs). This makes it practical for the light client -protocol to transmit complete note ciphertexts, including the AEAD tag, in +V7-onward note ciphertext to 100 bytes (excluding any other changes to +the note plaintext proposed by other ZIPs). This makes it practical for the +light client protocol to transmit complete note ciphertexts, including the AEAD +tag, in exchange for a relatively minor bandwidth increase compared to the current truncated ciphertexts. This allows light clients to perform fully authenticated decryption, ensuring security against chosen ciphertext attacks and simplifying the security @@ -136,10 +142,10 @@ After the activation of this ZIP, recipient count and memo count are decoupled. It becomes possible to construct transactions for which there are many more recipients than distinct memos, or vice versa. Without mitigation, this could result in more observably distinct patterns relating the number of recipients -to the number of possible memos. In particular, a v6-onward transaction with no memo +to the number of possible memos. In particular, a V7 transaction with no memo would be distinguishable from one with a memo. -To mitigate this, a v6-onward transaction with any shielded outputs is required to +To mitigate this, a V7 transaction with any shielded outputs is required to include at least 2 memo chunks in its memo bundle and pad the memo to a multiple of 2 chunks (see [Memo bundle padding]). This ensures that the common use case of sending a transaction without including explicit memo data is @@ -200,15 +206,15 @@ potential distinguisher along another. # Specification -Since this proposal is defined only for v6 and later transactions, it is not +Since this proposal is defined only for V7 transactions, it is not necessary to consider Sprout JoinSplit outputs. The following sections apply -to both Sapling and Orchard outputs in v6-onward transactions. +to both Sapling and Orchard outputs in V7 transactions. ## Changes to ZIP 248 This ZIP proposes to register a new bundle type for Memos and new versions of -the Sapling and Orchard bundle types in the V6 transaction bundle type registry -defined in ZIP 248 [^zip-0248]: +the Sapling and Orchard bundle types in the V7 transaction bundle type +registry defined in ZIP 248 [^zip-0248]: | BundleType | BundleVariant | `mValuePoolDeltas` | `mEffectBundles` | `mAuthBundles` | Bundle kind | |------------|---------------|--------------------|------------------|----------------|----------------------| @@ -358,7 +364,7 @@ A memo bundle consists of a sequence of 272-byte memo chunks, each encrypting a 256-byte chunk of memo plaintext. These memo chunks represent zero or more encrypted memos. -Each v6-onward transaction may contain a single memo bundle, and a memo bundle may contain +Each V7 transaction may contain a single memo bundle, and a memo bundle may contain at most $\mathsf{memo\_chunk\_limit}$ = 64 memo chunks. This limits the total amount of memo data that can be conveyed within a single transaction to $\mathsf{memo\_chunk\_limit}$ × 256 = 16384 bytes, or 16 KiB. @@ -385,7 +391,7 @@ $\mathsf{K^{memo}}$ value is placed in each recipient's note plaintext; this does not violate the above constraint because all recipients decrypt the same memo. -In note plaintexts of v6-onward transactions, the 512-byte memo field +In note plaintexts of V7 transactions, the 512-byte memo field is replaced by the 32-byte $\mathsf{K^{memo}}$. The explicit encodings of the note plaintexts for Sapling and Orchard outputs @@ -512,14 +518,15 @@ process that is independent of the trial decryption of note ciphertexts. Rationale for deferred memo decryption -In pre-v6 transactions performed by full-node wallets, trial decryption of each -shielded output performs constant work regardless of whether the output belongs -to the wallet: the AEAD decryption of the full 580-byte note ciphertext costs -the same whether it succeeds or fails. +In pre-V7 transactions performed by full-node wallets, trial decryption +of each shielded output performs constant work regardless of whether the output +belongs to the wallet: the AEAD decryption of the full 580-byte note ciphertext +costs the same whether it succeeds or fails. -With memo bundles, successful trial decryption of a 100-byte v6 note ciphertext -yields a memo key $\mathsf{K^{memo}}$, and if the key is not the no-memo -sentinel, the wallet must scan up to $\mathsf{memo\_chunk\_limit}$ memo chunks +With memo bundles, successful trial decryption of a 100-byte V7-onward +note ciphertext yields a memo key $\mathsf{K^{memo}}$, and if the key is not the +no-memo sentinel, the wallet must scan up to $\mathsf{memo\_chunk\_limit}$ memo +chunks to recover the memo. This additional work — potentially up to 64 AEAD operations — creates a timing differential between successful and unsuccessful trial decryptions that could be exploited by an adversary to determine whether @@ -574,7 +581,7 @@ The memo bundle digest is used in place of the full memo bundle when the bundle has been pruned. TODO: finish this as a modification to ZIP 248 [^zip-0248], which defines -the v6 transaction digest structure. Note that $\mathtt{fAllPruned}$ MUST NOT +the V7 transaction digest structure. Note that $\mathtt{fAllPruned}$ MUST NOT contribute to the transaction digest, as it is not part of the committed transaction data. @@ -607,7 +614,7 @@ from a server that has pruned it. The changes to support memo bundles that affect the definitions of note plaintexts and note ciphertexts, interact with the addition of an -$\mathsf{asset\_base}$ field to v6-onward Orchard note plaintexts in order to +$\mathsf{asset\_base}$ field to V7-onward Orchard note plaintexts in order to support ZSAs, which must be merged with the changes in this section. Changes to the algorithms for encryption and decryption are specified below. @@ -625,29 +632,29 @@ In § 3.2.1 ‘Note Plaintexts and Memo Fields’: > The form of a Sapling or Orchard note plaintext depends on the version of > the transaction in which it will be included; specifically whether that - > version is pre-v6, or v6-onward. + > version is pre-V7, or V7-onward. > - > Each pre-v6 Sapling or Orchard note plaintext (denoted $\mathbf{np}$) consists of + > Each pre-V7 Sapling or Orchard note plaintext (denoted $\mathbf{np}$) consists of > > $\hspace{2em}(\mathsf{leadByte} \;{\small ⦂}\; \mathbb{B}^{{\kern-0.05em\tiny\mathbb{Y}}}, \mathsf{d} \;{\small ⦂}\; \mathbb{B}^{[\ell_{\mathsf{d}}]}, \mathsf{rseed} \;{\small ⦂}\; \mathbb{B}^{{\kern-0.05em\tiny\mathbb{Y}}[32]}, \mathsf{memo} \;{\small ⦂}\; \mathbb{B}^{{\kern-0.05em\tiny\mathbb{Y}}[512]})$ > - > Each v6-onward Sapling or Orchard note plaintext (denoted $\mathbf{np}$) consists of + > Each V7-onward Sapling or Orchard note plaintext (denoted $\mathbf{np}$) consists of > > $\hspace{2em}(\mathsf{leadByte} \;{\small ⦂}\; \mathbb{B}^{{\kern-0.05em\tiny\mathbb{Y}}}, \mathsf{d} \;{\small ⦂}\; \mathbb{B}^{[\ell_{\mathsf{d}}]}, \mathsf{rseed} \;⦂\; \mathbb{B}^{{\kern-0.05em\tiny\mathbb{Y}}[32]}, \mathsf{K^{memo}} \;{\small ⦂}\; \mathbb{B}^{{\kern-0.05em\tiny\mathbb{Y}}[32]})$ In § 5.5 ‘Encodings of Note Plaintexts and Memo Fields’ [^protocol-noteptencoding]: * Change the paragraph that describes "The encoding of a Sapling or Orchard note plaintext" - to refer to "The encoding of a pre-v6 Sapling or Orchard note plaintext". + to refer to "The encoding of a pre-V7 Sapling or Orchard note plaintext". * Add a new paragraph at the end of the section: - > The encoding of a v6-onward Sapling or Orchard note plaintext consists of: + > The encoding of a V7-onward Sapling or Orchard note plaintext consists of: > > $\begin{array}{|c|c|c|c|c|} \hline \raisebox{0.6ex}{\mathstrut} \text{8-bit } \mathsf{leadByte} & \text{88-bit } \mathsf{d} & \text{64-bit } \mathsf{v} & \text{256-bit } \mathsf{rseed} & \text{32-byte } \mathsf{K^{memo}} \\\hline \end{array}$ > - > * A byte {{MBLEADBYTE}}, indicating this version of the encoding of a v6-onward - > Sapling or Orchard note plaintext. + > * A byte {{MBLEADBYTE}}, indicating this version of the encoding of an + > V7-onward Sapling or Orchard note plaintext. > * 11 bytes specifying $\mathsf{d}$. > * 8 bytes specifying $\mathsf{v}$. > * 32 bytes specifying $\mathsf{rseed}$. @@ -660,7 +667,8 @@ In § 4.7.2 ‘Sending Notes (Sapling)’ [^protocol-saplingsend] and § 4.7.3 ‘Sending Notes (Orchard)’ [^protocol-orchardsend]: * Add a reference to this ZIP specifying the construction of the memo bundle and - derivation of $\mathsf{K^{memo}}$ in the case of a v6-onward note plaintext. + derivation of $\mathsf{K^{memo}}$ in the case of a V7-onward note + plaintext. * Change @@ -669,28 +677,28 @@ In § 4.7.2 ‘Sending Notes (Sapling)’ [^protocol-saplingsend] and to > Let $\mathbf{np}$ be the encoding of a Sapling note plaintext using $\mathsf{leadByte}$, $\mathsf{d}$, - > $\mathsf{v}$, $\mathsf{rseed}$, and either $\mathsf{memo}$ for a pre-v6 note plaintext or - > $\mathsf{K^{memo}}$ for a v6-onward note plaintext. + > $\mathsf{v}$, $\mathsf{rseed}$, and either $\mathsf{memo}$ for a pre-V7 note plaintext or + > $\mathsf{K^{memo}}$ for a V7-onward note plaintext. replacing "Sapling" with Orchard in the case of § 4.7.3. In § 4.20.1 ‘Encryption (Sapling and Orchard)’ [^protocol-saplingandorchardinband]: -* For v6-onward note ciphertexts, the KDF used to derive the note encryption key - uses a different BLAKE2b-256 personalization string than for pre-v6 note +* For V7-onward note ciphertexts, the KDF used to derive the note encryption key + uses a different BLAKE2b-256 personalization string than for pre-V7 note ciphertexts, to provide domain separation. The personalization string is formed by concatenating a protocol prefix with the 4-byte little-endian encoding of the transaction version group id ($\mathsf{nVersionGroupId}$): - > For v6-onward Sapling note ciphertexts: + > For V7-onward Sapling note ciphertexts: > > $\hspace{2em}\mathsf{KDF^{Sapling}}(\mathsf{sharedSecret}, \mathsf{ephemeralKey}) := \mathsf{BLAKE2b\text{-}256}(\text{"Zc_SaplingKD"} \,||\, \mathsf{I2LEOSP}_{32}(\mathsf{nVersionGroupId}), \mathsf{sharedSecret} \,||\, \mathsf{ephemeralKey})$ > - > For v6-onward Orchard note ciphertexts: + > For V7-onward Orchard note ciphertexts: > > $\hspace{2em}\mathsf{KDF^{Orchard}}(\mathsf{sharedSecret}, \mathsf{ephemeralKey}) := \mathsf{BLAKE2b\text{-}256}(\text{"Zc_OrchardKD"} \,||\, \mathsf{I2LEOSP}_{32}(\mathsf{nVersionGroupId}), \mathsf{sharedSecret} \,||\, \mathsf{ephemeralKey})$ - This prevents a malicious lightwalletd server from presenting a v6 note ciphertext + This prevents a malicious lightwalletd server from presenting a V7 note ciphertext to a wallet as though it were a partial v5 ciphertext, which could otherwise cause the wallet to decrypt and act on unauthenticated plaintext. @@ -703,12 +711,12 @@ In § 4.20.1 ‘Encryption (Sapling and Orchard)’ [^protocol-saplingandorchard to > Let $\mathbf{np}$ be the encoding of the Sapling or Orchard note plaintext (which may be - > pre-v6 or v6-onward), as defined in § 5.5 ‘Encodings of Note Plaintexts and Memo Fields’. + > pre-V7 or V7-onward), as defined in § 5.5 ‘Encodings of Note Plaintexts and Memo Fields’. * Add another normative note to that section: > * $\mathsf{C^{enc}}$ will be of length either 580 or 100 bytes, depending on whether - > $\mathbf{np}$ is a pre-v6 or v6-onward note plaintext. + > $\mathbf{np}$ is a pre-V7 or V7-onward note plaintext. In § 4.20.2 ‘Decryption using an Incoming Viewing Key (Sapling and Orchard)’ [^protocol-decryptivk] and § 4.20.3 ‘Decryption using an Outgoing Viewing Key (Sapling and Orchard)’ [^protocol-decryptovk]: @@ -716,8 +724,8 @@ and § 4.20.3 ‘Decryption using an Outgoing Viewing Key (Sapling and Orchard) * Replace $\mathsf{memo} \;{\small ⦂}\; \mathbb{B}^{{\kern-0.05em\tiny\mathbb{Y}}[512]}$ with $\mathsf{memoOrKey}$. * Specify that the type of $\mathsf{memoOrKey}$ is $\mathbb{B}^{{\kern-0.05em\tiny\mathbb{Y}}[512]}$ - when decrypting a pre-v6 note ciphertext, or $\mathbb{B}^{{\kern-0.05em\tiny\mathbb{Y}}[32]}$ when - decrypting a v6-onward note ciphertext. In the latter case, it is used as $\mathsf{K^{memo}}$ + when decrypting a pre-V7 note ciphertext, or $\mathbb{B}^{{\kern-0.05em\tiny\mathbb{Y}}[32]}$ when + decrypting a V7-onward note ciphertext. In the latter case, it is used as $\mathsf{K^{memo}}$ to decrypt the memo bundle as described in [Memo bundle]. ## Applicability @@ -866,14 +874,14 @@ $\mathsf{encryption\_key}$ for two reasons: ## Domain separation of note ciphertexts -V6-onward note ciphertexts use KDF personalization strings that incorporate the +V7-onward note ciphertexts use KDF personalization strings that incorporate the transaction version group id ($\text{"Zc_SaplingKD"} \,||\, \mathsf{nVersionGroupId}$ and $\text{"Zc_OrchardKD"} \,||\, \mathsf{nVersionGroupId}$), providing domain -separation from pre-v6 note ciphertexts. This prevents a downgrade attack in -which a malicious lightwalletd server presents a v6 note ciphertext as a partial +separation from pre-V7 note ciphertexts. This prevents a downgrade attack in +which a malicious lightwalletd server presents a V7 note ciphertext as a partial v5 note ciphertext. Without domain separation, a wallet that supports the v5 partial-ciphertext optimization (downloading note ciphertexts without the MAC to -save bandwidth) could decrypt a v6 ciphertext without verifying its +save bandwidth) could decrypt a V7 ciphertext without verifying its authentication tag, potentially acting on unauthenticated data. Using the version group id rather than a fixed suffix ensures that domain separation extends automatically to future transaction versions. diff --git a/zips/zip-0233.md b/zips/zip-0233.md index 002bd60f3..ce4f44dcc 100644 --- a/zips/zip-0233.md +++ b/zips/zip-0233.md @@ -101,7 +101,7 @@ network. ## Changes to ZIP 248 This ZIP proposes to register bundle type 5 variant 0 ("ZIP 233 NSM field") in -the V6 transaction bundle type registry defined in ZIP 248 [^zip-0248]. +the V7 transaction bundle type registry defined in ZIP 248 [^zip-0248]. | BundleType | BundleVariant | `mValuePoolDeltas` | `mEffectBundles` | `mAuthBundles` | |------------|---------------|--------------------|------------------|----------------| @@ -205,8 +205,6 @@ This ZIP is proposed to activate with Network Upgrade 7. [^draft-arya-deploy-nu7 [^zip-0200]: [ZIP 200: Network Upgrade Mechanism](zip-0200.rst) -[^zip-0230]: [ZIP 230: Version 6 Transaction Format](zip-0230.rst) - [^zip-0234]: [ZIP 234: Network Sustainability Mechanism: Issuance Smoothing](zip-0234.rst) [^zip-0235]: [ZIP 235: Remove 60% of Transaction Fees From Circulation](zip-0235.rst) diff --git a/zips/zip-0248.rst b/zips/zip-0248.rst index d05e60248..b88b4c34a 100644 --- a/zips/zip-0248.rst +++ b/zips/zip-0248.rst @@ -32,6 +32,17 @@ The term "full validator" in this document is to be interpreted as defined in § The terms below are to be interpreted as follows: +V7 transaction format + The transaction format defined by this ZIP, identified by transaction + version 7. Its version group ID is not yet assigned. + +V7 transaction + A transaction that is encoded using the V7 transaction format. + +pre-V7 transaction format + Any transaction format that precedes the V7 transaction format; that is, any + of the V1 to V6 transaction formats. + transparent transaction value pool An ephemeral value for the balance of an asset within the scope of a single transaction, which is modified by additions and subtractions in the @@ -43,7 +54,7 @@ transparent transaction value pool Abstract ======== -This ZIP proposes an encoding for V6 Zcash transactions that is intended to +This ZIP proposes an encoding for V7 Zcash transactions that is intended to reduce the impact of future changes to the Zcash transaction format on the Zcash ecosystem. It defines a new typecode-length-value encoding for a sequence of protocol bundles, and a "value balance" map that describes the effect of @@ -283,10 +294,10 @@ the original bundle type. This ensures that a client that does not recognize a particular ``bundleVariant`` can still determine which pool(s) are affected by the bundle and inform its user accordingly. -V6 Transaction Bundle Type Registry +V7 Transaction Bundle Type Registry ``````````````````````````````````` -The following ``(bundleType, bundleVariant)`` pairs are registered for the V6 +The following ``(bundleType, bundleVariant)`` pairs are registered for the V7 transaction format. All currently-defined values are encoded as single-byte ``compactSize`` values where they appear in the transaction format. @@ -487,9 +498,9 @@ BundleData Parsing Rules ------------- -The rules in this section are requirements on the byte encoding of a V6 +The rules in this section are requirements on the byte encoding of a V7 transaction. A byte stream that violates any of these rules is not a -well-formed V6 transaction and MUST be rejected by any parser, regardless +well-formed V7 transaction and MUST be rejected by any parser, regardless of which bundle types the parser understands. Enforcement of these rules is what makes it safe for a wallet to parse, identify, and compute the transaction identifier for a transaction containing bundle types that the @@ -521,7 +532,7 @@ wallet does not itself implement. entry with the same ``bundleVariant`` MUST exist in ``mEffectBundles``. * A bundle type MUST NOT appear in any map for which the corresponding column - of the `V6 Transaction Bundle Type Registry`_ is marked ❌, and MUST NOT + of the `V7 Transaction Bundle Type Registry`_ is marked ❌, and MUST NOT appear in any map at all if its row in the registry is marked as Reserved. * Within the encoding of any bundle's effecting and authorizing data, every @@ -539,7 +550,7 @@ wallet does not itself implement. ``proofsOrchard`` aggregates exactly ``nActionsOrchard`` per-action proofs. -A wallet that successfully parses a V6 transaction under these rules is +A wallet that successfully parses a V7 transaction under these rules is guaranteed to be able to compute the transaction identifier (given, for each bundle type it does not understand, the corresponding 32-byte ``bundle_effects_digest`` value as described in `Implications for Wallets`_), @@ -825,7 +836,7 @@ Zcash Protocol Specification. These rules are additional to the parsing rules above; a transaction that satisfies the parsing rules but violates any of these consensus rules is well-formed but invalid. -Let ``FeeBundleId`` be the identifier of the fee bundle. In V6 transactions, +Let ``FeeBundleId`` be the identifier of the fee bundle. In V7 transactions, $\mathsf{FeeBundleId} = 4$ as defined in the table above. Bundle-local rules @@ -898,7 +909,7 @@ digest): where ``associatedData`` is specific to the bundle it appears in. -The following sighash algorithm versions are defined for V6 transactions: +The following sighash algorithm versions are defined for V7 transactions: +--------------------+-------------------------------------------------------+ | |:math:`\hspace{4.5em}` ``associatedData`` | @@ -921,7 +932,7 @@ Per-Signature Structures ```````````````````````` The following structures carry sighash version information alongside each -signature in the authorizing data of a V6 transaction. +signature in the authorizing data of a V7 transaction. Transparent Sighash Information (``TransparentSighashInfo``) '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' @@ -983,7 +994,7 @@ TxId Digest ``````````` A new transaction digest algorithm is defined that constructs the identifier for -a V6 transaction from a tree of hashes. The overall structure of the hash is as +a V7 transaction from a tree of hashes. The overall structure of the hash is as follows:: txid_digest @@ -1364,7 +1375,7 @@ transaction. This follows closely the algorithm from ZIP 244 [#zip-0244]_. The digest algorithm used for a given signature is determined by the ``sighashVersion`` from the signer's ``sighashInfo``, as specified in the `Sighash Versioning`_ section. For sighash version 0 (the only version -currently defined for V6 transactions), the digest algorithm is as specified +currently defined for V7 transactions), the digest algorithm is as specified below. Future network upgrades may define additional sighash algorithm versions with divergent behavior. @@ -1541,7 +1552,7 @@ The personalization field of this hash is set to:: "ZTxAuthHash_" || CONSENSUS_BRANCH_ID -For transaction versions before V6, a placeholder value consisting of 32 bytes +For transaction versions before V7, a placeholder value consisting of 32 bytes of ``0xFF`` is used in place of the authorizing data commitment. A.1: auth_bundles_digest @@ -1631,20 +1642,20 @@ In the case that the transaction has no Orchard actions:: Implications for Wallets ------------------------ -Sending v6 transactions +Sending V7 transactions ``````````````````````` -*All* Zcash wallets SHOULD, without undue delay, switch to sending only v6 +*All* Zcash wallets SHOULD, without undue delay, switch to sending only V7 transactions once they are allowed on the network. This applies to all -transactions regardless of whether they use new v6 features. +transactions regardless of whether they use new V7 features. -Support for receiving funds in v6 transactions +Support for receiving funds in V7 transactions `````````````````````````````````````````````` -Zcash wallets MUST support parsing v6 transactions by the time they are allowed +Zcash wallets MUST support parsing V7 transactions by the time they are allowed on the network. -Because the v6 transaction format uses a type-length-value encoding for +Because the V7 transaction format uses a type-length-value encoding for bundles, a wallet is not required to understand the internal encoding of every bundle in order to parse a transaction. However, a wallet that encounters a bundle with an unrecognized ``bundleType`` SHOULD alert the user that the diff --git a/zips/zip-2002.rst b/zips/zip-2002.rst index bdb9fc398..8d21ad26b 100644 --- a/zips/zip-2002.rst +++ b/zips/zip-2002.rst @@ -28,11 +28,14 @@ Specification. [#protocol]_ The terms "Mainnet" and "Testnet" are to be interpreted as described in § 3.12 ‘Mainnet and Testnet’. [#protocol-networks]_ +The terms "V7 transaction format" and "V7 transaction" are to be interpreted as +defined in ZIP 248. [#zip-0248]_ + Abstract ======== -This proposal makes the transaction fee explicit in the v6 transaction format, +This proposal makes the transaction fee explicit in the V7 transaction format, as an entry in the transparent transaction value pool balance map defined in ZIP 248 [#zip-0248]_. Instead of fees being implicit in the difference between the input value and output value of the transaction, all value transfers, @@ -74,7 +77,7 @@ Changes to ZIP 248 ------------------ This ZIP proposes to register bundle type 4 variant 0 ("Transaction fee") in -the V6 transaction bundle type registry defined in ZIP 248 [#zip-0248]_. +the V7 transaction bundle type registry defined in ZIP 248 [#zip-0248]_. +------------+---------------+----------------------+--------------------+------------------+ | BundleType | BundleVariant | ``mValuePoolDeltas`` | ``mEffectBundles`` | ``mAuthBundles`` | @@ -106,11 +109,11 @@ ZIP 236 [#zip-0236]_), add the following consensus rules: ``bundleType`` $= \mathsf{FeeBundleId}$ MUST be 0. That is, fee amounts MUST be denominated in ZEC. - * [NU7 onward] For v6 and later non-coinbase transactions, the value of + * [NU7 onward] For non-coinbase V7 transactions, the value of $\mathsf{mValuePoolDeltas}[(\mathsf{FeeBundleId}, \mathsf{Zec})]$ MUST be nonpositive. Its absolute value represents the transaction fee in zatoshis. - * [NU7 onward] For v6 and later coinbase transactions, the value of + * [NU7 onward] For coinbase V7 transactions, the value of $\mathsf{mValuePoolDeltas}[(\mathsf{FeeBundleId}, \mathsf{Zec})]$ MUST be nonnegative. It represents the total transaction fees collected from all other transactions in the block. @@ -141,7 +144,7 @@ Deployment ========== This ZIP is proposed to be deployed with the next transaction version change, -which is assumed to be v6. [#zip-0230]_ +which is assumed to be V7. [#zip-0248]_ Reference implementation @@ -160,6 +163,5 @@ References .. [#protocol-txnconsensus] `Zcash Protocol Specification, Version 2025.6.2 [NU6.1]. Section 7.1.2: Transaction Consensus Rules `_ .. [#bitcointalk-fee-error] `Bitcoin Forum post by @Voiceeeeee, March 8, 2017. "PLEASE HELP.. I sent a transaction with a 2.5 BTC transaction fee" `_ .. [#zip-0200] `ZIP 200: Network Upgrade Mechanism `_ -.. [#zip-0230] `ZIP 230: Version 6 Transaction Format `_ .. [#zip-0236] `ZIP 236: Blocks should balance exactly `_ .. [#zip-0248] `ZIP 248: Extensible Transaction Format `_ From 96a22d7e6c3a6fa4750bcb222ce0adeb3ce8f828 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Tue, 1 Sep 2026 13:10:45 -0600 Subject: [PATCH 37/51] [ZIP 231]: Drop remaining references to the withdrawn ZIP 230. The citation of ZIP 230 for the explicit note plaintext encodings used a footnote label that was never defined, so it rendered as literal text. Point it at this ZIP's own Changes to the Zcash Protocol Specification section, which gives those encodings. Also remove the uncited ZIP 230 note plaintexts reference definition, and the duplicate ZIP 248 reference definition that pointed at a pull request URL. Co-Authored-By: Claude Opus 5 --- zips/zip-0231.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/zips/zip-0231.md b/zips/zip-0231.md index 125f42937..3e4e2f21c 100644 --- a/zips/zip-0231.md +++ b/zips/zip-0231.md @@ -395,7 +395,7 @@ In note plaintexts of V7 transactions, the 512-byte memo field is replaced by the 32-byte $\mathsf{K^{memo}}$. The explicit encodings of the note plaintexts for Sapling and Orchard outputs -are specified in ZIP 230 [^zip-0230-orchard-note-plaintext]. +are specified in [Changes to the Zcash Protocol Specification]. The transaction builder generates a 32-byte salt value $\mathsf{salt}$ from a CSPRNG. A new salt MUST be generated for each memo bundle. @@ -960,10 +960,6 @@ TBD [^draft-arya-deploy-nu7]: [draft-arya-deploy-nu7: Deployment of the NU7 Network Upgrade](draft-arya-deploy-nu7.md) -[^zip-0230-note-plaintexts]: [ZIP 230: Version 6 Transaction Format — Note Plaintexts](zip-0230.rst#note-plaintexts) - -[^zip-0248]: [ZIP 248: Extensible Transaction Format (PR: zcash/zips#1156)](https://github.com/zcash/zips/pull/1156) - [^zip-0302]: [ZIP 302: Standardized Memo Field Format](zip-0302.rst) [^zip-0307]: [ZIP 307: Light Client Protocol for Payment Detection](zip-0307.rst) From 735f76c10337bb443e7a562045e7325ff58a186f Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Tue, 1 Sep 2026 13:30:52 -0600 Subject: [PATCH 38/51] [ZIP 248]: Represent the coinbase subsidy as a bundle. Registers bundle type 1 variant 0 as the coinbase bundle, which the registry previously held as reserved. The block subsidy previously entered the transparent transaction value pool implicitly, which made the coinbase transaction the sole exception to the value pool delta balance rule: its deltas summed to the negation of the subsidy rather than to zero. The coinbase bundle carries the subsidy as its value pool delta, so the balance rule now holds for every transaction in every asset. The bundle's effecting data is the height of the block in which the transaction is mined, followed by a compactSize-prefixed field of at most 94 bytes for miner-chosen data. Both replace content that was previously encoded as the scriptSig of a transparent input whose previous output reference identified no output. The presence of the coinbase bundle now identifies a coinbase transaction, so that input is gone entirely, along with its sequence number. Also state the value of a lookup for a key absent from mValuePoolDeltas, which the balance rule requires in order to be well defined when the block subsidy is zero, and cross-reference the balance rule from the AssetUuid definition that supplies its grouping. Co-Authored-By: Claude Opus 5 --- zips/zip-0248.rst | 155 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 126 insertions(+), 29 deletions(-) diff --git a/zips/zip-0248.rst b/zips/zip-0248.rst index b88b4c34a..0c1742309 100644 --- a/zips/zip-0248.rst +++ b/zips/zip-0248.rst @@ -238,13 +238,15 @@ the pool (e.g., a shielded spend releasing value), while a negative delta means the bundle is consuming value from the pool (e.g., a shielded output absorbing value, or a transaction fee). -For a valid non-coinbase transaction, the sum of all value pool deltas for each -asset MUST equal zero. This ensures that value is neither created nor destroyed -— it is only transferred between bundles within the transaction. +For a valid transaction, the sum of all value pool deltas for each asset MUST +equal zero. This ensures that value is neither created nor destroyed — it is +only transferred between bundles within the transaction. -For a coinbase transaction, the sum of value pool deltas for ZEC equals the -negative of the block subsidy, reflecting that the block subsidy implicitly -adds value to the transparent transaction value pool. +This holds for coinbase transactions as well. The block subsidy enters the +transparent transaction value pool as the value pool delta of the coinbase +bundle, and the fees collected from the other transactions in the block enter +it as the value pool delta of the fee bundle; the coinbase outputs then consume +that value like any other bundle. Bundle Type Registration ```````````````````````` @@ -321,7 +323,7 @@ be present. +============+===============+======================+====================+==================+==============+==============================================+ | 0 | 0 |✅ |✅ |✅ | This ZIP | Transparent | +------------+---------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ -| 1 | | | | | | Reserved | +| 1 | 0 |✅ |✅ |❌ | This ZIP | Coinbase | +------------+---------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ | 2 | 0 |✅ |✅ |✅ | This ZIP | Sapling | +------------+---------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ @@ -431,7 +433,9 @@ Transaction Format ``mValuePoolDeltas`` is interpreted as a map keyed by the tuple $(\mathsf{BundleType}, \mathsf{AssetUuid})$. Lookups in this map are denoted with the syntax -$\mathsf{mValuePoolDeltas}[(\mathsf{BundleType}, \mathsf{AssetUuid})].$ +$\mathsf{mValuePoolDeltas}[(\mathsf{BundleType}, \mathsf{AssetUuid})].$ A +lookup for a key that is not present yields 0, consistent with the requirement +that a record having zero value is elided from the encoding. ``mEffectBundles`` and ``mAuthBundles`` are interpreted as maps keyed by ``bundleType``. @@ -477,6 +481,10 @@ Let $\mathsf{AssetUuid}(\mathsf{d})$ be the asset indicated by the ``mValuePoolD \bot & \text{otherwise} \end{cases} +$\mathsf{AssetUuid}$ groups the entries of ``mValuePoolDeltas`` by asset. The +values of the entries in each such group are required to sum to zero; this +balance rule is specified in `Cross-bundle and chain-context rules`_. + BundleData ---------- @@ -564,17 +572,16 @@ Transparent Bundle The transparent bundle's value pool delta in ``mValuePoolDeltas`` represents the net value flowing from the transparent inputs to the transparent outputs. -For a non-coinbase transaction, a full validator MUST verify that the ZEC -value pool delta for ``bundleType = 0`` equals the total value of the -transparent inputs minus the total value of the transparent outputs. (The -input values are not encoded in the transaction itself; they are obtained -from the UTXOs being spent.) +A full validator MUST verify that the ZEC value pool delta for +``bundleType = 0`` equals the total value of the transparent inputs minus the +total value of the transparent outputs. (The input values are not encoded in +the transaction itself; they are obtained from the UTXOs being spent.) -For a coinbase transaction, the total transparent input value is implicitly -the block subsidy plus the total transaction fees paid by other transactions -in the block. A full validator MUST verify that the ZEC value pool delta for -``bundleType = 0`` equals this implicit input value minus the total value of -the coinbase transparent outputs. +This rule applies to coinbase transactions unchanged. A coinbase transaction +has no transparent inputs, so its transparent value pool delta is the negation +of the total value of its transparent outputs; the value that those outputs +consume is contributed to the transparent transaction value pool by the +coinbase bundle and the fee bundle. Transparent Effecting Data `````````````````````````` @@ -653,6 +660,40 @@ It consists of a ``compactSize``-prefixed byte array containing the sighash version and any associated data required by that version. +Coinbase Bundle +--------------- + +A transaction is a *coinbase transaction* if and only if ``mEffectBundles`` +contains an entry with ``bundleType = 1``. The coinbase bundle replaces the +otherwise-unspendable transparent input that identified a coinbase transaction +in previous transaction versions, and carries the block height that that input +was required to encode. + +The coinbase bundle's value pool delta in ``mValuePoolDeltas`` is the block +subsidy, which the coinbase bundle contributes to the transparent transaction +value pool. The fees collected from the other transactions in the block are +contributed separately, as the value pool delta of the fee bundle. + +The coinbase bundle has no authorizing data. + +Coinbase Effecting Data +``````````````````````` + ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +| Bytes | Name | Data Type | Description | ++=============================+==========================+========================================+=====================================================================+ +|``4`` |``blockHeight`` |``uint32`` |The height of the block in which the transaction is mined. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``varies`` |``coinbaseDataLen`` |``compactSize`` |Length of the ``coinbaseData`` byte array. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``coinbaseDataLen`` |``coinbaseData`` |``byte[coinbaseDataLen]`` |Data chosen by the miner. Consensus assigns no meaning to its | +| | | |contents. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ + +* ``blockHeight`` MUST be in the range {1 .. 499999999}. +* ``coinbaseDataLen`` MUST be at most 94. + + Sapling Bundle -------------- @@ -836,8 +877,10 @@ Zcash Protocol Specification. These rules are additional to the parsing rules above; a transaction that satisfies the parsing rules but violates any of these consensus rules is well-formed but invalid. -Let ``FeeBundleId`` be the identifier of the fee bundle. In V7 transactions, -$\mathsf{FeeBundleId} = 4$ as defined in the table above. +Let ``CoinbaseBundleId`` be the identifier of the coinbase bundle, and +``FeeBundleId`` be the identifier of the fee bundle. In V7 transactions, +$\mathsf{CoinbaseBundleId} = 1$ and $\mathsf{FeeBundleId} = 4$ as defined in +the table above. Bundle-local rules `````````````````` @@ -850,6 +893,14 @@ it understands the bundle type that the rule applies to. ``bundleType = FeeBundleId`` MUST be 0 (fee amounts are denominated in ZEC and no other asset). +* The ``assetClass`` value for any entry in ``mValuePoolDeltas`` having + ``bundleType = CoinbaseBundleId`` MUST be 0 (the block subsidy is + denominated in ZEC and no other asset). + +* A coinbase transaction MUST NOT spend any transparent output. If a + transparent bundle is present in a coinbase transaction, its effecting data + MUST have ``tx_in_count = 0``. + * For coinbase transactions, the ``enableSpendsOrchard`` bit of the Orchard bundle's ``flagsOrchard`` field MUST be 0. @@ -873,20 +924,24 @@ full validators. That is, the fees collected by the coinbase transaction MUST equal the sum of fees paid by all other transactions in the block. -* For the coinbase transaction, the sum of value pool deltas in the ZEC asset - MUST be equal to the negative of the block subsidy for that block; the block - subsidy adds an implicit input value to the transparent transaction value - pool that the coinbase outputs consume. +* Exactly one transaction in a block MUST be a coinbase transaction, and it + MUST be the first transaction in the block. + +* The ``blockHeight`` field of the coinbase bundle's effecting data MUST equal + the height of the block containing the transaction. + +* The value of $\mathsf{mValuePoolDeltas}[(\mathsf{CoinbaseBundleId}, \mathsf{Zec})]$ + MUST equal the block subsidy for the block containing the transaction. .. math:: - \sum_{\mathsf{d} \in \mathsf{mValuePoolDeltas} | \mathsf{AssetUuid}(\mathsf{d}) = \mathsf{Zec}} \mathsf{d.value} = -\mathsf{BlockSubsidy}(\mathsf{height}) + \mathsf{mValuePoolDeltas}[(\mathsf{CoinbaseBundleId}, \mathsf{Zec})] = \mathsf{BlockSubsidy}(\mathsf{blockHeight}) where $\mathsf{BlockSubsidy}$ is defined in § 7.8 'Block Subsidy and Founders' Reward'. [#protocol-subsidies]_ -* For all non-coinbase transactions, the sum of value pool delta values in each - asset MUST equal 0. +* For every transaction, the sum of value pool delta values in each asset MUST + equal 0. .. math:: @@ -1002,6 +1057,7 @@ follows:: ├── value_pool_deltas_digest └── effects_bundles_digest ├─ (bundle_type_id || bundle_variant || transparent_effects_digest) + ├─ (bundle_type_id || bundle_variant || coinbase_effects_digest) ├─ (bundle_type_id || bundle_variant || sapling_effects_digest) │ ├── sapling_spends_digest │ │ ├── sapling_spends_compact_digest @@ -1167,6 +1223,21 @@ outputs, ``outputs_digest`` is:: BLAKE2b-256("ZTxIdOutputsHash", []) +T.3.1: coinbase_effects_digest +.............................. + +A BLAKE2b-256 hash of the following values:: + + T.3.1a: blockHeight (4-byte little-endian block height) + T.3.1b: coinbaseData (byte array with leading ``compactSize`` length) + +The personalization field of this hash is set to:: + + "ZTxIdCoinbasHash" + +This digest is present only for coinbase transactions; a transaction that has +no coinbase bundle contributes no entry for it to ``effects_bundles_digest``. + T.3.2: sapling_effects_digest ............................. @@ -1680,6 +1751,32 @@ Effecting data bundles and authorizing data bundles are stored separately in the transaction format so that the authorizing data may be pruned by straightforward truncation of the encoded representation of the transaction. +Representing the coinbase as a bundle makes the value pool delta balance rule +universal. Previously the coinbase transaction was the sole exception: its +deltas summed to the negation of the block subsidy rather than to zero, because +the subsidy entered the transparent transaction value pool implicitly. With the +subsidy carried as the coinbase bundle's value pool delta, every transaction +balances to zero in every asset, and a wallet can enumerate the value flows of +a coinbase transaction using the same rule it applies to any other transaction. + +The coinbase bundle also gives the coinbase metadata a place of its own. In +previous transaction versions that metadata was encoded as the ``scriptSig`` of +a single transparent input whose previous output reference pointed at nothing, +so a coinbase transaction had to be recognized by that unspendable reference, +and the block height had to be encoded as a script push. The coinbase bundle +encodes the height directly, and its presence identifies the transaction. The +``coinbaseData`` limit of 94 bytes holds the encoded size of that field to +what the previous encoding spent on the same content. A coinbase ``scriptSig`` +was limited to 100 bytes, of which the leading push of the block height took 5; +of the 95 bytes that remained, the ``compactSize`` length prefix of +``coinbaseData`` now takes one. + +Neither the previous output reference nor the sequence number of the input +being replaced is carried over. Both were artifacts of encoding the coinbase +metadata as a transparent input: the reference identified no output, and the +sequence number had no effect on the validity of a transaction that spends +nothing. + Deployment ========== @@ -1768,8 +1865,8 @@ Treat bundles as individually versioned. * NSM field similarly never produces value * ZSA burns would be split into "value balance out of Orchard pool" and "value balance being removed from ZSA issuance" - * See also the conversation we had about refactoring coinbase transactions. - TODO: Figure out how to integrate the two. + * The coinbase subsidy is a bundle that only produces value; see + `Coinbase Bundle`_. * Privacy effect is minimal * We already follow a bundle approach with a transparent transaction value From 79d06dfe6ceeba10925d0a0edb17172c4230959c Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Tue, 1 Sep 2026 13:35:04 -0600 Subject: [PATCH 39/51] [ZIP 248]: Carry the block subsidy in the coinbase bundle's effecting data. The coinbase bundle's value pool delta is the block subsidy: the new issuance that consensus awards to the miner of the block, as distinct from the fees, which the fee bundle carries. That subsidy is now also stated as a blockSubsidy field of the coinbase bundle's own effecting data, and so committed to the transaction identifier along with the rest of that data. Deriving it instead is not open to every client, because the subsidy is not a function of the block height alone once issuance depends on accumulated chain state. Co-Authored-By: Claude Opus 5 --- zips/zip-0248.rst | 40 ++++++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/zips/zip-0248.rst b/zips/zip-0248.rst index 0c1742309..7807ccc18 100644 --- a/zips/zip-0248.rst +++ b/zips/zip-0248.rst @@ -670,9 +670,12 @@ in previous transaction versions, and carries the block height that that input was required to encode. The coinbase bundle's value pool delta in ``mValuePoolDeltas`` is the block -subsidy, which the coinbase bundle contributes to the transparent transaction -value pool. The fees collected from the other transactions in the block are -contributed separately, as the value pool delta of the fee bundle. +subsidy: the new issuance that consensus awards to the miner of the block. The +fees collected from the other transactions in the block are contributed +separately, as the value pool delta of the fee bundle. + +The subsidy is also carried in the bundle's own effecting data, as +``blockSubsidy``. The coinbase bundle has no authorizing data. @@ -684,6 +687,8 @@ Coinbase Effecting Data +=============================+==========================+========================================+=====================================================================+ |``4`` |``blockHeight`` |``uint32`` |The height of the block in which the transaction is mined. | +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``8`` |``blockSubsidy`` |``int64`` |The block subsidy for that block, in zatoshis. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ |``varies`` |``coinbaseDataLen`` |``compactSize`` |Length of the ``coinbaseData`` byte array. | +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ |``coinbaseDataLen`` |``coinbaseData`` |``byte[coinbaseDataLen]`` |Data chosen by the miner. Consensus assigns no meaning to its | @@ -691,6 +696,7 @@ Coinbase Effecting Data +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ * ``blockHeight`` MUST be in the range {1 .. 499999999}. +* ``blockSubsidy`` MUST be nonnegative. * ``coinbaseDataLen`` MUST be at most 94. @@ -907,8 +913,8 @@ it understands the bundle type that the rule applies to. Cross-bundle and chain-context rules ```````````````````````````````````` -The following rules relate value pool deltas across bundles within a -transaction, or across transactions within a block. They MUST be enforced by +The following rules relate the contents of a bundle to the other bundles of +its transaction, or to the block that contains it. They MUST be enforced by full validators. * For coinbase transactions, the value of $\mathsf{mValuePoolDeltas}[(\mathsf{FeeBundleId}, \mathsf{Zec})]$ @@ -930,15 +936,16 @@ full validators. * The ``blockHeight`` field of the coinbase bundle's effecting data MUST equal the height of the block containing the transaction. +* The ``blockSubsidy`` field of the coinbase bundle's effecting data MUST equal + the block subsidy for that block, as defined in § 7.8 'Block Subsidy and + Founders' Reward'. [#protocol-subsidies]_ + * The value of $\mathsf{mValuePoolDeltas}[(\mathsf{CoinbaseBundleId}, \mathsf{Zec})]$ - MUST equal the block subsidy for the block containing the transaction. + MUST equal the ``blockSubsidy`` field of the coinbase bundle's effecting data. .. math:: - \mathsf{mValuePoolDeltas}[(\mathsf{CoinbaseBundleId}, \mathsf{Zec})] = \mathsf{BlockSubsidy}(\mathsf{blockHeight}) - - where $\mathsf{BlockSubsidy}$ is defined in § 7.8 'Block Subsidy and - Founders' Reward'. [#protocol-subsidies]_ + \mathsf{mValuePoolDeltas}[(\mathsf{CoinbaseBundleId}, \mathsf{Zec})] = \mathsf{blockSubsidy} * For every transaction, the sum of value pool delta values in each asset MUST equal 0. @@ -1229,7 +1236,8 @@ T.3.1: coinbase_effects_digest A BLAKE2b-256 hash of the following values:: T.3.1a: blockHeight (4-byte little-endian block height) - T.3.1b: coinbaseData (byte array with leading ``compactSize`` length) + T.3.1b: blockSubsidy (8-byte signed little-endian) + T.3.1c: coinbaseData (byte array with leading ``compactSize`` length) The personalization field of this hash is set to:: @@ -1755,10 +1763,18 @@ Representing the coinbase as a bundle makes the value pool delta balance rule universal. Previously the coinbase transaction was the sole exception: its deltas summed to the negation of the block subsidy rather than to zero, because the subsidy entered the transparent transaction value pool implicitly. With the -subsidy carried as the coinbase bundle's value pool delta, every transaction +subsidy carried in the coinbase bundle's value pool delta, every transaction balances to zero in every asset, and a wallet can enumerate the value flows of a coinbase transaction using the same rule it applies to any other transaction. +Carrying ``blockSubsidy`` in the effecting data states the subsidy in the +bundle it belongs to, and commits it to the transaction identifier along with +the rest of that data. Deriving it instead is not open to every client: the +subsidy is not a function of the block height alone once issuance depends on +accumulated chain state, so evaluating the issuance schedule would require a +client to track that state. Its value is the coinbase bundle's value pool +delta, and a consensus rule ties the two together. + The coinbase bundle also gives the coinbase metadata a place of its own. In previous transaction versions that metadata was encoded as the ``scriptSig`` of a single transparent input whose previous output reference pointed at nothing, From bccf8f74f5443d8719f169ea70caccc173f81184 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Tue, 1 Sep 2026 14:07:56 -0600 Subject: [PATCH 40/51] [ZIP 248]: Register the Ironwood bundle type. The Ironwood bundle takes bundle type 4, and the fee, NSM, key rotation, and lockbox disbursement bundles shift up by one to 5, 6, 7, and 8. ZIPs 2002 and 233 follow. The *Orchard pool* and the *Ironwood pool* are two pools of the same shielded protocol, so the section that specified the Orchard bundle now specifies the encoding of an Orchard protocol bundle, which the Orchard and Ironwood bundle types share. The anchor is described relative to the bundle's own pool, and the restriction on enableSpendsOrchard in a coinbase transaction applies to every Orchard protocol bundle rather than to the Orchard bundle alone. The pools need separate bundle types rather than variants of one type: a variant must affect the same value pool as the type it varies, so that a client that does not recognize the variant still knows which pools are touched. The Ironwood digests are the same shape as the Orchard ones over the same fields, with distinct personalization strings so that the digest of a bundle acting on one pool cannot be reused as the digest of a bundle acting on the other. Personalizations follow the stems ZIP 229 uses for the equivalent v6 digests. Co-Authored-By: Claude Opus 5 --- zips/zip-0233.md | 12 ++-- zips/zip-0248.rst | 146 +++++++++++++++++++++++++++++++++++----------- zips/zip-2002.rst | 10 ++-- 3 files changed, 124 insertions(+), 44 deletions(-) diff --git a/zips/zip-0233.md b/zips/zip-0233.md index ce4f44dcc..5d154e655 100644 --- a/zips/zip-0233.md +++ b/zips/zip-0233.md @@ -100,12 +100,12 @@ network. ## Changes to ZIP 248 -This ZIP proposes to register bundle type 5 variant 0 ("ZIP 233 NSM field") in +This ZIP proposes to register bundle type 6 variant 0 ("ZIP 233 NSM field") in the V7 transaction bundle type registry defined in ZIP 248 [^zip-0248]. | BundleType | BundleVariant | `mValuePoolDeltas` | `mEffectBundles` | `mAuthBundles` | |------------|---------------|--------------------|------------------|----------------| -| 5 | 0 |✅ |❌ |❌ | +| 6 | 0 |✅ |❌ |❌ | $\mathsf{zip233\_amount}$ does not result in an output being produced in any chain value pool, and therefore from the point at which the transaction is @@ -117,11 +117,11 @@ circulation may be reissued through future block subsidies. The NSM bundle has no effecting data and no authorizing data. The amount to be removed from circulation is represented solely as an entry in `mValuePoolDeltas` -with `bundleType = 5` and `assetClass = 0` (ZEC). +with `bundleType = 6` and `assetClass = 0` (ZEC). ## NSM Amount -When the `mValuePoolDeltas` map contains an entry with `bundleType = 5`, the +When the `mValuePoolDeltas` map contains an entry with `bundleType = 6`, the transaction removes funds from circulation. The entry's `value` field MUST BE nonpositive; its negation is denoted $\mathsf{zip233\_amount}$ and represents the value in zatoshis removed from circulation when the transaction is mined. @@ -138,7 +138,7 @@ issued supply in subsequent blocks. ## Changes to the Zcash Protocol Specification -Let $\mathsf{NSMBundleId} = 5.$ +Let $\mathsf{NSMBundleId} = 6.$ Let $\mathsf{Zec}$ be the asset UUID for ZEC as defined in ZIP 248 [^zip-0248]. @@ -163,7 +163,7 @@ In § 7.1 'Transaction Encoding and Consensus' [^protocol-txnconsensus], add: The $\mathsf{zip233\_amount}$ is committed to the transaction identifier and signature digest via the `value_pool_deltas_digest` defined in ZIP 248 [^zip-0248]. -Since the NSM bundle (bundle type 5) has no effecting data and no authorizing +Since the NSM bundle (bundle type 6) has no effecting data and no authorizing data, its only contribution to the transaction digest is through its entry in `mValuePoolDeltas`. diff --git a/zips/zip-0248.rst b/zips/zip-0248.rst index 7807ccc18..2681e568c 100644 --- a/zips/zip-0248.rst +++ b/zips/zip-0248.rst @@ -335,13 +335,15 @@ be present. +------------+---------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ | 3 | |✅ |✅ |✅ | ZIP 226 | OrchardZSA | +------------+---------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ -| 4 | 0 |✅ |❌ |❌ | ZIP 2002 | Transaction fee | +| 4 | 0 |✅ |✅ |✅ | This ZIP | Ironwood | +------------+---------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ -| 5 | 0 |✅ |❌ |❌ | ZIP 233 | ZIP 233 NSM field | +| 5 | 0 |✅ |❌ |❌ | ZIP 2002 | Transaction fee | +------------+---------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ -| 6 | 0 |❌ |✅ |✅ | ZIP 270 | Key rotation | +| 6 | 0 |✅ |❌ |❌ | ZIP 233 | ZIP 233 NSM field | +------------+---------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ -| 7 | 0 |✅ |✅ |✅ | TBD | Lockbox disbursement | +| 7 | 0 |❌ |✅ |✅ | ZIP 270 | Key rotation | ++------------+---------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ +| 8 | 0 |✅ |✅ |✅ | TBD | Lockbox disbursement | +------------+---------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ | | 0 |❌ |✅ |❌ | ZIP 231 | Memos | +------------+---------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ @@ -554,9 +556,9 @@ wallet does not itself implement. * ``vSpendProofsSapling`` and ``vSpendAuthSigsSapling`` each have ``nSpendsSapling`` elements; * ``vOutputProofsSapling`` has ``nOutputsSapling`` elements; - * ``vSpendAuthSigsOrchard`` has ``nActionsOrchard`` elements, and - ``proofsOrchard`` aggregates exactly ``nActionsOrchard`` per-action - proofs. + * in each Orchard protocol bundle, ``vSpendAuthSigsOrchard`` has + ``nActionsOrchard`` elements, and ``proofsOrchard`` aggregates exactly + ``nActionsOrchard`` per-action proofs. A wallet that successfully parses a V7 transaction under these rules is guaranteed to be able to compute the transaction identifier (given, for @@ -791,15 +793,28 @@ elements of the corresponding effecting data are required by the parsing rules in `Parsing Rules`_. -Orchard Bundle --------------- +Orchard Protocol Bundles +------------------------ -Orchard Effecting Data -`````````````````````` +The Orchard protocol supports two value pools: the *Orchard pool*, and the +*Ironwood pool* introduced by ZIP 229 [#zip-0229]_. Each has its own note +commitment tree, nullifier set, and chain value pool balance, and each is acted +upon by its own bundle type: the Orchard bundle, ``bundleType = 3``, acts on +the *Orchard pool*, and the Ironwood bundle, ``bundleType = 4``, acts on the +*Ironwood pool*. -The effecting data for the Orchard bundle describes the Orchard actions. Unlike -the V5 transaction format defined in ZIP 225 [#zip-0225]_, the value balance is -not included here; it appears in ``mValuePoolDeltas`` instead. +Both bundle types use the encoding defined in this section. Where a field is +described below as belonging to the bundle's pool, that pool is the +*Orchard pool* for an Orchard bundle and the *Ironwood pool* for an Ironwood +bundle. + +Orchard Protocol Effecting Data +``````````````````````````````` + +The effecting data for an Orchard protocol bundle describes the Orchard +actions. Unlike the V5 transaction format defined in ZIP 225 [#zip-0225]_, the +value balance is not included here; it appears in ``mValuePoolDeltas`` +instead. +-----------------------------+--------------------------+-------------------------------------------+---------------------------------------------------------------------+ | Bytes | Name | Data Type | Description | @@ -814,8 +829,8 @@ not included here; it appears in ``mValuePoolDeltas`` instead. | | | |* ``enableOutputsOrchard`` | | | | |* The remaining bits are set to :math:`0\!`. | +-----------------------------+--------------------------+-------------------------------------------+---------------------------------------------------------------------+ -|``32`` |``anchorOrchard`` |``byte[32]`` |A root of the Orchard note commitment tree at some block height | -| | | |in the past. | +|``32`` |``anchorOrchard`` |``byte[32]`` |A root of the note commitment tree of the bundle's pool, at some | +| | | |block height in the past. | +-----------------------------+--------------------------+-------------------------------------------+---------------------------------------------------------------------+ * The fields ``flagsOrchard`` and ``anchorOrchard`` are present if and only if @@ -845,11 +860,11 @@ OrchardActionEffecting | | | |of the transmission key with the ephemeral secret key. | +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -Orchard Authorizing Data -```````````````````````` +Orchard Protocol Authorizing Data +````````````````````````````````` -The authorizing data for the Orchard bundle contains the proofs and signatures -that authorize the actions. +The authorizing data for an Orchard protocol bundle contains the proofs and +signatures that authorize the actions. +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ | Bytes | Name | Data Type | Description | @@ -870,9 +885,9 @@ that authorize the actions. * The fields ``sizeProofsOrchard``, ``proofsOrchard``, and ``bindingSigOrchard`` are present if and only if $\mathtt{nActionsOrchard} > 0$. -The 1:1 correspondences between Orchard authorizing-data elements and the -elements of the corresponding effecting data are required by the parsing -rules in `Parsing Rules`_. +The 1:1 correspondences between the authorizing-data elements of an Orchard +protocol bundle and the elements of the corresponding effecting data are +required by the parsing rules in `Parsing Rules`_. Consensus Rules @@ -885,7 +900,7 @@ these consensus rules is well-formed but invalid. Let ``CoinbaseBundleId`` be the identifier of the coinbase bundle, and ``FeeBundleId`` be the identifier of the fee bundle. In V7 transactions, -$\mathsf{CoinbaseBundleId} = 1$ and $\mathsf{FeeBundleId} = 4$ as defined in +$\mathsf{CoinbaseBundleId} = 1$ and $\mathsf{FeeBundleId} = 5$ as defined in the table above. Bundle-local rules @@ -907,8 +922,8 @@ it understands the bundle type that the rule applies to. transparent bundle is present in a coinbase transaction, its effecting data MUST have ``tx_in_count = 0``. -* For coinbase transactions, the ``enableSpendsOrchard`` bit of the Orchard - bundle's ``flagsOrchard`` field MUST be 0. +* For coinbase transactions, the ``enableSpendsOrchard`` bit of the + ``flagsOrchard`` field of every Orchard protocol bundle MUST be 0. Cross-bundle and chain-context rules ```````````````````````````````````` @@ -973,13 +988,13 @@ where ``associatedData`` is specific to the bundle it appears in. The following sighash algorithm versions are defined for V7 transactions: -+--------------------+-------------------------------------------------------+ -| |:math:`\hspace{4.5em}` ``associatedData`` | -+--------------------+-------------+-------------+-------------+-------------+ -| ``sighashVersion`` | Transparent | Sapling | Orchard | Issuance | -+--------------------+-------------+-------------+-------------+-------------+ -| 0 |``[]`` |``[]`` |``[]`` |``[]`` | -+--------------------+-------------+-------------+-------------+-------------+ ++--------------------+---------------------------------------------------------------------+ +| |:math:`\hspace{4.5em}` ``associatedData`` | ++--------------------+-------------+-------------+-------------+-------------+-------------+ +| ``sighashVersion`` | Transparent | Sapling | Orchard | Ironwood | Issuance | ++--------------------+-------------+-------------+-------------+-------------+-------------+ +| 0 |``[]`` |``[]`` |``[]`` |``[]`` |``[]`` | ++--------------------+-------------+-------------+-------------+-------------+-------------+ Version 0 is by convention the "commit to all effecting data" sighash algorithm. Other versions can commit to whatever makes sense for desired functionality @@ -1077,6 +1092,10 @@ follows:: │ ├── orchard_actions_compact_digest │ ├── orchard_actions_memos_digest │ └── orchard_actions_noncompact_digest + ├─ (bundle_type_id || bundle_variant || ironwood_effects_digest) + │ ├── ironwood_actions_compact_digest + │ ├── ironwood_actions_memos_digest + │ └── ironwood_actions_noncompact_digest └─ (bundle_type_id || bundle_variant || unknown_bundle_effects_digest) ... Each node written as ``snake_case`` in this tree is a BLAKE2b-256 hash of its @@ -1381,6 +1400,10 @@ The personalization field of this hash is set to:: T.3.3: orchard_effects_digest ............................. +The digest defined here and in its child sections is the Orchard bundle's +instance of a digest shape shared with the Ironwood bundle; T.3.4 gives the +Ironwood instance. + In the case that Orchard actions are present, the Orchard effects digest is a BLAKE2b-256 hash of the following values:: @@ -1444,6 +1467,34 @@ The personalization field of this hash is set to:: "ZTxIdOrcActNHash" +T.3.4: ironwood_effects_digest +.............................. + +The Ironwood bundle uses the same effecting data encoding as the Orchard +bundle, and ``ironwood_effects_digest`` is computed over that data exactly as +``orchard_effects_digest`` and its children are computed (T.3.3), except that +each personalization string is replaced as follows: + ++-------------------------------------+----------------------+----------------------+ +| Digest | Orchard bundle | Ironwood bundle | ++=====================================+======================+======================+ +| effects digest |``ZTxIdOrchardHash`` |``ZTxIdIronwd_Hash`` | ++-------------------------------------+----------------------+----------------------+ +| actions compact digest |``ZTxIdOrcActCHash`` |``ZTxIdIrnActCHash`` | ++-------------------------------------+----------------------+----------------------+ +| actions memos digest |``ZTxIdOrcActMHash`` |``ZTxIdIrnActMHash`` | ++-------------------------------------+----------------------+----------------------+ +| actions noncompact digest |``ZTxIdOrcActNHash`` |``ZTxIdIrnActNHash`` | ++-------------------------------------+----------------------+----------------------+ + +The personalization strings differ so that the digest of a bundle acting on one +pool cannot be reused as the digest of a bundle acting on the other. + +In the case that the transaction has no Ironwood actions, +``ironwood_effects_digest`` is:: + + BLAKE2b-256("ZTxIdIronwd_Hash", []) + Signature Digest ```````````````` @@ -1618,6 +1669,7 @@ the authorizing data of a transaction. The overall structure is:: ├─ (bundle_type_id || bundle_variant || transparent_auth_digest) ├─ (bundle_type_id || bundle_variant || sapling_auth_digest) ├─ (bundle_type_id || bundle_variant || orchard_auth_digest) + ├─ (bundle_type_id || bundle_variant || ironwood_auth_digest) └─ (bundle_type_id || bundle_variant || unknown_bundle_auth_digest) ... auth_digest @@ -1717,6 +1769,20 @@ In the case that the transaction has no Orchard actions:: BLAKE2b-256("ZTxAuthOrchaHash", []) +A.1.4: ironwood_auth_digest +........................... + +The Ironwood bundle uses the same authorizing data encoding as the Orchard +bundle, and ``ironwood_auth_digest`` is computed over that data exactly as +``orchard_auth_digest`` (A.1.3), except that the personalization field of the +hash is set to:: + + "ZTxAuthIrnwdHash" + +In the case that the transaction has no Ironwood actions:: + + BLAKE2b-256("ZTxAuthIrnwdHash", []) + Implications for Wallets ------------------------ @@ -1775,6 +1841,19 @@ accumulated chain state, so evaluating the issuance schedule would require a client to track that state. Its value is the coinbase bundle's value pool delta, and a consensus rule ties the two together. +The Orchard and Ironwood bundles share one encoding because the *Orchard pool* +and the *Ironwood pool* are two pools of the same shielded protocol +[#zip-0229]_. The action encoding, proving system, authorization, and note +encryption are common to both; the pools differ in their note commitment trees, +nullifier sets, and chain value pool balances. + +Each pool gets its own bundle type rather than a variant of a single type +because a variant is required to affect the same value pool(s) as the type it +varies, so that a client encountering an unrecognized variant still knows which +pools the bundle touches. Two pools therefore cannot share a bundle type, and +separate types also keep the two value pool deltas separable, which a client +needs in order to report the two chain value pool balances independently. + The coinbase bundle also gives the coinbase metadata a place of its own. In previous transaction versions that metadata was encoded as the ``scriptSig`` of a single transparent input whose previous output reference pointed at nothing, @@ -2034,6 +2113,7 @@ References .. [#zip-0203] `ZIP 203: Transaction Expiry `_ .. [#zip-0212] `ZIP 212: Allow Recipient to Derive Ephemeral Secret from Note Plaintext `_ .. [#zip-0225] `ZIP 225: Version 5 Transaction Format `_ +.. [#zip-0229] `ZIP 229: Version 6 Transaction Format `_ .. [#zip-0239] `ZIP 239: Relay of Version 5 Transactions `_ .. [#zip-0244] `ZIP 244: Transaction Identifier Non-Malleability `_ .. [#zip-0307] `ZIP 307: Light Client Protocol for Payment Detection `_ diff --git a/zips/zip-2002.rst b/zips/zip-2002.rst index 8d21ad26b..51e63c06b 100644 --- a/zips/zip-2002.rst +++ b/zips/zip-2002.rst @@ -76,18 +76,18 @@ Specification Changes to ZIP 248 ------------------ -This ZIP proposes to register bundle type 4 variant 0 ("Transaction fee") in +This ZIP proposes to register bundle type 5 variant 0 ("Transaction fee") in the V7 transaction bundle type registry defined in ZIP 248 [#zip-0248]_. +------------+---------------+----------------------+--------------------+------------------+ | BundleType | BundleVariant | ``mValuePoolDeltas`` | ``mEffectBundles`` | ``mAuthBundles`` | +============+===============+======================+====================+==================+ -| 4 | 0 |✅ |❌ |❌ | +| 5 | 0 |✅ |❌ |❌ | +------------+---------------+----------------------+--------------------+------------------+ The fee bundle has no effecting data and no authorizing data. The transaction fee is represented solely as an entry in ``mValuePoolDeltas`` with -``bundleType = 4`` and ``assetClass = 0`` (ZEC). +``bundleType = 5`` and ``assetClass = 0`` (ZEC). For non-coinbase transactions, the ``value`` field of this entry MUST be nonpositive, representing the fee being removed from the transparent @@ -98,7 +98,7 @@ the block being added to the ZEC transparent transaction value pool. Changes to the Zcash Protocol Specification ------------------------------------------- -Let $\mathsf{FeeBundleId} = 4.$ +Let $\mathsf{FeeBundleId} = 5.$ Let $\mathsf{Zec}$ be the asset UUID for ZEC as defined in ZIP 248 [#zip-0248]_. @@ -129,7 +129,7 @@ Modifications to Digest Algorithms The fee amount is committed to the transaction identifier and signature digest via the ``value_pool_deltas_digest`` defined in ZIP 248 [#zip-0248]_. -Since the fee bundle (bundle type 4) has no effecting data and no authorizing +Since the fee bundle (bundle type 5) has no effecting data and no authorizing data, its only contribution to the transaction digest is through its entry in ``mValuePoolDeltas``. From f7c25fbb67c926e75996acb5d610ec1ad47082aa Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Tue, 1 Sep 2026 14:28:33 -0600 Subject: [PATCH 41/51] [ZIP 248]: Add enableCrossAddress to the Orchard protocol bundle. Bit 2 of flagsOrchard is the enableCrossAddress bit specified by ZIP 2006, and bits 3..7 are the reserved ones. The bit MUST be 0 in an Orchard bundle, which is what restricts transfers into the Orchard pool to the protocol-level address of the action's spend; it is unrestricted in an Ironwood bundle. The other two bits lose their Orchard suffix, becoming enableSpends and enableOutputs, because they mean the same thing for both pools. ZIP 229 renamed them for that reason when it gave the Ironwood pool its own flags field. ZIP 231 now registers its Orchard variant against every bundle type that uses the Orchard protocol bundle encoding, rather than against the Orchard pool alone, and its copy of the encoding follows the flags field. The terms taken from ZIP 229 are declared in both Terminology sections. Co-Authored-By: Claude Opus 5 --- zips/zip-0231.md | 82 +++++++++++++++++++++++++++-------------------- zips/zip-0248.rst | 38 +++++++++++++++------- 2 files changed, 75 insertions(+), 45 deletions(-) diff --git a/zips/zip-0231.md b/zips/zip-0231.md index 3e4e2f21c..76149c8bd 100644 --- a/zips/zip-0231.md +++ b/zips/zip-0231.md @@ -33,6 +33,10 @@ format" are to be interpreted as defined in ZIP 248. [^zip-0248] A note plaintext or note ciphertext is described as "V7-onward" or "pre-V7" according to the format of the transaction that contains it. +The terms "Orchard protocol", "*Orchard pool*", and "*Ironwood pool*" are to be +interpreted as described in ZIP 229. [^zip-0229] The term "Orchard protocol +bundle" is to be interpreted as defined in ZIP 248. [^zip-0248] + # Abstract @@ -207,38 +211,43 @@ potential distinguisher along another. # Specification Since this proposal is defined only for V7 transactions, it is not -necessary to consider Sprout JoinSplit outputs. The following sections apply -to both Sapling and Orchard outputs in V7 transactions. +necessary to consider Sprout JoinSplit outputs. The following sections apply to +Sapling outputs, and to the outputs of Orchard protocol actions in either the +*Orchard pool* or the *Ironwood pool*, in V7 transactions. ## Changes to ZIP 248 -This ZIP proposes to register a new bundle type for Memos and new versions of -the Sapling and Orchard bundle types in the V7 transaction bundle type -registry defined in ZIP 248 [^zip-0248]: +This ZIP proposes to register a new bundle type for Memos, and new versions of +the Sapling bundle type and of each Orchard protocol bundle type, in the +V7 transaction bundle type registry defined in ZIP 248 [^zip-0248]: -| BundleType | BundleVariant | `mValuePoolDeltas` | `mEffectBundles` | `mAuthBundles` | Bundle kind | -|------------|---------------|--------------------|------------------|----------------|----------------------| -| TBD | 0 |❌ |✅ |❌ | Memos | -| 2 | TBD |✅ |✅ |✅ | Sapling-post-ZIP 231 | -| 3 | TBD |✅ |✅ |✅ | Orchard-post-ZIP 231 | +| BundleType | BundleVariant | `mValuePoolDeltas` | `mEffectBundles` | `mAuthBundles` | Bundle kind | +|------------|---------------|--------------------|------------------|----------------|----------------------------------| +| TBD | 0 |❌ |✅ |❌ | Memos | +| 2 | TBD |✅ |✅ |✅ | Sapling-post-ZIP 231 | +| 3 | TBD |✅ |✅ |✅ | Orchard-protocol-post-ZIP 231 | +| 4 | TBD |✅ |✅ |✅ | Orchard-protocol-post-ZIP 231 | The Memos bundle has no value pool deltas (memo data does not involve value transfers) and no authorizing data. The effecting data consists of the encoded memo bundle as defined in [Encoding in transactions]. -The Sapling-post-ZIP 231 and Orchard-post-ZIP 231 entries are new variants of -the existing Sapling (``bundleType`` 2) and Orchard (``bundleType`` 3) bundle -types respectively. Because ZIP 248 requires that each bundle map is keyed by -``bundleType`` alone, a transaction that includes a Sapling-post-ZIP 231 bundle -cannot also include a pre-ZIP 231 Sapling bundle, and similarly for Orchard. - -If this ZIP is activated in the same network upgrade as ZIP 248, the encoding -of the Sapling and Orchard bundles described in this ZIP will be used for -bundle type 2 variant 0 and bundle type 3 variant 0, respectively, and -ZIP 248's definition of the Sapling and Orchard bundles must be updated -accordingly. If this ZIP is activated in a network upgrade AFTER the network -upgrade in which ZIP 248 is activated, the encodings it describes will be -assigned distinct bundle variant identifiers for their respective bundle types. +The Sapling-post-ZIP 231 entry is a new variant of the existing Sapling bundle +type (`bundleType` 2). The Orchard-protocol-post-ZIP 231 entry is a new variant +of each of the bundle types that use the Orchard protocol bundle encoding — the +Orchard bundle (`bundleType` 3) and the Ironwood bundle (`bundleType` 4) — with +one encoding shared between them, as in ZIP 248. Because ZIP 248 requires that +each bundle map is keyed by `bundleType` alone, a transaction that includes a +Sapling-post-ZIP 231 bundle cannot also include a pre-ZIP 231 Sapling bundle, +and likewise for each Orchard protocol bundle type. + +If this ZIP is activated in the same network upgrade as ZIP 248, the encodings +of the Sapling bundle and of the Orchard protocol bundles described in this ZIP +will be used for variant 0 of bundle types 2, 3, and 4, and ZIP 248's +definitions of those bundles must be updated accordingly. If this ZIP is +activated in a network upgrade AFTER the network upgrade in which ZIP 248 is +activated, the encodings it describes will be assigned distinct bundle variant +identifiers for their respective bundle types. ## Sapling-post-ZIP 231 Bundle @@ -300,29 +309,32 @@ ZIP 248 [^zip-0248]. that the proof at a given index corresponds to the `SaplingOutputPostZIP231` at the same index. -## Orchard-post-ZIP 231 Bundle +## Orchard-protocol-post-ZIP 231 Bundle -The Orchard-post-ZIP 231 bundle replaces the Orchard bundle defined in -ZIP 248 [^zip-0248]. As with Sapling, the only change is that the note +The Orchard-protocol-post-ZIP 231 bundle replaces the Orchard protocol bundle +defined in ZIP 248 [^zip-0248], and like it is shared by the Orchard and +Ironwood bundle types. As with Sapling, the only change is that the note plaintext in each Orchard action is shortened: the 512-byte memo field is replaced by a 32-byte $\mathsf{K^{memo}}$, reducing `encCiphertext` from 580 bytes to 100 bytes. -### Orchard-post-ZIP 231 Effecting Data +### Orchard-protocol-post-ZIP 231 Effecting Data -The effecting data for the Orchard-post-ZIP 231 bundle describes the Orchard -actions. +The effecting data for an Orchard-protocol-post-ZIP 231 bundle describes the +Orchard actions. | Bytes | Name | Data Type | Description | |--------------------------|--------------------|-------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------| | varies | `nActionsOrchard` | `compactSize` | The number of Orchard Action descriptions. | | 340 \* nActionsOrchard | `vActionsOrchard` | `OrchardActionPostZIP231[nActionsOrchard]` | Effecting data for each Orchard Action. | -| 1 | `flagsOrchard` | `byte` | An 8-bit value representing a set of flags. Ordered from LSB to MSB: `enableSpendsOrchard`, `enableOutputsOrchard`. The remaining bits are set to $0$. | -| 32 | `anchorOrchard` | `byte[32]` | A root of the Orchard note commitment tree at some block height in the past. | +| 1 | `flagsOrchard` | `byte` | An 8-bit value representing a set of flags. Ordered from LSB to MSB: `enableSpends`, `enableOutputs`, `enableCrossAddress`. The remaining bits are set to $0$. | +| 32 | `anchorOrchard` | `byte[32]` | A root of the note commitment tree of the bundle's pool, at some block height in the past. | * The fields `flagsOrchard` and `anchorOrchard` are present if and only if $\mathtt{nActionsOrchard} > 0$. -* For coinbase transactions, the `enableSpendsOrchard` bit MUST be set to $0$. +* For coinbase transactions, the `enableSpends` bit MUST be set to $0$. +* In an Orchard bundle, the `enableCrossAddress` bit MUST be set to $0$. The bit + is unrestricted in an Ironwood bundle. #### OrchardActionPostZIP231 @@ -336,9 +348,9 @@ actions. | 100 | `encCiphertext` | `byte[100]` | The encrypted contents of the note plaintext, which contains $\mathsf{K^{memo}}$ in place of the 512-byte memo field. | | 80 | `outCiphertext` | `byte[80]` | The encrypted contents of the byte string created by concatenation of the transmission key with the ephemeral secret key. | -### Orchard-post-ZIP 231 Authorizing Data +### Orchard-protocol-post-ZIP 231 Authorizing Data -The authorizing data is unchanged from the Orchard bundle defined in +The authorizing data is unchanged from the Orchard protocol bundle defined in ZIP 248 [^zip-0248]. | Bytes | Name | Data Type | Description | @@ -956,6 +968,8 @@ TBD [^zip-0200]: [ZIP 200: Network Upgrade Mechanism](zip-0200.rst) +[^zip-0229]: [ZIP 229: Version 6 Transaction Format](zip-0229.md) + [^zip-0248]: [ZIP 248: Extensible Transaction Format](zip-0248.rst) [^draft-arya-deploy-nu7]: [draft-arya-deploy-nu7: Deployment of the NU7 Network Upgrade](draft-arya-deploy-nu7.md) diff --git a/zips/zip-0248.rst b/zips/zip-0248.rst index 2681e568c..967e8df01 100644 --- a/zips/zip-0248.rst +++ b/zips/zip-0248.rst @@ -30,6 +30,11 @@ The terms "Mainnet" and "Testnet" are to be interpreted as described in § 3.12 The term "full validator" in this document is to be interpreted as defined in § 3.3 ‘The Block Chain’. [#protocol-blockchain]_ +The terms "Orchard protocol", "*Orchard pool*", and "*Ironwood pool*" are to be +interpreted as described in ZIP 229. [#zip-0229]_ Following the convention in +the Zcash Protocol Specification, *slanted text* refers to pool names, to +distinguish them from shielded protocols. + The terms below are to be interpreted as follows: V7 transaction format @@ -796,9 +801,8 @@ rules in `Parsing Rules`_. Orchard Protocol Bundles ------------------------ -The Orchard protocol supports two value pools: the *Orchard pool*, and the -*Ironwood pool* introduced by ZIP 229 [#zip-0229]_. Each has its own note -commitment tree, nullifier set, and chain value pool balance, and each is acted +The Orchard protocol supports two value pools, each with its own note +commitment tree, nullifier set, and chain value pool balance. Each is acted upon by its own bundle type: the Orchard bundle, ``bundleType = 3``, acts on the *Orchard pool*, and the Ironwood bundle, ``bundleType = 4``, acts on the *Ironwood pool*. @@ -808,6 +812,11 @@ described below as belonging to the bundle's pool, that pool is the *Orchard pool* for an Orchard bundle and the *Ironwood pool* for an Ironwood bundle. +The bits of ``flagsOrchard`` have the same meaning for both pools, and so are +named without the ``Orchard`` suffix they carried in the V5 transaction format, +following ZIP 229 [#zip-0229]_. Their values are constrained per pool by the +`Bundle-local rules`_. + Orchard Protocol Effecting Data ``````````````````````````````` @@ -825,8 +834,9 @@ instead. +-----------------------------+--------------------------+-------------------------------------------+---------------------------------------------------------------------+ |``1`` |``flagsOrchard`` |``byte`` |An 8-bit value representing a set of flags. Ordered from LSB to MSB: | | | | | | -| | | |* ``enableSpendsOrchard`` | -| | | |* ``enableOutputsOrchard`` | +| | | |* ``enableSpends`` | +| | | |* ``enableOutputs`` | +| | | |* ``enableCrossAddress`` [#zip-2006]_ | | | | |* The remaining bits are set to :math:`0\!`. | +-----------------------------+--------------------------+-------------------------------------------+---------------------------------------------------------------------+ |``32`` |``anchorOrchard`` |``byte[32]`` |A root of the note commitment tree of the bundle's pool, at some | @@ -922,8 +932,13 @@ it understands the bundle type that the rule applies to. transparent bundle is present in a coinbase transaction, its effecting data MUST have ``tx_in_count = 0``. -* For coinbase transactions, the ``enableSpendsOrchard`` bit of the - ``flagsOrchard`` field of every Orchard protocol bundle MUST be 0. +* For coinbase transactions, the ``enableSpends`` bit of the ``flagsOrchard`` + field of every Orchard protocol bundle MUST be 0. + +* In an Orchard bundle, the ``enableCrossAddress`` bit of ``flagsOrchard`` MUST + be 0; that is, transfers into the *Orchard pool* are restricted to the + protocol-level address of the action's spend. [#zip-2006]_ The bit is + unrestricted in an Ironwood bundle. Cross-bundle and chain-context rules ```````````````````````````````````` @@ -1842,10 +1857,10 @@ client to track that state. Its value is the coinbase bundle's value pool delta, and a consensus rule ties the two together. The Orchard and Ironwood bundles share one encoding because the *Orchard pool* -and the *Ironwood pool* are two pools of the same shielded protocol -[#zip-0229]_. The action encoding, proving system, authorization, and note -encryption are common to both; the pools differ in their note commitment trees, -nullifier sets, and chain value pool balances. +and the *Ironwood pool* are two pools of the same shielded protocol. The action +encoding, proving system, authorization, and note encryption are common to +both; the pools differ in their note commitment trees, nullifier sets, and +chain value pool balances. Each pool gets its own bundle type rather than a variant of a single type because a variant is required to affect the same value pool(s) as the type it @@ -2117,4 +2132,5 @@ References .. [#zip-0239] `ZIP 239: Relay of Version 5 Transactions `_ .. [#zip-0244] `ZIP 244: Transaction Identifier Non-Malleability `_ .. [#zip-0307] `ZIP 307: Light Client Protocol for Payment Detection `_ +.. [#zip-2006] `ZIP 2006: Restricting Transfers into the Orchard Pool `_ From 873532a7849bacbbc21c38e8470e6ff7d061e18c Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Tue, 1 Sep 2026 14:58:28 -0600 Subject: [PATCH 42/51] [ZIP 248]: Move unallocated bundle kinds out of the registry. The registry now lists only the (bundleType, bundleVariant) pairs this upgrade allocates, and runs 0 to 6 without a gap. Everything whose identifier is still open moves to the potential future bundle types section: key rotation, lockbox disbursement, memos, and ZSA issuance, none of which has a bundle type; and the post-ZIP 231 and OrchardZSA variants, which have a bundle type but no variant identifier. That section gains the Defining ZIP column, so the entries that name a ZIP keep it, and its lead-in no longer describes every entry as illustrative. The Orchard variant that ZIP 231 defines is also renamed to match that ZIP and registered against the Ironwood bundle as well as the Orchard bundle, which is what ZIP 231 asks for now that both use the Orchard protocol bundle encoding. Co-Authored-By: Claude Opus 5 --- zips/zip-0248.rst | 69 +++++++++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 32 deletions(-) diff --git a/zips/zip-0248.rst b/zips/zip-0248.rst index 967e8df01..c0de52f3c 100644 --- a/zips/zip-0248.rst +++ b/zips/zip-0248.rst @@ -332,28 +332,14 @@ be present. +------------+---------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ | 2 | 0 |✅ |✅ |✅ | This ZIP | Sapling | +------------+---------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ -| 2 | |✅ |✅ |✅ | ZIP 231 | Sapling-post-ZIP 231 | -+------------+---------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ | 3 | 0 |✅ |✅ |✅ | This ZIP | Orchard | +------------+---------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ -| 3 | |✅ |✅ |✅ | ZIP 231 | Orchard-post-ZIP 231 | -+------------+---------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ -| 3 | |✅ |✅ |✅ | ZIP 226 | OrchardZSA | -+------------+---------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ | 4 | 0 |✅ |✅ |✅ | This ZIP | Ironwood | +------------+---------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ | 5 | 0 |✅ |❌ |❌ | ZIP 2002 | Transaction fee | +------------+---------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ | 6 | 0 |✅ |❌ |❌ | ZIP 233 | ZIP 233 NSM field | +------------+---------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ -| 7 | 0 |❌ |✅ |✅ | ZIP 270 | Key rotation | -+------------+---------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ -| 8 | 0 |✅ |✅ |✅ | TBD | Lockbox disbursement | -+------------+---------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ -| | 0 |❌ |✅ |❌ | ZIP 231 | Memos | -+------------+---------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ -| | 0 |✅ |✅ |✅ | ZIP 227 | ZSA Issuance | -+------------+---------------+----------------------+--------------------+------------------+--------------+----------------------------------------------+ Additional bundle types or variants MAY be added to this registry via modifications to this ZIP specified in other ZIPs. Such modifications MUST @@ -368,26 +354,45 @@ Potential Future Bundle Types
Click to show/hide -The following entries are provided to illustrate how potential future upgrades +The following bundle kinds have no allocated ``(bundleType, bundleVariant)`` +pair. Where a bundle type is given, the kind is a new variant of that existing +type and only its variant identifier is unassigned. Those proposed by a ZIP +name it; the rest are provided to illustrate how potential future upgrades might affect the bundle registry: -+------------+---------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ -| BundleType | BundleVariant | ``mValuePoolDeltas`` | ``mEffectBundles`` | ``mAuthBundles`` | Bundle kind | -+============+===============+======================+====================+==================+=============================================================+ -| | 0 |✅ |✅ |✅ | TZEs | -+------------+---------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ -| | 0 |✅ |✅ |✅ | Pool that only has a long-term storage protocol (PQ, very | -| | | | | | simple thus insulated from counterfeiting fears, can be | -| | | | | | used for payments but higher latency for that purpose) | -+------------+---------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ -| | 0 |✅ |✅ |✅ | Tachyon | -+------------+---------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ -| | 0 |✅ |✅ |❌ | Staking | -+------------+---------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ -| | 0 |✅ |✅ |✅ | Unstaking (if it can't be combined with the Staking bundle) | -+------------+---------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ -| | 0 |✅ |✅ |✅ | Post-quantum fast payment protocol | -+------------+---------------+----------------------+--------------------+------------------+-------------------------------------------------------------+ ++------------+-----------------+----------------------+--------------------+------------------+--------------+-------------------------------------------------------------+ +| BundleType | BundleVariant | ``mValuePoolDeltas`` | ``mEffectBundles`` | ``mAuthBundles`` | Defining ZIP | Bundle kind | ++============+=================+======================+====================+==================+==============+=============================================================+ +| 2 | 1 (provisional) |✅ |✅ |✅ | ZIP 231 | Sapling-post-ZIP 231 | ++------------+-----------------+----------------------+--------------------+------------------+--------------+-------------------------------------------------------------+ +| 3 | 1 (provisional) |✅ |✅ |✅ | ZIP 231 | Orchard post-ZIP 231 | ++------------+-----------------+----------------------+--------------------+------------------+--------------+-------------------------------------------------------------+ +| 3 | 2 (provisional) |✅ |✅ |✅ | ZIP 226 | OrchardZSA | ++------------+-----------------+----------------------+--------------------+------------------+--------------+-------------------------------------------------------------+ +| 4 | 1 (provisional) |✅ |✅ |✅ | ZIP 231 | Ironwood post-ZIP 231 | ++------------+-----------------+----------------------+--------------------+------------------+--------------+-------------------------------------------------------------+ +| | 0 |❌ |✅ |✅ | ZIP 270 | Key rotation | ++------------+-----------------+----------------------+--------------------+------------------+--------------+-------------------------------------------------------------+ +| | 0 |✅ |✅ |✅ | TBD | Lockbox disbursement | ++------------+-----------------+----------------------+--------------------+------------------+--------------+-------------------------------------------------------------+ +| | 0 |❌ |✅ |❌ | ZIP 231 | Memos | ++------------+-----------------+----------------------+--------------------+------------------+--------------+-------------------------------------------------------------+ +| | 0 |✅ |✅ |✅ | ZIP 227 | ZSA Issuance | ++------------+-----------------+----------------------+--------------------+------------------+--------------+-------------------------------------------------------------+ +| | 0 |✅ |✅ |✅ | | TZEs | ++------------+-----------------+----------------------+--------------------+------------------+--------------+-------------------------------------------------------------+ +| | 0 |✅ |✅ |✅ | | Pool that only has a long-term storage protocol (PQ, very | +| | | | | | | simple thus insulated from counterfeiting fears, can be | +| | | | | | | used for payments but higher latency for that purpose) | ++------------+-----------------+----------------------+--------------------+------------------+--------------+-------------------------------------------------------------+ +| | 0 |✅ |✅ |✅ | | Tachyon | ++------------+-----------------+----------------------+--------------------+------------------+--------------+-------------------------------------------------------------+ +| | 0 |✅ |✅ |❌ | | Staking | ++------------+-----------------+----------------------+--------------------+------------------+--------------+-------------------------------------------------------------+ +| | 0 |✅ |✅ |✅ | | Unstaking (if it can't be combined with the Staking bundle) | ++------------+-----------------+----------------------+--------------------+------------------+--------------+-------------------------------------------------------------+ +| | 0 |✅ |✅ |✅ | | Post-quantum fast payment protocol | ++------------+-----------------+----------------------+--------------------+------------------+--------------+-------------------------------------------------------------+ .. raw:: html From 96cf52a253b89bdedf0f4afb5d238f6ab9742354 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Tue, 1 Sep 2026 18:03:33 -0600 Subject: [PATCH 43/51] [ZIP 248]: Move the per-bundle definitions to the end of the Specification. Addresses str4d's review comment on PR 1156. Everything a reader needs in order to parse, identify, and digest a transaction without knowing any bundle type now comes first: the registry, the transaction format, the parsing rules, the consensus rules, sighash versioning, and the bundle-agnostic parts of the digest trees. A new Bundle Definitions section at the end then defines the four bundle types this ZIP registers, in the shape that another ZIP would use to register one of its own. Each bundle's effecting data, authorizing data, sighash algorithms, and digest contributions are now given together, so T.3.x, S.3.0, and A.1.x sit beside the structures they hash rather than in a separate digest section. The table of associatedData per protocol is replaced by a per-bundle statement of the sighash algorithm versions available at variant 0, which is where a ZIP registering a bundle type would state them. Sighash Versioning keeps the versioning mechanism and the per-signature structures. Co-Authored-By: Claude Opus 5 --- zips/zip-0248.rst | 1384 +++++++++++++++++++++++---------------------- 1 file changed, 712 insertions(+), 672 deletions(-) diff --git a/zips/zip-0248.rst b/zips/zip-0248.rst index c0de52f3c..36e817177 100644 --- a/zips/zip-0248.rst +++ b/zips/zip-0248.rst @@ -578,333 +578,6 @@ and to enumerate the transparent value flows of the transaction at the granularity of bundle types. -Transparent Bundle ------------------- - -The transparent bundle's value pool delta in ``mValuePoolDeltas`` represents -the net value flowing from the transparent inputs to the transparent outputs. - -A full validator MUST verify that the ZEC value pool delta for -``bundleType = 0`` equals the total value of the transparent inputs minus the -total value of the transparent outputs. (The input values are not encoded in -the transaction itself; they are obtained from the UTXOs being spent.) - -This rule applies to coinbase transactions unchanged. A coinbase transaction -has no transparent inputs, so its transparent value pool delta is the negation -of the total value of its transparent outputs; the value that those outputs -consume is contributed to the transparent transaction value pool by the -coinbase bundle and the fee bundle. - -Transparent Effecting Data -`````````````````````````` - -The effecting data for the transparent bundle describes the transparent inputs -being spent and the transparent outputs being created. - -+-----------------------------+--------------------------+------------------------------------------+---------------------------------------------------------------------+ -| Bytes | Name | Data Type | Description | -+=============================+==========================+==========================================+=====================================================================+ -|``varies`` |``tx_in_count`` |``compactSize`` |Number of transparent inputs. | -+-----------------------------+--------------------------+------------------------------------------+---------------------------------------------------------------------+ -|``varies`` |``tx_in_effecting`` |``TransparentInputEffecting[tx_in_count]``|Effecting data for each transparent input. | -+-----------------------------+--------------------------+------------------------------------------+---------------------------------------------------------------------+ -|``varies`` |``tx_out_count`` |``compactSize`` |Number of transparent outputs. | -+-----------------------------+--------------------------+------------------------------------------+---------------------------------------------------------------------+ -|``varies`` |``tx_out`` |``TransparentOutput[tx_out_count]`` |Transparent outputs. | -+-----------------------------+--------------------------+------------------------------------------+---------------------------------------------------------------------+ - -TransparentInputEffecting -''''''''''''''''''''''''' - -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -| Bytes | Name | Data Type | Description | -+=============================+==========================+========================================+=====================================================================+ -|``32`` |``prevout_hash`` |``byte[32]`` |The transaction ID of the output being spent. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -|``4`` |``prevout_index`` |``uint32`` |The index of the output being spent within that transaction. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -|``4`` |``nSequence`` |``uint32`` |Sequence number, encoded as in Bitcoin. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ - -TransparentOutput -''''''''''''''''' - -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -| Bytes | Name | Data Type | Description | -+=============================+==========================+========================================+=====================================================================+ -|``8`` |``value`` |``int64`` |The value of the output in zatoshi. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -|``varies`` |``scriptPubKeyLen`` |``compactSize`` |Length of the scriptPubKey. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -|``scriptPubKeyLen`` |``scriptPubKey`` |``byte[scriptPubKeyLen]`` |The script that must be satisfied to spend this output. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ - -Transparent Authorizing Data -```````````````````````````` - -The authorizing data for the transparent bundle contains the scripts that -authorize spending of the referenced transparent inputs. - -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -| Bytes | Name | Data Type | Description | -+=============================+==========================+========================================+=====================================================================+ -|``varies`` |``tx_in_auth`` |``TransparentInputAuth[tx_in_count]`` |Authorizing data for each transparent input. The number of entries | -| | | |MUST equal ``tx_in_count`` from the effecting data. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ - -TransparentInputAuth -'''''''''''''''''''' - -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -| Bytes | Name | Data Type | Description | -+=============================+==========================+========================================+=====================================================================+ -|``varies`` |``sighashInfo`` |``TransparentSighashInfo`` |The sighash version and associated information for this input, | -| | | |as defined in `Per-Signature Structures`_. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -|``varies`` |``scriptSigLen`` |``compactSize`` |Length of the scriptSig. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -|``scriptSigLen`` |``scriptSig`` |``byte[scriptSigLen]`` |The script satisfying the conditions of the referenced output's | -| | | |scriptPubKey. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ - -The ``TransparentSighashInfo`` type is defined in `Per-Signature Structures`_. -It consists of a ``compactSize``-prefixed byte array containing the sighash -version and any associated data required by that version. - - -Coinbase Bundle ---------------- - -A transaction is a *coinbase transaction* if and only if ``mEffectBundles`` -contains an entry with ``bundleType = 1``. The coinbase bundle replaces the -otherwise-unspendable transparent input that identified a coinbase transaction -in previous transaction versions, and carries the block height that that input -was required to encode. - -The coinbase bundle's value pool delta in ``mValuePoolDeltas`` is the block -subsidy: the new issuance that consensus awards to the miner of the block. The -fees collected from the other transactions in the block are contributed -separately, as the value pool delta of the fee bundle. - -The subsidy is also carried in the bundle's own effecting data, as -``blockSubsidy``. - -The coinbase bundle has no authorizing data. - -Coinbase Effecting Data -``````````````````````` - -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -| Bytes | Name | Data Type | Description | -+=============================+==========================+========================================+=====================================================================+ -|``4`` |``blockHeight`` |``uint32`` |The height of the block in which the transaction is mined. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -|``8`` |``blockSubsidy`` |``int64`` |The block subsidy for that block, in zatoshis. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -|``varies`` |``coinbaseDataLen`` |``compactSize`` |Length of the ``coinbaseData`` byte array. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -|``coinbaseDataLen`` |``coinbaseData`` |``byte[coinbaseDataLen]`` |Data chosen by the miner. Consensus assigns no meaning to its | -| | | |contents. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ - -* ``blockHeight`` MUST be in the range {1 .. 499999999}. -* ``blockSubsidy`` MUST be nonnegative. -* ``coinbaseDataLen`` MUST be at most 94. - - -Sapling Bundle --------------- - -Sapling Effecting Data -`````````````````````` - -The effecting data for the Sapling bundle describes the Sapling spends and -outputs. Unlike the V5 transaction format defined in ZIP 225 [#zip-0225]_, -the value balance is not included here; it appears in ``mValuePoolDeltas`` -instead. - -+-----------------------------+--------------------------+-----------------------------------------+---------------------------------------------------------------------+ -| Bytes | Name | Data Type | Description | -+=============================+==========================+=========================================+=====================================================================+ -|``varies`` |``nSpendsSapling`` |``compactSize`` |Number of Sapling Spend descriptions. | -+-----------------------------+--------------------------+-----------------------------------------+---------------------------------------------------------------------+ -|``96 * nSpendsSapling`` |``vSpendsSapling`` |``SaplingSpendEffecting[nSpendsSapling]``|Effecting data for each Sapling Spend. | -+-----------------------------+--------------------------+-----------------------------------------+---------------------------------------------------------------------+ -|``varies`` |``nOutputsSapling`` |``compactSize`` |Number of Sapling Output descriptions. | -+-----------------------------+--------------------------+-----------------------------------------+---------------------------------------------------------------------+ -|``756 * nOutputsSapling`` |``vOutputsSapling`` |``SaplingOutput[nOutputsSapling]`` |Sapling Output descriptions. | -+-----------------------------+--------------------------+-----------------------------------------+---------------------------------------------------------------------+ -|``32`` |``anchorSapling`` |``byte[32]`` |A root of the Sapling note commitment tree at some block height | -| | | |in the past. | -+-----------------------------+--------------------------+-----------------------------------------+---------------------------------------------------------------------+ - -* The field ``anchorSapling`` is present if and only if $\mathtt{nSpendsSapling} > 0$. - -SaplingSpendEffecting -''''''''''''''''''''' - -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -| Bytes | Name | Data Type | Description | -+=============================+==========================+========================================+=====================================================================+ -|``32`` |``cv`` |``byte[32]`` |A value commitment to the net value of the input note. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -|``32`` |``nullifier`` |``byte[32]`` |The nullifier of the input note. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -|``32`` |``rk`` |``byte[32]`` |The randomized validating key for this Spend. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ - -SaplingOutput -''''''''''''' - -This is identical to ``OutputDescriptionV5`` as defined in ZIP 225 [#zip-0225]_. - -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -| Bytes | Name | Data Type | Description | -+=============================+==========================+========================================+=====================================================================+ -|``32`` |``cv`` |``byte[32]`` |A value commitment to the net value of the output note. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -|``32`` |``cmu`` |``byte[32]`` |The :math:`u\!`-coordinate of the note commitment for the output | -| | | |note. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -|``32`` |``ephemeralKey`` |``byte[32]`` |An encoding of an ephemeral Jubjub public key. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -|``580`` |``encCiphertext`` |``byte[580]`` |The encrypted contents of the note plaintext. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -|``80`` |``outCiphertext`` |``byte[80]`` |The encrypted contents of the byte string created by concatenation | -| | | |of the transmission key with the ephemeral secret key. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ - -Sapling Authorizing Data -```````````````````````` - -The authorizing data for the Sapling bundle contains the proofs and signatures -that authorize the spends and validate the outputs. - -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -| Bytes | Name | Data Type | Description | -+=============================+==========================+========================================+=====================================================================+ -|``192 * nSpendsSapling`` |``vSpendProofsSapling`` |``byte[192 * nSpendsSapling]`` |Encodings of the zk-SNARK proofs for each Sapling Spend. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -|``varies`` |``vSpendAuthSigsSapling`` |``SaplingSignature[nSpendsSapling]`` |Authorizing signatures for each Sapling Spend. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -|``192 * nOutputsSapling`` |``vOutputProofsSapling`` |``byte[192 * nOutputsSapling]`` |Encodings of the zk-SNARK proofs for each Sapling Output. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -|``varies`` |``bindingSigSapling`` |``SaplingSignature`` |A Sapling binding signature on the SIGHASH transaction hash. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ - -* The values of ``nSpendsSapling`` and ``nOutputsSapling`` are not re-encoded in - the authorizing data; they are taken from the corresponding effecting data. - -* The field ``bindingSigSapling`` is present if and only if - $\mathtt{nSpendsSapling} + \mathtt{nOutputsSapling} > 0$. - -The 1:1 correspondences between Sapling authorizing-data elements and the -elements of the corresponding effecting data are required by the parsing -rules in `Parsing Rules`_. - - -Orchard Protocol Bundles ------------------------- - -The Orchard protocol supports two value pools, each with its own note -commitment tree, nullifier set, and chain value pool balance. Each is acted -upon by its own bundle type: the Orchard bundle, ``bundleType = 3``, acts on -the *Orchard pool*, and the Ironwood bundle, ``bundleType = 4``, acts on the -*Ironwood pool*. - -Both bundle types use the encoding defined in this section. Where a field is -described below as belonging to the bundle's pool, that pool is the -*Orchard pool* for an Orchard bundle and the *Ironwood pool* for an Ironwood -bundle. - -The bits of ``flagsOrchard`` have the same meaning for both pools, and so are -named without the ``Orchard`` suffix they carried in the V5 transaction format, -following ZIP 229 [#zip-0229]_. Their values are constrained per pool by the -`Bundle-local rules`_. - -Orchard Protocol Effecting Data -``````````````````````````````` - -The effecting data for an Orchard protocol bundle describes the Orchard -actions. Unlike the V5 transaction format defined in ZIP 225 [#zip-0225]_, the -value balance is not included here; it appears in ``mValuePoolDeltas`` -instead. - -+-----------------------------+--------------------------+-------------------------------------------+---------------------------------------------------------------------+ -| Bytes | Name | Data Type | Description | -+=============================+==========================+===========================================+=====================================================================+ -|``varies`` |``nActionsOrchard`` |``compactSize`` |The number of Orchard Action descriptions. | -+-----------------------------+--------------------------+-------------------------------------------+---------------------------------------------------------------------+ -|``820 * nActionsOrchard`` |``vActionsOrchard`` |``OrchardActionEffecting[nActionsOrchard]``|Effecting data for each Orchard Action. | -+-----------------------------+--------------------------+-------------------------------------------+---------------------------------------------------------------------+ -|``1`` |``flagsOrchard`` |``byte`` |An 8-bit value representing a set of flags. Ordered from LSB to MSB: | -| | | | | -| | | |* ``enableSpends`` | -| | | |* ``enableOutputs`` | -| | | |* ``enableCrossAddress`` [#zip-2006]_ | -| | | |* The remaining bits are set to :math:`0\!`. | -+-----------------------------+--------------------------+-------------------------------------------+---------------------------------------------------------------------+ -|``32`` |``anchorOrchard`` |``byte[32]`` |A root of the note commitment tree of the bundle's pool, at some | -| | | |block height in the past. | -+-----------------------------+--------------------------+-------------------------------------------+---------------------------------------------------------------------+ - -* The fields ``flagsOrchard`` and ``anchorOrchard`` are present if and only if - $\mathtt{nActionsOrchard} > 0$. - -OrchardActionEffecting -'''''''''''''''''''''' - -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -| Bytes | Name | Data Type | Description | -+=============================+==========================+========================================+=====================================================================+ -|``32`` |``cv`` |``byte[32]`` |A value commitment to the net value of the input note minus the | -| | | |output note. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -|``32`` |``nullifier`` |``byte[32]`` |The nullifier of the input note. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -|``32`` |``rk`` |``byte[32]`` |The randomized validating key for this Action. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -|``32`` |``cmx`` |``byte[32]`` |The :math:`x\!`-coordinate of the note commitment for the output | -| | | |note. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -|``32`` |``ephemeralKey`` |``byte[32]`` |An encoding of an ephemeral Pallas public key. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -|``580`` |``encCiphertext`` |``byte[580]`` |The encrypted contents of the note plaintext. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -|``80`` |``outCiphertext`` |``byte[80]`` |The encrypted contents of the byte string created by concatenation | -| | | |of the transmission key with the ephemeral secret key. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ - -Orchard Protocol Authorizing Data -````````````````````````````````` - -The authorizing data for an Orchard protocol bundle contains the proofs and -signatures that authorize the actions. - -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -| Bytes | Name | Data Type | Description | -+=============================+==========================+========================================+=====================================================================+ -|``varies`` |``sizeProofsOrchard`` |``compactSize`` |Length in bytes of ``proofsOrchard``. Value is | -| | | |:math:`2720 + 2272 \cdot \mathtt{nActionsOrchard}\!`. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -|``sizeProofsOrchard`` |``proofsOrchard`` |``byte[sizeProofsOrchard]`` |Encoding of aggregated zk-SNARK proofs for Orchard Actions. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -|``varies`` |``vSpendAuthSigsOrchard`` |``OrchardSignature[nActionsOrchard]`` |Authorizing signatures for each Orchard Action. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -|``varies`` |``bindingSigOrchard`` |``OrchardSignature`` |An Orchard binding signature on the SIGHASH transaction hash. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ - -* The value of ``nActionsOrchard`` is not re-encoded in the authorizing data; it - is taken from the corresponding effecting data. - -* The fields ``sizeProofsOrchard``, ``proofsOrchard``, and ``bindingSigOrchard`` - are present if and only if $\mathtt{nActionsOrchard} > 0$. - -The 1:1 correspondences between the authorizing-data elements of an Orchard -protocol bundle and the elements of the corresponding effecting data are -required by the parsing rules in `Parsing Rules`_. - - Consensus Rules --------------- @@ -1006,15 +679,10 @@ digest): where ``associatedData`` is specific to the bundle it appears in. -The following sighash algorithm versions are defined for V7 transactions: - -+--------------------+---------------------------------------------------------------------+ -| |:math:`\hspace{4.5em}` ``associatedData`` | -+--------------------+-------------+-------------+-------------+-------------+-------------+ -| ``sighashVersion`` | Transparent | Sapling | Orchard | Ironwood | Issuance | -+--------------------+-------------+-------------+-------------+-------------+-------------+ -| 0 |``[]`` |``[]`` |``[]`` |``[]`` |``[]`` | -+--------------------+-------------+-------------+-------------+-------------+-------------+ +Each bundle type defines the sighash algorithm versions available to its +signers, the ``associatedData`` that each version requires, and the digest that +a signature using it commits to. Those definitions are given for the bundle +types registered by this ZIP in `Bundle Definitions`_. Version 0 is by convention the "commit to all effecting data" sighash algorithm. Other versions can commit to whatever makes sense for desired functionality @@ -1192,7 +860,7 @@ the following values are concatenated:: T.3c: bundle_effects_digest (32-byte hash output) where ``bundle_effects_digest`` is the root hash of the bundle's effecting data -tree, as defined below for each known bundle type. +tree, as defined for each bundle type in `Bundle Definitions`_. The personalization field of this hash is set to:: @@ -1203,6 +871,255 @@ is:: BLAKE2b-256("ZTxIdEffBnd_Hash", []) +Signature Digest +```````````````` + +A new per-input transaction digest algorithm is defined that constructs a hash +that may be signed by a transaction creator to commit to the effects of the +transaction. This follows closely the algorithm from ZIP 244 [#zip-0244]_. + +The digest algorithm used for a given signature is determined by the +``sighashVersion`` from the signer's ``sighashInfo``, as specified in the +`Sighash Versioning`_ section. For sighash version 0 (the only version +currently defined for V7 transactions), the digest algorithm is as specified +below. Future network upgrades may define additional sighash algorithm versions +with divergent behavior. + +For transactions that have no transparent inputs, the signature digest is +identical to the transaction identifier digest. + +For transactions with transparent inputs, the signature digest replaces +``effects_bundles_digest`` with a ``signature_bundles_digest`` that incorporates +``hash_type``-dependent transparent signing data:: + + signature_digest + ├── header_digest + ├── value_pool_deltas_digest + └── signature_bundles_digest + +signature_digest +'''''''''''''''' + +A BLAKE2b-256 hash of the following values:: + + S.1: header_digest (32-byte hash output) + S.2: value_pool_deltas_digest (32-byte hash output) + S.3: signature_bundles_digest (32-byte hash output) + +The personalization field of this hash is set to:: + + "ZcashTxHash_" || CONSENSUS_BRANCH_ID + +This value has the same personalization as the transaction identifier digest, +so that what is being signed in the case that there are no transparent inputs +is exactly the transaction id. + +S.3: signature_bundles_digest +''''''''''''''''''''''''''''' + +If the transaction has no transparent inputs, ``signature_bundles_digest`` is +identical to ``effects_bundles_digest``. + +Otherwise, ``signature_bundles_digest`` is constructed the same as +``effects_bundles_digest``, except that ``transparent_effects_digest`` is +replaced with ``transparent_sig_digest``. + +Authorizing Data Commitment +``````````````````````````` + +A transaction digest algorithm is defined that constructs a digest committing to +the authorizing data of a transaction. The overall structure is:: + + auth_digest + └── auth_bundles_digest + ├─ (bundle_type_id || bundle_variant || transparent_auth_digest) + ├─ (bundle_type_id || bundle_variant || sapling_auth_digest) + ├─ (bundle_type_id || bundle_variant || orchard_auth_digest) + ├─ (bundle_type_id || bundle_variant || ironwood_auth_digest) + └─ (bundle_type_id || bundle_variant || unknown_bundle_auth_digest) ... + +auth_digest +''''''''''' + +A BLAKE2b-256 hash of the following value:: + + A.1: auth_bundles_digest (32-byte hash output) + +The personalization field of this hash is set to:: + + "ZTxAuthHash_" || CONSENSUS_BRANCH_ID + +For transaction versions before V7, a placeholder value consisting of 32 bytes +of ``0xFF`` is used in place of the authorizing data commitment. + +A.1: auth_bundles_digest +'''''''''''''''''''''''' + +A BLAKE2b-256 hash of the concatenated tagged bundle auth digests for all +bundles present in ``mAuthBundles``, in transaction order. For each bundle, +the following values are concatenated:: + + A.1a: bundleType (compactSize encoding) + A.1b: bundleVariant (compactSize encoding) + A.1c: bundle_auth_digest (32-byte hash output) + +The personalization field of this hash is set to:: + + "ZTxAuthBnd__Hash" (2 underscore characters) + +In the case that the transaction has no auth bundles, ``auth_bundles_digest`` is:: + + BLAKE2b-256("ZTxAuthBnd__Hash", []) + +Implications for Wallets +------------------------ + +Sending V7 transactions +``````````````````````` + +*All* Zcash wallets SHOULD, without undue delay, switch to sending only V7 +transactions once they are allowed on the network. This applies to all +transactions regardless of whether they use new V7 features. + +Support for receiving funds in V7 transactions +`````````````````````````````````````````````` + +Zcash wallets MUST support parsing V7 transactions by the time they are allowed +on the network. + +Because the V7 transaction format uses a type-length-value encoding for +bundles, a wallet is not required to understand the internal encoding of every +bundle in order to parse a transaction. However, a wallet that encounters a +bundle with an unrecognized ``bundleType`` SHOULD alert the user that the +transaction contains components it does not understand. A wallet that +encounters a bundle with a recognized ``bundleType`` but unrecognized +``bundleVariant`` SHOULD alert the user that the transaction affects a pool the +wallet is aware of, but in a way the wallet does not fully understand. + +For bundle types not understood by a wallet, the wallet can compute the +transaction identifier so long as it has been provided with the 32-byte +``bundle_effects_digest`` value for each bundle that it does not understand. +This enables partial verification of transactions containing unknown bundle +types. + +A wallet MUST NOT construct or sign a transaction containing a bundle type or +variant that it does not fully understand. + + +Bundle Definitions +------------------ + +The sections above are independent of any particular bundle type. This section +defines the bundle types that this ZIP registers: the encoding of their +effecting and authorizing data, the sighash algorithm versions available to +their signers, and their contributions to the digests defined in +`Digest Algorithms`_. A ZIP that registers a further bundle type defines the +same things for it, as required by `Bundle Type Registration`_. + +Transparent Bundle +`````````````````` + +The transparent bundle's value pool delta in ``mValuePoolDeltas`` represents +the net value flowing from the transparent inputs to the transparent outputs. + +A full validator MUST verify that the ZEC value pool delta for +``bundleType = 0`` equals the total value of the transparent inputs minus the +total value of the transparent outputs. (The input values are not encoded in +the transaction itself; they are obtained from the UTXOs being spent.) + +This rule applies to coinbase transactions unchanged. A coinbase transaction +has no transparent inputs, so its transparent value pool delta is the negation +of the total value of its transparent outputs; the value that those outputs +consume is contributed to the transparent transaction value pool by the +coinbase bundle and the fee bundle. + +Transparent Effecting Data +'''''''''''''''''''''''''' + +The effecting data for the transparent bundle describes the transparent inputs +being spent and the transparent outputs being created. + ++-----------------------------+--------------------------+------------------------------------------+---------------------------------------------------------------------+ +| Bytes | Name | Data Type | Description | ++=============================+==========================+==========================================+=====================================================================+ +|``varies`` |``tx_in_count`` |``compactSize`` |Number of transparent inputs. | ++-----------------------------+--------------------------+------------------------------------------+---------------------------------------------------------------------+ +|``varies`` |``tx_in_effecting`` |``TransparentInputEffecting[tx_in_count]``|Effecting data for each transparent input. | ++-----------------------------+--------------------------+------------------------------------------+---------------------------------------------------------------------+ +|``varies`` |``tx_out_count`` |``compactSize`` |Number of transparent outputs. | ++-----------------------------+--------------------------+------------------------------------------+---------------------------------------------------------------------+ +|``varies`` |``tx_out`` |``TransparentOutput[tx_out_count]`` |Transparent outputs. | ++-----------------------------+--------------------------+------------------------------------------+---------------------------------------------------------------------+ + +TransparentInputEffecting +......................... + ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +| Bytes | Name | Data Type | Description | ++=============================+==========================+========================================+=====================================================================+ +|``32`` |``prevout_hash`` |``byte[32]`` |The transaction ID of the output being spent. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``4`` |``prevout_index`` |``uint32`` |The index of the output being spent within that transaction. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``4`` |``nSequence`` |``uint32`` |Sequence number, encoded as in Bitcoin. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ + +TransparentOutput +................. + ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +| Bytes | Name | Data Type | Description | ++=============================+==========================+========================================+=====================================================================+ +|``8`` |``value`` |``int64`` |The value of the output in zatoshi. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``varies`` |``scriptPubKeyLen`` |``compactSize`` |Length of the scriptPubKey. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``scriptPubKeyLen`` |``scriptPubKey`` |``byte[scriptPubKeyLen]`` |The script that must be satisfied to spend this output. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ + +Transparent Authorizing Data +'''''''''''''''''''''''''''' + +The authorizing data for the transparent bundle contains the scripts that +authorize spending of the referenced transparent inputs. + ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +| Bytes | Name | Data Type | Description | ++=============================+==========================+========================================+=====================================================================+ +|``varies`` |``tx_in_auth`` |``TransparentInputAuth[tx_in_count]`` |Authorizing data for each transparent input. The number of entries | +| | | |MUST equal ``tx_in_count`` from the effecting data. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ + +TransparentInputAuth +.................... + ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +| Bytes | Name | Data Type | Description | ++=============================+==========================+========================================+=====================================================================+ +|``varies`` |``sighashInfo`` |``TransparentSighashInfo`` |The sighash version and associated information for this input, | +| | | |as defined in `Per-Signature Structures`_. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``varies`` |``scriptSigLen`` |``compactSize`` |Length of the scriptSig. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``scriptSigLen`` |``scriptSig`` |``byte[scriptSigLen]`` |The script satisfying the conditions of the referenced output's | +| | | |scriptPubKey. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ + +The ``TransparentSighashInfo`` type is defined in `Per-Signature Structures`_. +It consists of a ``compactSize``-prefixed byte array containing the sighash +version and any associated data required by that version. + +Transparent Sighash Algorithms +'''''''''''''''''''''''''''''' + +For the transparent bundle at ``bundleVariant = 0``, sighash version 0 is the +only version defined, and its ``associatedData`` is the empty byte string. A +signature made with it commits to the digest defined in +`S.3.0: transparent_sig_digest`_. + +Transparent Digests +''''''''''''''''''' + T.3.0: transparent_effects_digest ................................. @@ -1269,21 +1186,295 @@ outputs, ``outputs_digest`` is:: BLAKE2b-256("ZTxIdOutputsHash", []) -T.3.1: coinbase_effects_digest -.............................. +S.3.0: transparent_sig_digest +............................. + +This digest is a BLAKE2b-256 hash of the following values:: + + S.3.0a: hash_type (1 byte) + S.3.0b: prevouts_sig_digest (32-byte hash) + S.3.0c: amounts_sig_digest (32-byte hash) + S.3.0d: scriptpubkeys_sig_digest (32-byte hash) + S.3.0e: sequence_sig_digest (32-byte hash) + S.3.0f: outputs_sig_digest (32-byte hash) + S.3.0g: txin_sig_digest (32-byte hash) + +The personalization field of this hash is set to:: + + "ZTxIdTranspaHash" + +S.3.0a: hash_type +~~~~~~~~~~~~~~~~~ + +An 8-bit unsigned value. The ``SIGHASH`` encodings from the legacy script system +are used: one of ``SIGHASH_ALL`` (0x01), ``SIGHASH_NONE`` (0x02), or +``SIGHASH_SINGLE`` (0x03), optionally combined with ``SIGHASH_ANYONECANPAY`` (0x80). + +The following restrictions apply: + +- Using any undefined ``hash_type`` (not 0x01, 0x02, 0x03, 0x81, 0x82, or 0x83) + causes validation failure. +- Using ``SIGHASH_SINGLE`` without a corresponding output at the same index + causes validation failure. + + +S.3.0b: prevouts_sig_digest +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If the ``SIGHASH_ANYONECANPAY`` flag is not set, identical to ``prevouts_digest`` +(T.3.0a). + +Otherwise:: + + BLAKE2b-256("ZTxIdPrevoutHash", []) + +S.3.0c: amounts_sig_digest +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If the ``SIGHASH_ANYONECANPAY`` flag is not set, a BLAKE2b-256 hash of the +concatenation of the 8-byte signed little-endian representations of all ``value`` +fields for the coins spent by the transparent inputs to the transaction. + +The personalization field of this hash is set to:: + + "ZTxTrAmountsHash" + +If the ``SIGHASH_ANYONECANPAY`` flag is set:: + + BLAKE2b-256("ZTxTrAmountsHash", []) + +S.3.0d: scriptpubkeys_sig_digest +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If the ``SIGHASH_ANYONECANPAY`` flag is not set, a BLAKE2b-256 hash of the +concatenation of the field encodings (each including a leading ``compactSize``) +of all ``scriptPubKey`` fields for the coins spent by the transparent inputs. + +The personalization field of this hash is set to:: + + "ZTxTrScriptsHash" + +If the ``SIGHASH_ANYONECANPAY`` flag is set:: + + BLAKE2b-256("ZTxTrScriptsHash", []) + +S.3.0e: sequence_sig_digest +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Identical to ``sequence_digest`` (T.3.0b) regardless of ``hash_type``. + +S.3.0f: outputs_sig_digest +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If the sighash type is neither ``SIGHASH_SINGLE`` nor ``SIGHASH_NONE``, identical +to ``outputs_digest`` (T.3.0c). + +If the sighash type is ``SIGHASH_SINGLE`` and a transparent output exists at the +same index as the input being signed, a hash of that output's encoding. + +Otherwise:: + + BLAKE2b-256("ZTxIdOutputsHash", []) + +S.3.0g: txin_sig_digest +~~~~~~~~~~~~~~~~~~~~~~~ + +For signatures over a transparent input, a BLAKE2b-256 hash of:: + + S.3.0g.i: prevout (36 bytes: 32-byte hash + 4-byte index) + S.3.0g.ii: value (8-byte signed little-endian) + S.3.0g.iii: scriptPubKey (with compactSize length prefix) + S.3.0g.iv: nSequence (4-byte unsigned little-endian) + +The personalization field of this hash is set to:: + + "Zcash___TxInHash" (3 underscores) + +For signatures over a Sapling Spend or Orchard Action:: + + BLAKE2b-256("Zcash___TxInHash", []) + +A.1.0: transparent_auth_digest +.............................. + +In the case that the transaction contains transparent inputs, this is a +BLAKE2b-256 hash of the following concatenated values for each transparent +input:: + + A.1.0a: TransparentSighashInfo (field encoding bytes) + A.1.0b: scriptSig (field encoding bytes, with compactSize length prefix) + +The field encoding of ``TransparentSighashInfo`` is defined in +`Per-Signature Structures`_. + +The personalization field of this hash is set to:: + + "ZTxAuthTransHash" + +In the case that the transaction has no transparent inputs:: + + BLAKE2b-256("ZTxAuthTransHash", []) + + +Coinbase Bundle +``````````````` + +A transaction is a *coinbase transaction* if and only if ``mEffectBundles`` +contains an entry with ``bundleType = 1``. The coinbase bundle replaces the +otherwise-unspendable transparent input that identified a coinbase transaction +in previous transaction versions, and carries the block height that that input +was required to encode. + +The coinbase bundle's value pool delta in ``mValuePoolDeltas`` is the block +subsidy: the new issuance that consensus awards to the miner of the block. The +fees collected from the other transactions in the block are contributed +separately, as the value pool delta of the fee bundle. + +The subsidy is also carried in the bundle's own effecting data, as +``blockSubsidy``. + +The coinbase bundle has no authorizing data. + +Coinbase Effecting Data +''''''''''''''''''''''' + ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +| Bytes | Name | Data Type | Description | ++=============================+==========================+========================================+=====================================================================+ +|``4`` |``blockHeight`` |``uint32`` |The height of the block in which the transaction is mined. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``8`` |``blockSubsidy`` |``int64`` |The block subsidy for that block, in zatoshis. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``varies`` |``coinbaseDataLen`` |``compactSize`` |Length of the ``coinbaseData`` byte array. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``coinbaseDataLen`` |``coinbaseData`` |``byte[coinbaseDataLen]`` |Data chosen by the miner. Consensus assigns no meaning to its | +| | | |contents. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ + +* ``blockHeight`` MUST be in the range {1 .. 499999999}. +* ``blockSubsidy`` MUST be nonnegative. +* ``coinbaseDataLen`` MUST be at most 94. + +Coinbase Digests +'''''''''''''''' + +T.3.1: coinbase_effects_digest +.............................. + +A BLAKE2b-256 hash of the following values:: + + T.3.1a: blockHeight (4-byte little-endian block height) + T.3.1b: blockSubsidy (8-byte signed little-endian) + T.3.1c: coinbaseData (byte array with leading ``compactSize`` length) + +The personalization field of this hash is set to:: + + "ZTxIdCoinbasHash" + +This digest is present only for coinbase transactions; a transaction that has +no coinbase bundle contributes no entry for it to ``effects_bundles_digest``. + + +Sapling Bundle +`````````````` + +Sapling Effecting Data +'''''''''''''''''''''' + +The effecting data for the Sapling bundle describes the Sapling spends and +outputs. Unlike the V5 transaction format defined in ZIP 225 [#zip-0225]_, +the value balance is not included here; it appears in ``mValuePoolDeltas`` +instead. + ++-----------------------------+--------------------------+-----------------------------------------+---------------------------------------------------------------------+ +| Bytes | Name | Data Type | Description | ++=============================+==========================+=========================================+=====================================================================+ +|``varies`` |``nSpendsSapling`` |``compactSize`` |Number of Sapling Spend descriptions. | ++-----------------------------+--------------------------+-----------------------------------------+---------------------------------------------------------------------+ +|``96 * nSpendsSapling`` |``vSpendsSapling`` |``SaplingSpendEffecting[nSpendsSapling]``|Effecting data for each Sapling Spend. | ++-----------------------------+--------------------------+-----------------------------------------+---------------------------------------------------------------------+ +|``varies`` |``nOutputsSapling`` |``compactSize`` |Number of Sapling Output descriptions. | ++-----------------------------+--------------------------+-----------------------------------------+---------------------------------------------------------------------+ +|``756 * nOutputsSapling`` |``vOutputsSapling`` |``SaplingOutput[nOutputsSapling]`` |Sapling Output descriptions. | ++-----------------------------+--------------------------+-----------------------------------------+---------------------------------------------------------------------+ +|``32`` |``anchorSapling`` |``byte[32]`` |A root of the Sapling note commitment tree at some block height | +| | | |in the past. | ++-----------------------------+--------------------------+-----------------------------------------+---------------------------------------------------------------------+ + +* The field ``anchorSapling`` is present if and only if $\mathtt{nSpendsSapling} > 0$. + +SaplingSpendEffecting +..................... + ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +| Bytes | Name | Data Type | Description | ++=============================+==========================+========================================+=====================================================================+ +|``32`` |``cv`` |``byte[32]`` |A value commitment to the net value of the input note. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``32`` |``nullifier`` |``byte[32]`` |The nullifier of the input note. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``32`` |``rk`` |``byte[32]`` |The randomized validating key for this Spend. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ + +SaplingOutput +............. + +This is identical to ``OutputDescriptionV5`` as defined in ZIP 225 [#zip-0225]_. + ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +| Bytes | Name | Data Type | Description | ++=============================+==========================+========================================+=====================================================================+ +|``32`` |``cv`` |``byte[32]`` |A value commitment to the net value of the output note. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``32`` |``cmu`` |``byte[32]`` |The :math:`u\!`-coordinate of the note commitment for the output | +| | | |note. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``32`` |``ephemeralKey`` |``byte[32]`` |An encoding of an ephemeral Jubjub public key. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``580`` |``encCiphertext`` |``byte[580]`` |The encrypted contents of the note plaintext. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``80`` |``outCiphertext`` |``byte[80]`` |The encrypted contents of the byte string created by concatenation | +| | | |of the transmission key with the ephemeral secret key. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ + +Sapling Authorizing Data +'''''''''''''''''''''''' + +The authorizing data for the Sapling bundle contains the proofs and signatures +that authorize the spends and validate the outputs. + ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +| Bytes | Name | Data Type | Description | ++=============================+==========================+========================================+=====================================================================+ +|``192 * nSpendsSapling`` |``vSpendProofsSapling`` |``byte[192 * nSpendsSapling]`` |Encodings of the zk-SNARK proofs for each Sapling Spend. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``varies`` |``vSpendAuthSigsSapling`` |``SaplingSignature[nSpendsSapling]`` |Authorizing signatures for each Sapling Spend. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``192 * nOutputsSapling`` |``vOutputProofsSapling`` |``byte[192 * nOutputsSapling]`` |Encodings of the zk-SNARK proofs for each Sapling Output. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``varies`` |``bindingSigSapling`` |``SaplingSignature`` |A Sapling binding signature on the SIGHASH transaction hash. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ + +* The values of ``nSpendsSapling`` and ``nOutputsSapling`` are not re-encoded in + the authorizing data; they are taken from the corresponding effecting data. -A BLAKE2b-256 hash of the following values:: +* The field ``bindingSigSapling`` is present if and only if + $\mathtt{nSpendsSapling} + \mathtt{nOutputsSapling} > 0$. - T.3.1a: blockHeight (4-byte little-endian block height) - T.3.1b: blockSubsidy (8-byte signed little-endian) - T.3.1c: coinbaseData (byte array with leading ``compactSize`` length) +The 1:1 correspondences between Sapling authorizing-data elements and the +elements of the corresponding effecting data are required by the parsing +rules in `Parsing Rules`_. -The personalization field of this hash is set to:: +Sapling Sighash Algorithms +'''''''''''''''''''''''''' - "ZTxIdCoinbasHash" +For the Sapling bundle at ``bundleVariant = 0``, sighash version 0 is the only +version defined, and its ``associatedData`` is the empty byte string. A Sapling +``spendAuthSig`` or ``bindingSig`` made with it commits to the digest defined +in `Signature Digest`_, computed with ``hash_type = SIGHASH_ALL`` (0x01). -This digest is present only for coinbase transactions; a transaction that has -no coinbase bundle contributes no entry for it to ``effects_bundles_digest``. +Sapling Digests +''''''''''''''' T.3.2: sapling_effects_digest ............................. @@ -1417,356 +1608,239 @@ The personalization field of this hash is set to:: "ZTxIdSOutN__Hash" (2 underscore characters) -T.3.3: orchard_effects_digest -............................. - -The digest defined here and in its child sections is the Orchard bundle's -instance of a digest shape shared with the Ironwood bundle; T.3.4 gives the -Ironwood instance. - -In the case that Orchard actions are present, the Orchard effects digest is a -BLAKE2b-256 hash of the following values:: - - T.3.3a: orchard_actions_compact_digest (32-byte hash) - T.3.3b: orchard_actions_memos_digest (32-byte hash) - T.3.3c: orchard_actions_noncompact_digest (32-byte hash) - T.3.3d: flagsOrchard (1 byte) - T.3.3e: anchorOrchard (32 bytes) - -The personalization field of this hash is set to:: - - "ZTxIdOrchardHash" - -Note that unlike ZIP 244, the value balance is not included here; it is committed -via ``value_pool_deltas_digest`` instead. - -In the case that the transaction has no Orchard actions, ``orchard_effects_digest`` -is:: - - BLAKE2b-256("ZTxIdOrchardHash", []) - -T.3.3a: orchard_actions_compact_digest -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -A BLAKE2b-256 hash of the subset of Orchard action information intended for -inclusion in the ``CompactBlock`` format. For each action:: - - T.3.3a.i: nullifier (32 bytes) - T.3.3a.ii: cmx (32 bytes) - T.3.3a.iii: ephemeralKey (32 bytes) - T.3.3a.iv: encCiphertext[..52] (first 52 bytes) - -The personalization field of this hash is set to:: - - "ZTxIdOrcActCHash" - -T.3.3b: orchard_actions_memos_digest -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -A BLAKE2b-256 hash of the memo field data for all Orchard actions. For each -action:: - - T.3.3b.i: encCiphertext[52..564] (512 bytes, encrypted memo) - -The personalization field of this hash is set to:: - - "ZTxIdOrcActMHash" - -T.3.3c: orchard_actions_noncompact_digest -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -A BLAKE2b-256 hash of the remaining Orchard action information not intended for -inclusion in the ``CompactBlock`` format. For each action:: - - T.3.3c.i: cv (32 bytes) - T.3.3c.ii: rk (32 bytes) - T.3.3c.iii: encCiphertext[564..] (post-memo AEAD tag, 16 bytes) - T.3.3c.iv: outCiphertext (80 bytes) - -The personalization field of this hash is set to:: - - "ZTxIdOrcActNHash" - -T.3.4: ironwood_effects_digest -.............................. - -The Ironwood bundle uses the same effecting data encoding as the Orchard -bundle, and ``ironwood_effects_digest`` is computed over that data exactly as -``orchard_effects_digest`` and its children are computed (T.3.3), except that -each personalization string is replaced as follows: - -+-------------------------------------+----------------------+----------------------+ -| Digest | Orchard bundle | Ironwood bundle | -+=====================================+======================+======================+ -| effects digest |``ZTxIdOrchardHash`` |``ZTxIdIronwd_Hash`` | -+-------------------------------------+----------------------+----------------------+ -| actions compact digest |``ZTxIdOrcActCHash`` |``ZTxIdIrnActCHash`` | -+-------------------------------------+----------------------+----------------------+ -| actions memos digest |``ZTxIdOrcActMHash`` |``ZTxIdIrnActMHash`` | -+-------------------------------------+----------------------+----------------------+ -| actions noncompact digest |``ZTxIdOrcActNHash`` |``ZTxIdIrnActNHash`` | -+-------------------------------------+----------------------+----------------------+ - -The personalization strings differ so that the digest of a bundle acting on one -pool cannot be reused as the digest of a bundle acting on the other. - -In the case that the transaction has no Ironwood actions, -``ironwood_effects_digest`` is:: - - BLAKE2b-256("ZTxIdIronwd_Hash", []) - -Signature Digest -```````````````` - -A new per-input transaction digest algorithm is defined that constructs a hash -that may be signed by a transaction creator to commit to the effects of the -transaction. This follows closely the algorithm from ZIP 244 [#zip-0244]_. - -The digest algorithm used for a given signature is determined by the -``sighashVersion`` from the signer's ``sighashInfo``, as specified in the -`Sighash Versioning`_ section. For sighash version 0 (the only version -currently defined for V7 transactions), the digest algorithm is as specified -below. Future network upgrades may define additional sighash algorithm versions -with divergent behavior. - -For transactions that have no transparent inputs, the signature digest is -identical to the transaction identifier digest. - -For transactions with transparent inputs, the signature digest replaces -``effects_bundles_digest`` with a ``signature_bundles_digest`` that incorporates -``hash_type``-dependent transparent signing data:: - - signature_digest - ├── header_digest - ├── value_pool_deltas_digest - └── signature_bundles_digest - -signature_digest -'''''''''''''''' - -A BLAKE2b-256 hash of the following values:: - - S.1: header_digest (32-byte hash output) - S.2: value_pool_deltas_digest (32-byte hash output) - S.3: signature_bundles_digest (32-byte hash output) - -The personalization field of this hash is set to:: - - "ZcashTxHash_" || CONSENSUS_BRANCH_ID - -This value has the same personalization as the transaction identifier digest, -so that what is being signed in the case that there are no transparent inputs -is exactly the transaction id. - -S.3: signature_bundles_digest -''''''''''''''''''''''''''''' - -If the transaction has no transparent inputs, ``signature_bundles_digest`` is -identical to ``effects_bundles_digest``. - -Otherwise, ``signature_bundles_digest`` is constructed the same as -``effects_bundles_digest``, except that ``transparent_effects_digest`` is -replaced with ``transparent_sig_digest``. - -S.3.0: transparent_sig_digest -............................. - -This digest is a BLAKE2b-256 hash of the following values:: - - S.3.0a: hash_type (1 byte) - S.3.0b: prevouts_sig_digest (32-byte hash) - S.3.0c: amounts_sig_digest (32-byte hash) - S.3.0d: scriptpubkeys_sig_digest (32-byte hash) - S.3.0e: sequence_sig_digest (32-byte hash) - S.3.0f: outputs_sig_digest (32-byte hash) - S.3.0g: txin_sig_digest (32-byte hash) - -The personalization field of this hash is set to:: - - "ZTxIdTranspaHash" - -S.3.0a: hash_type -~~~~~~~~~~~~~~~~~ - -An 8-bit unsigned value. The ``SIGHASH`` encodings from the legacy script system -are used: one of ``SIGHASH_ALL`` (0x01), ``SIGHASH_NONE`` (0x02), or -``SIGHASH_SINGLE`` (0x03), optionally combined with ``SIGHASH_ANYONECANPAY`` (0x80). - -The following restrictions apply: - -- Using any undefined ``hash_type`` (not 0x01, 0x02, 0x03, 0x81, 0x82, or 0x83) - causes validation failure. -- Using ``SIGHASH_SINGLE`` without a corresponding output at the same index - causes validation failure. - -For sighash version 0, signatures over Sapling Spends or Orchard Actions use -``hash_type = SIGHASH_ALL`` (0x01). - -S.3.0b: prevouts_sig_digest -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -If the ``SIGHASH_ANYONECANPAY`` flag is not set, identical to ``prevouts_digest`` -(T.3.0a). - -Otherwise:: +A.1.2: sapling_auth_digest +.......................... - BLAKE2b-256("ZTxIdPrevoutHash", []) +In the case that Sapling spends or outputs are present, this is a BLAKE2b-256 +hash of the following concatenated values:: -S.3.0c: amounts_sig_digest -~~~~~~~~~~~~~~~~~~~~~~~~~~ + A.1.2a: vSpendProofsSapling (192 bytes per spend) + A.1.2b: vSpendAuthSigsSapling (SaplingSignature field encoding per spend) + A.1.2c: vOutputProofsSapling (192 bytes per output) + A.1.2d: bindingSigSapling (SaplingSignature field encoding) -If the ``SIGHASH_ANYONECANPAY`` flag is not set, a BLAKE2b-256 hash of the -concatenation of the 8-byte signed little-endian representations of all ``value`` -fields for the coins spent by the transparent inputs to the transaction. +The ``SaplingSignature`` field encoding is defined in `Per-Signature Structures`_ +and includes ``sighashInfo``. The personalization field of this hash is set to:: - "ZTxTrAmountsHash" - -If the ``SIGHASH_ANYONECANPAY`` flag is set:: - - BLAKE2b-256("ZTxTrAmountsHash", []) + "ZTxAuthSapliHash" -S.3.0d: scriptpubkeys_sig_digest -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +In the case that the transaction has no Sapling spends or outputs:: -If the ``SIGHASH_ANYONECANPAY`` flag is not set, a BLAKE2b-256 hash of the -concatenation of the field encodings (each including a leading ``compactSize``) -of all ``scriptPubKey`` fields for the coins spent by the transparent inputs. + BLAKE2b-256("ZTxAuthSapliHash", []) -The personalization field of this hash is set to:: - "ZTxTrScriptsHash" +Orchard Protocol Bundles +```````````````````````` -If the ``SIGHASH_ANYONECANPAY`` flag is set:: +The Orchard protocol supports two value pools, each with its own note +commitment tree, nullifier set, and chain value pool balance. Each is acted +upon by its own bundle type: the Orchard bundle, ``bundleType = 3``, acts on +the *Orchard pool*, and the Ironwood bundle, ``bundleType = 4``, acts on the +*Ironwood pool*. - BLAKE2b-256("ZTxTrScriptsHash", []) +Both bundle types use the encoding defined in this section. Where a field is +described below as belonging to the bundle's pool, that pool is the +*Orchard pool* for an Orchard bundle and the *Ironwood pool* for an Ironwood +bundle. -S.3.0e: sequence_sig_digest -~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The bits of ``flagsOrchard`` have the same meaning for both pools, and so are +named without the ``Orchard`` suffix they carried in the V5 transaction format, +following ZIP 229 [#zip-0229]_. Their values are constrained per pool by the +`Bundle-local rules`_. -Identical to ``sequence_digest`` (T.3.0b) regardless of ``hash_type``. +Orchard Protocol Effecting Data +''''''''''''''''''''''''''''''' -S.3.0f: outputs_sig_digest -~~~~~~~~~~~~~~~~~~~~~~~~~~ +The effecting data for an Orchard protocol bundle describes the Orchard +actions. Unlike the V5 transaction format defined in ZIP 225 [#zip-0225]_, the +value balance is not included here; it appears in ``mValuePoolDeltas`` +instead. -If the sighash type is neither ``SIGHASH_SINGLE`` nor ``SIGHASH_NONE``, identical -to ``outputs_digest`` (T.3.0c). ++-----------------------------+--------------------------+-------------------------------------------+---------------------------------------------------------------------+ +| Bytes | Name | Data Type | Description | ++=============================+==========================+===========================================+=====================================================================+ +|``varies`` |``nActionsOrchard`` |``compactSize`` |The number of Orchard Action descriptions. | ++-----------------------------+--------------------------+-------------------------------------------+---------------------------------------------------------------------+ +|``820 * nActionsOrchard`` |``vActionsOrchard`` |``OrchardActionEffecting[nActionsOrchard]``|Effecting data for each Orchard Action. | ++-----------------------------+--------------------------+-------------------------------------------+---------------------------------------------------------------------+ +|``1`` |``flagsOrchard`` |``byte`` |An 8-bit value representing a set of flags. Ordered from LSB to MSB: | +| | | | | +| | | |* ``enableSpends`` | +| | | |* ``enableOutputs`` | +| | | |* ``enableCrossAddress`` [#zip-2006]_ | +| | | |* The remaining bits are set to :math:`0\!`. | ++-----------------------------+--------------------------+-------------------------------------------+---------------------------------------------------------------------+ +|``32`` |``anchorOrchard`` |``byte[32]`` |A root of the note commitment tree of the bundle's pool, at some | +| | | |block height in the past. | ++-----------------------------+--------------------------+-------------------------------------------+---------------------------------------------------------------------+ -If the sighash type is ``SIGHASH_SINGLE`` and a transparent output exists at the -same index as the input being signed, a hash of that output's encoding. +* The fields ``flagsOrchard`` and ``anchorOrchard`` are present if and only if + $\mathtt{nActionsOrchard} > 0$. -Otherwise:: +OrchardActionEffecting +...................... - BLAKE2b-256("ZTxIdOutputsHash", []) ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +| Bytes | Name | Data Type | Description | ++=============================+==========================+========================================+=====================================================================+ +|``32`` |``cv`` |``byte[32]`` |A value commitment to the net value of the input note minus the | +| | | |output note. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``32`` |``nullifier`` |``byte[32]`` |The nullifier of the input note. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``32`` |``rk`` |``byte[32]`` |The randomized validating key for this Action. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``32`` |``cmx`` |``byte[32]`` |The :math:`x\!`-coordinate of the note commitment for the output | +| | | |note. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``32`` |``ephemeralKey`` |``byte[32]`` |An encoding of an ephemeral Pallas public key. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``580`` |``encCiphertext`` |``byte[580]`` |The encrypted contents of the note plaintext. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``80`` |``outCiphertext`` |``byte[80]`` |The encrypted contents of the byte string created by concatenation | +| | | |of the transmission key with the ephemeral secret key. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -S.3.0g: txin_sig_digest -~~~~~~~~~~~~~~~~~~~~~~~ +Orchard Protocol Authorizing Data +''''''''''''''''''''''''''''''''' -For signatures over a transparent input, a BLAKE2b-256 hash of:: +The authorizing data for an Orchard protocol bundle contains the proofs and +signatures that authorize the actions. - S.3.0g.i: prevout (36 bytes: 32-byte hash + 4-byte index) - S.3.0g.ii: value (8-byte signed little-endian) - S.3.0g.iii: scriptPubKey (with compactSize length prefix) - S.3.0g.iv: nSequence (4-byte unsigned little-endian) ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +| Bytes | Name | Data Type | Description | ++=============================+==========================+========================================+=====================================================================+ +|``varies`` |``sizeProofsOrchard`` |``compactSize`` |Length in bytes of ``proofsOrchard``. Value is | +| | | |:math:`2720 + 2272 \cdot \mathtt{nActionsOrchard}\!`. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``sizeProofsOrchard`` |``proofsOrchard`` |``byte[sizeProofsOrchard]`` |Encoding of aggregated zk-SNARK proofs for Orchard Actions. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``varies`` |``vSpendAuthSigsOrchard`` |``OrchardSignature[nActionsOrchard]`` |Authorizing signatures for each Orchard Action. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``varies`` |``bindingSigOrchard`` |``OrchardSignature`` |An Orchard binding signature on the SIGHASH transaction hash. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -The personalization field of this hash is set to:: +* The value of ``nActionsOrchard`` is not re-encoded in the authorizing data; it + is taken from the corresponding effecting data. - "Zcash___TxInHash" (3 underscores) +* The fields ``sizeProofsOrchard``, ``proofsOrchard``, and ``bindingSigOrchard`` + are present if and only if $\mathtt{nActionsOrchard} > 0$. -For signatures over a Sapling Spend or Orchard Action:: +The 1:1 correspondences between the authorizing-data elements of an Orchard +protocol bundle and the elements of the corresponding effecting data are +required by the parsing rules in `Parsing Rules`_. - BLAKE2b-256("Zcash___TxInHash", []) +Orchard Protocol Sighash Algorithms +''''''''''''''''''''''''''''''''''' -Authorizing Data Commitment -``````````````````````````` +For the Orchard and Ironwood bundles at ``bundleVariant = 0``, sighash version +0 is the only version defined, and its ``associatedData`` is the empty byte +string. An Orchard ``spendAuthSig`` or ``bindingSig`` made with it commits to +the digest defined in `Signature Digest`_, computed with +``hash_type = SIGHASH_ALL`` (0x01). -A transaction digest algorithm is defined that constructs a digest committing to -the authorizing data of a transaction. The overall structure is:: +Orchard Protocol Digests +'''''''''''''''''''''''' - auth_digest - └── auth_bundles_digest - ├─ (bundle_type_id || bundle_variant || transparent_auth_digest) - ├─ (bundle_type_id || bundle_variant || sapling_auth_digest) - ├─ (bundle_type_id || bundle_variant || orchard_auth_digest) - ├─ (bundle_type_id || bundle_variant || ironwood_auth_digest) - └─ (bundle_type_id || bundle_variant || unknown_bundle_auth_digest) ... +T.3.3: orchard_effects_digest +............................. -auth_digest -''''''''''' +The digest defined here and in its child sections is the Orchard bundle's +instance of a digest shape shared with the Ironwood bundle; T.3.4 gives the +Ironwood instance. -A BLAKE2b-256 hash of the following value:: +In the case that Orchard actions are present, the Orchard effects digest is a +BLAKE2b-256 hash of the following values:: - A.1: auth_bundles_digest (32-byte hash output) + T.3.3a: orchard_actions_compact_digest (32-byte hash) + T.3.3b: orchard_actions_memos_digest (32-byte hash) + T.3.3c: orchard_actions_noncompact_digest (32-byte hash) + T.3.3d: flagsOrchard (1 byte) + T.3.3e: anchorOrchard (32 bytes) The personalization field of this hash is set to:: - "ZTxAuthHash_" || CONSENSUS_BRANCH_ID - -For transaction versions before V7, a placeholder value consisting of 32 bytes -of ``0xFF`` is used in place of the authorizing data commitment. + "ZTxIdOrchardHash" -A.1: auth_bundles_digest -'''''''''''''''''''''''' +Note that unlike ZIP 244, the value balance is not included here; it is committed +via ``value_pool_deltas_digest`` instead. -A BLAKE2b-256 hash of the concatenated tagged bundle auth digests for all -bundles present in ``mAuthBundles``, in transaction order. For each bundle, -the following values are concatenated:: +In the case that the transaction has no Orchard actions, ``orchard_effects_digest`` +is:: - A.1a: bundleType (compactSize encoding) - A.1b: bundleVariant (compactSize encoding) - A.1c: bundle_auth_digest (32-byte hash output) + BLAKE2b-256("ZTxIdOrchardHash", []) -The personalization field of this hash is set to:: +T.3.3a: orchard_actions_compact_digest +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - "ZTxAuthBnd__Hash" (2 underscore characters) +A BLAKE2b-256 hash of the subset of Orchard action information intended for +inclusion in the ``CompactBlock`` format. For each action:: -In the case that the transaction has no auth bundles, ``auth_bundles_digest`` is:: + T.3.3a.i: nullifier (32 bytes) + T.3.3a.ii: cmx (32 bytes) + T.3.3a.iii: ephemeralKey (32 bytes) + T.3.3a.iv: encCiphertext[..52] (first 52 bytes) - BLAKE2b-256("ZTxAuthBnd__Hash", []) +The personalization field of this hash is set to:: -A.1.0: transparent_auth_digest -.............................. + "ZTxIdOrcActCHash" -In the case that the transaction contains transparent inputs, this is a -BLAKE2b-256 hash of the following concatenated values for each transparent -input:: +T.3.3b: orchard_actions_memos_digest +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - A.1.0a: TransparentSighashInfo (field encoding bytes) - A.1.0b: scriptSig (field encoding bytes, with compactSize length prefix) +A BLAKE2b-256 hash of the memo field data for all Orchard actions. For each +action:: -The field encoding of ``TransparentSighashInfo`` is defined in -`Per-Signature Structures`_. + T.3.3b.i: encCiphertext[52..564] (512 bytes, encrypted memo) The personalization field of this hash is set to:: - "ZTxAuthTransHash" + "ZTxIdOrcActMHash" -In the case that the transaction has no transparent inputs:: +T.3.3c: orchard_actions_noncompact_digest +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - BLAKE2b-256("ZTxAuthTransHash", []) +A BLAKE2b-256 hash of the remaining Orchard action information not intended for +inclusion in the ``CompactBlock`` format. For each action:: -A.1.2: sapling_auth_digest -.......................... + T.3.3c.i: cv (32 bytes) + T.3.3c.ii: rk (32 bytes) + T.3.3c.iii: encCiphertext[564..] (post-memo AEAD tag, 16 bytes) + T.3.3c.iv: outCiphertext (80 bytes) -In the case that Sapling spends or outputs are present, this is a BLAKE2b-256 -hash of the following concatenated values:: +The personalization field of this hash is set to:: - A.1.2a: vSpendProofsSapling (192 bytes per spend) - A.1.2b: vSpendAuthSigsSapling (SaplingSignature field encoding per spend) - A.1.2c: vOutputProofsSapling (192 bytes per output) - A.1.2d: bindingSigSapling (SaplingSignature field encoding) + "ZTxIdOrcActNHash" -The ``SaplingSignature`` field encoding is defined in `Per-Signature Structures`_ -and includes ``sighashInfo``. +T.3.4: ironwood_effects_digest +.............................. -The personalization field of this hash is set to:: +The Ironwood bundle uses the same effecting data encoding as the Orchard +bundle, and ``ironwood_effects_digest`` is computed over that data exactly as +``orchard_effects_digest`` and its children are computed (T.3.3), except that +each personalization string is replaced as follows: - "ZTxAuthSapliHash" ++-------------------------------------+----------------------+----------------------+ +| Digest | Orchard bundle | Ironwood bundle | ++=====================================+======================+======================+ +| effects digest |``ZTxIdOrchardHash`` |``ZTxIdIronwd_Hash`` | ++-------------------------------------+----------------------+----------------------+ +| actions compact digest |``ZTxIdOrcActCHash`` |``ZTxIdIrnActCHash`` | ++-------------------------------------+----------------------+----------------------+ +| actions memos digest |``ZTxIdOrcActMHash`` |``ZTxIdIrnActMHash`` | ++-------------------------------------+----------------------+----------------------+ +| actions noncompact digest |``ZTxIdOrcActNHash`` |``ZTxIdIrnActNHash`` | ++-------------------------------------+----------------------+----------------------+ -In the case that the transaction has no Sapling spends or outputs:: +The personalization strings differ so that the digest of a bundle acting on one +pool cannot be reused as the digest of a bundle acting on the other. - BLAKE2b-256("ZTxAuthSapliHash", []) +In the case that the transaction has no Ironwood actions, +``ironwood_effects_digest`` is:: + + BLAKE2b-256("ZTxIdIronwd_Hash", []) A.1.3: orchard_auth_digest .......................... @@ -1804,40 +1878,6 @@ In the case that the transaction has no Ironwood actions:: BLAKE2b-256("ZTxAuthIrnwdHash", []) -Implications for Wallets ------------------------- - -Sending V7 transactions -``````````````````````` - -*All* Zcash wallets SHOULD, without undue delay, switch to sending only V7 -transactions once they are allowed on the network. This applies to all -transactions regardless of whether they use new V7 features. - -Support for receiving funds in V7 transactions -`````````````````````````````````````````````` - -Zcash wallets MUST support parsing V7 transactions by the time they are allowed -on the network. - -Because the V7 transaction format uses a type-length-value encoding for -bundles, a wallet is not required to understand the internal encoding of every -bundle in order to parse a transaction. However, a wallet that encounters a -bundle with an unrecognized ``bundleType`` SHOULD alert the user that the -transaction contains components it does not understand. A wallet that -encounters a bundle with a recognized ``bundleType`` but unrecognized -``bundleVariant`` SHOULD alert the user that the transaction affects a pool the -wallet is aware of, but in a way the wallet does not fully understand. - -For bundle types not understood by a wallet, the wallet can compute the -transaction identifier so long as it has been provided with the 32-byte -``bundle_effects_digest`` value for each bundle that it does not understand. -This enables partial verification of transactions containing unknown bundle -types. - -A wallet MUST NOT construct or sign a transaction containing a bundle type or -variant that it does not fully understand. - Rationale ========= From 50c05e689b418974b40c08f2863a573d2b2f0e74 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Tue, 1 Sep 2026 21:33:56 -0600 Subject: [PATCH 44/51] [ZIP 248]: Split the coinbase bundle's issuance into subsidy and lockbox. Addresses str4d's review comments on PR 1156. The block subsidy is the whole of the new issuance for a block, which consensus splits between the miner, the funding streams that pay to an address, and the funding streams that deposit into the deferred pool. Describing it as what the miner is awarded was wrong, and so was equating it with the coinbase bundle's value pool delta: the part deposited into the lockbox is never paid out by the transaction. The coinbase bundle's effecting data now carries lockboxValue alongside blockSubsidy, and the value pool delta is their difference. Both components are stated because the delta alone shows what the coinbase pays out, not what was issued or what the lockbox received. Co-Authored-By: Claude Opus 5 --- zips/zip-0248.rst | 65 +++++++++++++++++++++++++++++++---------------- 1 file changed, 43 insertions(+), 22 deletions(-) diff --git a/zips/zip-0248.rst b/zips/zip-0248.rst index 36e817177..20d5b9881 100644 --- a/zips/zip-0248.rst +++ b/zips/zip-0248.rst @@ -247,11 +247,11 @@ For a valid transaction, the sum of all value pool deltas for each asset MUST equal zero. This ensures that value is neither created nor destroyed — it is only transferred between bundles within the transaction. -This holds for coinbase transactions as well. The block subsidy enters the -transparent transaction value pool as the value pool delta of the coinbase -bundle, and the fees collected from the other transactions in the block enter -it as the value pool delta of the fee bundle; the coinbase outputs then consume -that value like any other bundle. +This holds for coinbase transactions as well. The part of the block subsidy +that the transaction pays out enters the transparent transaction value pool as +the value pool delta of the coinbase bundle, and the fees collected from the +other transactions in the block enter it as the value pool delta of the fee +bundle; the coinbase outputs then consume that value like any other bundle. Bundle Type Registration ```````````````````````` @@ -604,7 +604,8 @@ it understands the bundle type that the rule applies to. * The ``assetClass`` value for any entry in ``mValuePoolDeltas`` having ``bundleType = CoinbaseBundleId`` MUST be 0 (the block subsidy is - denominated in ZEC and no other asset). + denominated in ZEC and no other asset). The same applies to the + ``blockSubsidy`` and ``lockboxValue`` fields of its effecting data. * A coinbase transaction MUST NOT spend any transparent output. If a transparent bundle is present in a coinbase transaction, its effecting data @@ -648,12 +649,18 @@ full validators. the block subsidy for that block, as defined in § 7.8 'Block Subsidy and Founders' Reward'. [#protocol-subsidies]_ +* The ``lockboxValue`` field of the coinbase bundle's effecting data MUST equal + the total value that the funding streams for that block deposit into the + deferred pool, as defined in § 7.10 'Payment of Funding Streams, Deferred + Lockbox, and Lockbox Disbursement'. [#protocol-fundingstreams]_ + * The value of $\mathsf{mValuePoolDeltas}[(\mathsf{CoinbaseBundleId}, \mathsf{Zec})]$ - MUST equal the ``blockSubsidy`` field of the coinbase bundle's effecting data. + MUST equal the part of the block subsidy that is not deposited into the + lockbox. .. math:: - \mathsf{mValuePoolDeltas}[(\mathsf{CoinbaseBundleId}, \mathsf{Zec})] = \mathsf{blockSubsidy} + \mathsf{mValuePoolDeltas}[(\mathsf{CoinbaseBundleId}, \mathsf{Zec})] = \mathsf{blockSubsidy} - \mathsf{lockboxValue} * For every transaction, the sum of value pool delta values in each asset MUST equal 0. @@ -1325,13 +1332,18 @@ otherwise-unspendable transparent input that identified a coinbase transaction in previous transaction versions, and carries the block height that that input was required to encode. -The coinbase bundle's value pool delta in ``mValuePoolDeltas`` is the block -subsidy: the new issuance that consensus awards to the miner of the block. The -fees collected from the other transactions in the block are contributed -separately, as the value pool delta of the fee bundle. +The block subsidy is the whole of the new issuance for the block, which +consensus splits between the miner, the funding streams that pay to an address, +and the funding streams that deposit into the deferred pool (the "lockbox") +[#zip-2001]_. Only the part that is not deposited into the lockbox is paid out +by this transaction, so the coinbase bundle's value pool delta in +``mValuePoolDeltas`` is the block subsidy less the lockbox deposit. The fees +collected from the other transactions in the block are contributed separately, +as the value pool delta of the fee bundle. -The subsidy is also carried in the bundle's own effecting data, as -``blockSubsidy``. +The bundle's own effecting data carries the two components, as ``blockSubsidy`` +and ``lockboxValue``, so that the split is recoverable from the transaction +rather than only their difference. The coinbase bundle has no authorizing data. @@ -1345,6 +1357,9 @@ Coinbase Effecting Data +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ |``8`` |``blockSubsidy`` |``int64`` |The block subsidy for that block, in zatoshis. | +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``8`` |``lockboxValue`` |``int64`` |The part of that block subsidy deposited into the lockbox, in | +| | | |zatoshis. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ |``varies`` |``coinbaseDataLen`` |``compactSize`` |Length of the ``coinbaseData`` byte array. | +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ |``coinbaseDataLen`` |``coinbaseData`` |``byte[coinbaseDataLen]`` |Data chosen by the miner. Consensus assigns no meaning to its | @@ -1353,6 +1368,7 @@ Coinbase Effecting Data * ``blockHeight`` MUST be in the range {1 .. 499999999}. * ``blockSubsidy`` MUST be nonnegative. +* ``lockboxValue`` MUST be in the range {0 .. ``blockSubsidy``}. * ``coinbaseDataLen`` MUST be at most 94. Coinbase Digests @@ -1365,7 +1381,8 @@ A BLAKE2b-256 hash of the following values:: T.3.1a: blockHeight (4-byte little-endian block height) T.3.1b: blockSubsidy (8-byte signed little-endian) - T.3.1c: coinbaseData (byte array with leading ``compactSize`` length) + T.3.1c: lockboxValue (8-byte signed little-endian) + T.3.1d: coinbaseData (byte array with leading ``compactSize`` length) The personalization field of this hash is set to:: @@ -1893,13 +1910,15 @@ subsidy carried in the coinbase bundle's value pool delta, every transaction balances to zero in every asset, and a wallet can enumerate the value flows of a coinbase transaction using the same rule it applies to any other transaction. -Carrying ``blockSubsidy`` in the effecting data states the subsidy in the -bundle it belongs to, and commits it to the transaction identifier along with -the rest of that data. Deriving it instead is not open to every client: the -subsidy is not a function of the block height alone once issuance depends on -accumulated chain state, so evaluating the issuance schedule would require a -client to track that state. Its value is the coinbase bundle's value pool -delta, and a consensus rule ties the two together. +Carrying ``blockSubsidy`` and ``lockboxValue`` in the effecting data states +both components of the issuance in the bundle they belong to, and commits them +to the transaction identifier along with the rest of that data. The value pool +delta is their difference, so without them a client could see how much the +coinbase pays out but not how much was issued or how much went to the lockbox. +Deriving them instead is not open to every client: the subsidy is not a +function of the block height alone once issuance depends on accumulated chain +state, so evaluating the issuance schedule would require a client to track that +state. The Orchard and Ironwood bundles share one encoding because the *Orchard pool* and the *Ironwood pool* are two pools of the same shielded protocol. The action @@ -2170,6 +2189,7 @@ References .. [#protocol-blockchain] `Zcash Protocol Specification, Version 2025.6.3 [NU6.1]. Section 3.3: The Block Chain `_ .. [#protocol-networks] `Zcash Protocol Specification, Version 2025.6.3 [NU6.1]. Section 3.12: Mainnet and Testnet `_ .. [#protocol-subsidies] `Zcash Protocol Specification, Version 2025.6.3 [NU6.1]. Section 7.8: Block Subsidy and Founders' Reward `_ +.. [#protocol-fundingstreams] `Zcash Protocol Specification, Version 2025.6.3 [NU6.1]. Section 7.10: Payment of Funding Streams, Deferred Lockbox, and Lockbox Disbursement `_ .. [#zip-0203] `ZIP 203: Transaction Expiry `_ .. [#zip-0212] `ZIP 212: Allow Recipient to Derive Ephemeral Secret from Note Plaintext `_ .. [#zip-0225] `ZIP 225: Version 5 Transaction Format `_ @@ -2177,5 +2197,6 @@ References .. [#zip-0239] `ZIP 239: Relay of Version 5 Transactions `_ .. [#zip-0244] `ZIP 244: Transaction Identifier Non-Malleability `_ .. [#zip-0307] `ZIP 307: Light Client Protocol for Payment Detection `_ +.. [#zip-2001] `ZIP 2001: Lockbox Funding Streams `_ .. [#zip-2006] `ZIP 2006: Restricting Transfers into the Orchard Pool `_ From eba588c01b7fbd66af796c51859542fbf93e2ed7 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Tue, 1 Sep 2026 21:38:36 -0600 Subject: [PATCH 45/51] [ZIP 248]: Move the Sapling and Orchard anchors to authorizing data. Addresses the review comments on PR 1156, following ZIP 229. An anchor selects the note commitment tree state that a bundle's proofs are verified against, which is a property of how the spends are authorized rather than of what the transaction does. Carrying it as authorizing data lets a bundle be re-anchored to a more recent root without changing the transaction identifier, while the proofs still bind to the anchor actually used. anchorSapling and anchorOrchard move to the end of their bundles' authorizing data, and to the auth digests after the existing fields. Each is present only when its bundle has a spend or action referencing it, so a Sapling bundle with outputs but no spends now references no anchor at all, rather than hashing 32 zero bytes in its place. The personalizations of the four digests whose directly hashed content changes are distinguished as ZIP 229 distinguishes its own: ZTxIdSaplingH_v7, ZTxAuthSapliH_v7, ZTxIdOrchardH_v7, and ZTxAuthOrchaH_v7. The Ironwood digests keep theirs, which this ZIP already introduced. ZIP 231's copies of the Sapling and Orchard encodings follow. Co-Authored-By: Claude Opus 5 --- zips/zip-0231.md | 18 ++++++---- zips/zip-0248.rst | 86 +++++++++++++++++++++++++++++------------------ 2 files changed, 66 insertions(+), 38 deletions(-) diff --git a/zips/zip-0231.md b/zips/zip-0231.md index 76149c8bd..613ecaf01 100644 --- a/zips/zip-0231.md +++ b/zips/zip-0231.md @@ -268,9 +268,9 @@ spends and outputs. | 96 \* nSpendsSapling | `vSpendsSapling` | `SaplingSpendEffecting[nSpendsSapling]` | Effecting data for each Sapling Spend. | | varies | `nOutputsSapling` | `compactSize` | Number of Sapling Output descriptions. | | 276 \* nOutputsSapling | `vOutputsSapling` | `SaplingOutputPostZIP231[nOutputsSapling]` | Sapling Output descriptions. | -| 32 | `anchorSapling` | `byte[32]` | A root of the Sapling note commitment tree at some block height in the past. | -* The field `anchorSapling` is present if and only if $\mathtt{nSpendsSapling} > 0$. +As in ZIP 248 [^zip-0248], the anchor is not part of the effecting data; it +appears in the authorizing data below. `SaplingSpendEffecting` is unchanged from ZIP 248 [^zip-0248]. @@ -295,11 +295,14 @@ ZIP 248 [^zip-0248]. | 64 \* nSpendsSapling | `vSpendAuthSigsSapling` | `byte[64 * nSpendsSapling]` | Authorizing signatures for each Sapling Spend. | | 192 \* nOutputsSapling | `vOutputProofsSapling` | `byte[192 * nOutputsSapling]` | Encodings of the zk-SNARK proofs for each Sapling Output. | | 64 | `bindingSigSapling` | `byte[64]` | A Sapling binding signature on the SIGHASH transaction hash. | +| 32 | `anchorSapling` | `byte[32]` | A root of the Sapling note commitment tree at some block height in the past. | * The values of `nSpendsSapling` and `nOutputsSapling` are not re-encoded in the authorizing data; they are taken from the corresponding effecting data. * The field `bindingSigSapling` is present if and only if $\mathtt{nSpendsSapling} + \mathtt{nOutputsSapling} > 0$. +* The field `anchorSapling` is present if and only if + $\mathtt{nSpendsSapling} > 0$. * The elements of `vSpendProofsSapling` and `vSpendAuthSigsSapling` have a 1:1 correspondence to the elements of `vSpendsSapling` in the effecting data and MUST be ordered such that the element at a given index corresponds to the @@ -328,10 +331,12 @@ Orchard actions. | varies | `nActionsOrchard` | `compactSize` | The number of Orchard Action descriptions. | | 340 \* nActionsOrchard | `vActionsOrchard` | `OrchardActionPostZIP231[nActionsOrchard]` | Effecting data for each Orchard Action. | | 1 | `flagsOrchard` | `byte` | An 8-bit value representing a set of flags. Ordered from LSB to MSB: `enableSpends`, `enableOutputs`, `enableCrossAddress`. The remaining bits are set to $0$. | -| 32 | `anchorOrchard` | `byte[32]` | A root of the note commitment tree of the bundle's pool, at some block height in the past. | -* The fields `flagsOrchard` and `anchorOrchard` are present if and only if +* The field `flagsOrchard` is present if and only if $\mathtt{nActionsOrchard} > 0$. + +As in ZIP 248 [^zip-0248], the anchor is not part of the effecting data; it +appears in the authorizing data below. * For coinbase transactions, the `enableSpends` bit MUST be set to $0$. * In an Orchard bundle, the `enableCrossAddress` bit MUST be set to $0$. The bit is unrestricted in an Ironwood bundle. @@ -359,11 +364,12 @@ ZIP 248 [^zip-0248]. | sizeProofsOrchard | `proofsOrchard` | `byte[sizeProofsOrchard]` | Encoding of aggregated zk-SNARK proofs for Orchard Actions. | | 64 \* nActionsOrchard | `vSpendAuthSigsOrchard` | `byte[64 * nActionsOrchard]` | Authorizing signatures for each Orchard Action. | | 64 | `bindingSigOrchard` | `byte[64]` | An Orchard binding signature on the SIGHASH transaction hash. | +| 32 | `anchorOrchard` | `byte[32]` | A root of the note commitment tree of the bundle's pool, at some block height in the past. | * The value of `nActionsOrchard` is not re-encoded in the authorizing data; it is taken from the corresponding effecting data. -* The fields `sizeProofsOrchard`, `proofsOrchard`, and `bindingSigOrchard` are - present if and only if $\mathtt{nActionsOrchard} > 0$. +* The fields `sizeProofsOrchard`, `proofsOrchard`, `bindingSigOrchard`, and + `anchorOrchard` are present if and only if $\mathtt{nActionsOrchard} > 0$. * The proofs aggregated in `proofsOrchard`, and the elements of `vSpendAuthSigsOrchard`, each have a 1:1 correspondence to the elements of `vActionsOrchard` in the effecting data and MUST be ordered such that the diff --git a/zips/zip-0248.rst b/zips/zip-0248.rst index 20d5b9881..ec56fac6e 100644 --- a/zips/zip-0248.rst +++ b/zips/zip-0248.rst @@ -1414,11 +1414,9 @@ instead. +-----------------------------+--------------------------+-----------------------------------------+---------------------------------------------------------------------+ |``756 * nOutputsSapling`` |``vOutputsSapling`` |``SaplingOutput[nOutputsSapling]`` |Sapling Output descriptions. | +-----------------------------+--------------------------+-----------------------------------------+---------------------------------------------------------------------+ -|``32`` |``anchorSapling`` |``byte[32]`` |A root of the Sapling note commitment tree at some block height | -| | | |in the past. | -+-----------------------------+--------------------------+-----------------------------------------+---------------------------------------------------------------------+ -* The field ``anchorSapling`` is present if and only if $\mathtt{nSpendsSapling} > 0$. +The anchor is not part of the effecting data; it appears in +`Sapling Authorizing Data`_. SaplingSpendEffecting ..................... @@ -1471,6 +1469,9 @@ that authorize the spends and validate the outputs. +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ |``varies`` |``bindingSigSapling`` |``SaplingSignature`` |A Sapling binding signature on the SIGHASH transaction hash. | +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``32`` |``anchorSapling`` |``byte[32]`` |A root of the Sapling note commitment tree at some block height | +| | | |in the past. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ * The values of ``nSpendsSapling`` and ``nOutputsSapling`` are not re-encoded in the authorizing data; they are taken from the corresponding effecting data. @@ -1478,6 +1479,10 @@ that authorize the spends and validate the outputs. * The field ``bindingSigSapling`` is present if and only if $\mathtt{nSpendsSapling} + \mathtt{nOutputsSapling} > 0$. +* The field ``anchorSapling`` is present if and only if + $\mathtt{nSpendsSapling} > 0$. A Sapling bundle with outputs but no spends + references no anchor. + The 1:1 correspondences between Sapling authorizing-data elements and the elements of the corresponding effecting data are required by the parsing rules in `Parsing Rules`_. @@ -1501,24 +1506,20 @@ digest is a BLAKE2b-256 hash of the following values:: T.3.2a: sapling_spends_digest (32-byte hash) T.3.2b: sapling_outputs_digest (32-byte hash) - T.3.2c: anchorSapling (32 bytes) The personalization field of this hash is set to:: - "ZTxIdSaplingHash" + "ZTxIdSaplingH_v7" -If $\mathtt{nSpendsSapling} = 0$ (in which case the ``anchorSapling`` field is -not present in the wire encoding), the value hashed at position T.3.2c is 32 -zero bytes. Otherwise it is the encoding of ``anchorSapling`` as it appears in -the Sapling effecting data. - -Note that unlike ZIP 244, the value balance is not included here; it is committed -via ``value_pool_deltas_digest`` instead. +Note that unlike ZIP 244, neither the value balance nor the anchor is included +here. The value balance is committed via ``value_pool_deltas_digest``, and the +anchor via ``sapling_auth_digest``; the personalization differs from ZIP 244's +``ZTxIdSaplingHash`` because what is directly hashed has changed. In the case that the transaction has no Sapling spends or outputs, ``sapling_effects_digest`` is:: - BLAKE2b-256("ZTxIdSaplingHash", []) + BLAKE2b-256("ZTxIdSaplingH_v7", []) T.3.2a: sapling_spends_digest ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1635,17 +1636,21 @@ hash of the following concatenated values:: A.1.2b: vSpendAuthSigsSapling (SaplingSignature field encoding per spend) A.1.2c: vOutputProofsSapling (192 bytes per output) A.1.2d: bindingSigSapling (SaplingSignature field encoding) + A.1.2e: anchorSapling (32 bytes, present iff nSpendsSapling > 0) The ``SaplingSignature`` field encoding is defined in `Per-Signature Structures`_ and includes ``sighashInfo``. The personalization field of this hash is set to:: - "ZTxAuthSapliHash" + "ZTxAuthSapliH_v7" + +The personalization differs from ZIP 244's ``ZTxAuthSapliHash`` because this +digest now also commits to the anchor. In the case that the transaction has no Sapling spends or outputs:: - BLAKE2b-256("ZTxAuthSapliHash", []) + BLAKE2b-256("ZTxAuthSapliH_v7", []) Orchard Protocol Bundles @@ -1689,13 +1694,13 @@ instead. | | | |* ``enableCrossAddress`` [#zip-2006]_ | | | | |* The remaining bits are set to :math:`0\!`. | +-----------------------------+--------------------------+-------------------------------------------+---------------------------------------------------------------------+ -|``32`` |``anchorOrchard`` |``byte[32]`` |A root of the note commitment tree of the bundle's pool, at some | -| | | |block height in the past. | -+-----------------------------+--------------------------+-------------------------------------------+---------------------------------------------------------------------+ -* The fields ``flagsOrchard`` and ``anchorOrchard`` are present if and only if +* The field ``flagsOrchard`` is present if and only if $\mathtt{nActionsOrchard} > 0$. +The anchor is not part of the effecting data; it appears in +`Orchard Protocol Authorizing Data`_. + OrchardActionEffecting ...................... @@ -1738,12 +1743,16 @@ signatures that authorize the actions. +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ |``varies`` |``bindingSigOrchard`` |``OrchardSignature`` |An Orchard binding signature on the SIGHASH transaction hash. | +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``32`` |``anchorOrchard`` |``byte[32]`` |A root of the note commitment tree of the bundle's pool, at some | +| | | |block height in the past. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ * The value of ``nActionsOrchard`` is not re-encoded in the authorizing data; it is taken from the corresponding effecting data. -* The fields ``sizeProofsOrchard``, ``proofsOrchard``, and ``bindingSigOrchard`` - are present if and only if $\mathtt{nActionsOrchard} > 0$. +* The fields ``sizeProofsOrchard``, ``proofsOrchard``, ``bindingSigOrchard``, + and ``anchorOrchard`` are present if and only if + $\mathtt{nActionsOrchard} > 0$. The 1:1 correspondences between the authorizing-data elements of an Orchard protocol bundle and the elements of the corresponding effecting data are @@ -1775,19 +1784,20 @@ BLAKE2b-256 hash of the following values:: T.3.3b: orchard_actions_memos_digest (32-byte hash) T.3.3c: orchard_actions_noncompact_digest (32-byte hash) T.3.3d: flagsOrchard (1 byte) - T.3.3e: anchorOrchard (32 bytes) The personalization field of this hash is set to:: - "ZTxIdOrchardHash" + "ZTxIdOrchardH_v7" -Note that unlike ZIP 244, the value balance is not included here; it is committed -via ``value_pool_deltas_digest`` instead. +Note that unlike ZIP 244, neither the value balance nor the anchor is included +here. The value balance is committed via ``value_pool_deltas_digest``, and the +anchor via ``orchard_auth_digest``; the personalization differs from ZIP 244's +``ZTxIdOrchardHash`` because what is directly hashed has changed. In the case that the transaction has no Orchard actions, ``orchard_effects_digest`` is:: - BLAKE2b-256("ZTxIdOrchardHash", []) + BLAKE2b-256("ZTxIdOrchardH_v7", []) T.3.3a: orchard_actions_compact_digest ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1842,7 +1852,7 @@ each personalization string is replaced as follows: +-------------------------------------+----------------------+----------------------+ | Digest | Orchard bundle | Ironwood bundle | +=====================================+======================+======================+ -| effects digest |``ZTxIdOrchardHash`` |``ZTxIdIronwd_Hash`` | +| effects digest |``ZTxIdOrchardH_v7`` |``ZTxIdIronwd_Hash`` | +-------------------------------------+----------------------+----------------------+ | actions compact digest |``ZTxIdOrcActCHash`` |``ZTxIdIrnActCHash`` | +-------------------------------------+----------------------+----------------------+ @@ -1868,25 +1878,29 @@ following concatenated values:: A.1.3a: proofsOrchard (aggregated proofs) A.1.3b: vSpendAuthSigsOrchard (OrchardSignature field encoding per action) A.1.3c: bindingSigOrchard (OrchardSignature field encoding) + A.1.3d: anchorOrchard (32 bytes) The ``OrchardSignature`` field encoding is defined in `Per-Signature Structures`_ and includes ``sighashInfo``. The personalization field of this hash is set to:: - "ZTxAuthOrchaHash" + "ZTxAuthOrchaH_v7" + +The personalization differs from ZIP 244's ``ZTxAuthOrchaHash`` because this +digest now also commits to the anchor. In the case that the transaction has no Orchard actions:: - BLAKE2b-256("ZTxAuthOrchaHash", []) + BLAKE2b-256("ZTxAuthOrchaH_v7", []) A.1.4: ironwood_auth_digest ........................... The Ironwood bundle uses the same authorizing data encoding as the Orchard bundle, and ``ironwood_auth_digest`` is computed over that data exactly as -``orchard_auth_digest`` (A.1.3), except that the personalization field of the -hash is set to:: +``orchard_auth_digest`` (A.1.3), including its commitment to the anchor, except +that the personalization field of the hash is set to:: "ZTxAuthIrnwdHash" @@ -1933,6 +1947,14 @@ pools the bundle touches. Two pools therefore cannot share a bundle type, and separate types also keep the two value pool deltas separable, which a client needs in order to report the two chain value pool balances independently. +The Sapling and Orchard protocol anchors are authorizing data rather than +effecting data, following ZIP 229 [#zip-0229]_. An anchor selects the note +commitment tree state that the bundle's proofs are verified against, which is a +property of how the spends are authorized rather than of what the transaction +does. Placing it there lets a bundle be re-anchored to a more recent root +without changing the transaction identifier, while the proofs still bind to the +anchor actually used. + The coinbase bundle also gives the coinbase metadata a place of its own. In previous transaction versions that metadata was encoded as the ``scriptSig`` of a single transparent input whose previous output reference pointed at nothing, From f1abfc51a25791adeaf34613cb0b9ffaf1e92a98 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Tue, 1 Sep 2026 21:47:54 -0600 Subject: [PATCH 46/51] [ZIP 248]: Apply review suggestions from PR 1156. daira: correct Jack Grigg's address in the Owners field; drop REQUIRED from the BCP 14 key words, which the document does not use, and with it the template instruction that was still sitting above them; in ZIP 233, MUST BE -> MUST be. nuttycom: register the two Orchard protocol variants in ZIP 231 under their own names, Orchard post-ZIP 231 and Ironwood post-ZIP 231, rather than one name listed twice; and fix the wrapping of the ZIP 231 Motivation paragraph. Two more wrapping defects of my own are fixed alongside: the same paragraph shape in the deferred memo decryption rationale, and a note about the anchor that had been placed inside the flagsOrchard bullet list rather than after it. Co-Authored-By: Claude Opus 5 --- zips/zip-0231.md | 43 +++++++++++++++++++++---------------------- zips/zip-0233.md | 2 +- zips/zip-0248.rst | 9 ++++----- 3 files changed, 26 insertions(+), 28 deletions(-) diff --git a/zips/zip-0231.md b/zips/zip-0231.md index 613ecaf01..d6571248f 100644 --- a/zips/zip-0231.md +++ b/zips/zip-0231.md @@ -103,14 +103,13 @@ not meet the standard IND-CCA2 ∧ INT-CTXT security notion for an authenticated encryption scheme [^BN2000]. By decoupling memo data from note ciphertexts, this proposal reduces the -V7-onward note ciphertext to 100 bytes (excluding any other changes to -the note plaintext proposed by other ZIPs). This makes it practical for the -light client protocol to transmit complete note ciphertexts, including the AEAD -tag, in +V7-onward note ciphertext to 100 bytes (excluding any other changes to the note +plaintext proposed by other ZIPs). This makes it practical for the light client +protocol to transmit complete note ciphertexts, including the AEAD tag, in exchange for a relatively minor bandwidth increase compared to the current truncated ciphertexts. This allows light clients to perform fully authenticated -decryption, ensuring security against chosen ciphertext attacks and simplifying the security -argument. +decryption, ensuring security against chosen ciphertext attacks and simplifying +the security argument. Instead of the memo data, this ZIP proposes that it is possible to indicate whether a memo is present for the recipient. When using the light client @@ -225,21 +224,22 @@ V7 transaction bundle type registry defined in ZIP 248 [^zip-0248]: |------------|---------------|--------------------|------------------|----------------|----------------------------------| | TBD | 0 |❌ |✅ |❌ | Memos | | 2 | TBD |✅ |✅ |✅ | Sapling-post-ZIP 231 | -| 3 | TBD |✅ |✅ |✅ | Orchard-protocol-post-ZIP 231 | -| 4 | TBD |✅ |✅ |✅ | Orchard-protocol-post-ZIP 231 | +| 3 | TBD |✅ |✅ |✅ | Orchard post-ZIP 231 | +| 4 | TBD |✅ |✅ |✅ | Ironwood post-ZIP 231 | The Memos bundle has no value pool deltas (memo data does not involve value transfers) and no authorizing data. The effecting data consists of the encoded memo bundle as defined in [Encoding in transactions]. The Sapling-post-ZIP 231 entry is a new variant of the existing Sapling bundle -type (`bundleType` 2). The Orchard-protocol-post-ZIP 231 entry is a new variant -of each of the bundle types that use the Orchard protocol bundle encoding — the -Orchard bundle (`bundleType` 3) and the Ironwood bundle (`bundleType` 4) — with -one encoding shared between them, as in ZIP 248. Because ZIP 248 requires that -each bundle map is keyed by `bundleType` alone, a transaction that includes a -Sapling-post-ZIP 231 bundle cannot also include a pre-ZIP 231 Sapling bundle, -and likewise for each Orchard protocol bundle type. +type (`bundleType` 2). The Orchard post-ZIP 231 and Ironwood post-ZIP 231 +entries are new variants of the two bundle types that use the Orchard protocol +bundle encoding — the Orchard bundle (`bundleType` 3) and the Ironwood bundle +(`bundleType` 4) — and share one encoding between them, as in ZIP 248. Because +ZIP 248 requires that each bundle map is keyed by `bundleType` alone, a +transaction that includes a Sapling-post-ZIP 231 bundle cannot also include a +pre-ZIP 231 Sapling bundle, and likewise for each Orchard protocol bundle +type. If this ZIP is activated in the same network upgrade as ZIP 248, the encodings of the Sapling bundle and of the Orchard protocol bundles described in this ZIP @@ -334,13 +334,13 @@ Orchard actions. * The field `flagsOrchard` is present if and only if $\mathtt{nActionsOrchard} > 0$. - -As in ZIP 248 [^zip-0248], the anchor is not part of the effecting data; it -appears in the authorizing data below. * For coinbase transactions, the `enableSpends` bit MUST be set to $0$. * In an Orchard bundle, the `enableCrossAddress` bit MUST be set to $0$. The bit is unrestricted in an Ironwood bundle. +As in ZIP 248 [^zip-0248], the anchor is not part of the effecting data; it +appears in the authorizing data below. + #### OrchardActionPostZIP231 | Bytes | Name | Data Type | Description | @@ -541,11 +541,10 @@ of each shielded output performs constant work regardless of whether the output belongs to the wallet: the AEAD decryption of the full 580-byte note ciphertext costs the same whether it succeeds or fails. -With memo bundles, successful trial decryption of a 100-byte V7-onward -note ciphertext yields a memo key $\mathsf{K^{memo}}$, and if the key is not the +With memo bundles, successful trial decryption of a 100-byte V7-onward note +ciphertext yields a memo key $\mathsf{K^{memo}}$, and if the key is not the no-memo sentinel, the wallet must scan up to $\mathsf{memo\_chunk\_limit}$ memo -chunks -to recover the memo. This additional work — potentially up to 64 AEAD +chunks to recover the memo. This additional work — potentially up to 64 AEAD operations — creates a timing differential between successful and unsuccessful trial decryptions that could be exploited by an adversary to determine whether a node's wallet recognized a particular output. diff --git a/zips/zip-0233.md b/zips/zip-0233.md index 5d154e655..80669e908 100644 --- a/zips/zip-0233.md +++ b/zips/zip-0233.md @@ -122,7 +122,7 @@ with `bundleType = 6` and `assetClass = 0` (ZEC). ## NSM Amount When the `mValuePoolDeltas` map contains an entry with `bundleType = 6`, the -transaction removes funds from circulation. The entry's `value` field MUST BE +transaction removes funds from circulation. The entry's `value` field MUST be nonpositive; its negation is denoted $\mathsf{zip233\_amount}$ and represents the value in zatoshis removed from circulation when the transaction is mined. If no such entry is present, $\mathsf{zip233\_amount}$ is defined to be 0. diff --git a/zips/zip-0248.rst b/zips/zip-0248.rst index ec56fac6e..8a9c5ef9c 100644 --- a/zips/zip-0248.rst +++ b/zips/zip-0248.rst @@ -2,7 +2,7 @@ ZIP: 248 Title: Extensible Transaction Format - Owners: Jack Grigg + Owners: Jack Grigg Kris Nuttycombe Daira-Emma Hopwood Schell Scivally @@ -16,10 +16,9 @@ Terminology =========== -{Edit this to reflect the key words that are actually used.} -The key words "MUST", "REQUIRED", "MUST NOT", "SHOULD", and "MAY" in this -document are to be interpreted as described in BCP 14 [#BCP14]_ when, and only -when, they appear in all capitals. +The key words "MUST", "MUST NOT", "SHOULD", and "MAY" in this document are to +be interpreted as described in BCP 14 [#BCP14]_ when, and only when, they +appear in all capitals. The character § is used when referring to sections of the Zcash Protocol Specification. [#protocol]_ From 03f7e44ed6c4308aa7a78d34ea601aa4872e3699 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Tue, 1 Sep 2026 22:02:30 -0600 Subject: [PATCH 47/51] [ZIP 231]: Name v5 and v6 as the downgrade targets; drop AssetBase. Addresses the review comments on PR 1156. The downgrade attack that the KDF domain separation prevents is one against the partial-ciphertext optimization, which v5 and v6 have; it is not a property of every earlier ciphertext format. Both places that described the target now say v5 or v6. The domain separation itself is still from every pre-V7 note ciphertext, so that statement is unchanged. The note that the memo bundle changes must be merged with the addition of an asset_base field to Orchard note plaintexts is removed; that work is not part of this PR. Co-Authored-By: Claude Opus 5 --- zips/zip-0231.md | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/zips/zip-0231.md b/zips/zip-0231.md index d6571248f..9fb20d9f4 100644 --- a/zips/zip-0231.md +++ b/zips/zip-0231.md @@ -629,11 +629,6 @@ from a server that has pruned it. ## Changes to the Zcash Protocol Specification -The changes to support memo bundles that affect the definitions of note -plaintexts and note ciphertexts, interact with the addition of an -$\mathsf{asset\_base}$ field to V7-onward Orchard note plaintexts in order to -support ZSAs, which must be merged with the changes in this section. - Changes to the algorithms for encryption and decryption are specified below. Note that [^zip-2005] also updates these algorithms, but the merge is trivial. @@ -716,7 +711,7 @@ In § 4.20.1 ‘Encryption (Sapling and Orchard)’ [^protocol-saplingandorchard > $\hspace{2em}\mathsf{KDF^{Orchard}}(\mathsf{sharedSecret}, \mathsf{ephemeralKey}) := \mathsf{BLAKE2b\text{-}256}(\text{"Zc_OrchardKD"} \,||\, \mathsf{I2LEOSP}_{32}(\mathsf{nVersionGroupId}), \mathsf{sharedSecret} \,||\, \mathsf{ephemeralKey})$ This prevents a malicious lightwalletd server from presenting a V7 note ciphertext - to a wallet as though it were a partial v5 ciphertext, which could otherwise cause + to a wallet as though it were a partial v5 or v6 ciphertext, which could otherwise cause the wallet to decrypt and act on unauthenticated plaintext. * Change @@ -896,9 +891,9 @@ transaction version group id ($\text{"Zc_SaplingKD"} \,||\, \mathsf{nVersionGrou and $\text{"Zc_OrchardKD"} \,||\, \mathsf{nVersionGroupId}$), providing domain separation from pre-V7 note ciphertexts. This prevents a downgrade attack in which a malicious lightwalletd server presents a V7 note ciphertext as a partial -v5 note ciphertext. Without domain separation, a wallet that supports the v5 -partial-ciphertext optimization (downloading note ciphertexts without the MAC to -save bandwidth) could decrypt a V7 ciphertext without verifying its +v5 or v6 note ciphertext. Without domain separation, a wallet that supports the +v5/v6 partial-ciphertext optimization (downloading note ciphertexts without the +MAC to save bandwidth) could decrypt a V7 ciphertext without verifying its authentication tag, potentially acting on unauthenticated data. Using the version group id rather than a fixed suffix ensures that domain separation extends automatically to future transaction versions. From 5b3163f51b10de60878f5a35acf97d10fbea7d16 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Wed, 2 Sep 2026 18:04:19 -0600 Subject: [PATCH 48/51] [ZIP 248]: Put the anchor first in each bundle's authorizing data. Addresses str4d's review comments on PR 1156. The anchor precedes the proofs and signatures it constrains, in the encoding and in the auth digests alike. This is symmetric with other descriptions of the Sapling and Orchard protocols, and it follows the direction in which the data depends: changing an anchor forces the proofs to be recomputed, while the proofs can be recomputed against an unchanged anchor. Note this orders the auth digests differently from ZIP 229, which appends each anchor after the existing fields. ZIP 231's copies of both encodings follow. Co-Authored-By: Claude Opus 5 --- zips/zip-0231.md | 12 ++++++------ zips/zip-0248.rst | 42 +++++++++++++++++++++--------------------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/zips/zip-0231.md b/zips/zip-0231.md index 9fb20d9f4..68c11928b 100644 --- a/zips/zip-0231.md +++ b/zips/zip-0231.md @@ -291,18 +291,18 @@ ZIP 248 [^zip-0248]. | Bytes | Name | Data Type | Description | |--------------------------|--------------------------|-----------------------------------|--------------------------------------------------------------| +| 32 | `anchorSapling` | `byte[32]` | A root of the Sapling note commitment tree at some block height in the past. | | 192 \* nSpendsSapling | `vSpendProofsSapling` | `byte[192 * nSpendsSapling]` | Encodings of the zk-SNARK proofs for each Sapling Spend. | | 64 \* nSpendsSapling | `vSpendAuthSigsSapling` | `byte[64 * nSpendsSapling]` | Authorizing signatures for each Sapling Spend. | | 192 \* nOutputsSapling | `vOutputProofsSapling` | `byte[192 * nOutputsSapling]` | Encodings of the zk-SNARK proofs for each Sapling Output. | | 64 | `bindingSigSapling` | `byte[64]` | A Sapling binding signature on the SIGHASH transaction hash. | -| 32 | `anchorSapling` | `byte[32]` | A root of the Sapling note commitment tree at some block height in the past. | +* The field `anchorSapling` is present if and only if + $\mathtt{nSpendsSapling} > 0$. * The values of `nSpendsSapling` and `nOutputsSapling` are not re-encoded in the authorizing data; they are taken from the corresponding effecting data. * The field `bindingSigSapling` is present if and only if $\mathtt{nSpendsSapling} + \mathtt{nOutputsSapling} > 0$. -* The field `anchorSapling` is present if and only if - $\mathtt{nSpendsSapling} > 0$. * The elements of `vSpendProofsSapling` and `vSpendAuthSigsSapling` have a 1:1 correspondence to the elements of `vSpendsSapling` in the effecting data and MUST be ordered such that the element at a given index corresponds to the @@ -360,16 +360,16 @@ ZIP 248 [^zip-0248]. | Bytes | Name | Data Type | Description | |--------------------------|--------------------------|-----------------------------------|--------------------------------------------------------------------------------------------| +| 32 | `anchorOrchard` | `byte[32]` | A root of the note commitment tree of the bundle's pool, at some block height in the past. | | varies | `sizeProofsOrchard` | `compactSize` | Length in bytes of `proofsOrchard`. Value is $2720 + 2272 \cdot \mathtt{nActionsOrchard}$. | | sizeProofsOrchard | `proofsOrchard` | `byte[sizeProofsOrchard]` | Encoding of aggregated zk-SNARK proofs for Orchard Actions. | | 64 \* nActionsOrchard | `vSpendAuthSigsOrchard` | `byte[64 * nActionsOrchard]` | Authorizing signatures for each Orchard Action. | | 64 | `bindingSigOrchard` | `byte[64]` | An Orchard binding signature on the SIGHASH transaction hash. | -| 32 | `anchorOrchard` | `byte[32]` | A root of the note commitment tree of the bundle's pool, at some block height in the past. | * The value of `nActionsOrchard` is not re-encoded in the authorizing data; it is taken from the corresponding effecting data. -* The fields `sizeProofsOrchard`, `proofsOrchard`, `bindingSigOrchard`, and - `anchorOrchard` are present if and only if $\mathtt{nActionsOrchard} > 0$. +* The fields `anchorOrchard`, `sizeProofsOrchard`, `proofsOrchard`, and + `bindingSigOrchard` are present if and only if $\mathtt{nActionsOrchard} > 0$. * The proofs aggregated in `proofsOrchard`, and the elements of `vSpendAuthSigsOrchard`, each have a 1:1 correspondence to the elements of `vActionsOrchard` in the effecting data and MUST be ordered such that the diff --git a/zips/zip-0248.rst b/zips/zip-0248.rst index 8a9c5ef9c..598920a21 100644 --- a/zips/zip-0248.rst +++ b/zips/zip-0248.rst @@ -1460,6 +1460,9 @@ that authorize the spends and validate the outputs. +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ | Bytes | Name | Data Type | Description | +=============================+==========================+========================================+=====================================================================+ +|``32`` |``anchorSapling`` |``byte[32]`` |A root of the Sapling note commitment tree at some block height | +| | | |in the past. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ |``192 * nSpendsSapling`` |``vSpendProofsSapling`` |``byte[192 * nSpendsSapling]`` |Encodings of the zk-SNARK proofs for each Sapling Spend. | +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ |``varies`` |``vSpendAuthSigsSapling`` |``SaplingSignature[nSpendsSapling]`` |Authorizing signatures for each Sapling Spend. | @@ -1468,9 +1471,10 @@ that authorize the spends and validate the outputs. +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ |``varies`` |``bindingSigSapling`` |``SaplingSignature`` |A Sapling binding signature on the SIGHASH transaction hash. | +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -|``32`` |``anchorSapling`` |``byte[32]`` |A root of the Sapling note commitment tree at some block height | -| | | |in the past. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ + +* The field ``anchorSapling`` is present if and only if + $\mathtt{nSpendsSapling} > 0$. A Sapling bundle with outputs but no spends + references no anchor. * The values of ``nSpendsSapling`` and ``nOutputsSapling`` are not re-encoded in the authorizing data; they are taken from the corresponding effecting data. @@ -1478,10 +1482,6 @@ that authorize the spends and validate the outputs. * The field ``bindingSigSapling`` is present if and only if $\mathtt{nSpendsSapling} + \mathtt{nOutputsSapling} > 0$. -* The field ``anchorSapling`` is present if and only if - $\mathtt{nSpendsSapling} > 0$. A Sapling bundle with outputs but no spends - references no anchor. - The 1:1 correspondences between Sapling authorizing-data elements and the elements of the corresponding effecting data are required by the parsing rules in `Parsing Rules`_. @@ -1631,11 +1631,11 @@ A.1.2: sapling_auth_digest In the case that Sapling spends or outputs are present, this is a BLAKE2b-256 hash of the following concatenated values:: - A.1.2a: vSpendProofsSapling (192 bytes per spend) - A.1.2b: vSpendAuthSigsSapling (SaplingSignature field encoding per spend) - A.1.2c: vOutputProofsSapling (192 bytes per output) - A.1.2d: bindingSigSapling (SaplingSignature field encoding) - A.1.2e: anchorSapling (32 bytes, present iff nSpendsSapling > 0) + A.1.2a: anchorSapling (32 bytes, present iff nSpendsSapling > 0) + A.1.2b: vSpendProofsSapling (192 bytes per spend) + A.1.2c: vSpendAuthSigsSapling (SaplingSignature field encoding per spend) + A.1.2d: vOutputProofsSapling (192 bytes per output) + A.1.2e: bindingSigSapling (SaplingSignature field encoding) The ``SaplingSignature`` field encoding is defined in `Per-Signature Structures`_ and includes ``sighashInfo``. @@ -1733,6 +1733,9 @@ signatures that authorize the actions. +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ | Bytes | Name | Data Type | Description | +=============================+==========================+========================================+=====================================================================+ +|``32`` |``anchorOrchard`` |``byte[32]`` |A root of the note commitment tree of the bundle's pool, at some | +| | | |block height in the past. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ |``varies`` |``sizeProofsOrchard`` |``compactSize`` |Length in bytes of ``proofsOrchard``. Value is | | | | |:math:`2720 + 2272 \cdot \mathtt{nActionsOrchard}\!`. | +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ @@ -1742,15 +1745,12 @@ signatures that authorize the actions. +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ |``varies`` |``bindingSigOrchard`` |``OrchardSignature`` |An Orchard binding signature on the SIGHASH transaction hash. | +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -|``32`` |``anchorOrchard`` |``byte[32]`` |A root of the note commitment tree of the bundle's pool, at some | -| | | |block height in the past. | -+-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ * The value of ``nActionsOrchard`` is not re-encoded in the authorizing data; it is taken from the corresponding effecting data. -* The fields ``sizeProofsOrchard``, ``proofsOrchard``, ``bindingSigOrchard``, - and ``anchorOrchard`` are present if and only if +* The fields ``anchorOrchard``, ``sizeProofsOrchard``, ``proofsOrchard``, + and ``bindingSigOrchard`` are present if and only if $\mathtt{nActionsOrchard} > 0$. The 1:1 correspondences between the authorizing-data elements of an Orchard @@ -1874,10 +1874,10 @@ A.1.3: orchard_auth_digest In the case that Orchard actions are present, this is a BLAKE2b-256 hash of the following concatenated values:: - A.1.3a: proofsOrchard (aggregated proofs) - A.1.3b: vSpendAuthSigsOrchard (OrchardSignature field encoding per action) - A.1.3c: bindingSigOrchard (OrchardSignature field encoding) - A.1.3d: anchorOrchard (32 bytes) + A.1.3a: anchorOrchard (32 bytes) + A.1.3b: proofsOrchard (aggregated proofs) + A.1.3c: vSpendAuthSigsOrchard (OrchardSignature field encoding per action) + A.1.3d: bindingSigOrchard (OrchardSignature field encoding) The ``OrchardSignature`` field encoding is defined in `Per-Signature Structures`_ and includes ``sighashInfo``. From 5fb4b7962bcdd56d2ee45116f3aa18d575b5e66b Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Wed, 2 Sep 2026 18:06:42 -0600 Subject: [PATCH 49/51] [ZIP 248]: Define each per-signature structure in its own bundle section. Addresses str4d's review comments on PR 1156. TransparentSighashInfo, SaplingSignature, and OrchardSignature move from the shared Per-Signature Structures subsection into the authorizing data of the bundles that carry them, replacing the cross-references that stood in their place. Sighash Versioning keeps only the versioning mechanism, which is what is bundle-agnostic about it. The Signature Digest section is renamed v0 Signature Digest, since it is the digest that sighash version 0 selects rather than the only one a signer can ever commit to. Co-Authored-By: Claude Opus 5 --- zips/zip-0248.rst | 122 +++++++++++++++++++++------------------------- 1 file changed, 56 insertions(+), 66 deletions(-) diff --git a/zips/zip-0248.rst b/zips/zip-0248.rst index 598920a21..8f0a00513 100644 --- a/zips/zip-0248.rst +++ b/zips/zip-0248.rst @@ -696,58 +696,7 @@ within a given transaction version. Consensus rules choose the digest algorithm for each signer based on ``sighashVersion``. Sighash version information is present alongside each signature in the -authorizing data of the transaction, via the per-signature structures defined -below. - -Per-Signature Structures -```````````````````````` - -The following structures carry sighash version information alongside each -signature in the authorizing data of a V7 transaction. - -Transparent Sighash Information (``TransparentSighashInfo``) -'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' - -+-----------------------------+------------------------------+----------------------------------+---------------------------------------------------+ -| Bytes | Name | Data Type | Description | -+=============================+==============================+==================================+===================================================+ -| varies |``sizeSighashInfo`` |``compactSize`` |The size in bytes of ``sighashInfo``. | -+-----------------------------+------------------------------+----------------------------------+---------------------------------------------------+ -| ``sizeSighashInfo`` |``sighashInfo`` |``byte[sizeSighashInfo]`` |The sighash version and associated information, | -| | | |as defined in `Sighash Versioning`_. | -+-----------------------------+------------------------------+----------------------------------+---------------------------------------------------+ - -Sapling Signature (``SaplingSignature``) -'''''''''''''''''''''''''''''''''''''''' - -+-----------------------------+------------------------------+----------------------------------+---------------------------------------------------+ -| Bytes | Name | Data Type | Description | -+=============================+==============================+==================================+===================================================+ -| varies |``sizeSighashInfo`` |``compactSize`` |The size in bytes of ``sighashInfo``. | -+-----------------------------+------------------------------+----------------------------------+---------------------------------------------------+ -| ``sizeSighashInfo`` |``sighashInfo`` |``byte[sizeSighashInfo]`` |The sighash version and associated information, | -| | | |as defined in `Sighash Versioning`_. | -+-----------------------------+------------------------------+----------------------------------+---------------------------------------------------+ -| 64 |``signature`` |``byte[64]`` |An encoding of a RedJubjub signature, which may be | -| | | |either a ``spendAuthSig`` or ``bindingSig`` | -| | | |depending on context. | -+-----------------------------+------------------------------+----------------------------------+---------------------------------------------------+ - -Orchard Signature (``OrchardSignature``) -'''''''''''''''''''''''''''''''''''''''' - -+-----------------------------+------------------------------+----------------------------------+---------------------------------------------------+ -| Bytes | Name | Data Type | Description | -+=============================+==============================+==================================+===================================================+ -| varies |``sizeSighashInfo`` |``compactSize`` |The size in bytes of ``sighashInfo``. | -+-----------------------------+------------------------------+----------------------------------+---------------------------------------------------+ -| ``sizeSighashInfo`` |``sighashInfo`` |``byte[sizeSighashInfo]`` |The sighash version and associated information, | -| | | |as defined in `Sighash Versioning`_. | -+-----------------------------+------------------------------+----------------------------------+---------------------------------------------------+ -| 64 |``signature`` |``byte[64]`` |An encoding of a RedPallas signature, which may be | -| | | |either a ``spendAuthSig`` or ``bindingSig`` | -| | | |depending on context. | -+-----------------------------+------------------------------+----------------------------------+---------------------------------------------------+ +authorizing data of each bundle. Digest Algorithms ----------------- @@ -877,8 +826,8 @@ is:: BLAKE2b-256("ZTxIdEffBnd_Hash", []) -Signature Digest -```````````````` +v0 Signature Digest +``````````````````` A new per-input transaction digest algorithm is defined that constructs a hash that may be signed by a transaction creator to commit to the effects of the @@ -891,7 +840,7 @@ currently defined for V7 transactions), the digest algorithm is as specified below. Future network upgrades may define additional sighash algorithm versions with divergent behavior. -For transactions that have no transparent inputs, the signature digest is +For transactions that have no transparent inputs, the v0 signature digest is identical to the transaction identifier digest. For transactions with transparent inputs, the signature digest replaces @@ -1103,7 +1052,8 @@ TransparentInputAuth | Bytes | Name | Data Type | Description | +=============================+==========================+========================================+=====================================================================+ |``varies`` |``sighashInfo`` |``TransparentSighashInfo`` |The sighash version and associated information for this input, | -| | | |as defined in `Per-Signature Structures`_. | +| | | |as defined in | +| | | |`Transparent Sighash Information (``TransparentSighashInfo``)`_. | +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ |``varies`` |``scriptSigLen`` |``compactSize`` |Length of the scriptSig. | +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ @@ -1111,9 +1061,17 @@ TransparentInputAuth | | | |scriptPubKey. | +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -The ``TransparentSighashInfo`` type is defined in `Per-Signature Structures`_. -It consists of a ``compactSize``-prefixed byte array containing the sighash -version and any associated data required by that version. +Transparent Sighash Information (``TransparentSighashInfo``) +............................................................ + ++-----------------------------+------------------------------+----------------------------------+---------------------------------------------------+ +| Bytes | Name | Data Type | Description | ++=============================+==============================+==================================+===================================================+ +| varies |``sizeSighashInfo`` |``compactSize`` |The size in bytes of ``sighashInfo``. | ++-----------------------------+------------------------------+----------------------------------+---------------------------------------------------+ +| ``sizeSighashInfo`` |``sighashInfo`` |``byte[sizeSighashInfo]`` |The sighash version and associated information, | +| | | |as defined in `Sighash Versioning`_. | ++-----------------------------+------------------------------+----------------------------------+---------------------------------------------------+ Transparent Sighash Algorithms '''''''''''''''''''''''''''''' @@ -1311,7 +1269,7 @@ input:: A.1.0b: scriptSig (field encoding bytes, with compactSize length prefix) The field encoding of ``TransparentSighashInfo`` is defined in -`Per-Signature Structures`_. +`Transparent Sighash Information (``TransparentSighashInfo``)`_. The personalization field of this hash is set to:: @@ -1482,6 +1440,22 @@ that authorize the spends and validate the outputs. * The field ``bindingSigSapling`` is present if and only if $\mathtt{nSpendsSapling} + \mathtt{nOutputsSapling} > 0$. +Sapling Signature (``SaplingSignature``) +........................................ + ++-----------------------------+------------------------------+----------------------------------+---------------------------------------------------+ +| Bytes | Name | Data Type | Description | ++=============================+==============================+==================================+===================================================+ +| varies |``sizeSighashInfo`` |``compactSize`` |The size in bytes of ``sighashInfo``. | ++-----------------------------+------------------------------+----------------------------------+---------------------------------------------------+ +| ``sizeSighashInfo`` |``sighashInfo`` |``byte[sizeSighashInfo]`` |The sighash version and associated information, | +| | | |as defined in `Sighash Versioning`_. | ++-----------------------------+------------------------------+----------------------------------+---------------------------------------------------+ +| 64 |``signature`` |``byte[64]`` |An encoding of a RedJubjub signature, which may be | +| | | |either a ``spendAuthSig`` or ``bindingSig`` | +| | | |depending on context. | ++-----------------------------+------------------------------+----------------------------------+---------------------------------------------------+ + The 1:1 correspondences between Sapling authorizing-data elements and the elements of the corresponding effecting data are required by the parsing rules in `Parsing Rules`_. @@ -1492,7 +1466,7 @@ Sapling Sighash Algorithms For the Sapling bundle at ``bundleVariant = 0``, sighash version 0 is the only version defined, and its ``associatedData`` is the empty byte string. A Sapling ``spendAuthSig`` or ``bindingSig`` made with it commits to the digest defined -in `Signature Digest`_, computed with ``hash_type = SIGHASH_ALL`` (0x01). +in `v0 Signature Digest`_, computed with ``hash_type = SIGHASH_ALL`` (0x01). Sapling Digests ''''''''''''''' @@ -1637,8 +1611,8 @@ hash of the following concatenated values:: A.1.2d: vOutputProofsSapling (192 bytes per output) A.1.2e: bindingSigSapling (SaplingSignature field encoding) -The ``SaplingSignature`` field encoding is defined in `Per-Signature Structures`_ -and includes ``sighashInfo``. +The ``SaplingSignature`` field encoding is defined in +`Sapling Signature (``SaplingSignature``)`_ and includes ``sighashInfo``. The personalization field of this hash is set to:: @@ -1753,6 +1727,22 @@ signatures that authorize the actions. and ``bindingSigOrchard`` are present if and only if $\mathtt{nActionsOrchard} > 0$. +Orchard Signature (``OrchardSignature``) +........................................ + ++-----------------------------+------------------------------+----------------------------------+---------------------------------------------------+ +| Bytes | Name | Data Type | Description | ++=============================+==============================+==================================+===================================================+ +| varies |``sizeSighashInfo`` |``compactSize`` |The size in bytes of ``sighashInfo``. | ++-----------------------------+------------------------------+----------------------------------+---------------------------------------------------+ +| ``sizeSighashInfo`` |``sighashInfo`` |``byte[sizeSighashInfo]`` |The sighash version and associated information, | +| | | |as defined in `Sighash Versioning`_. | ++-----------------------------+------------------------------+----------------------------------+---------------------------------------------------+ +| 64 |``signature`` |``byte[64]`` |An encoding of a RedPallas signature, which may be | +| | | |either a ``spendAuthSig`` or ``bindingSig`` | +| | | |depending on context. | ++-----------------------------+------------------------------+----------------------------------+---------------------------------------------------+ + The 1:1 correspondences between the authorizing-data elements of an Orchard protocol bundle and the elements of the corresponding effecting data are required by the parsing rules in `Parsing Rules`_. @@ -1763,7 +1753,7 @@ Orchard Protocol Sighash Algorithms For the Orchard and Ironwood bundles at ``bundleVariant = 0``, sighash version 0 is the only version defined, and its ``associatedData`` is the empty byte string. An Orchard ``spendAuthSig`` or ``bindingSig`` made with it commits to -the digest defined in `Signature Digest`_, computed with +the digest defined in `v0 Signature Digest`_, computed with ``hash_type = SIGHASH_ALL`` (0x01). Orchard Protocol Digests @@ -1879,8 +1869,8 @@ following concatenated values:: A.1.3c: vSpendAuthSigsOrchard (OrchardSignature field encoding per action) A.1.3d: bindingSigOrchard (OrchardSignature field encoding) -The ``OrchardSignature`` field encoding is defined in `Per-Signature Structures`_ -and includes ``sighashInfo``. +The ``OrchardSignature`` field encoding is defined in +`Orchard Signature (``OrchardSignature``)`_ and includes ``sighashInfo``. The personalization field of this hash is set to:: From fced490dc0a10e3599aa15ec7675aa6a1b4f6162 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Wed, 2 Sep 2026 18:07:46 -0600 Subject: [PATCH 50/51] [ZIP 248]: Correct the registry and coinbase consensus rules. Addresses str4d's and nuttycom's review comments on PR 1156. Conformance to the bundle type registry moves from the parsing rules to the bundle-local consensus rules. A parser cannot check it for a bundle type it does not know, because the registry grows with each network upgrade, whereas a full validator always knows the registry in force for the block it is validating. The coinbase restriction on shielded spends was stated for the Orchard protocol bundles but not for Sapling; nSpendsSapling MUST now be 0 in a coinbase transaction as well. blockSubsidy and lockboxValue become uint64, which consensus already requires of them, so blockSubsidy no longer needs a separate nonnegativity rule. The example in Privacy Implications is stated against NU8 and a hypothetical NU9. Co-Authored-By: Claude Opus 5 --- zips/zip-0248.rst | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/zips/zip-0248.rst b/zips/zip-0248.rst index 8f0a00513..56334e6cc 100644 --- a/zips/zip-0248.rst +++ b/zips/zip-0248.rst @@ -116,8 +116,8 @@ transaction format change. In the future, this change may reduce the amount of information leakage, since transactions created using the proposed TLV format will include bundles only for those protocols for which the transaction modifies chain state. For example, -if this transaction format change is deployed in NU7 and NU8 defines a bundle -type for TZE components, it will not be possible for a chain observer to +if this transaction format change is deployed in NU8 and a hypothetical NU9 +defines a bundle type for TZE components, it will not be possible for a chain observer to distinguish whether or not the wallet that produced an Orchard-only transaction is one that has been updated to understand the TZE component. Under prior practices for changing the transaction format, this would have been @@ -550,10 +550,6 @@ wallet does not itself implement. * For each ``bundleType`` that appears in ``mAuthBundles``, a corresponding entry with the same ``bundleVariant`` MUST exist in ``mEffectBundles``. -* A bundle type MUST NOT appear in any map for which the corresponding column - of the `V7 Transaction Bundle Type Registry`_ is marked ❌, and MUST NOT - appear in any map at all if its row in the registry is marked as Reserved. - * Within the encoding of any bundle's effecting and authorizing data, every per-element sequence in the authorizing data that is described as corresponding to a per-element sequence in the effecting data MUST have @@ -597,6 +593,13 @@ The following rules constrain the contents of individual bundles. A wallet or full validator only needs to enforce a given rule in this subsection if it understands the bundle type that the rule applies to. +* A bundle type MUST NOT appear in any map for which the corresponding column + of the `V7 Transaction Bundle Type Registry`_ is marked ❌, and MUST NOT + appear in any map at all if its row in the registry is marked as Reserved. + A parser cannot check this for a bundle type it does not know, because the + registry grows with each network upgrade; a full validator always knows the + registry in force for the block it is validating. + * The ``assetClass`` value for any entry in ``mValuePoolDeltas`` having ``bundleType = FeeBundleId`` MUST be 0 (fee amounts are denominated in ZEC and no other asset). @@ -610,6 +613,9 @@ it understands the bundle type that the rule applies to. transparent bundle is present in a coinbase transaction, its effecting data MUST have ``tx_in_count = 0``. +* For coinbase transactions, the ``nSpendsSapling`` field of the Sapling + bundle's effecting data MUST be 0. + * For coinbase transactions, the ``enableSpends`` bit of the ``flagsOrchard`` field of every Orchard protocol bundle MUST be 0. @@ -1312,9 +1318,9 @@ Coinbase Effecting Data +=============================+==========================+========================================+=====================================================================+ |``4`` |``blockHeight`` |``uint32`` |The height of the block in which the transaction is mined. | +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -|``8`` |``blockSubsidy`` |``int64`` |The block subsidy for that block, in zatoshis. | +|``8`` |``blockSubsidy`` |``uint64`` |The block subsidy for that block, in zatoshis. | +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ -|``8`` |``lockboxValue`` |``int64`` |The part of that block subsidy deposited into the lockbox, in | +|``8`` |``lockboxValue`` |``uint64`` |The part of that block subsidy deposited into the lockbox, in | | | | |zatoshis. | +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ |``varies`` |``coinbaseDataLen`` |``compactSize`` |Length of the ``coinbaseData`` byte array. | @@ -1324,7 +1330,6 @@ Coinbase Effecting Data +-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ * ``blockHeight`` MUST be in the range {1 .. 499999999}. -* ``blockSubsidy`` MUST be nonnegative. * ``lockboxValue`` MUST be in the range {0 .. ``blockSubsidy``}. * ``coinbaseDataLen`` MUST be at most 94. @@ -1337,8 +1342,8 @@ T.3.1: coinbase_effects_digest A BLAKE2b-256 hash of the following values:: T.3.1a: blockHeight (4-byte little-endian block height) - T.3.1b: blockSubsidy (8-byte signed little-endian) - T.3.1c: lockboxValue (8-byte signed little-endian) + T.3.1b: blockSubsidy (8-byte unsigned little-endian) + T.3.1c: lockboxValue (8-byte unsigned little-endian) T.3.1d: coinbaseData (byte array with leading ``compactSize`` length) The personalization field of this hash is set to:: From dba8be91b56a3767e70ce0b55610c8522a6060df Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Wed, 2 Sep 2026 19:23:43 -0600 Subject: [PATCH 51/51] Apply suggestion from @str4d Co-authored-by: Jack Grigg --- zips/zip-0248.rst | 3 --- 1 file changed, 3 deletions(-) diff --git a/zips/zip-0248.rst b/zips/zip-0248.rst index 56334e6cc..d38e825ec 100644 --- a/zips/zip-0248.rst +++ b/zips/zip-0248.rst @@ -596,9 +596,6 @@ it understands the bundle type that the rule applies to. * A bundle type MUST NOT appear in any map for which the corresponding column of the `V7 Transaction Bundle Type Registry`_ is marked ❌, and MUST NOT appear in any map at all if its row in the registry is marked as Reserved. - A parser cannot check this for a bundle type it does not know, because the - registry grows with each network upgrade; a full validator always knows the - registry in force for the block it is validating. * The ``assetClass`` value for any entry in ``mValuePoolDeltas`` having ``bundleType = FeeBundleId`` MUST be 0 (fee amounts are denominated in ZEC