From 1e5db9ab5d0ecf19c999e804d9a4682f2a88bed7 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Sat, 10 Jan 2026 17:20:38 -0700 Subject: [PATCH 01/19] [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 00000000..b084d0db --- /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 e89bd91d9d89c6269caf712726ab5635dcb91fe1 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Mon, 19 Jan 2026 12:14:45 -0700 Subject: [PATCH 02/19] [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 b084d0db..d32536ee 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 e4486d2c053bcd3788589e958a4f3ff1f243fe68 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Mon, 19 Jan 2026 13:17:13 -0700 Subject: [PATCH 03/19] [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 d32536ee..671e6a3c 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 27aa9a2f8c040eb9db37891759eee81e04019c64 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Mon, 19 Jan 2026 19:17:13 -0700 Subject: [PATCH 04/19] [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 671e6a3c..7714cca9 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 e23b88ac84b1e5a6b39a0d52acda5210ad58f821 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Mon, 19 Jan 2026 19:49:48 -0700 Subject: [PATCH 05/19] [ZIP 248]: Fix rst rendering --- zips/zip-0248.rst | 255 ++++++++++++++++++++++++++-------------------- 1 file changed, 145 insertions(+), 110 deletions(-) diff --git a/zips/zip-0248.rst b/zips/zip-0248.rst index 7714cca9..80cba293 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 d18f77286fdf5ddf5e710103817f43985445f954 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Mon, 19 Jan 2026 23:01:36 -0700 Subject: [PATCH 06/19] [ZIP 248]: Render update to README.rst --- README.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.rst b/README.rst index 1a92f05b..b5630906 100644 --- a/README.rst +++ b/README.rst @@ -181,6 +181,7 @@ written. 235 Remove 60% of Transaction Fees From Circulation Draft zips#924 245 Transaction Identifier Digests & Signature Validation for Transparent Zcash Extensions Draft zips#384 246 Digests for the Version 6 Transaction Format Draft + 248 Extensible Transaction Format Draft zips/pull/1163 270 Key Rotation for Tracked Signing Keys Reserved zips#1047 302 Standardized Memo Field Format Draft zips#366 303 Sprout Payment Disclosure Reserved @@ -320,6 +321,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 Version 6 Transaction Format Draft + 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 From 7b93924ff9adea5fd1962133b708cd7b237d1426 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Thu, 22 Jan 2026 18:52:51 -0700 Subject: [PATCH 07/19] [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 80cba293..529708c6 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 6be0664ba69f69aa9e4295bf7977a373b1d45f0b Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Fri, 23 Jan 2026 15:35:39 -0700 Subject: [PATCH 08/19] [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 529708c6..5c750153 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 5cd8d6e87b73f27369be3a6b655086c43ecfdae4 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Sun, 25 Jan 2026 11:07:51 -0700 Subject: [PATCH 09/19] [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 5c750153..4a125be7 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 c47f2c04e419566b41704e423ee0b3c42f684e6b Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Sun, 25 Jan 2026 11:27:25 -0700 Subject: [PATCH 10/19] [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 4a125be7..dd03bddd 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: version_group_id (4-byte little-endian version group identifier) + T.1c: consensus_branch_id (4-byte little-endian consensus branch id) + T.1d: lock_time (4-byte little-endian nLockTime value) + T.1e: expiry_height (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 31eae36153b5423b3e718418c6e952acde4a483e Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Wed, 28 Jan 2026 10:59:59 -0700 Subject: [PATCH 11/19] [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 dd03bddd..f9d5f05e 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 7e899d2c2de8fdb72a8aad49b28e9c81da943cd2 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Wed, 28 Jan 2026 15:13:54 -0700 Subject: [PATCH 12/19] [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 f9d5f05e..6164f9e2 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 2dbfa8ebde8641a7c35cca9f12219ffdeb16c270 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Wed, 28 Jan 2026 15:37:56 -0700 Subject: [PATCH 13/19] [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 6164f9e2..b8c0591e 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 76cef5b6551190e528d442f9ff249a7dfc2df18b Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Fri, 30 Jan 2026 14:05:34 -0700 Subject: [PATCH 14/19] [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 b8c0591e..41b575d4 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 dc72c5f005d0153a1c23b886301330de00b04e3c Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Wed, 4 Feb 2026 14:18:10 -0700 Subject: [PATCH 15/19] [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 41b575d4..593a4ed4 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 803454e5..67e6a98d 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 9d18ac544b327c7c3e1fd4784fb0a7ac8337957c Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Wed, 4 Feb 2026 14:21:02 -0700 Subject: [PATCH 16/19] [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 | 115 +++++++++++++++++++++++------------------------ 1 file changed, 56 insertions(+), 59 deletions(-) diff --git a/zips/zip-0233.md b/zips/zip-0233.md index bca2ef1f..759e24ea 100644 --- a/zips/zip-0233.md +++ b/zips/zip-0233.md @@ -75,82 +75,83 @@ 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]. -$\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 -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 again become available. +| BundleType | `mValuePoolDeltas` | `mEffectBundles` | `mAuthBundles` | +|------------|--------------------| -----------------|----------------| +| 5 |✅ |❌ |❌ | -## Changes to ZIP 230 [^zip-0230] +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). -The following field is appended to the Common Transaction Fields of the v6 -transaction format after `nExpiryHeight` [^zip-0230-transaction-format]: +## NSM Amount -| Bytes | Name | Data Type | Description | -|-------|----------------|-----------|----------------------------------------------------------------------------| -| 8 | `zip233Amount` | `uint64` | The value to be removed from circulation in this transaction, in zatoshis. | +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. -The $\mathsf{zip233\_amount}$ of a transaction is defined to be the value of the -`zip233Amount` field if present, and otherwise 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]. +Let $\mathsf{NSMBundleId} = 5.$ -In § 7.1 ‘Transaction Encoding and Consensus’ [^protocol-txnconsensus], add: - -> [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 @@ -192,14 +193,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 b5134cef2cd8cbf7e4e4ab35d08f2a4f47f0d687 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Wed, 4 Feb 2026 14:24:15 -0700 Subject: [PATCH 17/19] [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 | 173 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 165 insertions(+), 8 deletions(-) diff --git a/zips/zip-0231.md b/zips/zip-0231.md index 909ce8a4..43f1dbff 100644 --- a/zips/zip-0231.md +++ b/zips/zip-0231.md @@ -143,6 +143,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. +## 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 @@ -254,6 +397,9 @@ followed by $\mathtt{0x01}$), ensuring that a malformed memo is not returned. ## 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 all chunks have been pruned, otherwise 0. | @@ -276,19 +422,28 @@ If $\mathtt{fAllPruned} = 0$, then: If $\mathtt{fAllPruned} = 1$, then: - $\mathtt{nonceOrHash}$ represents the overall hash for the memo bundle as defined in - [Transaction sighash]. + [Transaction Digest]. - The $\mathtt{nMemoChunks}$, $\mathtt{pruned}$, 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 structure is a performance optimization for the case -where all memo chunks in a transaction have been pruned. +where all memo chunks in a transaction have been pruned. When $\mathtt{fAllPruned} = 1$, +the $\mathtt{nonceOrHash}$ field contains the pre-computed $\mathsf{memo\_bundle\_digest}$. -TODO: finish this to be a modification to the equivalent of ZIP 244 for -transaction v6. +Since the memo bundle has no authorizing data, it does not contribute to the +`auth_bundles_digest`. ## Changes to ZIP 317 [^zip-0317] @@ -581,9 +736,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-0302]: [ZIP 302: Standardized Memo Field Format](zip-0302.rst) From 3dd37578530342eb4a5a94a73d8983f778fe6eea Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Wed, 4 Feb 2026 14:25:51 -0700 Subject: [PATCH 18/19] [ZIP 227]: Propose to register a ZIP 248 bundle type for ZSA Issuance. - Register ZSA Issuance bundle type in the V6 bundle registry - Update digest section to reference effects_bundles_digest and auth_bundles_digest - Add reference to extensible transaction format ZIP - Remove unused ZIP 244 and ZIP 246 references Co-Authored-By: Claude Opus 4.5 --- zips/zip-0227.rst | 159 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 141 insertions(+), 18 deletions(-) diff --git a/zips/zip-0227.rst b/zips/zip-0227.rst index 7a58b4e3..4eabc32e 100644 --- a/zips/zip-0227.rst +++ b/zips/zip-0227.rst @@ -325,9 +325,9 @@ An Issue Note is a tuple $(\mathsf{d}, \mathsf{pk_d}, \mathsf{v}, \mathsf{AssetB - $\text{ρ}: \mathbb{F}_{q_{\mathbb{P}}}$ is used to derive the nullifier of the note, and is computed as in `Computation of ρ`_. - $\mathsf{rseed}: \mathbb{B}^{[\mathbb{Y}^{32}]}$ MUST be sampled uniformly at random by the issuer. -ZIP 230 [#zip-0230-issue-note]_ defines, in ``IssueNoteDescription``, field encodings which together with -$\mathsf{issuer}$ from the parent `Issuance Bundle`_ and $\mathsf{AssetDescHash}$ from the parent -`Issuance Action`_, specify an Issue Note. +The `IssueNoteDescription`_ encoding, together with +$\mathsf{issuer}$ from the parent `Issuance Bundle`_ and $\mathsf{assetDescHash}$ from the parent +`Issuance Action`_, specifies an Issue Note. Let $\mathsf{Note^{Issue}}$ be the type of an Issue Note, i.e. @@ -352,7 +352,8 @@ An issuance action, ``IssueAction``, is the instance of issuing a specific Custo The $\mathsf{finalize}$ boolean is set by the Issuer to signal that there will be no further issuance of the specific Custom Asset. As we will see in `Specification: Consensus Rule Changes`_, transactions that attempt to issue further amounts of a Custom Asset that has previously been finalized will be rejected. -The complete encoding of these fields into an ``IssueAction`` is defined in ZIP 230 [#zip-0230-issuance-action-description]_. +The complete encoding of these fields into an ``IssueAction`` is defined +in `Issuance Action Description`_ below. Issuance Bundle @@ -366,8 +367,129 @@ It contains the following fields: - ``vIssueActions``: an array of issuance actions, of type ``IssueAction``. - ``issueAuthSig``: the encoding of a signature of the transaction SIGHASH, signed by the issuance authorizing key, $\mathsf{isk}$, that validates the issuance. -The issuance bundle is added within the transaction format as a new bundle. -The detailed encoding of the issuance bundle as a part of the V6 transaction format is defined in ZIP 230 [#zip-0230-transaction-format]_. +The issuance bundle is added within the transaction format as a new bundle. +The encoding of the issuance bundle's effecting and authorizing data is +defined in `Changes to ZIP 248`_ below. + +This ZIP proposes to register the ZSA Issuance bundle type in the V6 +transaction bundle type registry defined in ZIP 248 [#zip-0248]_: + +Changes to ZIP 248 +`````````````````` + ++------------+----------------------+--------------------+------------------+--------------+ +| BundleType | ``mValuePoolDeltas`` | ``mEffectBundles`` | ``mAuthBundles`` | Bundle kind | ++============+======================+====================+==================+==============+ +| TBD |✅ |✅ |✅ | ZSA Issuance | ++------------+----------------------+--------------------+------------------+--------------+ + +The ZSA Issuance bundle has value pool deltas (issuance adds value to the +transparent transaction value pool for Custom Assets), effecting data (the +issuance actions and issue notes), and authorizing data (the issuance +authorization signature). + +.. _`Issuance Effecting Data`: + +Issuance Effecting Data +''''''''''''''''''''''' + ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| Bytes | Name | Data Type | Description | ++=============================+==============================+================================================+=====================================================================+ +| varies |``issuerLength`` |``compactSize`` |The length of the issuer identifier. | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| ``issuerLength`` |``issuer`` |``byte[issuerLength]`` |The issuer identifier as defined in `Issuer Identifier`_. | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| varies |``nIssueActions`` |``compactSize`` |The number of issuance actions in the bundle. | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| varies |``vIssueActions`` |``IssueAction[nIssueActions]`` |A sequence of issuance action descriptions, encoded per | +| | | |`Issuance Action Description`_. | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ + +* The fields ``issuerLength``, ``issuer``, ``nIssueActions``, and + ``vIssueActions`` are always present. +* If $\mathtt{nIssueActions} = 0$ then ``issuerLength`` MUST be set to $0$ + (``issuer`` and ``vIssueActions`` will be empty in this case). + +.. _`Issuance Action Description`: + +Issuance Action Description (``IssueAction``) +'''''''''''''''''''''''''''''''''''''''''''''' + +An issuance action, ``IssueAction``, is the instance of issuing a specific +Custom Asset, and contains the following fields: + ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| Bytes | Name | Data Type | Description | ++=============================+==============================+================================================+=====================================================================+ +| 32 |``assetDescHash`` |``byte[32]`` |A hash of the description of the Custom Asset. | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| varies |``nNotes`` |``compactSize`` |The number of notes in the Issuance Action. | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| 115 × ``nNotes`` |``vNotes`` |``IssueNoteDescription[nNotes]`` |A sequence of issue note descriptions within the Issuance Action. | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| 1 |``flagsIssuance`` |``byte`` |An 8-bit value representing a set of flags. Ordered from LSB to MSB: | +| | | | | +| | | |* :math:`\mathsf{finalize}` | +| | | |* The remaining bits are set to :math:`0\!`. | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ + +The encoding of ``IssueNoteDescription`` is described below. +Note that we allow the number of notes (represented by ``nNotes``) to be zero. +This allows for issuers to create Issuance Actions to only finalize an issued +Asset, without needing them to simultaneously issue more of that Asset. + +.. _`IssueNoteDescription`: + +Issue Note Description (``IssueNoteDescription``) +'''''''''''''''''''''''''''''''''''''''''''''''''' + +An issuance note description, ``IssueNoteDescription``, contains the following +fields: + ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| Bytes | Name | Data Type | Description | ++=============================+==============================+================================================+=====================================================================+ +| 43 |``recipient`` |``byte[43]`` |The encoding of a recipient's diversified payment address, as | +| | | |:math:`\mathsf{LEBS2OSP}_{88}(\mathsf{d})\| | +| | | |\mathsf{LEBS2OSP}_{256}(\mathsf{repr}_{\mathbb{P}} | +| | | |(\mathsf{pk}_\mathsf{d}))\!`, where :math:`\mathsf{d}` is the | +| | | |diversifier and :math:`\mathsf{pk_d}` is the diversified | +| | | |transmission key. **Non Normative Note**: This is the same as the | +| | | |encoding of an Orchard Raw Payment Address, as defined in | +| | | |§5.6.4.2 'Orchard Raw Payment Addresses'. | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| 8 |``value`` |``uint64`` |The amount being issued in this note. | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| 32 |``rho`` |``byte[32]`` |This is defined and encoded in the same manner as for Orchard notes | +| | | |in §3.2.1 'Note Plaintexts and Memo Fields'. | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| 32 |``rseed`` |``byte[32]`` |The ``rseed`` field of the note, encoded as for Orchard notes in | +| | | |§3.2.1 'Note Plaintexts and Memo Fields'. | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ + +.. _`Issuance Authorizing Data`: + +Issuance Authorizing Data +''''''''''''''''''''''''' + ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| Bytes | Name | Data Type | Description | ++=============================+==============================+================================================+=====================================================================+ +| varies |``sizeSighashInfo`` |``compactSize`` |The size in bytes of ``sighashInfo``. | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| ``sizeSighashInfo`` |``sighashInfo`` |``byte[sizeSighashInfo]`` |The sighash version and associated information. | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| varies |``sizeSignature`` |``compactSize`` |The size in bytes of ``signature``. | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| varies |``signature`` |``byte[sizeSignature]`` |The signature of the transaction SIGHASH, signed by the issuer, | +| | | |preceded by a ``0x00`` byte indicating a BIP 340 signature. It is | +| | | |validated as specified in | +| | | |`Issuance Authorization Signing and Validation`_. | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ + +* The issuance authorizing data is present if and only if + $\mathtt{nIssueActions} > 0$. Computation of ρ ---------------- @@ -409,7 +531,7 @@ For all actions ``IssueAction``: - encode the ``IssueAction`` into the vector ``vIssueActions`` of the bundle. -For the ``IssueBundle`` (see “ZSA Issuance Bundle Fields” in [#zip-0230-transaction-format]_): +For the ``IssueBundle`` (see `Issuance Effecting Data`_): - encode the ``vIssueActions`` vector. - fill the ``issuerLength`` and ``issuer`` fields using $\mathsf{issuer}$. @@ -487,7 +609,7 @@ If the transaction contains an issuance bundle: - The issuance authorization signature, $\mathsf{issueAuthSig}$, MUST be a valid $\mathsf{IssueAuthSig}$ signature over $\mathsf{SigHash}$, i.e. $\mathsf{IssueAuthSig}.\!\mathsf{Validate}(\mathsf{ik}, \mathsf{SigHash}, \mathsf{issueAuthSig}) = 1$. - For every issuance action description ($\mathsf{IssueAction}_\mathsf{i},\ 1 \leq i \leq \mathtt{nIssueActions}$) in the issuance bundle: - - Every ``IssueNoteDescription`` in the ``IssueAction`` MUST be a valid field encoding as defined in ZIP 230 [#zip-0230-issue-note]_. + - Every ``IssueNoteDescription`` in the ``IssueAction`` MUST be a valid field encoding as defined in `IssueNoteDescription`_. - Let an Issue Note (with type $\mathsf{Note^{Issue}}$) be constructed from the fields of each ``IssueNoteDescription``, with the $\mathsf{AssetBase}$ derived from the ``assetDescHash`` field of the ``IssueAction`` and the ``issuer`` field of the issuance bundle, as described in the `Specification: Asset Identifier, Asset Digest, and Asset Base`_ section. - It MUST be the case that $\mathsf{issued\_assets}_{\mathsf{OUT}}(\mathsf{AssetBase}).\mathsf{final} \neq 1$. - If $\mathsf{issued\_assets}_{\mathsf{OUT}}(\mathsf{AssetBase}).\mathsf{note_{ref}} = \bot$, then let $\mathsf{new\_note_{ref}}$ be the first Issue Note in the Issuance Action. @@ -593,12 +715,17 @@ Concrete Applications -Modifications relative to ZIP 244 [#zip-0244]_ -============================================== +Modifications to Digest Algorithms +================================== -Relative to the sighash algorithm defined in ZIP 244, the sighash algorithm -that applies to v6 transactions differs by including the issuance bundle -components within the tree hash. See ZIP 246 [#zip-0246]_ for details. +The ZSA Issuance bundle contributes to the transaction identifier and signature +digest via the ``effects_bundles_digest`` and ``auth_bundles_digest`` defined +in ZIP 248 [#zip-0248]_. + +The issuance bundle's value pool deltas are committed via +``value_pool_deltas_digest``. The issuance effecting data (issuance actions and +issue notes) is committed via ``effects_bundles_digest``. The issuance +authorization signature is committed via ``auth_bundles_digest``. Changes to ZIP 317 [#zip-0317]_ @@ -692,11 +819,7 @@ References .. [#zip-0226-assetburn] `ZIP 226: Transfer and Burn of Zcash Shielded Assets — Additional Consensus Rules for the assetBurn set `_ .. [#zip-0226-txiddigest] `ZIP 226: Transfer and Burn of Zcash Shielded Assets — TxId Digest `_ .. [#zip-0226-authcommitment] `ZIP 226: Transfer and Burn of Zcash Shielded Assets — Authorizing Data Commitment `_ -.. [#zip-0230-issuance-action-description] `ZIP 230: Version 6 Transaction Format — Issuance Action Description (IssueAction) `_ -.. [#zip-0230-issue-note] `ZIP 230: Version 6 Transaction Format — Issue Note Description (IssueNoteDescription) `_ -.. [#zip-0230-transaction-format] `ZIP 230: Version 6 Transaction Format — Transaction Format `_ -.. [#zip-0244] `ZIP 244: Transaction Identifier Non-Malleability `_ -.. [#zip-0246] `ZIP 246: Digests for the Version 6 Transaction Format `_ +.. [#zip-0248] `ZIP 248: Extensible Transaction Format `_ .. [#zip-0317] `ZIP 317: Proportional Transfer Fee Mechanism `_ .. [#zip-0317-fee-calculation] `ZIP 317: Proportional Transfer Fee Mechanism — Fee calculation `_ .. [#bip-0043] `BIP 43: Purpose Field for Deterministic Wallets `_ From 346b40dd6281434c40716c76c0d2890447f9f9db Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Wed, 4 Feb 2026 15:14:14 -0700 Subject: [PATCH 19/19] [ZIP 226]: Register ZIP 248 bundle type. - Register OrchardZSA bundle type in the V6 bundle registry - Update digest section to reference effects_bundles_digest and auth_bundles_digest - Add reference to extensible transaction format ZIP - Remove unused ZIP 244 and ZIP 246 references Co-Authored-By: Claude Opus 4.5 --- zips/zip-0226.rst | 203 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 194 insertions(+), 9 deletions(-) diff --git a/zips/zip-0226.rst b/zips/zip-0226.rst index b2d3bf95..ac76147b 100644 --- a/zips/zip-0226.rst +++ b/zips/zip-0226.rst @@ -363,11 +363,190 @@ The transaction format for v6 transactions is described in ZIP 230 [#zip-0230]_. The ZSA-related changes in v6 include: * updates to the transaction structure [#zip-0230-transaction-format]_ and the - sighash digest computation [#zip-0246]_; + sighash digest computation [#zip-0248]_; * new note plaintext formats for both Sapling and Orchard outputs [#zip-0230-note-plaintexts]_, with corresponding changes to the note decryption algorithms for incoming and outgoing viewing keys [#zip-2005]_. +Changes to ZIP 248 +`````````````````` + +This ZIP proposes to register the OrchardZSA bundle type in the V6 transaction +bundle type registry defined in ZIP 248 [#zip-0248]_: + ++------------+----------------------+--------------------+------------------+-------------+ +| BundleType | ``mValuePoolDeltas`` | ``mEffectBundles`` | ``mAuthBundles`` | Bundle kind | ++============+======================+====================+==================+=============+ +| TBD |✅ |✅ |✅ | OrchardZSA | ++------------+----------------------+--------------------+------------------+-------------+ + +OrchardZSA Effecting Data +''''''''''''''''''''''''' + ++-----------------------------+----------------------------------+------------------------------------------------------+---------------------------------------------------------------------+ +| Bytes | Name | Data Type | Description | ++=============================+==================================+======================================================+=====================================================================+ +| varies |``nActionGroupsOrchard`` |``compactSize`` |The number of Action Group descriptions in | +| | | |``vActionGroupsOrchard``. | ++-----------------------------+----------------------------------+------------------------------------------------------+---------------------------------------------------------------------+ +| varies |``vActionGroupsOrchard`` |``ActionGroupOrchardEffecting[nActionGroupsOrchard]`` |A sequence of ActionGroupOrchardEffecting descriptions, encoded as | +| | | |per `ActionGroupOrchardEffecting`_. | ++-----------------------------+----------------------------------+------------------------------------------------------+---------------------------------------------------------------------+ + +ActionGroupOrchardEffecting +''''''''''''''''''''''''''' + ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| Bytes | Name | Data Type | Description | ++=============================+==============================+================================================+=====================================================================+ +| varies |``nActionsOrchard`` |``compactSize`` |The number of Action descriptions in ``vActionsOrchard``. | +| | | |This MUST have a value strictly greater than ``0``. | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| 372 × ``nActionsOrchard`` |``vActionsOrchard`` |``OrchardZSAEffecting[nActionsOrchard]`` |A sequence of OrchardZSA Action descriptions in the Action Group. | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| 1 |``flagsOrchard`` |``byte`` |As defined in §7.1 ‘Transaction Encoding and Consensus’ | +| | | |[#protocol-txnencoding]_. | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| 32 |``anchorOrchard`` |``byte[32]`` |As defined in §7.1 ‘Transaction Encoding and Consensus’ | +| | | |[#protocol-txnencoding]_. | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| 4 |``nAGExpiryHeight`` |``uint32`` |A block height in the range {1 .. 499999999} after which any | +| | | |transaction including this Action Group cannot be mined, or 0 if | +| | | |this Action Group places no constraint on transaction expiry. | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| varies | ``nAssetBurn`` | ``compactSize`` |The number of Assets burnt. | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| 40 × ``nAssetBurn`` | ``vAssetBurn`` | ``AssetBurn[nAssetBurn]`` |A sequence of Asset Burn descriptions, encoded per | +| | | |`OrchardZSA Asset Burn Description`_. | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ + +The encodings of ``OrchardZSAEffecting`` and ``AssetBurn`` are described below. + +* If the value of ``nAGExpiryHeight`` is nonzero, it MUST be consistent with + the ``nExpiryHeight`` of the overall transaction. +* In NU7, ``nExpiryHeight`` MUST be set to ``0``; this restriction is expected + to be lifted in a future network upgrade. + +Rationale for nAGExpiryHeight +''''''''''''''''''''''''''''' + +We introduce the ``nAGExpiryHeight`` field in this transaction format in order +to be forward compatible with Swaps over ZSAs, as proposed in ZIP 228 +[#zip-0228]_. For the OrchardZSA protocol, which does not make use of an +additional expiry height for transactions, we set the value of +``nAGExpiryHeight`` to be ``0`` by consensus. This serves as a default value to +represent the situation where there is no expiry, analogous to the convention +adopted for ``nExpiryHeight`` in ZIP 203 [#zip-0203]. + +Rationale for including Burn fields inside OrchardZSA Action Groups +''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +Note that the bundle format includes the burn fields of the transaction inside +the OrchardZSA Action Group rather than at the transaction level. This is a +design choice that considers the future scenario where Action Groups may be +generated by different parties before being bundled together into a +transaction. In such a scenario, the individual parties can burn Assets of +their choice in their corresponding Action Groups. Maintaining the burn fields +at the transaction level would provide the ability to burn Assets only to the +party performing the bundling of the Action Groups. + +OrchardZSAEffecting +''''''''''''''''''' + ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +| 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. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``132`` |``encCiphertext`` |``byte[132]`` |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. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ + +.. _`OrchardZSA Asset Burn Description`: + +OrchardZSA Asset Burn Description +''''''''''''''''''''''''''''''''' + +An OrchardZSA Asset Burn description is encoded as an instance of an +``AssetBurn`` type: + ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| Bytes | Name | Data Type | Description | ++=============================+==============================+================================================+=====================================================================+ +| 32 |``AssetBase`` |``byte[32]`` |For the OrchardZSA protocol, this is the encoding of the Asset Base | +| | | |:math:`\mathsf{AssetBase^{Orchard}}\!`. | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ +| 8 |``valueBurn`` |``uint64`` |The amount being burnt. The value is checked by consensus to be | +| | | |non-zero. | ++-----------------------------+------------------------------+------------------------------------------------+---------------------------------------------------------------------+ + +OrchardZSA Authorizing Data +''''''''''''''''''''''''''' + +The authorizing data for the OrchardZSA bundle contains the proofs and +signatures that authorize the actions. The per-action-group data parallels the +structure of the effecting data. + ++-----------------------------+----------------------------------+------------------------------------------------------+---------------------------------------------------------------------+ +| Bytes | Name | Data Type | Description | ++=============================+==================================+======================================================+=====================================================================+ +| varies |``vActionGroupsOrchardAuth`` |``ActionGroupOrchardAuthorizing[nActionGroupsOrchard]``|Authorizing data for each Action Group, in the same order as | +| | | |``vActionGroupsOrchard`` in the effecting data. | ++-----------------------------+----------------------------------+------------------------------------------------------+---------------------------------------------------------------------+ +|``64`` |``bindingSigOrchard`` |``byte[64]`` |An Orchard binding signature on the SIGHASH transaction hash. | ++-----------------------------+----------------------------------+------------------------------------------------------+---------------------------------------------------------------------+ + +* The value of ``nActionGroupsOrchard`` is not re-encoded in the authorizing + data; it is taken from the corresponding effecting data. + +* The field ``bindingSigOrchard`` is present if and only if + $\mathtt{nActionGroupsOrchard} > 0$. + +ActionGroupOrchardAuthorizing +''''''''''''''''''''''''''''' + ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +| 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 OrchardZSA Actions | +| | | |in this Action Group. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ +|``64 * nActionsOrchard`` |``vSpendAuthSigsOrchard`` |``byte[64 * nActionsOrchard]`` |Authorizing signatures for each OrchardZSA Action in this | +| | | |Action Group. | ++-----------------------------+--------------------------+----------------------------------------+---------------------------------------------------------------------+ + +* The value of ``nActionsOrchard`` is not re-encoded in the authorizing data; it + is taken from the corresponding ``ActionGroupOrchardEffecting``. + +* The proofs aggregated in ``proofsOrchard``, and the elements of + ``vSpendAuthSigsOrchard``, each have a 1:1 correspondence to the elements of + ``vActionsOrchard`` in the corresponding ``ActionGroupOrchardEffecting`` and + MUST be ordered such that the proof or signature at a given index corresponds + to the ``OrchardZSAEffecting`` at the same index. + +The OrchardZSA bundle has value pool deltas (transfers move value in and out of +the transparent transaction value pool), effecting data (the OrchardZSA actions +and burn information), and authorizing data (the proofs and binding signature). + +A transaction MUST NOT contain both an Orchard bundle (type 3) and an OrchardZSA +bundle. The OrchardZSA bundle replaces the Orchard bundle for transactions that +transfer Custom Assets. + Implications for Wallets ```````````````````````` @@ -387,13 +566,18 @@ The following requirements on wallets are specified and motivated in ZIP 230 temporarily inaccessible, until the wallet is upgraded to fully support v6 and to rescan outputs since v6 activation. -Sighash modifications relative to ZIP 244 [#zip-0244]_ ------------------------------------------------------- +Modifications to Digest Algorithms +---------------------------------- + +The OrchardZSA bundle contributes to the transaction identifier and signature +digest via the ``effects_bundles_digest`` and ``auth_bundles_digest`` defined +in ZIP 248 [#zip-0248]_. -Relative to the sighash algorithm defined in ZIP 244 [#zip-0244]_, the sighash algorithm -that applies to v6 transactions differs by altering the Orchard bundle within -the tree hash to match the corresponding OrchardZSA changes. See ZIP 246 [#zip-0246]_ -for details. +The OrchardZSA bundle's value pool deltas (for both ZEC and Custom Assets) are +committed via ``value_pool_deltas_digest``. The OrchardZSA effecting data +(actions and burn information) is committed via ``effects_bundles_digest``. +The OrchardZSA authorizing data (proofs and binding signature) is committed +via ``auth_bundles_digest``. Transaction Fees ---------------- @@ -435,7 +619,9 @@ 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" `_ .. [#zip-0200] `ZIP 200: Network Upgrade Mechanism `_ .. [#zip-0209] `ZIP 209: Prohibit Negative Shielded Chain Value Pool Balances `_ +.. [#zip-0203] `ZIP 203: Transaction Expiry `_ .. [#zip-0224] `ZIP 224: Orchard `_ +.. [#zip-0228] `ZIP 228: Asset Swaps for Zcash Shielded Assets `_ .. [#zip-0227] `ZIP 227: Issuance of Zcash Shielded Assets `_ .. [#zip-0227-specification-global-issuance-state] `ZIP 227: Issuance of Zcash Shielded Assets — Specification: Global Issuance State `_ .. [#zip-0227-assetidentifier] `ZIP 227: Issuance of Zcash Shielded Assets — Specification: Asset Identifier `_ @@ -449,8 +635,7 @@ References .. [#zip-0230-note-plaintexts] `ZIP 230: Version 6 Transaction Format — Note Plaintexts `_ .. [#zip-0230-orchard-note-plaintext] `ZIP 230: Version 6 Transaction Format — Orchard Note Plaintext `_ .. [#zip-0230-implications-for-wallets] `ZIP 230: Version 6 Transaction Format — Implications for Wallets `_ -.. [#zip-0244] `ZIP 244: Transaction Identifier Non-Malleability `_ -.. [#zip-0246] `ZIP 246: Digests for the Version 6 Transaction Format `_ +.. [#zip-0248] `ZIP 248: Extensible Transaction Format `_ .. [#zip-0307] `ZIP 307: Light Client Protocol for Payment Detection `_ .. [#zip-2005] `ZIP 2005: Quantum Recoverability `_ .. [#protocol] `Zcash Protocol Specification, Version 2025.6.2 [NU6.1] or later. `_