From 1e5db9ab5d0ecf19c999e804d9a4682f2a88bed7 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Sat, 10 Jan 2026 17:20:38 -0700 Subject: [PATCH 01/25] [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/25] [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/25] [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/25] [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/25] [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/25] [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/25] [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/25] [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/25] [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/25] [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/25] [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/25] [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/25] [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/25] [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 43956911d9f93bbd4fa94a7ee158886224341892 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Wed, 4 Feb 2026 14:18:10 -0700 Subject: [PATCH 15/25] [ZIP 2002]: Register ZIP 248 bundle type. - 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-2002.rst | 91 ++++++++++++++++++++++++++--------------------- 1 file changed, 51 insertions(+), 40 deletions(-) diff --git a/zips/zip-2002.rst b/zips/zip-2002.rst index 803454e5..2d636127 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]_ -------------------------------- +Bundle Type Registration +------------------------ -The following field is appended to the Common Transaction Fields of the v6 -transaction format after ``nExpiryHeight`` [#zip-0230-transaction-format]_: +This ZIP registers 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 0770b132ebabc4acd33e66daa325f0a698b8b9ff Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Wed, 4 Feb 2026 14:21:02 -0700 Subject: [PATCH 16/25] [ZIP 233]: Register ZIP 248 bundle type. - 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..2f17c166 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 +## Bundle Type Registration -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 registers 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 483b3352d2e6672ea97ddc1a65e0435ac1d77a32 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Wed, 4 Feb 2026 14:24:15 -0700 Subject: [PATCH 17/25] [ZIP 231]: 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..98f0c50e 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. +## Bundle Type Registration + +This ZIP registers 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` | `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$. + +#### OrcharActionEffecting + +| 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 + `OrchardActionEffecting` value 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 b202868a0110bb4432f17b2e45c556ed6a7f20e0 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Wed, 4 Feb 2026 14:25:51 -0700 Subject: [PATCH 18/25] [ZIP 227]: Register ZIP 248 bundle type. - 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 | 40 +++++++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/zips/zip-0227.rst b/zips/zip-0227.rst index 7a58b4e3..b7efd4b3 100644 --- a/zips/zip-0227.rst +++ b/zips/zip-0227.rst @@ -308,6 +308,28 @@ where $\mathsf{GroupHash}^\mathbb{P}$ is defined as in [#protocol-concretegrouph Diagram relating the Issuer identifier, asset description, asset description hash, Asset Identifier, Asset Digest, and Asset Base for the OrchardZSA Protocol. +Bundle Type Registration +======================== + +This ZIP registers the ZSA Issuance bundle type in the V6 transaction bundle +type registry defined in ZIP 248 [#zip-0248]_: + ++------------+----------------------+--------------------+------------------+--------------+ +| 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). + +The effecting data for the ZSA Issuance bundle is encoded as specified in +`Issuance Bundle`_. The authorizing data consists of the ``issueAuthSig`` +field. + + Specification: Issue Note, Issuance Action, Issuance Bundle and Issuance Protocol ================================================================================= @@ -593,12 +615,17 @@ Concrete Applications -Modifications relative to ZIP 244 [#zip-0244]_ -============================================== +Modifications to Digest Algorithms +================================== + +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]_. -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 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]_ @@ -695,8 +722,7 @@ References .. [#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 986b0873491499b26dcac5b64d601e6d89317cf1 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Wed, 4 Feb 2026 15:14:14 -0700 Subject: [PATCH 19/25] [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 | 43 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/zips/zip-0226.rst b/zips/zip-0226.rst index b2d3bf95..309153e2 100644 --- a/zips/zip-0226.rst +++ b/zips/zip-0226.rst @@ -83,6 +83,27 @@ Privacy Implications - When including new Assets we would like to maintain the amount and identifiers of Assets private, which is achieved with the design. +Bundle Type Registration +======================== + +This ZIP registers 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 | ++------------+----------------------+--------------------+------------------+-------------+ + +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. + + Specification ============= @@ -363,7 +384,7 @@ 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]_. @@ -387,13 +408,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 ---------------- @@ -449,8 +475,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. `_ From 6ac3a920aabc4841482a1665ab2b406cdc3fde57 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood Date: Tue, 17 Feb 2026 11:32:29 +0000 Subject: [PATCH 20/25] Rename ZIP 2005 from "Quantum Recoverability" to "Orchard Quantum Recoverability". Signed-off-by: Daira-Emma Hopwood --- README.rst | 6 ++++-- zips/zip-2005.md | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index e2cbfd56..376ea6ae 100644 --- a/README.rst +++ b/README.rst @@ -210,9 +210,10 @@ written. 2002 Explicit Fees Draft zips#803 2003 Disallow version 4 transactions Draft zips#825 2004 Remove the dependency of consensus on note encryption Draft zips#917 - 2005 Quantum Recoverability Draft zips#1135 + 2005 Orchard Quantum Recoverability Draft zips#1135 guide-markdown {Something Short and To the Point} Draft guide {Something Short and To the Point} Draft + template {Something Short and To the Point} Draft Drafts without assigned ZIP numbers @@ -383,7 +384,8 @@ Index of ZIPs 2002 Explicit Fees Draft 2003 Disallow version 4 transactions Draft 2004 Remove the dependency of consensus on note encryption Draft - 2005 Quantum Recoverability Draft + 2005 Orchard Quantum Recoverability Draft guide-markdown {Something Short and To the Point} Draft guide {Something Short and To the Point} Draft + template {Something Short and To the Point} Draft diff --git a/zips/zip-2005.md b/zips/zip-2005.md index 241e18af..dbc039f9 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -1,6 +1,6 @@ ZIP: 2005 - Title: Quantum Recoverability + Title: Orchard Quantum Recoverability Owners: Daira-Emma Hopwood Jack Grigg Credits: Sean Bowe From 31dfa2bebd7ca7594a679488e3636bd84cc97e5c Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood Date: Tue, 17 Feb 2026 11:39:53 +0000 Subject: [PATCH 21/25] Protocol spec and ZIP 32: factor out (dk, ovk) derivation. Signed-off-by: Daira-Emma Hopwood --- protocol/protocol.tex | 32 +++++++++++++++++--------------- zips/zip-0032.rst | 29 ++++++++++++++++++----------- zips/zip-2005.md | 32 +++++++++++++++----------------- 3 files changed, 50 insertions(+), 43 deletions(-) diff --git a/protocol/protocol.tex b/protocol/protocol.tex index 80b64a81..fe88e44b 100644 --- a/protocol/protocol.tex +++ b/protocol/protocol.tex @@ -1690,6 +1690,7 @@ \newcommand{\DiversifierIndex}{\mathsf{index}} \newcommand{\FVK}{\mathsf{FVK}} \newcommand{\DeriveInternalFVKOrchard}{\mathsf{DeriveInternalFVK^{Orchard}}} +\newcommand{\DeriveDkAndOvkOrchard}{\mathsf{DeriveDkAndOvk^{Orchard}}} \newcommand{\DiversifiedTransmitBase}{\mathsf{g_d}} \newcommand{\DiversifiedTransmitBaseRepr}{\mathsf{g\Repr_d}} \newcommand{\DiversifiedTransmitBaseOld}{\mathsf{g^{old}_d}} @@ -4256,8 +4257,7 @@ $\PRFexpand{}$ is used in the following places: \begin{itemize} \item \sapling{\crossref{saplingkeycomponents}, with inputs $[\hexint{00}]$, $[\hexint{01}]$, $[\hexint{02}]$, and $[\hexint{03}, i \typecolon \byte]$;} - \nufiveonwarditem{in \crossref{orchardkeycomponents}, with inputs $[\hexint{06}]$, $[\hexint{07}]$, $[\hexint{08}]$, and with first byte $\hexint{82}$ - (the last of these is also specified in \cite{ZIP-32});} + \nufiveonwarditem{in \crossref{orchardkeycomponents}, with inputs $[\hexint{06}]$, $[\hexint{07}]$, $[\hexint{08}]$, and with first byte $\hexint{82}$;} \notnufive{ \item \sapling{sending (\crossref{saplingsend}) and receiving (\shortcrossref{saplingandorchardinband}) \Sapling \notes, with inputs $[\hexint{04}]$ and $[\hexint{05}]$;} @@ -4269,7 +4269,7 @@ } %notbeforenufive \item in \cite{ZIP-32}, \sapling{with inputs $[\hexint{00}]$, $[\hexint{01}]$, $[\hexint{02}]$ (intentionally matching \shortcrossref{saplingkeycomponents}), $[\hexint{10}]$, $[\hexint{13}]$, $[\hexint{14}]$, and} with first byte in - $\setof{\sapling{\hexint{11}, \hexint{12}, \hexint{15}, \hexint{16}, \hexint{17}, \hexint{18},\,}\hexint{80}\nufive{, \hexint{81}, \hexint{82}, \hexint{83}}}$; + $\setof{\sapling{\hexint{11}, \hexint{12}, \hexint{15}, \hexint{16}, \hexint{17}, \hexint{18},\,}\hexint{80}\nufive{, \hexint{81}, \hexint{83}}}$; \item in \cite{ZIP-316}, with first byte $\hexint{D0}$. \end{itemize} @@ -5401,6 +5401,18 @@ \vspace{-1.5ex} Define $\ToScalar{Orchard}(x \typecolon \PRFOutputExpand) := \LEOStoIPOf{\PRFOutputLengthExpand}{x} \pmod{\ParamP{r}}$. +Define $\DeriveDkAndOvkOrchard(\CommitIvkRand \typecolon \CommitIvkRandType, \AuthSignPublic \typecolon \AuthSignPublicTypeOrchard, \NullifierKey \typecolon \NullifierKeyTypeOrchard)$ +as follows: + +\begin{algorithm} + \item let $K = \ItoLEBSPOf{\SpendingKeyLength}{\CommitIvkRand}$ + \vspace{-0.3ex} + \item let $R = \PRFexpand{\!K}\big([\hexint{82}] \bconcat \ItoLEOSPOf{256}{\AuthSignPublic} \bconcat \ItoLEOSPOf{256}{\NullifierKey}\kern-0.25em\big)$ + \item let $\DiversifierKey \typecolon \DiversifierKeyType$ be the first $\DiversifierKeyLength/8$ bytes of $R$ and + let $\OutViewingKey \typecolon \OutViewingKeyType$ be the remaining $\OutViewingKeyLength/8$ bytes of $R$. + \item return $(\DiversifierKey, \OutViewingKey)$ +\end{algorithm} + \introlist A new \Orchard \spendingKey $\SpendingKey$ is generated by choosing a \bitSequence uniformly at random from $\SpendingKeyType$. @@ -5435,12 +5447,7 @@ \vspace{-0.3ex} \item if $\InViewingKey \in \setof{0, \bot}$, discard this key and repeat with a new $\SpendingKey$. \vspace{-0.2ex} - \item let $K = \ItoLEBSPOf{\SpendingKeyLength}{\CommitIvkRand}$ - \vspace{-0.5ex} - \item let $R = \PRFexpand{K}\big([\hexint{82}] \bconcat \ItoLEOSPOf{256}{\AuthSignPublic} \bconcat \ItoLEOSPOf{256}{\NullifierKey}\kern-0.25em\big)$ - \vspace{-0.2ex} - \item let $\DiversifierKey$ be the first $\DiversifierKeyLength/8$ bytes of $R$ and - let $\OutViewingKey$ be the remaining $\OutViewingKeyLength/8$ bytes of $R$. + \item let $(\DiversifierKey, \OutViewingKey) = \DeriveDkAndOvkOrchard(\CommitIvkRand, \AuthSignPublic, \NullifierKey)$ \vspace{-0.4ex} \item let $(\Internal{\AuthSignPublic}, \Internal{\NullifierKey}, \Internal{\CommitIvkRand}) = \DeriveInternalFVKOrchard(\AuthSignPublic, \NullifierKey, \CommitIvkRand)$ \vspace{-0.3ex} @@ -5448,12 +5455,7 @@ \vspace{-0.2ex} \item if $\Internal{\InViewingKey} \in \setof{0, \bot}$, discard this key and repeat with a new $\SpendingKey$. \vspace{-0.2ex} - \item let $\Internal{K} = \ItoLEBSPOf{\SpendingKeyLength}{\Internal{\CommitIvkRand}}$ - \vspace{-0.5ex} - \item let $\Internal{R} = \PRFexpand{\Internal{K}}\big([\hexint{82}] \bconcat \ItoLEOSPOf{256}{\Internal{\AuthSignPublic}} \bconcat \ItoLEOSPOf{256}{\Internal{\NullifierKey}}\kern-0.25em\big)$ - \vspace{-0.2ex} - \item let $\Internal{\DiversifierKey}$ be the first $\DiversifierKeyLength/8$ bytes of $\Internal{R}$ and - let $\Internal{\OutViewingKey}$ be the remaining $\OutViewingKeyLength/8$ bytes of $\Internal{R}$. + \item let $(\Internal{\DiversifierKey}, \Internal{\OutViewingKey}) = \DeriveDkAndOvkOrchard\big(\Internal{\CommitIvkRand}, \Internal{\AuthSignPublic}, \Internal{\NullifierKey}\big)$. \end{algorithm} \introlist diff --git a/zips/zip-0032.rst b/zips/zip-0032.rst index 5ced05e5..ce63227d 100644 --- a/zips/zip-0032.rst +++ b/zips/zip-0032.rst @@ -473,7 +473,7 @@ Define $\mathsf{DeriveInternalFVK^{Orchard}}(\mathsf{ak}, \mathsf{nk}, \mathsf{r as follows: - Let $K = \mathsf{I2LEBSP}_{256}(\mathsf{rivk})$. -- Let $\mathsf{rivk_{internal}} = \mathsf{ToScalar^{Orchard}}(\mathsf{PRF^{expand}}(K, [\mathtt{0x83}] \,||\, \mathsf{I2LEOSP_{256}}(\mathsf{ak}) \,||\, \mathsf{I2LEOSP_{256}}(\mathsf{nk})))$. +- Let $\mathsf{rivk_{internal}} = \mathsf{ToScalar^{Orchard}}\big(\mathsf{PRF}^{\mathsf{expand}}_{K}\big([\mathtt{0x83}] \,||\, \mathsf{I2LEOSP_{256}}(\mathsf{ak}) \,||\, \mathsf{I2LEOSP_{256}}(\mathsf{nk})\kern-0.1em\big)\kern-0.15em\big)$. - Return $(\mathsf{ak}, \mathsf{nk}, \mathsf{rivk_{internal}})$. The result of applying $\mathsf{DeriveInternalFVK^{Orchard}}$ to the external full viewing @@ -500,8 +500,8 @@ Account level. It was implemented in `zcashd` as part of support for ZIP 316 [#z Note that the resulting FVK may be invalid, as specified in [#protocol-orchardkeycomponents]_. -Orchard diversifier derivation ------------------------------- +Orchard diversifier and OVK derivation +-------------------------------------- As with Sapling, we define a mechanism for deterministically deriving a sequence of diversifiers, without leaking how many diversified addresses have already been generated for an account. Unlike Sapling, we do so @@ -510,18 +510,24 @@ key. This means that the full viewing key provides the capability to determine t within the sequence, which matches the capabilities of a Sapling extended full viewing key but simplifies the key structure. -Given an Orchard extended spending key $(\mathsf{sk}_i, \mathsf{c}_i)$: +Let $\mathsf{DeriveDkAndOvk^{Orchard}}$ be as defined in [#protocol-orchardkeycomponents]_. -- Let $(\mathsf{ak}, \mathsf{nk}, \mathsf{rivk})$ be the Orchard full viewing key for $\mathsf{sk}_i$. -- Let $K = \mathsf{I2LEBSP}_{256}(\mathsf{rivk})$. -- $\mathsf{dk}_i = \mathsf{truncate}_{32}(\mathsf{PRF^{expand}}(K, [\mathtt{0x82}] \,||\, \mathsf{I2LEOSP}_{256}(\mathsf{ak}) \,||\, \mathsf{I2LEOSP}_{256}(\mathsf{nk})))$. +Given an Orchard full viewing key $(\mathsf{ak}, \mathsf{nk}, \mathsf{rivk})$ (which may be +either external or internal): + +- $(\mathsf{dk}, \mathsf{ovk}) = \mathsf{DeriveDkAndOvk^{Orchard}}(\mathsf{rivk}, \mathsf{ak}, \mathsf{nk})$. - Let $j$ be the index of the desired diversifier, in the range $0\,..\, 2^{88} - 1$. -- $d_{i,j} = \mathsf{FF1}\text{-}\mathsf{AES256.Encrypt}(\mathsf{dk}_i, \texttt{“”}, \mathsf{I2LEBSP}_{88}(j))$. +- $\mathsf{d}_j = \mathsf{FF1}\text{-}\mathsf{AES256.Encrypt}\big(\mathsf{dk}, \texttt{“”}, \mathsf{I2LEBSP}_{88}(j)\kern-0.1em\big)$. + +Note that unlike Sapling, all Orchard diversifiers are valid, and thus all possible values +of $j$ yield valid diversifiers. -Note that unlike Sapling, all Orchard diversifiers are valid, and thus all possible values of $j$ yield -valid diversifiers. +The default diversifier for $(\mathsf{ak}, \mathsf{nk}, \mathsf{rivk})$ is defined to be +$\mathsf{d}_0.$ -The default diversifier for $(\mathsf{sk}_i, \mathsf{c}_i)$ is defined to be $d_{i,0}.$ +No mechanism is provided to derive distinct Outgoing Viewing Keys ($\!\mathsf{ovk}$) for +each diversified address. This is because payments are sent from accounts (with external +or internal scope), not from specific diversified addresses [#zip-0316-usage-of-outgoing-viewing-keys]_. Specification: Registered key derivation @@ -892,3 +898,4 @@ References .. [#NIST-SP-800-38G] `NIST Special Publication 800-38G — Recommendation for Block Cipher Modes of Operation: Methods for Format-Preserving Encryption `_ .. [#zip-0000] `ZIP 0: ZIP Process `_ .. [#zip-0316] `ZIP 316: Unified Addresses and Unified Viewing Keys `_ +.. [#zip-0316-usage-of-outgoing-viewing-keys] `ZIP 316: Unified Addresses and Unified Viewing Keys — Usage of Outgoing Viewing Keys `_ \ No newline at end of file diff --git a/zips/zip-2005.md b/zips/zip-2005.md index dbc039f9..21d5a673 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -462,28 +462,26 @@ In the list of places where $\mathsf{PRF^{expand}}$ is used: Replace -> * [**NU5** onward] in § 4.2.3 ‘Orchard Key Components’, with inputs -> $[\mathtt{0x06}]$, $[\mathtt{0x07}]$, $[\mathtt{0x08}]$, and with -> first byte $\mathtt{0x82}$ (the last of these is also specified in -> [[ZIP-32]](https://zips.z.cash/zip-0032)); -> * in the processes of sending (§ 4.7.2 ‘Sending Notes (Sapling)’ and -> § 4.7.3 ‘Sending Notes (Orchard)’) and of receiving -> (§ 4.20 ‘In-band secret distribution (Sapling and Orchard)’) notes, -> for Sapling with inputs $[\mathtt{0x04}]$ and $[\mathtt{0x05}]$, +> * [**NU5** onward] in § 4.2.3 ‘Orchard Key Components’ [^protocol-orchardkeycomponents], +> with inputs $[\mathtt{0x06}]$, $[\mathtt{0x07}]$, $[\mathtt{0x08}]$, and with +> first byte $\mathtt{0x82}$; +> * in the processes of sending (§ 4.7.2 ‘Sending Notes (Sapling)’ [^protocol-saplingsend] +> and § 4.7.3 ‘Sending Notes (Orchard)’ [^protocol-orchardsend]) and of receiving +> (§ 4.20 ‘In-band secret distribution (Sapling and Orchard)’ [^protocol-saplingandorchardinband]) +> notes, for Sapling with inputs $[\mathtt{0x04}]$ and $[\mathtt{0x05}]$, > and for Orchard $[t] || \underline{\text{ρ}}$ with > $t \in \{ \mathtt{0x05}, \mathtt{0x04}, \mathtt{0x09} \}$; with -> * [**NU5** onward] in § 4.2.3 ‘Orchard Key Components’, with inputs -> $[\mathtt{0x06}]$, $[\mathtt{0x07}]$, $[\mathtt{0x08}]$, with first -> byte in $\{ \mathtt{0x0C}, \mathtt{0x0D} \}$ (also specified in -> {{ reference to this ZIP }}), and with first byte $\mathtt{0x82}$ -> (also specified in [[ZIP-32]](https://zips.z.cash/zip-0032)); -> * in the processes of sending (§ 4.7.2 ‘Sending Notes (Sapling)’ and -> § 4.7.3 ‘Sending Notes (Orchard)’) and of receiving -> (§ 4.20 ‘In-band secret distribution (Sapling and Orchard)’) notes, -> for Sapling with inputs $[\mathtt{0x04}]$ and $[\mathtt{0x05}]$, +> * [**NU5** onward] in § 4.2.3 ‘Orchard Key Components’ [^protocol-orchardkeycomponents], +> with inputs $[\mathtt{0x06}]$, $[\mathtt{0x07}]$, $[\mathtt{0x08}]$, and with +> first byte in $\{ \mathtt{0x0C}, \mathtt{0x0D}, \mathtt{0x82} \}$ +> ($\mathtt{0x0C}$ and $\mathtt{0x0D}$ are also specified in [ZIP 2005]); +> * in the processes of sending (§ 4.7.2 ‘Sending Notes (Sapling)’ [^protocol-saplingsend] +> and § 4.7.3 ‘Sending Notes (Orchard)’ [^protocol-orchardsend]) and of receiving +> (§ 4.20 ‘In-band secret distribution (Sapling and Orchard)’ [^protocol-saplingandorchardinband]) +> notes, for Sapling with inputs $[\mathtt{0x04}]$ and $[\mathtt{0x05}]$, > and for Orchard with first byte in > $\{ \mathtt{0x05}, \mathtt{0x04}, \mathtt{0x09}, \mathtt{0x0A}, \mathtt{0x0B} \}$ > ($\mathtt{0x0A}$ and $\mathtt{0x0B}$ are also specified in From be9b30f153395bc637dfa09f617d7224ba1210df Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood Date: Tue, 17 Feb 2026 11:40:16 +0000 Subject: [PATCH 22/25] Protocol spec: cosmetics. Signed-off-by: Daira-Emma Hopwood --- protocol/protocol.tex | 79 +++++++++++++++++++++++-------------------- 1 file changed, 42 insertions(+), 37 deletions(-) diff --git a/protocol/protocol.tex b/protocol/protocol.tex index fe88e44b..1c438b68 100644 --- a/protocol/protocol.tex +++ b/protocol/protocol.tex @@ -5354,51 +5354,50 @@ \introsection \lsubsubsection{\OrchardText{} Key Components}{orchardkeycomponents} -\vspace{-1ex} Let $\PRFOutputLengthExpand$, $\SpendingKeyLength$, $\OutViewingKeyLength$, $\DiversifierLength$, and $\DiversifierKeyLength$ be as defined in \crossref{constants}. Let $\GroupP$, $\reprP$, $\ellP$, $\ParamP{q}$, and $\ParamP{r}$ be as defined in \crossref{pallasandvesta}. -\vspace{-0.25ex} +\vspace{-0.2ex} Let $\ExtractP$ be as defined in \crossref{concreteextractorpallas}. -\vspace{-0.35ex} +\vspace{-0.3ex} Let $\GroupPHash$ be as defined in \crossref{concretegrouphashpallasandvesta}. -\vspace{-0.25ex} +\vspace{-0.2ex} Let $\PRFexpand{}$ and $\PRFock{Orchard}{}$ be as defined in \crossref{concreteprfs}. -\vspace{-0.5ex} +\vspace{-0.4ex} Let $\DeriveInternalFVKOrchard$ be as defined in \cite[Orchard internal key derivation]{ZIP-32}. -\vspace{-0.25ex} +\vspace{-0.2ex} Let $\PRPd{} \typecolon \DiversifierKeyType \times \DiversifierType \rightarrow \DiversifierType$ be as defined in \crossref{concreteprps}. -\vspace{-0.35ex} +\vspace{-0.3ex} Let $\KA{Orchard}$, instantiated in \crossref{concreteorchardkeyagreement}, be a \keyAgreementScheme. -\vspace{-0.35ex} +\vspace{-0.3ex} Let $\CommitIvk{}$, instantiated in \crossref{concretesinsemillacommit}, be a \commitmentScheme. -\vspace{-0.25ex} +\vspace{-0.2ex} Let $\DiversifyHash{Orchard}$ be as defined in \crossref{concretediversifyhash}. -\vspace{-0.25ex} +\vspace{-0.2ex} Let $\SpendAuthSig{Orchard}$ instantiated in \crossref{concretespendauthsig} be a \rerandomizableSignatureScheme. -\vspace{-0.25ex} +\vspace{-0.2ex} Let $\ItoLEBSP{}$, $\ItoLEOSP{}$, and $\LEOStoIP{}$ be as defined in \crossref{endian}. -\vspace{0.5ex} +\vspace{0.4ex} Define $\ToBase{Orchard}(x \typecolon \PRFOutputExpand) := \LEOStoIPOf{\PRFOutputLengthExpand}{x} \pmod{\ParamP{q}}$. -\vspace{-1.5ex} +\vspace{-1.3ex} Define $\ToScalar{Orchard}(x \typecolon \PRFOutputExpand) := \LEOStoIPOf{\PRFOutputLengthExpand}{x} \pmod{\ParamP{r}}$. Define $\DeriveDkAndOvkOrchard(\CommitIvkRand \typecolon \CommitIvkRandType, \AuthSignPublic \typecolon \AuthSignPublicTypeOrchard, \NullifierKey \typecolon \NullifierKeyTypeOrchard)$ @@ -5458,9 +5457,11 @@ \item let $(\Internal{\DiversifierKey}, \Internal{\OutViewingKey}) = \DeriveDkAndOvkOrchard\big(\Internal{\CommitIvkRand}, \Internal{\AuthSignPublic}, \Internal{\NullifierKey}\big)$. \end{algorithm} +\vspace{-1ex} \introlist \pnote{$\Internal{\AuthSignPublic} = \AuthSignPublic$ and $\Internal{\NullifierKey} = \NullifierKey$.} +\vspace{1ex} As explained in \crossref{addressesandkeys}, \Orchard allows the efficient creation of multiple \diversifiedPaymentAddresses with the same \spendingAuthority. A group of such addresses shares the same \fullViewingKey, \incomingViewingKey, and @@ -5579,9 +5580,9 @@ a sequence of ciphertext components for the encrypted output \notes. \end{itemize} -\introlist The $\ephemeralKey$ and $\encCiphertexts$ fields together form the \notesCiphertextSprout. +\introlist The value $\hSig$ is also computed from $\RandomSeed$, $\nfOld{\allOld}$, and the $\joinSplitPubKey$ of the containing \transaction: \begin{formulae} @@ -5749,9 +5750,11 @@ } %sapling +\vspace{-2ex} \nufive{ \lsubsection{Action Descriptions}{actiondesc} +\vspace{-1ex} An \actionTransfer, as specified in \crossref{actions}, is encoded in \transactions as an \defining{\actionDescription}. Each version 5 \transaction includes a sequence of zero or more \defining{\actionDescriptions}. @@ -5777,45 +5780,47 @@ Let $\Action$ be as defined in \crossref{abstractzk}. -\vspace{1ex} +\vspace{0.5ex} \introsection -An \actionDescription comprises $(\cvNet{}, \rt{Orchard}, \nf, \AuthSignRandomizedPublic, \spendAuthSig, -\cmX, \EphemeralPublic, \TransmitCiphertext{}, \OutCiphertext, \enableSpends, \enableOutputs,$ $\Proof{})$ -where +An \actionDescription comprises $(\cvNet{}\kern-0.2em, \rt{Orchard}\kern-0.2em, \nf, \AuthSignRandomizedPublic, \spendAuthSig, +\cmX\kern-0.1em, \EphemeralPublic, \TransmitCiphertext{}\kern-0.2em, \OutCiphertext\kern-0.2em, \enableSpends, \enableOutputs, \Proof{})$: +\vspace{-1.5ex} \begin{itemize} \item $\cvNet{} \typecolon \ValueCommitOutput{Orchard}$ is the \valueCommitment to the value of the input \note minus the value of the output \note; \vspace{-0.5ex} \item $\rt{Orchard} \typecolon \MerkleHashOrchard$ is an \anchor, as defined in \crossref{transactions}, for the output \treestate of a previous \block; - \vspace{-0.25ex} + \vspace{-0.3ex} \item $\nf \typecolon \range{0}{\ParamP{q}-1}$ is the \nullifier for the input \note; - \vspace{-0.25ex} + \vspace{-0.3ex} \item $\AuthSignRandomizedPublic \typecolon \SpendAuthSigPublic{Orchard}$ is a randomized \validatingKey that should be used to validate $\spendAuthSig$; - \vspace{-0.25ex} + \vspace{-0.3ex} \item $\spendAuthSig \typecolon \SpendAuthSigSignature{Orchard}$ is a \spendAuthSignature, validated as specified in \crossref{spendauthsig}; - \vspace{-0.25ex} + \vspace{-0.3ex} \item $\cmX \typecolon \MerkleHashOrchard$ is the result of applying $\ExtractP$ to the \noteCommitment for the output \note; - \vspace{-0.25ex} + \vspace{-0.3ex} \item $\EphemeralPublic \typecolon \KAPublic{Orchard}$ is a key agreement \publicKey, used to derive the key for encryption of the \noteCiphertextOrchard (\crossref{saplinginband}); - \vspace{-0.25ex} + \vspace{-0.3ex} \item $\TransmitCiphertext{} \typecolon \Ciphertext$ is a ciphertext component for the encrypted output \note; - \vspace{-0.25ex} + \vspace{-0.3ex} \item $\OutCiphertext{} \typecolon \Ciphertext$ is a ciphertext component that allows the holder of the \outgoingCipherKey (which can be derived from a \fullViewingKey) to recover the recipient \diversifiedTransmissionKey $\DiversifiedTransmitPublic$ and the \ephemeralPrivateKey $\EphemeralPrivate$, hence the entire \notePlaintext; + \vspace{-0.15ex} \item $\enableSpends \typecolon \bit$ is a flag that is set in order to enable \nh{non-zero-valued} spends in this Action; + \vspace{-0.15ex} \item $\enableOutputs \typecolon \bit$ is a flag that is set in order to enable \nh{non-zero-valued} outputs in this Action; - \vspace{-0.25ex} + \vspace{-0.3ex} \item $\Proof{} \typecolon \ActionProof$ is a \zkSNARKProof with \primaryInput $(\cv, \rt{Orchard}\kern-0.1em, \nf\kern-0.1em, \AuthSignRandomizedPublic, \cmX, \enableSpends, \enableOutputs)$ for the \actionStatement defined in \crossref{actionstatement}. @@ -5823,10 +5828,9 @@ \vspace{-1.5ex} \pnote{The $\rt{Orchard}$, $\enableSpends$, and $\enableOutputs$ components are the same for all -\actionTransfers in a \transaction. They are encoded once in the \transaction body (see -\crossref{txnencoding}), not in the $\type{ActionDescription}$ structure. -$\Proof{}$ is aggregated with other Action proofs and encoded in the $\proofsOrchard$ field of a -\transaction.} +\actionTransfers in a \transaction, and are encoded once in the \transaction body +(\crossref{txnencoding}), not the $\type{ActionDescription}$ structure. +$\Proof{}$ is aggregated with other Action proofs and encoded in the $\proofsOrchard$ field.} \begin{consensusrules} \vspace{-0.25ex} @@ -5846,7 +5850,7 @@ i.e.\ $\ActionVerify\big(\kern-0.1em(\cv, \rt{Orchard}, \nf, \AuthSignRandomizedPublic, \cmX, \enableSpends, \enableOutputs), \Proof{}\big) = 1$. \end{consensusrules} -\vspace{-1.5ex} +\vspace{-2ex} \begin{nnotes} \vspace{-0.25ex} \item $\cv$ and $\AuthSignRandomizedPublic$ can be the zero point $\ZeroP$. $\EphemeralPublic$ cannot @@ -5858,7 +5862,7 @@ } %nufive -\vspace{-3ex} +\vspace{-2.5ex} \lsubsection{Sending Notes}{send} \vspace{-1ex} @@ -5871,15 +5875,16 @@ \introlist Let $\JoinSplitSig$ be as specified in \crossref{abstractsig}. -\vspace{-0.5ex} +\vspace{-0.6ex} Let $\NoteCommitAlg{Sprout}$ be as specified in \crossref{abstractcommit}. -\vspace{-0.5ex} +\vspace{-0.6ex} Let $\RandomSeedLength$ and $\NoteUniquePreRandLength$ be as specified in \crossref{constants}. Sending a \transaction containing \joinSplitDescriptions involves first generating a new $\JoinSplitSig$ key pair: +\vspace{-0.4ex} \begin{formulae} \item $\joinSplitPrivKey \leftarrowR \JoinSplitSigGenPrivate()$ \item $\joinSplitPubKey := \JoinSplitSigDerivePublic(\joinSplitPrivKey)$. @@ -5904,10 +5909,10 @@ \item Let $\NotePlaintext{i} = (\hexint{00}, \Value_i, \NoteUniqueRand_i, \NoteCommitRand_i, \Memo_i)$. \end{itemize} -\vspace{-1ex} +\vspace{-1.3ex} $\NotePlaintext{\allNew}$ are then encrypted to the recipient \transmissionKeys $\TransmitPublicSub{\allNew}$, giving the \notesCiphertextSprout -$(\EphemeralPublic, \TransmitCiphertext{\allNew})$, as described in \crossref{sproutinband}. +$\big(\EphemeralPublic, \TransmitCiphertext{\allNew}\big)$, as described in \crossref{sproutinband}. In order to minimize information leakage, the sender \SHOULD randomize the order of the input \notes and of the output \notes. Other considerations relating to @@ -5922,7 +5927,7 @@ \item $\joinSplitSig \leftarrowR \JoinSplitSigSign{\text{\small\joinSplitPrivKey}}(\dataToBeSigned)$ \end{formulae} -\vspace{-0.5ex} +\vspace{-1ex} Then the encoded \transaction including $\joinSplitSig$ is submitted to the \peerToPeerNetwork. \canopyonwardpnote{\cite{ZIP-211} specifies that nodes and wallets \MUST disable any facilities From 19cd0ea7e860710d33630e5b701173750c8c7b6e Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood Date: Tue, 17 Feb 2026 11:53:58 +0000 Subject: [PATCH 23/25] ZIP 2005: Explicitly describe changes when the proposal activates at the same time as, or prior to any possible activation of ZSAs. Signed-off-by: Daira-Emma Hopwood --- zips/zip-2005.md | 137 +++++++++++++++++++++++++++++++---------------- 1 file changed, 92 insertions(+), 45 deletions(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index 21d5a673..cfd19454 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -282,6 +282,17 @@ graph BT # Specification +## Usage with Zcash Shielded Assets + +This proposal has been designed to activate either at the same time as, or prior +to any possible activation of ZSAs [^zip-0226] [^zip-0227]. + +Whether or not ZSAs are deployed at the same time, the proposal anticipates that an +$\mathsf{AssetBase}$ field will be added to note plaintexts with lead byte $\mathtt{0x03}$. +This field will be set to the 32-byte constant +$\mathsf{LEBS2OSP}_{\ell_{\mathbb{P}}}​​\big(\mathsf{repr}_{\mathbb{P}​}(\mathcal{V}^{\mathsf{Orchard}})\kern-0.1em\big)$ +as long as ZSAs are not deployed. + ## Usage with FROST When generating Orchard keys for FROST, $\mathsf{ak}$ will be derived jointly @@ -424,10 +435,9 @@ wallet. ## Specification Updates This is written as a set of changes to version 2025.6.2 of the protocol -specification, and to the contents of ZIPs at the time of writing in -October 2025 (as proposed for the NU6.1 upgrade). It will need to be merged -with other changes for v6 transactions (memo bundles [^zip-0231] and -ZSAs [^zip-0226] [^zip-0227]). +specification, and to the contents of ZIPs as of February 2026. It will need +to be merged with other potential changes for v6 transactions (memo bundles +[^zip-0231] and ZSAs [^zip-0226] [^zip-0227]). ### Changes to the Protocol Specification @@ -497,11 +507,6 @@ Add Add $\ell_{\mathsf{qsk}}$ and $\ell_{\mathsf{qk}}$ to the constants obtained from § 5.3 ‘Constants’. -Insert after the definition of $\mathsf{ToScalar^{Orchard}}$: - -> Define $\mathsf{H}^{\mathsf{rivk\_ext}}_{\mathsf{qk}}(\mathsf{ak}, \mathsf{nk}) = \mathsf{ToScalar^{Orchard}}(\mathsf{PRF^{expand}_{qk}}([\mathtt{0x0D}] \,||\, \mathsf{I2LEOSP}_{256}(\mathsf{ak})$ -> $\hspace{23.9em} ||\, \mathsf{I2LEOSP}_{256}(\mathsf{nk})))$. - Replace from "From this spending key" up to and including the line "let $\mathsf{ak} = \mathsf{Extract}_{\mathbb{P}}(\mathsf{ak}^{\mathbb{P}})$" in the algorithm with: @@ -536,6 +541,7 @@ in the algorithm with: > * $\mathsf{H^{rivk}}(\mathsf{sk}) = \mathsf{ToScalar^{Orchard}}\big(\mathsf{PRF^{expand}_{sk}}([\mathtt{0x08}])\kern-0.1em\big)$ > * $\mathsf{H^{qsk}}(\mathsf{sk}) = \mathsf{truncate}_{32}\big(\mathsf{PRF^{expand}_{sk}}([\mathtt{0x0C}])\kern-0.1em\big)$ > * $\mathsf{H^{qk}}(\mathsf{qsk}) = \textsf{BLAKE2s\kern0.1em-256}(\texttt{“Zcash\_qk”}, \mathsf{qsk})$. +> * $\mathsf{H}^{\mathsf{rivk\_ext}}_{\mathsf{qk}}(\mathsf{ak}, \mathsf{nk}) = \mathsf{ToScalar^{Orchard}}\big(\mathsf{PRF^{expand}_{qk}}\big([\mathtt{0x0D}] \,||\, \mathsf{I2LEOSP}_{256}(\mathsf{ak}) \,||\, \mathsf{I2LEOSP}_{256}(\mathsf{nk})\kern-0.1em\big)\kern-0.15em\big)$. > > $\mathsf{ask} \;{\small ⦂}\; \mathbb{F}^{*}_{r_{\mathbb{P}}}$, > the Spend validating key $\mathsf{ak} \;{\small ⦂}\; \{ 1\,..\,q_{\mathbb{P}}-1 \}$, @@ -609,16 +615,25 @@ Replace the lines deriving $\mathsf{rcm}$ and $\mathsf{esk}$ with #### § 4.7.3 ‘Sending Notes (Orchard)’ -Add after the definition of $\mathsf{leadByte}$: +If this proposal is to be deployed without ZSAs, add after the definition of +$\mathsf{leadByte}$: + +> Let $\mathsf{AssetBase} = \mathcal{V}^{\mathsf{Orchard}}$ as defined in +> § 5.4.8.3 ‘Homomorphic Pedersen commitments (Sapling and Orchard)’. + +If it is deployed at the same time as ZSAs, it is assumed that $\mathsf{AssetBase}$ +will have been defined by the ZSA-related changes to § 4.7.3. -> Define $\mathsf{H^{rcm,Orchard}_{rseed}}\big(\mathsf{leadByte}, (\mathsf{g}\star_{\mathsf{d}}, \mathsf{pk}\star_{\mathsf{d}}, \mathsf{v}, \underline{\text{ρ}}, \text{ψ}[, \mathsf{AssetBase}\kern0.08em\star])\kern-0.1em\big) =$ +Add before "For each Action description": + +> Define $\mathsf{H^{rcm,Orchard}_{rseed}}\big(\mathsf{leadByte}, (\mathsf{g}\star_{\mathsf{d}}, \mathsf{pk}\star_{\mathsf{d}}, \mathsf{v}, \underline{\text{ρ}}, \text{ψ}, \mathsf{AssetBase}\kern0.05em\star)\kern-0.1em\big) =$ > $\mathsf{ToScalar^{Orchard}}\big(\mathsf{PRF^{expand}_{rseed}}(\mathsf{pre\_rcm})\kern-0.1em\big)$ > > where $\mathsf{pre\_rcm} = \begin{cases} > [\mathtt{0x05}] \,||\, \underline{\text{ρ}},&\!\!\!\text{if } \mathsf{leadByte} = \mathtt{0x02} \\ > [\mathtt{0x0B}, \mathsf{leadByte}] \,||\, \mathsf{LEBS2OSP}_{256}(\mathsf{g}\star_{\mathsf{d}}) \,||\, \mathsf{LEBS2OSP}_{256}(\mathsf{pk}\star_{\mathsf{d}}) \\ > \hphantom{[\mathtt{0x0B}, \mathsf{leadByte}]} \,||\, \mathsf{I2LEOSP}_{64}(\mathsf{v}) \,||\, \underline{\text{ρ}} \,||\, \mathsf{I2LEOSP}_{256}(\text{ψ}) \\ -> \hphantom{[\mathtt{0x0B}, \mathsf{leadByte}]}\,[\,||\, \mathsf{LEBS2OSP}_{256}(\mathsf{AssetBase}\kern0.08em\star)],&\!\!\!\text{if } \mathsf{leadByte} = \mathtt{0x03} +> \hphantom{[\mathtt{0x0B}, \mathsf{leadByte}]} \,||\, \mathsf{LEBS2OSP}_{256}(\mathsf{AssetBase}\kern0.05em\star),&\!\!\!\text{if } \mathsf{leadByte} = \mathtt{0x03} > \end{cases}$ > > Define $\mathsf{H^{esk,Orchard}_{rseed}}(\underline{\text{ρ}}) = \mathsf{ToScalar^{Orchard}}\big(\mathsf{PRF^{expand}_{rseed}}([\mathtt{0x04}] \,||\, \underline{\text{ρ}})\kern-0.1em\big)$. @@ -629,11 +644,14 @@ Add after the definition of $\mathsf{leadByte}$: > \mathtt{0x0A}&\text{if } \mathsf{split\_flag} = 1\text{.} > \end{cases}$ +If this proposal is to be deployed without ZSAs, replace $\mathsf{split\_domain}$ with +$\mathtt{0x09}$ above and elide its definition. + Insert before the derivation of $\mathsf{esk}$: > Let $\mathsf{g}\star_{\mathsf{d}} = \mathsf{repr}_{\mathbb{P}}(\mathsf{g_d})$, -> $\mathsf{pk}\star_{\mathsf{d}} = \mathsf{repr}_{\mathbb{P}}(\mathsf{pk_d}) [$, -> and $\mathsf{AssetBase}\kern0.08em\star = \mathsf{repr}_{\mathbb{P}}(\mathsf{AssetBase})]$. +> $\mathsf{pk}\star_{\mathsf{d}} = \mathsf{repr}_{\mathbb{P}}(\mathsf{pk_d})$, +> and $\mathsf{AssetBase}\kern0.05em\star = \mathsf{repr}_{\mathbb{P}}(\mathsf{AssetBase})$. and use these in the inputs to $\mathsf{NoteCommit^{Orchard}}$. @@ -642,7 +660,7 @@ with > Derive $\mathsf{esk} = \mathsf{H^{esk,Orchard}_{rseed}}(\underline{\text{ρ}})$ -> Derive $\mathsf{rcm} = \mathsf{H^{rcm,Orchard}_{rseed}}(\mathsf{leadByte}, (\mathsf{g}\star_{\mathsf{d}}, \mathsf{pk}\star_{\mathsf{d}}, \mathsf{v}, \underline{\text{ρ}}, \text{ψ}[, \mathsf{AssetBase}\kern0.08em\star]))$ +> Derive $\mathsf{rcm} = \mathsf{H^{rcm,Orchard}_{rseed}}\big(\mathsf{leadByte}, (\mathsf{g}\star_{\mathsf{d}}, \mathsf{pk}\star_{\mathsf{d}}, \mathsf{v}, \underline{\text{ρ}}, \text{ψ}, \mathsf{AssetBase}\kern0.05em\star)\kern-0.1em\big)$ > Derive $\text{ψ} = \mathsf{H^{\text{ψ},Orchard}_{rseed}}(\underline{\text{ρ}}, \mathsf{split\_flag})$ @@ -659,6 +677,12 @@ Replace the line deriving $\mathsf{rcm}$ with #### § 4.8.3 ‘Dummy Notes (Orchard)’ +If this proposal is to be deployed without ZSAs, add after the definition of +$\mathsf{leadByte}$: + +> Let $\mathsf{AssetBase} = \mathcal{V}^{\mathsf{Orchard}}$ as defined in +> § 5.4.8.3 ‘Homomorphic Pedersen commitments (Sapling and Orchard)’. + Insert before "The spend-related fields ...": > Let $\mathsf{H^{rcm,Orchard}}$ and $\mathsf{H^{\text{ψ},Orchard}}$ be @@ -667,10 +691,10 @@ Insert before "The spend-related fields ...": Replace the lines deriving $\mathsf{rcm}$ and $\text{ψ}$ with > Let $\mathsf{g}\star_{\mathsf{d}} = \mathsf{repr}_{\mathbb{P}}(\mathsf{g_d})$, -> $\mathsf{pk}\star_{\mathsf{d}} = \mathsf{repr}_{\mathbb{P}}(\mathsf{pk_d}) [$, -> and $\mathsf{AssetBase}\kern0.08em\star = \mathsf{repr}_{\mathbb{P}}(\mathsf{AssetBase})]$. +> $\mathsf{pk}\star_{\mathsf{d}} = \mathsf{repr}_{\mathbb{P}}(\mathsf{pk_d})$, +> and $\mathsf{AssetBase}\kern0.05em\star = \mathsf{repr}_{\mathbb{P}}(\mathsf{AssetBase})$. > -> Derive $\mathsf{rcm} = \mathsf{H^{rcm,Orchard}_{rseed}}(\mathsf{leadByte}, (\mathsf{g}\star_{\mathsf{d}}, \mathsf{pk}\star_{\mathsf{d}}, \mathsf{v}, \underline{\text{ρ}}, \text{ψ}[, \mathsf{AssetBase}\kern0.08em\star]))$ +> Derive $\mathsf{rcm} = \mathsf{H^{rcm,Orchard}_{rseed}}\big(\mathsf{leadByte}, (\mathsf{g}\star_{\mathsf{d}}, \mathsf{pk}\star_{\mathsf{d}}, \mathsf{v}, \underline{\text{ρ}}, \text{ψ}, \mathsf{AssetBase}\kern0.05em\star)\kern-0.1em\big)$ > > Derive $\text{ψ} = \mathsf{H^{\text{ψ},Orchard}_{rseed}}(\underline{\text{ρ}}, 0)$ @@ -680,7 +704,16 @@ $\mathsf{NoteCommit^{Orchard}}$. #### § 4.20.2 and § 4.20.3 ‘Decryption using an Incoming/Full Viewing Key (Sapling and Orchard)’ -For both § 4.20.2 and § 4.20.3, add before the decryption procedure: +If this proposal is to be deployed without ZSAs, add after the definition of +$\mathsf{leadByte}$: + +> Let $\mathsf{AssetBase} = \mathcal{V}^{\mathsf{Orchard}}$ as defined in +> § 5.4.8.3 ‘Homomorphic Pedersen commitments (Sapling and Orchard)’. + +If it is deployed at the same time as ZSAs, it is assumed that $\mathsf{AssetBase}$ +will have been defined by the ZSA-related changes to § 4.20.2 and § 4.20.3. + +For both § 4.20.2 and § 4.20.3, add before the decryption procedure: > Let $\mathsf{H^{rcm,Sapling}}$ and $\mathsf{H^{\text{esk},Sapling}}$ > be as defined in § 4.7.2 ‘Sending Notes (Sapling)’. @@ -733,11 +766,11 @@ with > $\hspace{2.5em}$ if $\mathsf{repr}_{\mathbb{G}}(\mathsf{KA.DerivePublic}(\mathsf{esk}, \mathsf{g_d})) \neq \mathtt{ephemeralKey}$, return $\bot$
> > $\hspace{1.0em}$ let $\mathsf{pk_d} = \mathsf{KA.DerivePublic}(\mathsf{ivk}, \mathsf{g_d})$
-> $\hspace{1.0em}$ let $\mathsf{g}\star_{\mathsf{d}} = \mathsf{repr}_{\mathbb{P}}(\mathsf{g_d})$, $\mathsf{pk}\star_{\mathsf{d}} = \mathsf{repr}_{\mathbb{P}}(\mathsf{pk_d}) [$, and $\mathsf{AssetBase}\kern0.08em\star = \mathsf{repr}_{\mathbb{P}}(\mathsf{AssetBase})]$
+> $\hspace{1.0em}$ let $\mathsf{g}\star_{\mathsf{d}} = \mathsf{repr}_{\mathbb{P}}(\mathsf{g_d})$, $\mathsf{pk}\star_{\mathsf{d}} = \mathsf{repr}_{\mathbb{P}}(\mathsf{pk_d})$, and $\mathsf{AssetBase}\kern0.05em\star = \mathsf{repr}_{\mathbb{P}}(\mathsf{AssetBase})$
> $\hspace{1.0em}$ let $\text{ψ} = \mathsf{H^{\text{ψ},Orchard}_{rseed}}(\underline{\text{ρ}}, 0)$ for Orchard or $\bot$ for Sapling
> $\hspace{1.0em}$ let $\mathsf{rcm} = \begin{cases} > \mathsf{LEOS2IP}_{256}(\mathsf{rseed}),&\!\!\!\text{if } \mathsf{leadByte} = \mathtt{0x01} \\ -> \mathsf{H^{rcm,protocol}_{rseed}}(\mathsf{leadByte}, (\mathsf{g}\star_{\mathsf{d}}, \mathsf{pk}\star_{\mathsf{d}}, \mathsf{v}, \underline{\text{ρ}}, \text{ψ}[, \mathsf{AssetBase}\kern0.08em\star])),&\!\!\!\text{otherwise} +> \mathsf{H^{rcm,protocol}_{rseed}}\big(\mathsf{leadByte}, (\mathsf{g}\star_{\mathsf{d}}, \mathsf{pk}\star_{\mathsf{d}}, \mathsf{v}, \underline{\text{ρ}}, \text{ψ}, \mathsf{AssetBase}\kern0.05em\star)\kern-0.1em\big),&\!\!\!\text{otherwise} > \end{cases}$
> $\hspace{1.0em}$ if $\mathsf{rcm} \geq r_{\mathbb{G}}$, return $\bot$ @@ -759,11 +792,11 @@ For § 4.20.3, replace with > $\hspace{1.0em}$ let $\mathsf{g_d} = \mathsf{DiversifyHash}(\mathsf{d})$. if (for Sapling) $\mathsf{g_d} = \bot$, return $\bot$
-> $\hspace{1.0em}$ let $\mathsf{g}\star_{\mathsf{d}} = \mathsf{repr}_{\mathbb{P}}(\mathsf{g_d})$, $\mathsf{pk}\star_{\mathsf{d}} = \mathsf{repr}_{\mathbb{P}}(\mathsf{pk_d}) [$, and $\mathsf{AssetBase}\kern0.08em\star = \mathsf{repr}_{\mathbb{P}}(\mathsf{AssetBase})]$
+> $\hspace{1.0em}$ let $\mathsf{g}\star_{\mathsf{d}} = \mathsf{repr}_{\mathbb{P}}(\mathsf{g_d})$, $\mathsf{pk}\star_{\mathsf{d}} = \mathsf{repr}_{\mathbb{P}}(\mathsf{pk_d})$, and $\mathsf{AssetBase}\kern0.05em\star = \mathsf{repr}_{\mathbb{P}}(\mathsf{AssetBase})$
> $\hspace{1.0em}$ let $\text{ψ} = \mathsf{H^{\text{ψ},Orchard}_{rseed}}(\underline{\text{ρ}}, 0)$ for Orchard or $\bot$ for Sapling
> $\hspace{1.0em}$ let $\mathsf{rcm} = \begin{cases} > \mathsf{LEOS2IP}_{256}(\mathsf{rseed}),&\!\!\!\text{if } \mathsf{leadByte} = \mathtt{0x01} \\ -> \mathsf{H^{rcm,protocol}_{rseed}}(\mathsf{leadByte}, (\mathsf{g}\star_{\mathsf{d}}, \mathsf{pk}\star_{\mathsf{d}}, \mathsf{v}, \underline{\text{ρ}}, \text{ψ}[, \mathsf{AssetBase}\kern0.08em\star])),&\!\!\!\text{otherwise} +> \mathsf{H^{rcm,protocol}_{rseed}}\big(\mathsf{leadByte}, (\mathsf{g}\star_{\mathsf{d}}, \mathsf{pk}\star_{\mathsf{d}}, \mathsf{v}, \underline{\text{ρ}}, \text{ψ}, \mathsf{AssetBase}\kern0.05em\star)\kern-0.1em\big),&\!\!\!\text{otherwise} > \end{cases}$
> $\hspace{1.0em}$ if $\mathsf{rcm} \geq r_{\mathbb{G}}$, return $\bot$ @@ -848,34 +881,36 @@ The proposed Recovery Protocol works, roughly speaking, by enforcing the derivations given in the [Flow diagram for the Orchard and OrchardZSA protocols], and we suggest having that diagram open in another window to refer to it. -Import this definition from § 4.7.3 ‘Sending Notes (Orchard)’: +Import this definition from § 4.2.3 ‘Orchard Key Components’ [^protocol-orchardkeycomponents]: -> Let $\mathsf{leadByte}$ be the note plaintext lead byte, chosen -> according to § 3.2.1 ‘Note Plaintexts and Memo Fields’ with -> $\mathsf{protocol} = \mathsf{Orchard}$. -> -> Define $\mathsf{H^{rcm,Orchard}_{rseed}}\big(\mathsf{leadByte}, (\mathsf{g}\star_{\mathsf{d}}, \mathsf{pk}\star_{\mathsf{d}}, \mathsf{v}, \underline{\text{ρ}}, \text{ψ}[, \mathsf{AssetBase}\kern0.08em\star])\kern-0.1em\big) =$ -> $\mathsf{ToScalar^{Orchard}}\big(\mathsf{PRF^{expand}_{rseed}}(\mathsf{pre\_rcm})\kern-0.1em\big)$ +> Define $\mathsf{H}^{\mathsf{rivk\_ext}}_{\mathsf{qk}}(\mathsf{ak}, \mathsf{nk}) = \mathsf{ToScalar^{Orchard}}\big(\mathsf{PRF^{expand}_{qk}}\big([\mathtt{0x0D}] \,||\, \mathsf{I2LEOSP}_{256}(\mathsf{ak}) \,||\, \mathsf{I2LEOSP}_{256}(\mathsf{nk})\kern-0.1em\big)\kern-0.15em\big)$. + +Import this definition from ZIP 32 [^zip-0032-orchard-internal-key-derivation]: + +> $\mathsf{H^{rivk\_int}_{rivk\_ext}}(\mathsf{ak}, \mathsf{nk}) = \mathsf{ToScalar^{Orchard}}(\mathsf{PRF^{expand}_{rivk\_ext}}([\mathtt{0x83}] \,||\, \mathsf{I2LEOSP}_{256}(\mathsf{ak})$ +> $\hspace{21.58em} ||\, \mathsf{I2LEOSP}_{256}(\mathsf{nk})))$ + +Import these definitions from § 4.7.3 ‘Sending Notes (Orchard)’ [^protocol-orchardsend], specialized to $\mathsf{leadByte} = \mathtt{0x03}$: + +> Define $\mathsf{H^{rcm,Orchard}_{rseed}}\big(\mathsf{leadByte}, (\mathsf{g}\star_{\mathsf{d}}, \mathsf{pk}\star_{\mathsf{d}}, \mathsf{v}, \underline{\text{ρ}}, \text{ψ}, \mathsf{AssetBase}\kern0.05em\star)\kern-0.1em\big) =$ +> $\mathsf{ToScalar^{Orchard}}\big(\mathsf{PRF^{expand}_{rseed}}(\mathsf{pre\_rcm})\kern-0.1em\big)$ > > where $\mathsf{pre\_rcm} = \begin{cases} -> [\mathtt{0x05}] \,||\, \underline{\text{ρ}},&\!\!\!\text{if } \mathsf{leadByte} = \mathtt{0x02} \\ +> \sout{[\mathtt{0x05}] \,||\, \underline{\text{ρ}},}&\!\!\!\sout{\text{if } \mathsf{leadByte} = \mathtt{0x02}} \\ > [\mathtt{0x0B}, \mathsf{leadByte}] \,||\, \mathsf{LEBS2OSP}_{256}(\mathsf{g}\star_{\mathsf{d}}) \,||\, \mathsf{LEBS2OSP}_{256}(\mathsf{pk}\star_{\mathsf{d}}) \\ > \hphantom{[\mathtt{0x0B}, \mathsf{leadByte}]} \,||\, \mathsf{I2LEOSP}_{64}(\mathsf{v}) \,||\, \underline{\text{ρ}} \,||\, \mathsf{I2LEOSP}_{256}(\text{ψ}) \\ -> \hphantom{[\mathtt{0x0B}, \mathsf{leadByte}]}\,[\,||\, \mathsf{LEBS2OSP}_{256}(\mathsf{AssetBase}\kern0.08em\star)],&\!\!\!\text{if } \mathsf{leadByte} = \mathtt{0x03}\text{.} \\ +> \hphantom{[\mathtt{0x0B}, \mathsf{leadByte}]} \,||\, \mathsf{LEBS2OSP}_{256}(\mathsf{AssetBase}\kern0.05em\star),&\!\!\!\text{if } \mathsf{leadByte} = \mathtt{0x03} +> \end{cases}$ +> +> Define $\mathsf{H^{\text{ψ},Orchard}_{rseed}}(\underline{\text{ρ}}, \mathsf{split\_flag}) = \mathsf{ToBase^{Orchard}}\big(\mathsf{PRF^{expand}_{rseed}}([\mathsf{split\_domain}] \,||\, \underline{\text{ρ}})\kern-0.1em\big)$. +> where $\mathsf{split\_domain} = \begin{cases} +> \mathtt{0x09},&\!\!\!\text{if } \mathsf{split\_flag} = 0 \\ +> \mathtt{0x0A},&\!\!\!\text{if } \mathsf{split\_flag} = 1\text{.} > \end{cases}$ -Define: +Import this definition from § 5.4.7.1 ‘Spend Authorization Signature (Sapling and Orchard)’ [^protocol-concretespendauthsig]: -* $\mathsf{H}^{\text{ψ},\mathsf{Orchard}}_{\mathsf{r}\text{ψ}}(\underline{\text{ρ}}, \mathsf{split\_flag}) = \mathsf{ToBase^{Orchard}}(\mathsf{PRF}^{\mathsf{expand}}_{\mathsf{r}\text{ψ}}([\mathsf{split\_domain}] \,||\, \underline{\text{ρ}}))$
- where $\mathsf{split\_domain} = \begin{cases} - \mathtt{0x09},&\!\!\!\text{if } \mathsf{split\_flag} = 0 \\ - \mathtt{0x0A},&\!\!\!\text{if } \mathsf{split\_flag} = 1\text{.} - \end{cases}$ -* $\mathsf{H^{rivk\_int}_{rivk\_ext}}(\mathsf{ak}, \mathsf{nk}) = \mathsf{ToScalar^{Orchard}}(\mathsf{PRF^{expand}_{rivk\_ext}}([\mathtt{0x83}] \,||\, \mathsf{I2LEOSP}_{256}(\mathsf{ak})$ - $\hspace{21.58em} ||\, \mathsf{I2LEOSP}_{256}(\mathsf{nk})))$ -* $\mathsf{H}^{\mathsf{rivk\_ext}}_{\mathsf{qk}}(\mathsf{ak}, \mathsf{nk}) = \mathsf{ToScalar^{Orchard}}(\mathsf{PRF^{expand}_{\rlap{qk}{\hphantom{rivk\_ext}}}}([\mathtt{0x84}] \,||\, \mathsf{I2LEOSP}_{256}(\mathsf{ak})$ - $\hspace{21.58em} ||\, \mathsf{I2LEOSP}_{256}(\mathsf{nk})))$ -* $\mathcal{G}^{\mathsf{Orchard}} = \mathsf{GroupHash}^{\mathbb{P}}(\texttt{“z.cash:Orchard”}, \texttt{“G”})$ +> Define $\mathcal{G}^{\mathsf{Orchard}} = \mathsf{GroupHash}^{\mathbb{P}}(\texttt{“z.cash:Orchard”}, \texttt{“G”})$. A valid instance of a Recovery statement assures that given a primary input: @@ -931,7 +966,7 @@ $\begin{array}{l} \wedge\; \mathsf{ivk} \not\in \{0, \bot\} \\ \wedge\; \text{let } \mathsf{pk_d} = [\mathsf{ivk}]\, \mathsf{g_d} \\ \wedge\; \text{let } \text{ψ} = \mathsf{H}^{\text{ψ}}_{\mathsf{r}\text{ψ}}(\underline{\text{ρ}}, \mathsf{split\_flag}) \\ -\wedge\; \text{let } \mathsf{note\_repr} = \big(\mathsf{repr}_{\mathbb{P}}(\mathsf{g_d}), \mathsf{repr}_{\mathbb{P}}(\mathsf{pk_d}), \mathsf{v}, \underline{\text{ρ}}, \text{ψ}[, \mathsf{AssetBase}\kern0.08em\star]\big) \\ +\wedge\; \text{let } \mathsf{note\_repr} = \big(\mathsf{repr}_{\mathbb{P}}(\mathsf{g_d}), \mathsf{repr}_{\mathbb{P}}(\mathsf{pk_d}), \mathsf{v}, \underline{\text{ρ}}, \text{ψ}, {\mathsf{AssetBase}\kern0.05em\star}\big) \\ \wedge\; \text{let } \mathsf{rcm} = \mathsf{H^{rcm,Orchard}_{rseed}}\big(\mathtt{0x03}, \mathsf{note\_repr}\big) \\ \wedge\; \text{let } \mathsf{cm} = \mathsf{NoteCommit^{Orchard}_{rcm}}(\mathsf{note\_repr}) \\ \wedge\; \mathsf{cm} \neq \bot \\ @@ -1028,7 +1063,7 @@ Balance property. We prefer to fix this without changing $\mathsf{NoteCommit^{Orchard}}$ itself. Instead we change how $\mathsf{rcm}$ is computed to be a hash of $\mathsf{rseed}$ and -$\mathsf{noterepr} = (\mathsf{g}\star_{\mathsf{d}}, \mathsf{pk}\star_{\mathsf{d}}, \mathsf{v}, \underline{\text{ρ}}, \text{ψ}[, \mathsf{AssetBase}\kern0.08em\star])$, +$\mathsf{noterepr} = (\mathsf{g}\star_{\mathsf{d}}, \mathsf{pk}\star_{\mathsf{d}}, \mathsf{v}, \underline{\text{ρ}}, \text{ψ}, \mathsf{AssetBase}\kern0.05em\star)$, as detailed in the [Specification] section. Specifically, when $\mathsf{leadByte} = \mathtt{0x03}$ we have: @@ -1373,10 +1408,22 @@ manipulate the note selection algorithm to some extent. [^protocol-networks]: [Zcash Protocol Specification, Version 2025.6.2 [NU6.1]. Section 3.12: Mainnet and Testnet](protocol/protocol.pdf#networks) +[^protocol-orchardkeycomponents]: [Zcash Protocol Specification, Version 2025.6.2 [NU6.1]. Section 4.2.3: Orchard Key Components](protocol/protocol.pdf#orchardkeycomponents) + +[^protocol-saplingsend]: [Zcash Protocol Specification, Version 2025.6.2 [NU6.1]. Section 4.7.2: Sending Notes (Sapling)](protocol/protocol.pdf#saplingsend) + +[^protocol-orchardsend]: [Zcash Protocol Specification, Version 2025.6.2 [NU6.1]. Section 4.7.3: Sending Notes (Orchard)](protocol/protocol.pdf#orchardsend) + +[^protocol-saplingandorchardinband]: [Zcash Protocol Specification, Version 2025.6.2 [NU6.1]. Section 4.20: In-band secret distribution (Sapling and Orchard)](protocol/protocol.pdf#saplingandorchardinband) + +[^protocol-constants]: [Zcash Protocol Specification, Version 2025.6.2 [NU6.1]. Section 5.3: Constants](protocol/protocol.pdf#constants) + [^protocol-concretesinsemillahash]: [Zcash Protocol Specification, Version 2025.6.2 [NU6.1]. Section 5.4.1.9: Sinsemilla Hash Function](protocol/protocol.pdf#concretesinsemillahash) [^protocol-sinsemillasecurity]: [Zcash Protocol Specification, Version 2025.6.2 [NU6.1]. Section 5.4.1.9: Sinsemilla Hash Function — Security argument](protocol/protocol.pdf#sinsemillasecurity) +[^protocol-concretespendauthsig]: [Zcash Protocol Specification, Version 2025.6.2 [NU6.1]. Section 5.4.7.1: Spend Authorization Signature (Sapling and Orchard)](protocol/protocol.pdf#concretespendauthsig) + [^zip-0032-sapling-child-key-derivation]: [ZIP 32: Shielded Hierarchical Deterministic Wallets — Sapling child key derivation](zip-0032.rst#sapling-child-key-derivation) [^zip-0032-sapling-internal-key-derivation]: [ZIP 32: Shielded Hierarchical Deterministic Wallets — Sapling internal key derivation](zip-0032.rst#sapling-internal-key-derivation) From 3907426c1e0d51c30f8a8c19f88570684a789f5f Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood Date: Tue, 17 Feb 2026 14:05:30 +0000 Subject: [PATCH 24/25] ZIP 2005: cosmetics and referencing. Signed-off-by: Daira-Emma Hopwood --- zips/zip-2005.md | 117 +++++++++++++++++++++++------------------------ 1 file changed, 58 insertions(+), 59 deletions(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index cfd19454..9139d5df 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -25,7 +25,7 @@ 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] +§ 3.12 ‘Mainnet and Testnet’. [^protocol-networks] We use the convention followed in the protocol specification that an $\underline{\mathsf{underlined}}$ variable indicates a byte sequence, @@ -303,7 +303,7 @@ This ZIP further constrains FROST key generation for Orchard as follows: participants MUST privately agree on a value $\mathsf{sk}$, and then use it with $\mathsf{use\_qsk} = \mathsf{true}$ to derive $\mathsf{nk}$, $\mathsf{qsk}$, $\mathsf{qk}$, and (using the $\mathsf{ak}$ output by the DKG protocol) -$\mathsf{rivk\_ext}$, as specified in § 4.2.3 ‘Orchard Key Components’. +$\mathsf{rivk\_ext}$, as specified in § 4.2.3 ‘Orchard Key Components’ [^protocol-orchardkeycomponents]. ```mermaid graph BT @@ -334,7 +334,7 @@ graph BT The protocol MUST ensure that all participants obtain the same values for $\mathsf{ak}$, $\mathsf{nk}$, and $\mathsf{rivk\_ext}$. (Provided that the -participants have followed § 4.2.3, this implies that they have the same +participants have followed § 4.2.3, this implies that they have the same $\mathsf{qsk}$ and $\mathsf{qk}$, by collision resistance of $\mathsf{H^{qk}}$ and $\mathsf{H^{rivk\_ext}}$.) @@ -494,18 +494,17 @@ with > notes, for Sapling with inputs $[\mathtt{0x04}]$ and $[\mathtt{0x05}]$, > and for Orchard with first byte in > $\{ \mathtt{0x05}, \mathtt{0x04}, \mathtt{0x09}, \mathtt{0x0A}, \mathtt{0x0B} \}$ -> ($\mathtt{0x0A}$ and $\mathtt{0x0B}$ are also specified in -> {{ reference to this ZIP }}); +> ($\mathtt{0x0A}$ and $\mathtt{0x0B}$ are also specified in [ZIP 2005]); Add -> * in {{ reference to this ZIP }}, with first byte in +> * in [ZIP 2005], with first byte in > $\{ \mathtt{0x0A}, \mathtt{0x0B}, \mathtt{0x0C}, \mathtt{0x0D} \}$. #### § 4.2.3 ‘Orchard Key Components’ Add $\ell_{\mathsf{qsk}}$ and $\ell_{\mathsf{qk}}$ to the constants obtained -from § 5.3 ‘Constants’. +from § 5.3 ‘Constants’ [^protocol-constants]. Replace from "From this spending key" up to and including the line "let $\mathsf{ak} = \mathsf{Extract}_{\mathbb{P}}(\mathsf{ak}^{\mathbb{P}})$" @@ -516,17 +515,17 @@ in the algorithm with: > directly from $\mathsf{sk}$. However, this might not be the case for > protocols that require distributed generation of shares of $\mathsf{ask}$, > such as FROST's Distributed Key Generation [^zip-0312-key-generation] -> (see {{ reference to the [Usage with FROST] section of this ZIP }} for -> further discussion). To support this we define an alternative derivation -> method using an additional "quantum spending key", $\mathsf{qsk}$, and +> (see [[ZIP 2005, Usage with Frost]](#usagewithfrost) for further +> discussion). To support this we define an alternative derivation method +> using an additional "quantum spending key", $\mathsf{qsk}$, and > "quantum intermediate key", $\mathsf{qk}$. > > There can also be advantages to not deriving $\mathsf{ask}$ directly from > $\mathsf{sk}$ for hardware wallets, in order to separate the authority to > make proofs for the Recovery Protocol from the spend authorization key -> that is kept on the device (see {{ reference to the [Usage with hardware wallets] -> section of this ZIP }}). The derivation from $\mathsf{qsk}$ can also be -> used in that case. +> that is kept on the device (see +> [[ZIP 2005, Usage with hardware wallets]](#usagewithhardwarewallets)). +> The derivation from $\mathsf{qsk}$ can also be used in that case. > > Let $\mathsf{use\_qsk} \;{\small ⦂}\; \mathbb{B}$ be a flag that is set > to true when the derivation from $\mathsf{qsk}$ is used, or false if @@ -577,24 +576,24 @@ Add the following notes: > * If $\mathsf{ask}$, $\mathsf{ak}$, $\mathsf{nk}$, $\mathsf{rivk}$, and > $\mathsf{rivk_{internal}}$ are not generated as specified in this > section, then it may not be possible to recover the resulting notes as -> specified in {{ reference to this ZIP }} in the event that attacks -> using quantum computers become practical. In addition, to recover -> notes it is necessary to retain, or be able to rederive the following -> information. -> * When $\mathsf{use\_qsk}$ is $\mathsf{false}$: the secret key $\mathsf{sk}$. -> This will be the case when $\mathsf{sk}$ is generated according to -> [[ZIP-32]](https://zips.z.cash/zip-0032), and the master seed *or* -> any secret key and chain code above $\mathsf{sk}$ in the derivation -> hierarchy is retained. -> * When $\mathsf{use\_qsk}$ is $\mathsf{true}$: the combination of the -> full viewing key $(\mathsf{ak}, \mathsf{nk}, \mathsf{rivk})$, the -> quantum spending key $\mathsf{qsk}$, and the ability to make spend -> authorization signatures with $\mathsf{ask}$. +> specified in [ZIP 2005] in the event that attacks using quantum computers +> become practical. In addition, to recover notes it is necessary to +> retain, or be able to rederive the following information. > -> When the latter option is used, see {{ reference to the -> [Usage with hardware wallets] section of this ZIP }} for -> recommendations on the storage of, and access to $\mathsf{qsk}$ -> and $\mathsf{qk}$. +> * When $\mathsf{use\_qsk}$ is $\mathsf{false}$: the secret key $\mathsf{sk}$. +> This will be the case when $\mathsf{sk}$ is generated according to +> [[ZIP-32]](https://zips.z.cash/zip-0032), and the master seed *or* +> any secret key and chain code above $\mathsf{sk}$ in the derivation +> hierarchy is retained. +> * When $\mathsf{use\_qsk}$ is $\mathsf{true}$: the combination of the +> full viewing key $(\mathsf{ak}, \mathsf{nk}, \mathsf{rivk})$, the +> quantum spending key $\mathsf{qsk}$, and the ability to make spend +> authorization signatures with $\mathsf{ask}$. +> +> When the latter option is used, see +> [[ZIP 2005, Usage with hardware wallets]](#usagewithhardwarewallets) +> for recommendations on the storage of, and access to $\mathsf{qsk}$ +> and $\mathsf{qk}$. #### § 4.7.2 ‘Sending Notes (Sapling)’ @@ -640,8 +639,8 @@ Add before "For each Action description": > > Define $\mathsf{H^{\text{ψ},Orchard}_{rseed}}(\underline{\text{ρ}}, \mathsf{split\_flag}) = \mathsf{ToBase^{Orchard}}\big(\mathsf{PRF^{expand}_{rseed}}([\mathsf{split\_domain}] \,||\, \underline{\text{ρ}})\kern-0.1em\big)$. > where $\mathsf{split\_domain} = \begin{cases} -> \mathtt{0x09}&\text{if } \mathsf{split\_flag} = 0 \\ -> \mathtt{0x0A}&\text{if } \mathsf{split\_flag} = 1\text{.} +> \mathtt{0x09},&\!\!\!\text{if } \mathsf{split\_flag} = 0 \\ +> \mathtt{0x0A},&\!\!\!\text{if } \mathsf{split\_flag} = 1\text{.} > \end{cases}$ If this proposal is to be deployed without ZSAs, replace $\mathsf{split\_domain}$ with @@ -669,7 +668,7 @@ with Add > Let $\mathsf{H^{rcm,Sapling}}$ be as defined in -> § 4.7.2 ‘Sending Notes (Sapling)’. +> § 4.7.2 ‘Sending Notes (Sapling)’. Replace the line deriving $\mathsf{rcm}$ with @@ -686,7 +685,7 @@ $\mathsf{leadByte}$: Insert before "The spend-related fields ...": > Let $\mathsf{H^{rcm,Orchard}}$ and $\mathsf{H^{\text{ψ},Orchard}}$ be -> as defined in § 4.7.3 ‘Sending Notes (Orchard)’. +> as defined in § 4.7.3 ‘Sending Notes (Orchard)’. Replace the lines deriving $\mathsf{rcm}$ and $\text{ψ}$ with @@ -699,7 +698,7 @@ Replace the lines deriving $\mathsf{rcm}$ and $\text{ψ}$ with > Derive $\text{ψ} = \mathsf{H^{\text{ψ},Orchard}_{rseed}}(\underline{\text{ρ}}, 0)$ and use $\mathsf{g}\star_{\mathsf{d}}$, $\mathsf{pk}\star_{\mathsf{d}}$, -and $\mathsf{AssetBase}\kern0.08em\star$ in the inputs to +and $\mathsf{AssetBase}\kern0.05em\star$ in the inputs to $\mathsf{NoteCommit^{Orchard}}$. #### § 4.20.2 and § 4.20.3 ‘Decryption using an Incoming/Full Viewing Key (Sapling and Orchard)’ @@ -715,14 +714,14 @@ will have been defined by the ZSA-related changes to § 4.20.2 and § 4.20.3. For both § 4.20.2 and § 4.20.3, add before the decryption procedure: -> Let $\mathsf{H^{rcm,Sapling}}$ and $\mathsf{H^{\text{esk},Sapling}}$ -> be as defined in § 4.7.2 ‘Sending Notes (Sapling)’. +> Let $\mathsf{H^{rcm,Sapling}}$ and $\mathsf{H^{esk,Sapling}}$ +> be as defined in § 4.7.2 ‘Sending Notes (Sapling)’. > -> Let $\mathsf{H^{rcm,Orchard}}$, $\mathsf{H^{\text{esk},Orchard}}$, +> Let $\mathsf{H^{rcm,Orchard}}$, $\mathsf{H^{esk,Orchard}}$, > and $\mathsf{H^{\text{ψ},Orchard}}$ be as defined in -> § 4.7.3 ‘Sending Notes (Orchard)’. +> § 4.7.3 ‘Sending Notes (Orchard)’. -For § 4.20.3, replace +For § 4.20.3, replace > $\hspace{1.0em}$ if $\mathsf{esk} \geq r_{\mathbb{G}}$ or $\mathsf{pk_d} = \bot$, return $\bot$ @@ -735,7 +734,7 @@ and in the note containing "However, this is technically redundant with the later check that returns $\bot$ if $\mathsf{pk_d} \not\in \mathbb{J}^{(r)*}$", delete the word "later". -For both § 4.20.2 and § 4.20.3, replace +For both § 4.20.2 and § 4.20.3, replace > $\hspace{1.0em}$ for Sapling, let $\mathsf{pre\_rcm} = [4]$ and $\mathsf{pre\_esk} = [5]$
> $\hspace{1.0em}$ for Orchard, let $\underline{\text{ρ}} = \mathsf{I2LEOSP}_{256}(\mathsf{nf^{old}}$ from the same Action description $\!)$, $\mathsf{pre\_rcm} = [5] \,||\, \underline{\text{ρ}}$, and $\mathsf{pre\_esk} = [4] \,||\, \underline{\text{ρ}}$ @@ -744,17 +743,17 @@ with > $\hspace{1.0em}$ let $\underline{\text{ρ}} = \mathsf{I2LEOSP}_{256}(\mathsf{nf^{old}}$ from the same Action description $\!)$ -For § 4.20.2, replace +For § 4.20.2, replace > $\hspace{1.0em}$ let $\mathsf{rcm} = \begin{cases} > \mathsf{LEOS2IP}_{256}(\mathsf{rseed}),&\!\!\!\text{if } \mathsf{leadByte} = \mathtt{0x01} \\ -> \mathsf{ToScalar}(\mathsf{PRF^{expand}_{rseed}}(\mathsf{pre\_rcm})),&\!\!\!\text{otherwise} +> \mathsf{ToScalar}\big(\mathsf{PRF^{expand}_{rseed}}(\mathsf{pre\_rcm})\kern-0.1em\big),&\!\!\!\text{otherwise} > \end{cases}$
> $\hspace{1.0em}$ if $\mathsf{rcm} \geq r_{\mathbb{G}}$, return $\bot$
> $\hspace{1.0em}$ let $\mathsf{g_d} = \mathsf{DiversifyHash}(\mathsf{d})$. if (for Sapling) $\mathsf{g_d} = \bot$, return $\bot$
> $\hspace{1.0em}$ [**Canopy** onward] if $\mathsf{leadByte} \neq \mathtt{0x01}$:
-> $\hspace{2.5em}$ $\mathsf{esk} = \mathsf{ToScalar^{protocol}}(\mathsf{PRF^{expand}_{rseed}}(\mathsf{pre\_esk}))$
-> $\hspace{2.5em}$ if $\mathsf{repr}_{\mathbb{G}}(\mathsf{KA.DerivePublic}(\mathsf{esk}, \mathsf{g_d})) \neq \mathtt{ephemeralKey}$, return $\bot$ +> $\hspace{2.5em}$ $\mathsf{esk} = \mathsf{ToScalar^{protocol}}\big(\mathsf{PRF^{expand}_{rseed}}(\mathsf{pre\_esk})\kern-0.1em\big)$
+> $\hspace{2.5em}$ if $\mathsf{repr}_{\mathbb{G}}\big(\mathsf{KA.DerivePublic}(\mathsf{esk}, \mathsf{g_d})\kern-0.1em\big) \neq \mathtt{ephemeralKey}$, return $\bot$ > > $\hspace{1.0em}$ let $\mathsf{pk_d} = \mathsf{KA.DerivePublic}(\mathsf{ivk}, \mathsf{g_d})$ @@ -763,7 +762,7 @@ with > $\hspace{1.0em}$ let $\mathsf{g_d} = \mathsf{DiversifyHash}(\mathsf{d})$. if (for Sapling) $\mathsf{g_d} = \bot$, return $\bot$
> $\hspace{1.0em}$ [**Canopy** onward] if $\mathsf{leadByte} \neq \mathtt{0x01}$:
> $\hspace{2.5em}$ let $\mathsf{esk} = \mathsf{H^{esk,protocol}_{rseed}}(\underline{\text{ρ}})$
-> $\hspace{2.5em}$ if $\mathsf{repr}_{\mathbb{G}}(\mathsf{KA.DerivePublic}(\mathsf{esk}, \mathsf{g_d})) \neq \mathtt{ephemeralKey}$, return $\bot$
+> $\hspace{2.5em}$ if $\mathsf{repr}_{\mathbb{G}}\big(\mathsf{KA.DerivePublic}(\mathsf{esk}, \mathsf{g_d})\kern-0.1em\big) \neq \mathtt{ephemeralKey}$, return $\bot$
> > $\hspace{1.0em}$ let $\mathsf{pk_d} = \mathsf{KA.DerivePublic}(\mathsf{ivk}, \mathsf{g_d})$
> $\hspace{1.0em}$ let $\mathsf{g}\star_{\mathsf{d}} = \mathsf{repr}_{\mathbb{P}}(\mathsf{g_d})$, $\mathsf{pk}\star_{\mathsf{d}} = \mathsf{repr}_{\mathbb{P}}(\mathsf{pk_d})$, and $\mathsf{AssetBase}\kern0.05em\star = \mathsf{repr}_{\mathbb{P}}(\mathsf{AssetBase})$
@@ -777,14 +776,14 @@ with The order of operations has to be altered because the derivation of $\mathsf{rcm}$ can depend on $\mathsf{g_d}$ and $\mathsf{pk_d}$. The definitions of $\mathsf{pre\_rcm}$ and $\mathsf{pre\_esk}$ are moved into -§ 4.7.2 ‘Sending Notes (Sapling)’ and § 4.7.3 ‘Sending Notes (Orchard)’ which +§ 4.7.2 ‘Sending Notes (Sapling)’ and § 4.7.3 ‘Sending Notes (Orchard)’ which define $\mathsf{H^{rcm,protocol}}$. -For § 4.20.3, replace +For § 4.20.3, replace > $\hspace{1.0em}$ let $\mathsf{rcm} = \begin{cases} > \mathsf{LEOS2IP}_{256}(\mathsf{rseed}),&\!\!\!\text{if } \mathsf{leadByte} = \mathtt{0x01} \\ -> \mathsf{ToScalar}(\mathsf{PRF^{expand}_{rseed}}(\mathsf{pre\_rcm})),&\!\!\!\text{otherwise} +> \mathsf{ToScalar}\big(\mathsf{PRF^{expand}_{rseed}}(\mathsf{pre\_rcm})\kern-0.1em\big),&\!\!\!\text{otherwise} > \end{cases}$
> $\hspace{1.0em}$ if $\mathsf{rcm} \geq r_{\mathbb{G}}$, return $\bot$
> $\hspace{1.0em}$ let $\mathsf{g_d} = \mathsf{DiversifyHash}(\mathsf{d})$. if (for Sapling) $\mathsf{g_d} = \bot$ or $\mathsf{pk_d} \not\in \mathbb{J}^{(r)*}$ (see note below), return $\bot$ @@ -800,7 +799,7 @@ with > \end{cases}$
> $\hspace{1.0em}$ if $\mathsf{rcm} \geq r_{\mathbb{G}}$, return $\bot$ -and delete "where $\text{ψ} = \mathsf{ToBase^{Orchard}}(\mathsf{PRF^{expand}_{rseed}}([9] \,||\, \underline{\text{ρ}}))$". +and delete "where $\text{ψ} = \mathsf{ToBase^{Orchard}}\big(\mathsf{PRF^{expand}_{rseed}}([9] \,||\, \underline{\text{ρ}})\kern-0.1em\big)$". #### § 5.3 ‘Constants’ @@ -819,12 +818,12 @@ in the diagram in section ‘Orchard internal key derivation’ > $\ast$ The derivations of $\mathsf{ask}$ and $\mathsf{rivk}$ shown in > the diagram are not the only possibility. For further detail see -> § 4.2.3 ‘Orchard Key Components’ in the protocol specification. +> § 4.2.3 ‘Orchard Key Components’ in the protocol specification. > However, if $\mathsf{ask}$, $\mathsf{ak}$, $\mathsf{nk}$, $\mathsf{rivk}$, > and $\mathsf{rivk_{internal}}$ are not generated as in the diagram, then > it may not be possible to recover the resulting notes as specified in -> {{ reference to this ZIP }} in the event that attacks using quantum -> computers become practical. +> [ZIP 2005] in the event that attacks using quantum computers become +> practical. #### ZIP 212 @@ -833,13 +832,13 @@ Add a note before the Abstract:
This ZIP reflects the changes made to note encryption for the Canopy upgrade. -It does not include subsequent changes in {{ reference to this ZIP }}. +It does not include subsequent changes in [ZIP 2005]. #### ZIP 226 Add the following to the section [Note Structure and Commitment](https://zips.z.cash/zip-0226#note-structure-and-commitment): -> When § 4.7.3 ‘Sending Notes (Orchard)’ or § 4.8.3 ‘Dummy Notes (Orchard)’ +> When § 4.7.3 ‘Sending Notes (Orchard)’ or § 4.8.3 ‘Dummy Notes (Orchard)’ > are invoked directly or indirectly in the computation of $\text{ρ}$ and > $\text{ψ}$ for an OrchardZSA note, $\mathsf{leadByte}$ MUST be set to > $\mathtt{0x03}$. @@ -956,7 +955,7 @@ such that the following conditions hold: $\begin{array}{l} \{\;\, \mathsf{use\_qsk} \Rightarrow \big(\;\, \mathsf{rk} = \mathsf{SpendAuthSig^{Orchard}.RandomizePublic}(\alpha, \mathsf{ak}^{\mathbb{P}}) \\ \hspace{6.7em} \wedge\; \mathsf{SoK^{qsk}.Validate}\big((\mathsf{qk}), \mathsf{SigHash}, \sigma_{\mathsf{qsk}}\big) \\ -\hspace{6.7em} \wedge\; \mathsf{rivk\_ext} = \mathsf{H^{rivk\_ext}_qk}(\mathsf{ak}, \mathsf{nk})\,\big) \\ +\hspace{6.7em} \wedge\; \mathsf{rivk\_ext} = \mathsf{H^{rivk\_ext}_{qk}}(\mathsf{ak}, \mathsf{nk})\,\big) \\ \wedge\; \text{not } \mathsf{use\_qsk} \Rightarrow \mathsf{SoK^{sk}.Validate}\big((\mathsf{ak}^{\mathbb{P}}, \mathsf{nk}, \mathsf{rivk\_ext}), \mathsf{SigHash}, \sigma_{\mathsf{sk}}\big) \\ \wedge\; \mathsf{rivk} = \begin{cases} \mathsf{rivk\_ext}&\text{if } \mathsf{is\_rivk\_internal} = 0 \\ @@ -1237,7 +1236,7 @@ choose to attack either): than to search for values of $\mathsf{sk}$ (possibly using a Grover search) to find one that reproduces a given $\mathsf{ivk}$. Since $\mathsf{ivk}$ must be an $x$-coordinate of a Pallas curve point (see the note at the end of - [§ 4.2.3 Orchard Key Components](https://zips.z.cash/protocol/protocol.pdf#orchardkeycomponents)), + [§ 4.2.3 Orchard Key Components](https://zips.z.cash/protocol/protocol.pdf#orchardkeycomponents)), it can take on $(r_{\mathbb{P}}-1)/2$ values. So if there are $T$ targets the success probability for each attempt in a classical search is $2T/(r_{\mathbb{P}}-1)$, which is negligible provided that @@ -1365,7 +1364,7 @@ As far as I'm aware, all existing Zcash wallets already derive $(\mathsf{ak}, \mathsf{nk}, \mathsf{rivk})$ from a spending key $\mathsf{sk}$ in the way specified for the $\mathsf{use\_qsk} = \mathsf{false}$ case in -[§ 4.2.3 Orchard Key Components](https://zips.z.cash/protocol/protocol.pdf#orchardkeycomponents). +§ 4.2.3 ‘Orchard Key Components’ [^protocol-orchardkeycomponents]. FROST distributed key generation requires the $\mathsf{use\_qsk} = \mathsf{true}$ case. There is no significant existing deployment of FROST, so we can @@ -1374,7 +1373,7 @@ from the start. The part of the protocol that is new is the different input for $\mathsf{pre\_rcm}$. It would have been possible to use a separate -pq-binding commitment, but $\mathsf{H^rcm}$ is already pq-binding and so +pq-binding commitment, but $\mathsf{H^{rcm}}$ is already pq-binding and so doing it this way involves fewer components. This also allows us to avoid any security compromise and use 256-bit cryptovalues for both integrity and randomization, which would otherwise have been difficult. From afae7ee45525853c2503a64209c763fe35745b29 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood Date: Tue, 17 Feb 2026 14:05:59 +0000 Subject: [PATCH 25/25] ZIP 2005: Fix typo in case of use_qsk. Signed-off-by: Daira-Emma Hopwood --- zips/zip-2005.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index 9139d5df..0dd466d1 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -1243,7 +1243,7 @@ choose to attack either): $T \ll r_{\mathbb{P}}$. This is also infeasible for a quantum adversary using a Grover search for reasonable values of $T$. -* Case $\mathsf{use\_qsk} = 0$: This case is almost the same except that +* Case $\mathsf{use\_qsk} = 1$: This case is almost the same except that $\mathsf{ivk}$ is now an essentially random function of $(\mathsf{nk}, \mathsf{ak}, \mathsf{qk})$. The success probability in terms of $T$ is also the same as for $\mathsf{use\_qsk} = 0$.