From 7c031bf44718a7dd175272250fa5b770540fcc5c Mon Sep 17 00:00:00 2001 From: teor Date: Wed, 13 Oct 2021 07:09:16 +1000 Subject: [PATCH 001/115] Link the transaction fee definition from the index --- protocol/protocol.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocol/protocol.tex b/protocol/protocol.tex index 313974645..9ae5d3b06 100644 --- a/protocol/protocol.tex +++ b/protocol/protocol.tex @@ -3346,7 +3346,7 @@ \defining{\xTransparentInputs} to a \transaction insert value into a \defining{\transparentTxValuePool} associated with the \transaction, and \defining{\transparentOutputs} remove value from this pool. As in \Bitcoin, the remaining value in the \transparentTxValuePool of a non-coinbase -\transaction is available to miners as a fee. The remaining value in the \transparentTxValuePool +\transaction is available to miners as a \transactionFee. The remaining value in the \transparentTxValuePool of a \coinbaseTransaction is destroyed. \vspace{-1ex} From 76625dbc475dc3aa74cb5228c104833e72a219fa Mon Sep 17 00:00:00 2001 From: teor Date: Thu, 21 Oct 2021 07:09:44 +1000 Subject: [PATCH 002/115] Also add defining to the transaction fee calculation --- protocol/protocol.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocol/protocol.tex b/protocol/protocol.tex index 9ae5d3b06..7582c51f9 100644 --- a/protocol/protocol.tex +++ b/protocol/protocol.tex @@ -3346,7 +3346,7 @@ \defining{\xTransparentInputs} to a \transaction insert value into a \defining{\transparentTxValuePool} associated with the \transaction, and \defining{\transparentOutputs} remove value from this pool. As in \Bitcoin, the remaining value in the \transparentTxValuePool of a non-coinbase -\transaction is available to miners as a \transactionFee. The remaining value in the \transparentTxValuePool +\transaction is available to miners as a \defining{\transactionFee}. The remaining value in the \transparentTxValuePool of a \coinbaseTransaction is destroyed. \vspace{-1ex} From df2015c53fea7a4a502f38261a9ec70e5ef37b82 Mon Sep 17 00:00:00 2001 From: Dev Ojha Date: Tue, 17 Mar 2026 03:15:23 +0800 Subject: [PATCH 003/115] Block time reduction initial commit --- zips/draft-valargroup-blocktime-reduction.md | 585 +++++++++++++++++++ 1 file changed, 585 insertions(+) create mode 100644 zips/draft-valargroup-blocktime-reduction.md diff --git a/zips/draft-valargroup-blocktime-reduction.md b/zips/draft-valargroup-blocktime-reduction.md new file mode 100644 index 000000000..fd7be0bda --- /dev/null +++ b/zips/draft-valargroup-blocktime-reduction.md @@ -0,0 +1,585 @@ + + ZIP: Unassigned + Title: Shorter Block Target Spacing + Owners: ValarDragon + Status: Draft + Category: Consensus + Created: 2026-03-13 + License: MIT + Discussions-To: + + +# Terminology + +The key words "MUST", "MUST NOT", "SHOULD", and "MAY" in this document +are to be interpreted as described in BCP 14 [^BCP14] when, and only +when, they appear in all capitals. + +The terms "block chain", "consensus rule change", "consensus branch", +and "network upgrade" are to be interpreted as defined in ZIP 200. +[^zip-0200] + +The term "block target spacing" means the time interval between blocks +targeted by the difficulty adjustment algorithm in a given consensus +branch. It is normally measured in seconds. (This is also sometimes +called the "target block time", but "block target spacing" is the term +used in the Zcash Protocol Specification [^protocol-diffadjustment].) + +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] + + +# Abstract + +This proposal specifies a change in the block target spacing from 75 +seconds to 25 seconds in NU7, and introduces per-pool action limits for +the Sapling and Orchard shielded protocols. + +This solves three problems. +- Significantly improves the UX for actors who need 1 or 2 conf's. (Near Intents, small payments) The user-latency goes down 3x. +- Increases consensus bandwidth, which amplifies the scaling impact of a future shielded pool which does not require shielded sync. +- Introduces action limits, which short term more than doubles the Orchard TPS (2.9 → 6.1 TPS), while lowering the worst-case sandblast bandwidth on shielded sync by 42% (270.5 → 156.83 MB/day). + +The action limits significantly decrease the number of Sprout and Sapling pool +outputs available per block, to lower the maximum shielded sync burden under +sandblasting. + +The emission schedule of mined ZEC will be the same in terms of ZEC/day, +but this requires the emission per block to be adjusted +to take account of the changed block target spacing. + +# Motivation + +The motivations for decreasing the block target spacing are: + +- **Reduced transaction latency.** Currently, users must wait + 75 seconds on average for even a single confirmation, regardless + of network utilization. This creates friction for point-of-sale + payments, exchange deposits, and cross-chain bridge operations. A + 25-second target spacing reduces the expected wait for a first + confirmation to 25 seconds on average. + +- **Greater throughput.** With 3× as many blocks per day and the same + 2 MB block size limit, we will have proven out higher consensus bandwidth. + Short term, when paired with the action limits, we will more than double the + Orchard TPS for 2-action transactions. Longer term, when we get a shielded pool with no shielded sync burden, we will have 3x higher throughput. + +- **Complementary to finality improvements.** This proposal is + complementary to, and does not compete with, finality mechanisms + such as Crosslink [^crosslink]. Faster block times improve the + responsiveness of the base layer regardless of whether an additional finality + gadget is also deployed. + +The throughput goal on its own could be achieved via a block size increase. +However the main goal of this proposal is to foremost improve the transaction +latency. + +It is estimated that this reduction in blocktime would increase the stale rate from today's 0.4% to 1.3%. For reference, Ethereum operated at 5.4% stale rate. + +Note that, for a given security requirement (in terms of the expected +cost of a rollback attack), the number of confirmations +needed increases more slowly than the decrease in block time. So decreasing the +block target spacing can provide a better trade-off between latency and +security while block validation + propogation times remains small relative to +block time. See [^slowfastblocks] for further analysis in various attack models. +That analysis suggests that this would improve finality times by a factor of at +least 2.9, if you assume the attacker has a fixed percentage of network +hashpower. Whereas if you assume the attack model depends on purely $ cost of +hashpower and block rewards, this reduces the variance of time until sufficient +economic finality. + +However, Zcash uniquely has a second cost on scaling, the shielded sync. In +Zcash, we refer to attacks where an adversary spams the chain as a sandblast +attack. Every shielded transaction induces a bandwidth overhead for every wallet +and an extra trial decryption. Today the worst case sandblast can induce 270.5 +MB of wallet sync download to clients per day, and ~4.8M trial decrypts per +day. We propose introducing action limits in Orchard (306 actions per block), +and (input+output) limits for Sapling (300 per block). With these limits, the +worst case becomes 156.83 MB bandwidth and ~2.1M trial decrypts per day. This +is a 42% improvement in worst case wallet sync bandwidth despite 3x more blocks. +This yields a 2x in Orchard TPS, and keeps Sapling TPS at a higher level than +today's Orchard TPS. + +However, every wallet does have to download every compact block header, which +is 90 bytes. This leads to an extra 200kb of wallet bandwidth per day in +exchange for the improved UX and sandblast attack benefits. + +The reduced Sapling and Sprout per-block limits are justified by the +current distribution of shielded funds across pools. As of March 2026: + +| Pool | Balance | Share of shielded supply | +|------|---------|--------------------------| +| Orchard | 4,511,193 ZEC | ~87.6% | +| Sapling | 616,131 ZEC | ~12.0% | +| Sprout | 25,480 ZEC | ~0.5% | + +The vast majority of shielded activity is already in Orchard, and this +trend is expected to continue. The Sapling and Sprout limits are set +generously relative to their current usage while substantially reducing +their potential for sandblast abuse. + +## Stale block rate + +The stale rate is the percentage of blocks that get orphaned, which relates to +mining centralization risk, block propogation delay, and block verification +times. Today the stale rate is 0.4%, but this may be lower than what pure block +propogation delay may imply due to hashpower centralization in mining pools. + +At 25-second block target spacing, the projected stale (orphan) block +rate is approximately 1.3% using theoretical models, or approximately +3.9% using significantly rounded-up estimates of Zcash network propagation +delays. Both figures are well below Ethereum's historical stale rate of 5.4% +when it operated under proof-of-work. [^forum-proposal] + +(TODO: Refine above numbers and expand on them. The 1.3% is derived from a very straightforward method, of estimating propogation delay using the current uncle +rate and block time as a poisson process. The 3.9% is taken from noticing that current p90 block propogation between EU and US nodes is 700ms, and then +rounding that up to 1s. This needs to be combined with measuring latencies when the blocks are full, yet it is hard to see how this could risk approaching 2s.) + +@evan-forbes is working on experiments to further show the block propogation delay, under different network and hardware configurations. + + +## Block processing time + +A prerequisite for shorter block times is that block validation and +propagation remain small relative to the target spacing. The per-pool +action limits introduced by this proposal ensure that worst-case block +processing time is *lower* per block than today's. The increase in consensus +bandwidth, and Orchard TPS does mean that full node sync will increase in net +time. We accept this trade-off (TODO: be concrete with timing increases, and +remark that more CPU cores fixes this) + +**Current worst case:** A full 2 MB block today can contain up to ~617 +Orchard actions or ~2,090 Sapling outputs, with no per-pool limits. A fully +packed Orchard block requires verifying all action proofs and spend +authorization signatures for those ~617 actions. + +**Proposed worst case:** With the action limits, a block contains at +most 306 Orchard actions or 300 Sapling IOs. This is roughly half the +current Orchard worst case and a fraction of the Sapling worst case. +The per-block verification work is therefore substantially reduced. + +**Batch verification.** Orchard transaction verification benefits from +batch validation, where proof and signature verification is amortized +across multiple transactions. In current node implementations, Orchard +transactions are batch-verified in groups of up to 64 transactions +(each worst case being 2 actions). Zebra has performed batch +verification during live network syncing since version 3.0.0. With the +action limits, a worst-case block's Orchard bundle can be fully +batch-verified in a small number of batches. + +**Estimated timing.** On a typical 4-core machine, worst-case full +block verification (including proof verification for all shielded +components) is estimated at under 500ms second for a block at the +action limits. (TODO: Refine with easily citeable benchmarks) +When transactions have already been pre-verified upon +entering the mempool, which is the typical case for a node that has +been online, block validation reduces to checking signatures and +state updates, which is even cheaper. + + +# Specification + +The changes described in this section are to be made in the Zcash +Protocol Specification [^protocol], relative to the specification as of +the activation of this proposal. + +## Consensus changes + +### Block target spacing + +In § 2 'Notation', add $\mathsf{NU7ActivationHeight}$ +and $\mathsf{PostNU7PoWTargetSpacing}$ to the list of +integer constants. + +In § 5.3 'Constants', define: + +$$\mathsf{PostNU7PoWTargetSpacing} := 25 \text{ seconds}$$ + +For a given network (production or test), define +$\mathsf{NU7ActivationHeight}$ as the height at which +this network upgrade activates on that network, as specified in a +separate deployment ZIP. + +Define: + +$$\mathsf{NU7PoWTargetSpacingRatio} := \mathsf{PostBlossomPoWTargetSpacing} \;/\; \mathsf{PostNU7PoWTargetSpacing} = 3$$ + +Define $\mathsf{IsNU7Activated}(\mathsf{height})$ to +return true if +$\mathsf{height} \geq \mathsf{NU7ActivationHeight}$, +otherwise false. + +In § 7.7.3 'Difficulty adjustment', redefine $\mathsf{PoWTargetSpacing}$ +as: + +$$ +\mathsf{PoWTargetSpacing}(\mathsf{height}) := + \begin{cases} + \mathsf{PreBlossomPoWTargetSpacing}, &\text{if not } \mathsf{IsBlossomActivated}(\mathsf{height}) \\ + \mathsf{PostBlossomPoWTargetSpacing}, &\text{if } \mathsf{IsBlossomActivated}(\mathsf{height}) \text{ and not } \mathsf{IsNU7Activated}(\mathsf{height}) \\ + \mathsf{PostNU7PoWTargetSpacing} &\text{otherwise} + \end{cases} +$$ + +### Halving interval and block subsidy + +Define: + +$$\mathsf{PostNU7HalvingInterval} := \lfloor \mathsf{PostBlossomHalvingInterval} \cdot \mathsf{NU7PoWTargetSpacingRatio} \rfloor = 5{,}040{,}000$$ + +Redefine the $\mathsf{Halving}$ function as: + +$$ +\mathsf{Halving}(\mathsf{height}) := + \begin{cases} + \left\lfloor \dfrac{\mathsf{height} - \mathsf{SlowStartShift}}{\mathsf{PreBlossomHalvingInterval}} \right\rfloor, + &\text{if not } \mathsf{IsBlossomActivated}(\mathsf{height}) \\[1.5ex] + \left\lfloor \dfrac{\mathsf{BlossomActivationHeight} - \mathsf{SlowStartShift}}{\mathsf{PreBlossomHalvingInterval}} + + \dfrac{\mathsf{height} - \mathsf{BlossomActivationHeight}}{\mathsf{PostBlossomHalvingInterval}} \right\rfloor, + &\text{if } \mathsf{IsBlossomActivated}(\mathsf{height}) \text{ and not } \mathsf{IsNU7Activated}(\mathsf{height}) \\[1.5ex] + \left\lfloor \dfrac{\mathsf{BlossomActivationHeight} - \mathsf{SlowStartShift}}{\mathsf{PreBlossomHalvingInterval}} + + \dfrac{\mathsf{NU7ActivationHeight} - \mathsf{BlossomActivationHeight}}{\mathsf{PostBlossomHalvingInterval}} + + \dfrac{\mathsf{height} - \mathsf{NU7ActivationHeight}}{\mathsf{PostNU7HalvingInterval}} \right\rfloor, + &\text{otherwise} + \end{cases} +$$ + +Redefine $\mathsf{BlockSubsidy}$ to add a case for post-activation +heights: + +$$ +\mathsf{BlockSubsidy}(\mathsf{height}) := + \begin{cases} + \ldots &\text{(prior cases unchanged)} \\[1ex] + \left\lfloor \dfrac{\mathsf{MaxBlockSubsidy}}{\mathsf{BlossomPoWTargetSpacingRatio} \cdot \mathsf{NU7PoWTargetSpacingRatio} \cdot 2^{\mathsf{Halving}(\mathsf{height})}} \right\rfloor, + &\text{if } \mathsf{IsNU7Activated}(\mathsf{height}) + \end{cases} +$$ + +This divides the per-block subsidy by an additional factor of 3 relative +to the post-Blossom subsidy, so that the total issuance per unit of wall +clock time remains the same. + +Note: the current post-Blossom block subsidy of 1.5625 ZEC does not +divide evenly by 3. The post-NU7 subsidy is +$\lfloor 156250000 / 6 \rfloor = 26041666$ zatoshi (0.26041666 ZEC), +losing approximately 0.33 zatoshi per block to rounding. Over a full +halving interval of 5,040,000 blocks this amounts to less than 0.017 ZEC +of total underpaid issuance, a negligible amount. Should any of the NSM ZIP's +be accepted, the difference can be credited to the NSM, else it will just be +under-minted from supply. + +### Shielded pool action limits + +Define the following constants in § 5.3 'Constants': + +$$\mathsf{GlobalShieldedBudget} := 306$$ +$$\mathsf{OrchardBlockActionLimit} := 306$$ +$$\mathsf{SaplingBlockIOLimit} := 300$$ +$$\mathsf{SproutBlockJoinSplitLimit} := 25$$ + +For each block at height $\mathsf{height}$ where +$\mathsf{IsNU7Activated}(\mathsf{height})$, the following limits MUST +be satisfied: + +**Per-pool limits:** + +- The total number of Orchard actions across all transactions in the + block MUST NOT exceed $\mathsf{OrchardBlockActionLimit}$. That is, + $\sum_{\mathit{tx} \in \mathit{block}} \mathit{nActionsOrchard}(\mathit{tx}) \leq 306$. + +- The total number of Sapling inputs and outputs across all + transactions in the block MUST NOT exceed + $\mathsf{SaplingBlockIOLimit}$. That is, + $\sum_{\mathit{tx} \in \mathit{block}} (\mathit{nSpendsSapling}(\mathit{tx}) + \mathit{nOutputsSapling}(\mathit{tx})) \leq 300$. + +- The total number of Sprout JoinSplits across all transactions in + the block MUST NOT exceed $\mathsf{SproutBlockJoinSplitLimit}$. That + is, + $\sum_{\mathit{tx} \in \mathit{block}} \mathit{nJoinSplit}(\mathit{tx}) \leq 25$. + +**Global shielded budget:** + +In addition to the per-pool limits, the total shielded cost across all +pools in a block MUST NOT exceed $\mathsf{GlobalShieldedBudget}$. The +shielded cost of a block is defined as: + +$$\sum_{\mathit{tx}} \mathit{nActionsOrchard}(\mathit{tx}) \;+\; \sum_{\mathit{tx}} (\mathit{nSpendsSapling}(\mathit{tx}) + \mathit{nOutputsSapling}(\mathit{tx})) \;+\; 2 \times \sum_{\mathit{tx}} \mathit{nJoinSplit}(\mathit{tx}) \;\leq\; 306$$ + +where the factor of 2 for Sprout JoinSplits reflects that each +JoinSplit produces 2 shielded outputs. + +This global budget ensures that the worst-case shielded sync bandwidth +per block is bounded regardless of which combination of pools is used. +If a block's Orchard actions reach the limit of 306, no Sapling or +Sprout shielded outputs may be included. If both pools are used, their +combined cost must stay within the budget. + +These limits do not apply to the transparent components of +transactions. The overall 2 MB block size limit continues to apply as +before. + +#### Compact sync bandwidth per action + +The limits above are chosen to bound the worst-case bandwidth that +lightweight wallets must download for shielded sync. The compact +representation used for syncing has the following per-note costs: + +**Orchard:** 148 bytes per action, consisting of: + +| Field | Size | +|-------|------| +| cmx (note commitment) | 32 bytes | +| nullifier | 32 bytes | +| ephemeral public key | 32 bytes | +| truncated note plaintext | 52 bytes | +| **Total** | **148 bytes** | + +**Sapling:** 32 bytes per spend (input) and 116 bytes per output, +consisting of: + +| Field | Size | +|-------|------| +| *Per spend:* nullifier | 32 bytes | +| *Per output:* cmu (note commitment) | 32 bytes | +| *Per output:* ephemeral public key | 32 bytes | +| *Per output:* truncated note plaintext | 52 bytes | +| **Per spend total** | **32 bytes** | +| **Per output total** | **116 bytes** | + +With these limits, the worst-case compact sync bandwidth per block is: + +- **Orchard:** $306 \times 148 = 45{,}288$ bytes +- **Sapling:** at most $300 \times 116 = 34{,}800$ bytes (all-output + pathological case) + +Due to the global shielded budget, these cannot stack: a block that +uses 306 Orchard actions has zero budget remaining for Sapling or +Sprout. The worst-case compact sync bandwidth per block is therefore +always bounded by the Orchard case at 45,288 bytes. + +See the [Rationale](#rationale) section for the full daily bandwidth +analysis. + +## Effect on difficulty adjustment + +As with the Blossom activation [^zip-0208], the difficulty adjustment +parameters $\mathsf{PoWAveragingWindow}$ and +$\mathsf{PoWMedianBlockSpan}$ refer to numbers of blocks and do *not* +change at activation. The change in the effective value of +$\mathsf{PoWTargetSpacing}$ will cause the block spacing to adjust to +the new target at the normal rate for a difficulty adjustment. + +It is likely that the difficulty adjustment for the first few blocks +after activation will be limited by $\mathsf{PoWMaxAdjustDown}$. This +is not anticipated to cause any problem. + +## Minimum difficulty blocks on Testnet + +On Testnet, the minimum-difficulty block threshold defined in ZIP 205 +[^zip-0205] and modified by ZIP 208 [^zip-0208] continues to use +$6 \cdot \mathsf{PoWTargetSpacing}(\mathsf{height})$ seconds. +After activation, this threshold becomes $6 \times 25 = 150$ seconds. + +## Non-consensus node behaviour + +### Default expiry delta + +When not overridden by the `-txexpirydelta` option, node +implementations that create transactions use a default expiry delta. +The current default of 40 blocks (approximately 50 minutes at 75-second +spacing) SHOULD change to +$\mathsf{NU7PoWTargetSpacingRatio} \times 40 = 120$ +blocks after activation, to maintain the approximate expiry time of +50 minutes. + +If the `-txexpirydelta` option is set, then the set value SHOULD be +used both before and after activation. + +### Block-count-based constants + +The following constants, measured in number of blocks, were reviewed. +Implementations SHOULD scale these by +$\mathsf{NU7PoWTargetSpacingRatio}$ where they represent +a time duration: + +| Constant | Current | Post-activation | Notes | +|---------------------------------------------|---------|-----------------|-------| +| `COINBASE_MATURITY` | 100 | 100 | No change; security measured in blocks | +| `MAX_REORG_LENGTH` | 99 | 99 | No change; follows `COINBASE_MATURITY` | +| `TX_EXPIRING_SOON_THRESHOLD` | 3 | 3 | No change; | +| `MAX_BLOCKS_IN_TRANSIT_PER_PEER` | 16 | 48 | Scale by 3 | +| `BLOCK_DOWNLOAD_WINDOW` | 1024 | 3072 | Scale by 3 | +| `MIN_BLOCKS_TO_KEEP` | 288 | 864 | Scale by 3; keep 6 hours worth of blocks | +| `NETWORK_UPGRADE_PEER_PREFERENCE_BLOCK_PERIOD` | 1728 | 1728 | No change; | + +### Anchor selection depth + +ZIP 213 [^zip-0213] recommends selecting an anchor 10 blocks back from +the chain tip when constructing shielded transactions. The recommended +anchor depth SHOULD remain at 10 blocks after activation, reducing the +wall-clock anchor delay from ~12.5 minutes to ~4.2 minutes. This +follows the same precedent set by the Blossom upgrade (ZIP 208 +[^zip-0208]), which halved the anchor delay from ~25 minutes to ~12.5 +minutes without changing the 10-block depth. + +| Parameter | Current | Post-activation | Notes | +|-----------|---------|-----------------|-------| +| Recommended anchor depth | 10 blocks (~12.5 min) | 10 blocks (~4.2 min) | No change; follows Blossom precedent | + + +# Rationale + +## Shielded sync bandwidth analysis + +The per-pool block space limits are chosen so that the worst-case daily +bandwidth for lightweight wallet syncing does not increase relative to +the current protocol. This section presents the analysis. + +### Parameters + +| Parameter | Value | +|-----------|-------| +| Block size limit | 2,000,000 bytes | +| Block target spacing | 25 seconds | +| Blocks per day | $ 86{,}400 / 25 = 3{,}456$ | +| Compact block header size | ~90 bytes | + +**Orchard pool:** + +| Parameter | Value | +|-----------|-------| +| $\mathsf{OrchardBlockActionLimit}$ | 306 actions | +| Compact sync bandwidth per action | 148 bytes | +| Compact bandwidth per block | $306 \times 148 = 45{,}288$ bytes | + +**Sapling pool:** + +| Parameter | Value | +|-----------|-------| +| $\mathsf{SaplingBlockIOLimit}$ | 300 (inputs + outputs) | +| Compact sync bandwidth per spend | 32 bytes | +| Compact sync bandwidth per output | 116 bytes | +| Compact bandwidth per block (worst case, all outputs) | $300 \times 116 = 34{,}800$ bytes | + +### Daily bandwidth comparison + +| Metric | Current (75s, no pool limits) | Proposed (25s, action limits) | +|--------|-------------------------------|-------------------------------| +| Blocks per day | 1,152 | 3,456 | +| Max Orchard actions/block | ~617 (block-size limited) | 306 | +| Max Sapling IOs/block | ~2,140 (block-size limited) | 300 | +| Orchard compact BW/day | ~105.2 MB | 156.52 MB | +| Sapling compact BW/day | ~270.38 MB | 120.27 MB | +| Compact block headers/day | ~0.10 MB | 0.31 MB | +| **Worst-case total BW/day** | **~270.5 MB** | **156.83 MB** | +| Worst-case trial decrypts/day | ~4.8M | ~2.1M | + +The worst-case compact sync bandwidth is **156.83 MB/day**, a reduction +of **42%** from today's worst case of approximately 270.5 MB/day. This +is despite a 3× increase in block frequency and overall throughput +capacity. + +The binding constraint is Orchard at 306 actions per block: +$306 \times 148 \times 3{,}456 + 90 \times 3{,}456 = 156.83\text{ MB/day}$. + +The trial decryption count also decreases significantly, since the +per-block action limits more than offset the 3× increase in block count. + +Note that the trial decrypt count is 2× the number of shielded +outputs/actions, because wallets must attempt decryption with both the +internal and external incoming viewing keys (IVKs). The internal IVK +detects change outputs sent back to the wallet, while the external IVK +detects incoming payments. In principle, wallets could avoid trial decrypts +with their IVK assuming other sync trade-offs are taken, but current Sapling and +Orchard wallets always attempt both. + +### Normal transaction throughput + +For standard 2-action Orchard transactions, the action limit of 306 +allows $\lfloor 306 / 2 \rfloor = 153$ transactions per block, giving: + +$$\mathsf{orchard\_tps} = 153 \;/\; 25 = 6.12 \text{ TPS}$$ + +For comparison, the current protocol (75s blocks, block-size limited) +supports approximately 2.9 TPS for 2-action Orchard transactions. This +is a **2.1× increase** in normal Orchard throughput. + +**Sapling throughput.** For standard Sapling transactions (2 spends + 2 +outputs = 4 IOs), the limit of 300 IOs allows $\lfloor 300 / 4 \rfloor += 75$ transactions per block, giving $75 / 25 = 3.0$ TPS. Even with +the reduced Sapling limit, the post-NU7 Sapling TPS (3.0) still +exceeds the current pre-NU7 Orchard TPS (2.9). + +### Fee incentives and sandblast resistance + +A concern with per-pool limits is that a sandblast attacker could fill +the Sapling or Sprout budget to crowd out Orchard transactions (or vice +versa). The global shielded budget prevents this from being worse than +filling any single pool, but it is worth examining whether fee +incentives create an asymmetry. + +Under ZIP 317 [^zip-0317], the conventional fee is based on *logical +actions*: each Sapling output or spend counts as one logical action, and +each Orchard action counts as one logical action. The marginal fee per +logical action is the same regardless of pool. Therefore, an attacker +gains no fee advantage by spamming Sapling instead of Orchard (or vice +versa) — the cost per unit of shielded budget consumed is identical. + +Furthermore, because the global shielded budget is shared, filling +the Sapling budget necessarily reduces the Orchard budget by the same +amount. An attacker who spends their entire budget on Sapling spam at +300 IOs leaves only 6 Orchard actions available in that block. But +this attack is no cheaper than filling 306 Orchard actions directly, +since the per-action fee is the same. The global budget ensures that +the total shielded sync cost per block is bounded to 306 units +regardless of the attacker's pool choice. + +The Orchard per-pool cap of 306 also guarantees that legitimate Orchard +transactions always have access to the full Orchard budget when Sapling +and Sprout are not used, which is the expected common case going +forward. + + +# Deployment + +This proposal is intended to be deployed as part of NU7, should tokenholder polling and developer consensus agree on it. A separate ZIP will specify the deployment details including +activation heights and consensus branch IDs. + + +# 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 or later](protocol/protocol.pdf) + +[^protocol-networks]: [Zcash Protocol Specification, Version 2025.6.3. Section 3.12: Mainnet and Testnet](protocol/protocol.pdf#networks) + +[^protocol-constants]: [Zcash Protocol Specification, Version 2025.6.3. Section 5.3: Constants](protocol/protocol.pdf#constants) + +[^protocol-diffadjustment]: [Zcash Protocol Specification, Version 2025.6.3. Section 7.7.3: Difficulty adjustment](protocol/protocol.pdf#diffadjustment) + +[^protocol-txnencoding]: [Zcash Protocol Specification, Version 2025.6.3. Section 7.1: Transaction Encoding and Consensus](protocol/protocol.pdf#txnencoding) + +[^zip-0200]: [ZIP 200: Network Upgrade Mechanism](zip-0200.rst) + +[^zip-0205]: [ZIP 205: Deployment of the Sapling Network Upgrade](zip-0205.rst) + +[^zip-0206]: [ZIP 206: Deployment of the Blossom Network Upgrade](zip-0206.rst) + +[^zip-0208]: [ZIP 208: Shorter Block Target Spacing](zip-0208.rst) + +[^zip-0213]: [ZIP 213: Shielded Coinbase](zip-0213.rst) + +[^zip-0315]: [ZIP 315: Best Practices for Wallet Implementations](zip-0315.rst) + +[^zip-0317]: [ZIP 317: Proportional Transfer Fee Mechanism](zip-0317.rst) + +[^crosslink]: [Crosslink — a Zcash Finality Protocol](https://electric-coin-company.github.io/zcash-crosslink/) + +[^slowfastblocks]: [On Slow and Fast Block Times](https://blog.ethereum.org/2015/09/14/on-slow-and-fast-block-times/) + +[^forum-proposal]: [Forum: Proposal — Lower Zcash Block Target Spacing to 25s](https://forum.zcashcommunity.com/t/proposal-lower-zcash-block-target-spacing-to-25s/54577) From a566dc0b35493cf2cd2fd3d578218e403b03f7c8 Mon Sep 17 00:00:00 2001 From: Dev Ojha Date: Tue, 17 Mar 2026 18:44:07 +0800 Subject: [PATCH 004/115] Address comments --- zips/draft-valargroup-blocktime-reduction.md | 63 +++++++++++--------- 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/zips/draft-valargroup-blocktime-reduction.md b/zips/draft-valargroup-blocktime-reduction.md index fd7be0bda..21d09550c 100644 --- a/zips/draft-valargroup-blocktime-reduction.md +++ b/zips/draft-valargroup-blocktime-reduction.md @@ -41,11 +41,11 @@ the Sapling and Orchard shielded protocols. This solves three problems. - Significantly improves the UX for actors who need 1 or 2 conf's. (Near Intents, small payments) The user-latency goes down 3x. - Increases consensus bandwidth, which amplifies the scaling impact of a future shielded pool which does not require shielded sync. -- Introduces action limits, which short term more than doubles the Orchard TPS (2.9 → 6.1 TPS), while lowering the worst-case sandblast bandwidth on shielded sync by 42% (270.5 → 156.83 MB/day). +- Introduces action limits, which short term more than doubles the Orchard TPS (2.9 → 6.1 TPS), while lowering the impact a DoS attacker can impose on wallets for shielded sync by 42% (270.5 → 156.83 MB/day). The action limits significantly decrease the number of Sprout and Sapling pool outputs available per block, to lower the maximum shielded sync burden under -sandblasting. +attempted DoS. The emission schedule of mined ZEC will be the same in terms of ZEC/day, but this requires the emission per block to be adjusted @@ -79,47 +79,54 @@ latency. It is estimated that this reduction in blocktime would increase the stale rate from today's 0.4% to 1.3%. For reference, Ethereum operated at 5.4% stale rate. -Note that, for a given security requirement (in terms of the expected -cost of a rollback attack), the number of confirmations -needed increases more slowly than the decrease in block time. So decreasing the -block target spacing can provide a better trade-off between latency and -security while block validation + propogation times remains small relative to -block time. See [^slowfastblocks] for further analysis in various attack models. -That analysis suggests that this would improve finality times by a factor of at -least 2.9, if you assume the attacker has a fixed percentage of network -hashpower. Whereas if you assume the attack model depends on purely $ cost of -hashpower and block rewards, this reduces the variance of time until sufficient -economic finality. - -However, Zcash uniquely has a second cost on scaling, the shielded sync. In -Zcash, we refer to attacks where an adversary spams the chain as a sandblast -attack. Every shielded transaction induces a bandwidth overhead for every wallet -and an extra trial decryption. Today the worst case sandblast can induce 270.5 -MB of wallet sync download to clients per day, and ~4.8M trial decrypts per +There are multiple threat models for rollback attacks. Loosely speaking, +lowering block time while keeping it significantly lower than block propogation +delay helps improve finality time. This is because more honest +miners quickly build on the block, and the block propogation constraint ensures +stale rates have not significantly increased. See [^slowfastblocks] for +analysis in various attack models. As this proposal meets the constraint of +keeping stale rates low, this should under the "X% of hashpower is byzantine" +threat model improve user confirmation times by a factor slightly under 3x. +Under the posts "Economic" threat model, where the user requires the block +rewards built on-top of their payment to exceed the value of the payment, this +significantly improves the variance in confirmation latency. (But makes the +mean latency a bit higher due to stale rate) As noted there, this attack model +is not applied at sizable transactions. Its only potentially applied for small +value ones, where actually the granularity of block times likely lowers time +until sufficient finality. We do not argue for reducing wall-clock block +confirmation counts aside from exisitng 1-2 confirmation users in this ZIP. +However, we do expect many classes of users to be able to wall-clock lower +theirs under consistent threat modelling of what they choose today. + +However, Zcash uniquely has a second cost on scaling, the shielded sync. Every +shielded transaction induces a bandwidth overhead for every wallet +and an extra trial decryption, so we must carefully understand the impact a DOS +attacker can cause. Today the worst case DOS attack can induce 270.5 +MB of wallet sync download to clients per day, and 4.8M trial decrypts per day. We propose introducing action limits in Orchard (306 actions per block), and (input+output) limits for Sapling (300 per block). With these limits, the -worst case becomes 156.83 MB bandwidth and ~2.1M trial decrypts per day. This +worst case becomes 156.83 MB bandwidth and 2.1M trial decrypts per day. This is a 42% improvement in worst case wallet sync bandwidth despite 3x more blocks. This yields a 2x in Orchard TPS, and keeps Sapling TPS at a higher level than today's Orchard TPS. However, every wallet does have to download every compact block header, which is 90 bytes. This leads to an extra 200kb of wallet bandwidth per day in -exchange for the improved UX and sandblast attack benefits. +exchange for the improved UX. The reduced Sapling and Sprout per-block limits are justified by the current distribution of shielded funds across pools. As of March 2026: | Pool | Balance | Share of shielded supply | |------|---------|--------------------------| -| Orchard | 4,511,193 ZEC | ~87.6% | -| Sapling | 616,131 ZEC | ~12.0% | -| Sprout | 25,480 ZEC | ~0.5% | +| Orchard | 4,511,193 ZEC | 87.5% | +| Sapling | 616,131 ZEC | 12.0% | +| Sprout | 25,480 ZEC | 0.5% | The vast majority of shielded activity is already in Orchard, and this trend is expected to continue. The Sapling and Sprout limits are set generously relative to their current usage while substantially reducing -their potential for sandblast abuse. +their potential for DOS abuse. ## Stale block rate @@ -514,9 +521,9 @@ outputs = 4 IOs), the limit of 300 IOs allows $\lfloor 300 / 4 \rfloor the reduced Sapling limit, the post-NU7 Sapling TPS (3.0) still exceeds the current pre-NU7 Orchard TPS (2.9). -### Fee incentives and sandblast resistance +### Fee incentives and DoS resistance -A concern with per-pool limits is that a sandblast attacker could fill +A concern with per-pool limits is that a DoS attacker could fill the Sapling or Sprout budget to crowd out Orchard transactions (or vice versa). The global shielded budget prevents this from being worse than filling any single pool, but it is worth examining whether fee @@ -527,7 +534,7 @@ actions*: each Sapling output or spend counts as one logical action, and each Orchard action counts as one logical action. The marginal fee per logical action is the same regardless of pool. Therefore, an attacker gains no fee advantage by spamming Sapling instead of Orchard (or vice -versa) — the cost per unit of shielded budget consumed is identical. +versa). The cost per unit of shielded budget consumed is identical. Furthermore, because the global shielded budget is shared, filling the Sapling budget necessarily reduces the Orchard budget by the same From 49ce53d2307770e93e453f7f387f4406e9cac4c7 Mon Sep 17 00:00:00 2001 From: Dev Ojha Date: Tue, 17 Mar 2026 18:47:51 +0800 Subject: [PATCH 005/115] typo fix --- zips/draft-valargroup-blocktime-reduction.md | 23 ++++++++++---------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/zips/draft-valargroup-blocktime-reduction.md b/zips/draft-valargroup-blocktime-reduction.md index 21d09550c..3940c56c9 100644 --- a/zips/draft-valargroup-blocktime-reduction.md +++ b/zips/draft-valargroup-blocktime-reduction.md @@ -63,9 +63,10 @@ The motivations for decreasing the block target spacing are: confirmation to 25 seconds on average. - **Greater throughput.** With 3× as many blocks per day and the same - 2 MB block size limit, we will have proven out higher consensus bandwidth. - Short term, when paired with the action limits, we will more than double the - Orchard TPS for 2-action transactions. Longer term, when we get a shielded pool with no shielded sync burden, we will have 3x higher throughput. + 2 MB block size limit, we will have allocated higher consensus bandwidth + capacity. Short term, when paired with the action limits, we will more than + double the Orchard TPS for 2-action transactions. Longer term, when we get a + shielded pool with no shielded sync burden, we will have 3x higher throughput. - **Complementary to finality improvements.** This proposal is complementary to, and does not compete with, finality mechanisms @@ -80,9 +81,9 @@ latency. It is estimated that this reduction in blocktime would increase the stale rate from today's 0.4% to 1.3%. For reference, Ethereum operated at 5.4% stale rate. There are multiple threat models for rollback attacks. Loosely speaking, -lowering block time while keeping it significantly lower than block propogation +lowering block time while keeping it significantly lower than block propagation delay helps improve finality time. This is because more honest -miners quickly build on the block, and the block propogation constraint ensures +miners quickly build on the block, and the block propagation constraint ensures stale rates have not significantly increased. See [^slowfastblocks] for analysis in various attack models. As this proposal meets the constraint of keeping stale rates low, this should under the "X% of hashpower is byzantine" @@ -131,9 +132,9 @@ their potential for DOS abuse. ## Stale block rate The stale rate is the percentage of blocks that get orphaned, which relates to -mining centralization risk, block propogation delay, and block verification +mining centralization risk, block propagation delay, and block verification times. Today the stale rate is 0.4%, but this may be lower than what pure block -propogation delay may imply due to hashpower centralization in mining pools. +propagation delay may imply due to hashpower centralization in mining pools. At 25-second block target spacing, the projected stale (orphan) block rate is approximately 1.3% using theoretical models, or approximately @@ -141,11 +142,11 @@ rate is approximately 1.3% using theoretical models, or approximately delays. Both figures are well below Ethereum's historical stale rate of 5.4% when it operated under proof-of-work. [^forum-proposal] -(TODO: Refine above numbers and expand on them. The 1.3% is derived from a very straightforward method, of estimating propogation delay using the current uncle -rate and block time as a poisson process. The 3.9% is taken from noticing that current p90 block propogation between EU and US nodes is 700ms, and then +(TODO: Refine above numbers and expand on them. The 1.3% is derived from a very straightforward method, of estimating propagation delay using the current uncle +rate and block time as a poisson process. The 3.9% is taken from noticing that current p90 block propagation between EU and US nodes is 700ms, and then rounding that up to 1s. This needs to be combined with measuring latencies when the blocks are full, yet it is hard to see how this could risk approaching 2s.) -@evan-forbes is working on experiments to further show the block propogation delay, under different network and hardware configurations. +@evan-forbes is working on experiments to further show the block propagation delay, under different network and hardware configurations. ## Block processing time @@ -179,7 +180,7 @@ batch-verified in a small number of batches. **Estimated timing.** On a typical 4-core machine, worst-case full block verification (including proof verification for all shielded -components) is estimated at under 500ms second for a block at the +components) is estimated at under 500ms for a block at the action limits. (TODO: Refine with easily citeable benchmarks) When transactions have already been pre-verified upon entering the mempool, which is the typical case for a node that has From 654b942722d48eb251608558557a3b105b231f6c Mon Sep 17 00:00:00 2001 From: Dev Ojha Date: Tue, 17 Mar 2026 18:48:23 +0800 Subject: [PATCH 006/115] Apply suggestions from code review Co-authored-by: Kris Nuttycombe --- zips/draft-valargroup-blocktime-reduction.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/zips/draft-valargroup-blocktime-reduction.md b/zips/draft-valargroup-blocktime-reduction.md index 3940c56c9..e6faeac92 100644 --- a/zips/draft-valargroup-blocktime-reduction.md +++ b/zips/draft-valargroup-blocktime-reduction.md @@ -226,8 +226,8 @@ as: $$ \mathsf{PoWTargetSpacing}(\mathsf{height}) := \begin{cases} - \mathsf{PreBlossomPoWTargetSpacing}, &\text{if not } \mathsf{IsBlossomActivated}(\mathsf{height}) \\ - \mathsf{PostBlossomPoWTargetSpacing}, &\text{if } \mathsf{IsBlossomActivated}(\mathsf{height}) \text{ and not } \mathsf{IsNU7Activated}(\mathsf{height}) \\ + \mathsf{PreBlossomPoWTargetSpacing}, &\text{if not } \mathsf{IsBlossomActivated}(\mathsf{height}) \\\\ + \mathsf{PostBlossomPoWTargetSpacing}, &\text{if } \mathsf{IsBlossomActivated}(\mathsf{height}) \text{ and not } \mathsf{IsNU7Activated}(\mathsf{height}) \\\\ \mathsf{PostNU7PoWTargetSpacing} &\text{otherwise} \end{cases} $$ @@ -244,10 +244,10 @@ $$ \mathsf{Halving}(\mathsf{height}) := \begin{cases} \left\lfloor \dfrac{\mathsf{height} - \mathsf{SlowStartShift}}{\mathsf{PreBlossomHalvingInterval}} \right\rfloor, - &\text{if not } \mathsf{IsBlossomActivated}(\mathsf{height}) \\[1.5ex] + &\text{if not } \mathsf{IsBlossomActivated}(\mathsf{height}) \\\\[1.5ex] \left\lfloor \dfrac{\mathsf{BlossomActivationHeight} - \mathsf{SlowStartShift}}{\mathsf{PreBlossomHalvingInterval}} + \dfrac{\mathsf{height} - \mathsf{BlossomActivationHeight}}{\mathsf{PostBlossomHalvingInterval}} \right\rfloor, - &\text{if } \mathsf{IsBlossomActivated}(\mathsf{height}) \text{ and not } \mathsf{IsNU7Activated}(\mathsf{height}) \\[1.5ex] + &\text{if } \mathsf{IsBlossomActivated}(\mathsf{height}) \text{ and not } \mathsf{IsNU7Activated}(\mathsf{height}) \\\\[1.5ex] \left\lfloor \dfrac{\mathsf{BlossomActivationHeight} - \mathsf{SlowStartShift}}{\mathsf{PreBlossomHalvingInterval}} + \dfrac{\mathsf{NU7ActivationHeight} - \mathsf{BlossomActivationHeight}}{\mathsf{PostBlossomHalvingInterval}} + \dfrac{\mathsf{height} - \mathsf{NU7ActivationHeight}}{\mathsf{PostNU7HalvingInterval}} \right\rfloor, From b019747ad64e009b943ea3433890e70dcb6514ad Mon Sep 17 00:00:00 2001 From: Dev Ojha Date: Fri, 20 Mar 2026 18:01:23 +0800 Subject: [PATCH 007/115] Update zips/draft-valargroup-blocktime-reduction.md Co-authored-by: Kris Nuttycombe --- zips/draft-valargroup-blocktime-reduction.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zips/draft-valargroup-blocktime-reduction.md b/zips/draft-valargroup-blocktime-reduction.md index e6faeac92..8781258aa 100644 --- a/zips/draft-valargroup-blocktime-reduction.md +++ b/zips/draft-valargroup-blocktime-reduction.md @@ -261,7 +261,7 @@ heights: $$ \mathsf{BlockSubsidy}(\mathsf{height}) := \begin{cases} - \ldots &\text{(prior cases unchanged)} \\[1ex] + \ldots &\text{(prior cases unchanged)} \\\\[1ex] \left\lfloor \dfrac{\mathsf{MaxBlockSubsidy}}{\mathsf{BlossomPoWTargetSpacingRatio} \cdot \mathsf{NU7PoWTargetSpacingRatio} \cdot 2^{\mathsf{Halving}(\mathsf{height})}} \right\rfloor, &\text{if } \mathsf{IsNU7Activated}(\mathsf{height}) \end{cases} From c741bb80dda28708401c9d1ea82dad947e0ed357 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Mar 2026 16:56:24 +0000 Subject: [PATCH 008/115] Bump DeterminateSystems/nix-installer-action from 21 to 22 Bumps [DeterminateSystems/nix-installer-action](https://github.com/determinatesystems/nix-installer-action) from 21 to 22. - [Release notes](https://github.com/determinatesystems/nix-installer-action/releases) - [Commits](https://github.com/determinatesystems/nix-installer-action/compare/c5a866b6ab867e88becbed4467b93592bce69f8a...ef8a148080ab6020fd15196c2084a2eea5ff2d25) --- updated-dependencies: - dependency-name: DeterminateSystems/nix-installer-action dependency-version: '22' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/render.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/render.yml b/.github/workflows/render.yml index 10546138e..adb4b3901 100644 --- a/.github/workflows/render.yml +++ b/.github/workflows/render.yml @@ -19,7 +19,7 @@ jobs: if [ -e base_ref ]; then exit 1; fi - name: Install Nix - uses: DeterminateSystems/nix-installer-action@c5a866b6ab867e88becbed4467b93592bce69f8a # v21 + uses: DeterminateSystems/nix-installer-action@ef8a148080ab6020fd15196c2084a2eea5ff2d25 # v22 - name: Restore Nix store cache id: nix-cache From a5c33abba2d78d5d3d1acadedc1879b6d3311167 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood Date: Thu, 2 Apr 2026 13:19:04 +0100 Subject: [PATCH 009/115] render.sh: correct usage string; avoid a spurious warning for 0 arguments. Signed-off-by: Daira-Emma Hopwood --- render.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/render.sh b/render.sh index 045e9e7b5..e499e0990 100755 --- a/render.sh +++ b/render.sh @@ -5,9 +5,9 @@ set -euo pipefail -if ! ( ( [ "x$1" = "x--rst" ] || [ "x$1" = "x--pandoc" ] || [ "x$1" = "x--mmd" ] ) && [ $# -eq 3 ] ); then +if ! ( [ $# -eq 3 ] && ( [ "x$1" = "x--rst" ] || [ "x$1" = "x--pandoc" ] || [ "x$1" = "x--mmd" ] ) ); then cat - < +Usage: render.sh --rst|--pandoc|--mmd <inputfile> <htmlfile> --rst render reStructuredText using rst2html5 --pandoc render Markdown using pandoc From 83e459ecf08a86c75afaaf1219674c2bb4e8e4d5 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Thu, 2 Apr 2026 13:19:19 +0100 Subject: [PATCH 010/115] Re-render `README.rst`. Signed-off-by: Daira-Emma Hopwood <daira@jacaranda.org> --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index f26255a5c..e59378eec 100644 --- a/README.rst +++ b/README.rst @@ -134,7 +134,7 @@ Released ZIPs <tr> <td>300</td> <td class="left"><a href="zips/zip-0300.rst">Cross-chain Atomic Transactions</a></td> <td>Proposed</td> <tr> <td>301</td> <td class="left"><a href="zips/zip-0301.rst">Zcash Stratum Protocol</a></td> <td>Active</td> <tr> <td>308</td> <td class="left"><a href="zips/zip-0308.rst">Sprout to Sapling Migration</a></td> <td>Active</td> - <tr> <td>316</td> <td class="left"><a href="zips/zip-0316.rst">Unified Addresses and Unified Viewing Keys</a></td> <td>[Revision 0] Active, [Revision 1] Proposed</td> + <tr> <td>316</td> <td class="left"><a href="zips/zip-0316.rst">Unified Addresses and Unified Viewing Keys</a></td> <td>[Revision 0] Active, [Revision 1] Withdrawn, [Revision 2] Draft</td> <tr> <td>317</td> <td class="left"><a href="zips/zip-0317.rst">Proportional Transfer Fee Mechanism</a></td> <td>Active</td> <tr> <td>320</td> <td class="left"><a href="zips/zip-0320.rst">Defining an Address Type to which funds can only be sent from Transparent Addresses</a></td> <td>Active</td> <tr> <td>321</td> <td class="left"><a href="zips/zip-0321.rst">Payment Request URIs</a></td> <td>Active</td> @@ -350,7 +350,7 @@ Index of ZIPs <tr> <td><strike>313</strike></td> <td class="left"><strike><a href="zips/zip-0313.rst">Reduce Conventional Transaction Fee to 1000 zatoshis</a></strike></td> <td>Obsolete</td> <tr> <td><span class="reserved">314</span></td> <td class="left"><a class="reserved" href="zips/zip-0314.rst">Privacy upgrades to the Zcash light client protocol</a></td> <td>Reserved</td> <tr> <td>315</td> <td class="left"><a href="zips/zip-0315.rst">Best Practices for Wallet Implementations</a></td> <td>Draft</td> - <tr> <td>316</td> <td class="left"><a href="zips/zip-0316.rst">Unified Addresses and Unified Viewing Keys</a></td> <td>[Revision 0] Active, [Revision 1] Proposed</td> + <tr> <td>316</td> <td class="left"><a href="zips/zip-0316.rst">Unified Addresses and Unified Viewing Keys</a></td> <td>[Revision 0] Active, [Revision 1] Withdrawn, [Revision 2] Draft</td> <tr> <td>317</td> <td class="left"><a href="zips/zip-0317.rst">Proportional Transfer Fee Mechanism</a></td> <td>Active</td> <tr> <td><span class="reserved">318</span></td> <td class="left"><a class="reserved" href="zips/zip-0318.rst">Associated Payload Encryption</a></td> <td>Reserved</td> <tr> <td><span class="reserved">319</span></td> <td class="left"><a class="reserved" href="zips/zip-0319.rst">Options for Shielded Pool Retirement</a></td> <td>Reserved</td> From 2faba0eb72a72e6f93603dc04036f459a0887011 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Tue, 7 Apr 2026 23:10:02 +0100 Subject: [PATCH 011/115] Fix syntax error in dependency check status workflow Missing closing paren on the `if` condition caused the github-script step to fail to parse, so the 'Dependency check result' status was never posted. Introduced in #1237. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --- .github/workflows/report_updatecheck.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/report_updatecheck.yml b/.github/workflows/report_updatecheck.yml index 60b3a6d2d..e6feee81c 100644 --- a/.github/workflows/report_updatecheck.yml +++ b/.github/workflows/report_updatecheck.yml @@ -27,7 +27,7 @@ jobs: run_id: runId, }); - if (artifacts.data.artifacts.some(a => a.name === 'neutral-signal') { + if (artifacts.data.artifacts.some(a => a.name === 'neutral-signal')) { conclusion = 'neutral'; title = 'Dependencies are correct but not up-to-date'; } else { From 84f324b13bc894a95b3520c8cc96e14c3a668365 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Apr 2026 15:22:38 +0000 Subject: [PATCH 012/115] Bump actions/github-script from 8 to 9 Bumps [actions/github-script](https://github.com/actions/github-script) from 8 to 9. - [Release notes](https://github.com/actions/github-script/releases) - [Commits](https://github.com/actions/github-script/compare/v8...v9) --- updated-dependencies: - dependency-name: actions/github-script dependency-version: '9' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> --- .github/workflows/report_updatecheck.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/report_updatecheck.yml b/.github/workflows/report_updatecheck.yml index e6feee81c..b03435115 100644 --- a/.github/workflows/report_updatecheck.yml +++ b/.github/workflows/report_updatecheck.yml @@ -12,7 +12,7 @@ jobs: post_status: runs-on: ubuntu-latest steps: - - uses: actions/github-script@v8 + - uses: actions/github-script@v9 with: script: | const runId = context.payload.workflow_run.id; From 9973910c152b360800cf733f044be3ae0db13bf6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Apr 2026 16:42:15 +0000 Subject: [PATCH 013/115] Bump actions/create-github-app-token from 3.0.0 to 3.1.1 Bumps [actions/create-github-app-token](https://github.com/actions/create-github-app-token) from 3.0.0 to 3.1.1. - [Release notes](https://github.com/actions/create-github-app-token/releases) - [Commits](https://github.com/actions/create-github-app-token/compare/f8d387b68d61c58ab83c6c016672934102569859...1b10c78c7865c340bc4f6099eb2f838309f1e8c3) --- updated-dependencies: - dependency-name: actions/create-github-app-token dependency-version: 3.1.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> --- .github/workflows/publish.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index b32f858d5..df53b6cb6 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -27,7 +27,7 @@ jobs: steps: - name: Generate app token id: app-token - uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 # v3.0.0 + uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1 with: app-id: ${{ secrets.APP_ID }} private-key: ${{ secrets.APP_PRIVATE_KEY }} From 74cda21d2dfa38f71178881da46ca3f14944fef1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Apr 2026 16:42:20 +0000 Subject: [PATCH 014/115] Bump actions/cache from 5.0.4 to 5.0.5 Bumps [actions/cache](https://github.com/actions/cache) from 5.0.4 to 5.0.5. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/668228422ae6a00e4ad889ee87cd7109ec5666a7...27d5ce7f107fe9357f9df03efb73ab90386fccae) --- updated-dependencies: - dependency-name: actions/cache dependency-version: 5.0.5 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> --- .github/workflows/render.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/render.yml b/.github/workflows/render.yml index 10546138e..77b51fc98 100644 --- a/.github/workflows/render.yml +++ b/.github/workflows/render.yml @@ -23,7 +23,7 @@ jobs: - name: Restore Nix store cache id: nix-cache - uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 + uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 with: path: /tmp/nix-closure key: nix-devshell-${{ runner.os }}-${{ hashFiles('flake.lock', 'flake.nix') }} From 1854c46f5ec2f017cb73c4c6a5b60ce3e479d884 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Apr 2026 16:42:25 +0000 Subject: [PATCH 015/115] Bump actions/upload-pages-artifact from 4.0.0 to 5.0.0 Bumps [actions/upload-pages-artifact](https://github.com/actions/upload-pages-artifact) from 4.0.0 to 5.0.0. - [Release notes](https://github.com/actions/upload-pages-artifact/releases) - [Commits](https://github.com/actions/upload-pages-artifact/compare/7b1f4a764d45c48632c6b24a0339c27f5614fb0b...fc324d3547104276b827a68afc52ff2a11cc49c9) --- updated-dependencies: - dependency-name: actions/upload-pages-artifact dependency-version: 5.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> --- .github/workflows/publish.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index b32f858d5..feea5eae8 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -78,7 +78,7 @@ jobs: default_author: github_actions - name: Upload artifact - uses: actions/upload-pages-artifact@7b1f4a764d45c48632c6b24a0339c27f5614fb0b # v4 + uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0 with: path: 'rendered' From 39a2828c50ef7782dea2231c1c54b085662879bb Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe <kris@nutty.land> Date: Fri, 17 Apr 2026 17:09:58 -0600 Subject: [PATCH 016/115] Fix rendering errors in zip-0316.rst Fix malformed `Revision 1` hyperlink target that broke the reference from the Changelog section, convert a Markdown-style link in the Revisions list to RST syntax, remove duplicate explicit targets that conflicted with section-implicit targets, and switch single backticks (rendered as `<cite>`) to double backticks (rendered as `<code>`) for consistency. Also, update `README.rst` with the `Withdrawn` status for ZIP 316, Revision 1. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --- README.rst | 4 ++-- zips/zip-0316.rst | 30 ++++++++++++++---------------- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/README.rst b/README.rst index f26255a5c..e59378eec 100644 --- a/README.rst +++ b/README.rst @@ -134,7 +134,7 @@ Released ZIPs <tr> <td>300</td> <td class="left"><a href="zips/zip-0300.rst">Cross-chain Atomic Transactions</a></td> <td>Proposed</td> <tr> <td>301</td> <td class="left"><a href="zips/zip-0301.rst">Zcash Stratum Protocol</a></td> <td>Active</td> <tr> <td>308</td> <td class="left"><a href="zips/zip-0308.rst">Sprout to Sapling Migration</a></td> <td>Active</td> - <tr> <td>316</td> <td class="left"><a href="zips/zip-0316.rst">Unified Addresses and Unified Viewing Keys</a></td> <td>[Revision 0] Active, [Revision 1] Proposed</td> + <tr> <td>316</td> <td class="left"><a href="zips/zip-0316.rst">Unified Addresses and Unified Viewing Keys</a></td> <td>[Revision 0] Active, [Revision 1] Withdrawn, [Revision 2] Draft</td> <tr> <td>317</td> <td class="left"><a href="zips/zip-0317.rst">Proportional Transfer Fee Mechanism</a></td> <td>Active</td> <tr> <td>320</td> <td class="left"><a href="zips/zip-0320.rst">Defining an Address Type to which funds can only be sent from Transparent Addresses</a></td> <td>Active</td> <tr> <td>321</td> <td class="left"><a href="zips/zip-0321.rst">Payment Request URIs</a></td> <td>Active</td> @@ -350,7 +350,7 @@ Index of ZIPs <tr> <td><strike>313</strike></td> <td class="left"><strike><a href="zips/zip-0313.rst">Reduce Conventional Transaction Fee to 1000 zatoshis</a></strike></td> <td>Obsolete</td> <tr> <td><span class="reserved">314</span></td> <td class="left"><a class="reserved" href="zips/zip-0314.rst">Privacy upgrades to the Zcash light client protocol</a></td> <td>Reserved</td> <tr> <td>315</td> <td class="left"><a href="zips/zip-0315.rst">Best Practices for Wallet Implementations</a></td> <td>Draft</td> - <tr> <td>316</td> <td class="left"><a href="zips/zip-0316.rst">Unified Addresses and Unified Viewing Keys</a></td> <td>[Revision 0] Active, [Revision 1] Proposed</td> + <tr> <td>316</td> <td class="left"><a href="zips/zip-0316.rst">Unified Addresses and Unified Viewing Keys</a></td> <td>[Revision 0] Active, [Revision 1] Withdrawn, [Revision 2] Draft</td> <tr> <td>317</td> <td class="left"><a href="zips/zip-0317.rst">Proportional Transfer Fee Mechanism</a></td> <td>Active</td> <tr> <td><span class="reserved">318</span></td> <td class="left"><a class="reserved" href="zips/zip-0318.rst">Associated Payload Encryption</a></td> <td>Reserved</td> <tr> <td><span class="reserved">319</span></td> <td class="left"><a class="reserved" href="zips/zip-0319.rst">Options for Shielded Pool Retirement</a></td> <td>Reserved</td> diff --git a/zips/zip-0316.rst b/zips/zip-0316.rst index c9c0e4d4b..7e7058f4c 100644 --- a/zips/zip-0316.rst +++ b/zips/zip-0316.rst @@ -321,22 +321,24 @@ Revisions * Revision 0: The initial version of this specification. -.. _`Revision 1` (Withdrawn): +.. _`Revision 1`: -* Revision 1 proposed a variant of this specification similar to that specified - for `Revision 2`_ addresses having the `tu` Human-Readable Part. It faced - [opposition from the community](https://forum.zcashcommunity.com/t/unified-addresses-composition/51024/7) +* Revision 1 (Withdrawn): Revision 1 proposed a variant of this specification + similar to that specified for `Revision 2`_ addresses having the ``tu`` + Human-Readable Part. It faced `opposition from the community + <https://forum.zcashcommunity.com/t/unified-addresses-composition/51024/7>`_ due to it being difficult to discern the privacy implications of sharing an address as that specified, and has been withdrawn. See - https://github.com/zcash/zips/blob/4acf32ac6db409d93041c463880dad6df83875e1/zips/zip-0316.rst - for the specification that was proposed. + `the previously proposed specification + <https://github.com/zcash/zips/blob/4acf32ac6db409d93041c463880dad6df83875e1/zips/zip-0316.rst>`_ + for details. .. _`Revision 2`: * Revision 2: This version adds support for `MUST-understand Typecodes`_ and `Address Expiration Metadata`_. It introduces two new variants of Unified - Addresses; `zu` addresses, which are prohibited from containing transparent - receivers, and `tu` addresses, which allow transparent receivers to be + Addresses; ``zu`` addresses, which are prohibited from containing transparent + receivers, and ``tu`` addresses, which allow transparent receivers to be augmented with metadata items. For Unified Viewing Keys, this version adopts ``uvf`` and ``uvi`` encoding prefixes for Unified Full Viewing Keys and Unified Incoming Viewing Keys respectively, drops the restriction that a UVK @@ -680,16 +682,14 @@ representation of viewing keys for P2SH addresses, which is an important use case with the advent of ZIP 48 [#zip-0048]_. In addition, transparent-only viewing keys can use Metadata Items to represent expiration heights/dates as described in `Address Expiration Metadata`_ that is useful in the generation of -`tu`-prefixed addresses. +``tu``-prefixed addresses. .. raw:: html </details> -.. _`Rationale for removing Transparent Receivers from zu Unified Addresses`: - -Rationale for removing Transparent Receivers from `zu` Unified Addresses -'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' +Rationale for removing Transparent Receivers from ``zu`` Unified Addresses +'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' .. raw:: html @@ -701,7 +701,7 @@ way for a user to visually distinguish a Unified Address that allowed the receipt of transparent funds from one that did not; Transparent addresses do not provide any privacy protection, and including them in UAs created a risk that Senders would fall back to transparent transfers even when the Recipient -supports shielded protocols. Historically, the `z` address prefix indicated +supports shielded protocols. Historically, the ``z`` address prefix indicated to the user that no element of the recipient address would cause information about the recipient to be leaked on-chain by transfers to that address. `Revision 2`_ restores this property. @@ -942,8 +942,6 @@ set this bound more tightly; a common expiry delta used by many wallets is 40 blocks from the current chain tip, as suggested in ZIP 203 [#zip-0203-default-expiry]_. -.. _`Typecode Registry`: - Typecode Registry ----------------- From 81756f22b8bc7bec8567aaef512ad8123485dd28 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Tue, 17 Feb 2026 11:32:29 +0000 Subject: [PATCH 017/115] Rename ZIP 2005 from "Quantum Recoverability" to "Orchard Quantum Recoverability". Signed-off-by: Daira-Emma Hopwood <daira@jacaranda.org> --- README.rst | 4 ++-- zips/zip-2005.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index e59378eec..739b6a21f 100644 --- a/README.rst +++ b/README.rst @@ -212,7 +212,7 @@ written. <tr> <td>2002</td> <td class="left"><a href="zips/zip-2002.rst">Explicit Fees</a></td> <td>Draft</td> <td class="left"><a href="https://github.com/zcash/zips/issues/803">zips#803</a></td> <tr> <td>2003</td> <td class="left"><a href="zips/zip-2003.rst">Disallow version 4 transactions</a></td> <td>Draft</td> <td class="left"><a href="https://github.com/zcash/zips/issues/825">zips#825</a></td> <tr> <td>2004</td> <td class="left"><a href="zips/zip-2004.rst">Remove the dependency of consensus on note encryption</a></td> <td>Draft</td> <td class="left"><a href="https://github.com/zcash/zips/issues/917">zips#917</a></td> - <tr> <td>2005</td> <td class="left"><a href="zips/zip-2005.md">Quantum Recoverability</a></td> <td>Draft</td> <td class="left"><a href="https://github.com/zcash/zips/issues/1135">zips#1135</a></td> + <tr> <td>2005</td> <td class="left"><a href="zips/zip-2005.md">Orchard Quantum Recoverability</a></td> <td>Draft</td> <td class="left"><a href="https://github.com/zcash/zips/issues/1135">zips#1135</a></td> <tr> <td>guide-markdown</td> <td class="left"><a href="zips/zip-guide-markdown.md">{Something Short and To the Point}</a></td> <td>Draft</td> <td class="left"></td> <tr> <td>guide</td> <td class="left"><a href="zips/zip-guide.rst">{Something Short and To the Point}</a></td> <td>Draft</td> <td class="left"></td> <tr> <td>template</td> <td class="left"><a href="zips/zip-template.md">{Template for new ZIPs}</a></td> <td>Draft</td> <td class="left"></td> @@ -388,7 +388,7 @@ Index of ZIPs <tr> <td>2002</td> <td class="left"><a href="zips/zip-2002.rst">Explicit Fees</a></td> <td>Draft</td> <tr> <td>2003</td> <td class="left"><a href="zips/zip-2003.rst">Disallow version 4 transactions</a></td> <td>Draft</td> <tr> <td>2004</td> <td class="left"><a href="zips/zip-2004.rst">Remove the dependency of consensus on note encryption</a></td> <td>Draft</td> - <tr> <td>2005</td> <td class="left"><a href="zips/zip-2005.md">Quantum Recoverability</a></td> <td>Draft</td> + <tr> <td>2005</td> <td class="left"><a href="zips/zip-2005.md">Orchard Quantum Recoverability</a></td> <td>Draft</td> <tr> <td>guide-markdown</td> <td class="left"><a href="zips/zip-guide-markdown.md">{Something Short and To the Point}</a></td> <td>Draft</td> <tr> <td>guide</td> <td class="left"><a href="zips/zip-guide.rst">{Something Short and To the Point}</a></td> <td>Draft</td> <tr> <td>template</td> <td class="left"><a href="zips/zip-template.md">{Template for new ZIPs}</a></td> <td>Draft</td> diff --git a/zips/zip-2005.md b/zips/zip-2005.md index 241e18af1..dbc039f98 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 <daira@jacaranda.org> Jack Grigg <thestr4d@gmail.com> Credits: Sean Bowe From 3b6060c4fbb452981efd27631d7bcdc75a92e31a Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Tue, 17 Feb 2026 11:53:58 +0000 Subject: [PATCH 018/115] 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 <daira@jacaranda.org> --- 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 dbc039f98..4577b32a8 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 @@ -499,11 +509,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: @@ -538,6 +543,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 \}$, @@ -611,16 +617,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)$. @@ -631,11 +646,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}}$. @@ -644,7 +662,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})$ @@ -661,6 +679,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 @@ -669,10 +693,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)$ @@ -682,7 +706,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)’. @@ -735,11 +768,11 @@ with > $\hspace{2.5em}$ if $\mathsf{repr}_{\mathbb{G}}(\mathsf{KA.DerivePublic}(\mathsf{esk}, \mathsf{g_d})) \neq \mathtt{ephemeralKey}$, return $\bot$ <br> > > $\hspace{1.0em}$ let $\mathsf{pk_d} = \mathsf{KA.DerivePublic}(\mathsf{ivk}, \mathsf{g_d})$ <br> -> $\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})]$ <br> +> $\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})$ <br> > $\hspace{1.0em}$ let $\text{ψ} = \mathsf{H^{\text{ψ},Orchard}_{rseed}}(\underline{\text{ρ}}, 0)$ for Orchard or $\bot$ for Sapling <br> > $\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}$ <br> > $\hspace{1.0em}$ if $\mathsf{rcm} \geq r_{\mathbb{G}}$, return $\bot$ @@ -761,11 +794,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$ <br> -> $\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})]$ <br> +> $\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})$ <br> > $\hspace{1.0em}$ let $\text{ψ} = \mathsf{H^{\text{ψ},Orchard}_{rseed}}(\underline{\text{ρ}}, 0)$ for Orchard or $\bot$ for Sapling <br> > $\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}$ <br> > $\hspace{1.0em}$ if $\mathsf{rcm} \geq r_{\mathbb{G}}$, return $\bot$ @@ -850,34 +883,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{ρ}}))$ <br> - 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: @@ -933,7 +968,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 \\ @@ -1030,7 +1065,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: @@ -1375,10 +1410,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 f25ee67af2693e7817a50e2ccafd7a7b3cf50469 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Tue, 17 Feb 2026 14:05:30 +0000 Subject: [PATCH 019/115] ZIP 2005: cosmetics and referencing. Signed-off-by: Daira-Emma Hopwood <daira@jacaranda.org> --- 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 4577b32a8..bfe07f145 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}}$.) @@ -496,18 +496,17 @@ with > 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}})$" @@ -518,17 +517,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 @@ -579,24 +578,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)’ @@ -642,8 +641,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 @@ -671,7 +670,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 @@ -688,7 +687,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 @@ -701,7 +700,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)’ @@ -717,14 +716,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$ @@ -737,7 +736,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]$ <br> > $\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{ρ}}$ @@ -746,17 +745,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}$ <br> > $\hspace{1.0em}$ if $\mathsf{rcm} \geq r_{\mathbb{G}}$, return $\bot$ <br> > $\hspace{1.0em}$ let $\mathsf{g_d} = \mathsf{DiversifyHash}(\mathsf{d})$. if (for Sapling) $\mathsf{g_d} = \bot$, return $\bot$ <br> > $\hspace{1.0em}$ [**Canopy** onward] if $\mathsf{leadByte} \neq \mathtt{0x01}$: <br> -> $\hspace{2.5em}$ $\mathsf{esk} = \mathsf{ToScalar^{protocol}}(\mathsf{PRF^{expand}_{rseed}}(\mathsf{pre\_esk}))$ <br> -> $\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)$ <br> +> $\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})$ @@ -765,7 +764,7 @@ with > $\hspace{1.0em}$ let $\mathsf{g_d} = \mathsf{DiversifyHash}(\mathsf{d})$. if (for Sapling) $\mathsf{g_d} = \bot$, return $\bot$ <br> > $\hspace{1.0em}$ [**Canopy** onward] if $\mathsf{leadByte} \neq \mathtt{0x01}$: <br> > $\hspace{2.5em}$ let $\mathsf{esk} = \mathsf{H^{esk,protocol}_{rseed}}(\underline{\text{ρ}})$ <br> -> $\hspace{2.5em}$ if $\mathsf{repr}_{\mathbb{G}}(\mathsf{KA.DerivePublic}(\mathsf{esk}, \mathsf{g_d})) \neq \mathtt{ephemeralKey}$, return $\bot$ <br> +> $\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$ <br> > > $\hspace{1.0em}$ let $\mathsf{pk_d} = \mathsf{KA.DerivePublic}(\mathsf{ivk}, \mathsf{g_d})$ <br> > $\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})$ <br> @@ -779,14 +778,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}$ <br> > $\hspace{1.0em}$ if $\mathsf{rcm} \geq r_{\mathbb{G}}$, return $\bot$ <br> > $\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$ @@ -802,7 +801,7 @@ with > \end{cases}$ <br> > $\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’ @@ -821,12 +820,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 @@ -835,13 +834,13 @@ Add a note before the Abstract: <div class="note"></div> 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}$. @@ -958,7 +957,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 \\ @@ -1239,7 +1238,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 @@ -1367,7 +1366,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 @@ -1376,7 +1375,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 98d0e5e99ab46b827aa1c68eecc2c709ef77ef6f Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Tue, 17 Feb 2026 14:05:59 +0000 Subject: [PATCH 020/115] ZIP 2005: Fix typo in case of use_qsk. Signed-off-by: Daira-Emma Hopwood <daira@jacaranda.org> --- 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 bfe07f145..cc1a41574 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -1245,7 +1245,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$. From 03ec9b3c673f14ae62c5129cc6e32fd9d7d4b59d Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Sat, 25 Apr 2026 14:09:22 +0100 Subject: [PATCH 021/115] ZIP 2005: fix cost-section compression count MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Recount each BLAKE2b-512 use in the Recovery circuit. The previous "9 compressions" total was wrong: H^rivk_ext, H^rivk_int, and H^ψ each take 1 compression (not 2 as claimed); H^rcm correctly takes 2. Worst-case total is 7, not 9. Also document the ℓ_qk ≤ 504 bits constraint that keeps the H^rivk_ext input qk ‖ [0x0D] ‖ ak ‖ nk within a single 128-byte BLAKE2b block. Part of #1135. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --- zips/zip-2005.md | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index cc1a41574..7428b4c64 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -988,9 +988,11 @@ non-split note. ### Cost -Note that in the "$\mathsf{use\_qsk}$" case, two BLAKE2b compressions -are required to compute $\mathsf{rivk\_ext}$, and in the -"not $\mathsf{use\_qsk}$" cases, three BLAKE2b compressions in total +Note that in the "$\mathsf{use\_qsk}$" case, one BLAKE2b compression +is required to compute $\mathsf{rivk\_ext}$ (provided $\ell_{\mathsf{qk}} \leq 504$ +bits, so that the input $\mathsf{qk} \,||\, [\mathtt{0x0D}] \,||\, \mathsf{ak} \,||\, \mathsf{nk}$ +fits in a single 128-byte BLAKE2b block), and in the +"not $\mathsf{use\_qsk}$" case, three BLAKE2b compressions in total are required to compute $\mathsf{H^{ask}}$, $\mathsf{H^{nk}}$, and $\mathsf{H^{rivk\_legacy}}$. Since these cases are mutually exclusive, it is possible to multiplex the same three compression function instances. @@ -1000,10 +1002,11 @@ So, supporting "$\mathsf{use\_qsk}$" in addition to All of the operations below need to be implemented with complete additions, even if they are incomplete in the current Orchard[ZSA] circuit. -* 9 BLAKE2b-512 compressions: - * 3 to compute $\mathsf{rivk\_ext}$ - * 2 to compute $\mathsf{H^{rivk\_int}}$ - * 2 to compute $\mathsf{H^{\text{ψ}}}$ +* 7 BLAKE2b-512 compressions: + * 3 multiplexed between $\mathsf{H^{rivk\_ext}}$ when $\mathsf{use\_qsk}$ is true (1 compression), + and $\mathsf{H^{ask}}$ + $\mathsf{H^{nk}}$ + $\mathsf{H^{rivk\_legacy}}$ when $\mathsf{use\_qsk}$ is false (3 compressions) + * 1 to compute $\mathsf{H^{rivk\_int}}$ + * 1 to compute $\mathsf{H^{\text{ψ}}}$ * 2 to compute $\mathsf{H^{rcm}}$ * we could potentially save these two by using Poseidon to implement $\mathsf{H^{rcm}}$, but it seems not worth it. * 1 use of $\mathsf{H^{qk}}$ @@ -1014,7 +1017,7 @@ even if they are incomplete in the current Orchard[ZSA] circuit. * 1 Merkle tree path check * 1 additional use of $\mathsf{MerkleCRH}$ to compute $\mathsf{leaf}$. -The expensive parts of this are the 9 BLAKE2b compressions. +The expensive parts of this are the 7 BLAKE2b compressions. ## Security analysis From 30dccde0f89cf5e86d8102b4d0e7e5ebc59523e3 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Sat, 25 Apr 2026 14:48:28 +0100 Subject: [PATCH 022/115] ZIP 2005: reference ZIP 312 PR #895, not #883 The ZIP 312 changes for use_qsk-supporting key generation are tracked in #895, which superseded the earlier #883. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --- 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 7428b4c64..8fe1c7fec 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -1373,7 +1373,7 @@ $\mathsf{use\_qsk} = \mathsf{false}$ case in FROST distributed key generation requires the $\mathsf{use\_qsk} = \mathsf{true}$ case. There is no significant existing deployment of FROST, so we can -[write this into ZIP 312](https://github.com/zcash/zips/pull/883/files) +[write this into ZIP 312](https://github.com/zcash/zips/pull/895/files) from the start. The part of the protocol that is new is the different input for From 920805981f4b526db720fee991ba40782e6d4615 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Sat, 25 Apr 2026 14:52:46 +0100 Subject: [PATCH 023/115] ZIP 2005: use boolean phrasing for use_qsk in security argument MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace 'Case use_qsk = 0/1' with 'Case (not) use_qsk' in the Informal Security Argument, matching the boolean type of the use_qsk flag as defined in § 4.2.3 and used elsewhere in this ZIP. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --- zips/zip-2005.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index 8fe1c7fec..0ec0a2891 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -1231,7 +1231,7 @@ $\mathsf{SinsemillaShortCommit}$ which is not post-quantum binding. There are two cases depending on $\mathsf{use\_qsk}$ (the adversary can choose to attack either): -* Case $\mathsf{use\_qsk} = 0$: The spender must prove knowledge of +* Case $\text{not } \mathsf{use\_qsk}$: The spender must prove knowledge of $\mathsf{sk}$, and that $\mathsf{ak}$, $\mathsf{nk}$, and $\mathsf{rivk}$ are derived correctly from $\mathsf{sk}$. This works because the derivations use post-quantum hashes (and $\mathsf{ask} \rightarrow \mathsf{ak}$ @@ -1248,10 +1248,10 @@ 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} = 1$: This case is almost the same except that +* Case $\mathsf{use\_qsk}$: 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$. + in terms of $T$ is also the same as for $\text{not } \mathsf{use\_qsk}$. ## Security argument for Spendability From 95e7707064385fd2ee32969b1621a4f1e115ce8f Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Tue, 17 Feb 2026 11:39:53 +0000 Subject: [PATCH 024/115] Protocol spec and ZIP 32: factor out (dk, ovk) derivation. Signed-off-by: Daira-Emma Hopwood <daira@jacaranda.org> --- protocol/protocol.tex | 32 +++++++++++++++++--------------- zips/zip-0032.rst | 29 ++++++++++++++++++----------- 2 files changed, 35 insertions(+), 26 deletions(-) diff --git a/protocol/protocol.tex b/protocol/protocol.tex index 80b64a816..fe88e44b5 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 8fba1d59b..7360d1f1b 100644 --- a/zips/zip-0032.rst +++ b/zips/zip-0032.rst @@ -518,7 +518,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 @@ -545,8 +545,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 @@ -555,18 +555,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 @@ -942,4 +948,5 @@ References .. [#zip-0000] `ZIP 0: ZIP Process <zip-0000.rst>`_ .. [#zip-0315-wallet-seeds] `ZIP 315: Best Practices for Wallet Implementations — Specification: Wallet seeds <zip-0315.rst#wallet-seeds>`_ .. [#zip-0316] `ZIP 316: Unified Addresses and Unified Viewing Keys <zip-0316.rst>`_ +.. [#zip-0316-usage-of-outgoing-viewing-keys] `ZIP 316: Unified Addresses and Unified Viewing Keys — Usage of Outgoing Viewing Keys <zip-0316.rst#usage-of-outgoing-viewing-keys>`_ .. [#zip-2005] `ZIP 2005: Orchard Quantum Recoverability <zip-2005.md>`_ From 0369f47e3ecac174e908f40bc3740a92e8bd3adb Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Tue, 17 Feb 2026 11:40:16 +0000 Subject: [PATCH 025/115] Protocol spec: cosmetics. Signed-off-by: Daira-Emma Hopwood <daira@jacaranda.org> --- protocol/protocol.tex | 79 +++++++++++++++++++++++-------------------- 1 file changed, 42 insertions(+), 37 deletions(-) diff --git a/protocol/protocol.tex b/protocol/protocol.tex index fe88e44b5..1c438b685 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 a6dfda7fb739f7a7b9ce8ab2b438c29fa80aa917 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Sat, 25 Apr 2026 15:26:54 +0100 Subject: [PATCH 026/115] ZIP 2005: tighten PRF^expand byte-tag list and add protocol-section footnotes In the protocol-spec edit block that lists the places where PRF^expand is used: - Consolidate the byte-tag enumeration: {0x0C, 0x0D, 0x82} as a single set, noting that 0x0C and 0x0D are specified in this ZIP. Drop the separate "(also specified in ZIP-32)" parenthetical for 0x82, since the (dk, ovk) refactor moves that specification entirely into the protocol spec (ZIP 32 just calls DeriveDkAndOvk^Orchard). - Add protocol-section footnote references for orchardkeycomponents, saplingsend, orchardsend, and saplingandorchardinband to make this paragraph cross-referenceable. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --- zips/zip-2005.md | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index 0ec0a2891..f95057400 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -472,28 +472,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 [ZIP 2005]); From 84ae5c7d9c12d3634ded9b87acf783d7b83bdca7 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Sat, 25 Apr 2026 18:04:32 +0100 Subject: [PATCH 027/115] ZIP 226 / ZIP 2005: apply ZIP 226 changes from ZIP 2005 directly to ZIP 226 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per the deployment ordering decision (ZIP 2005 deploys before any ZSA activation), the "ZIP 226" edit block in ZIP 2005 can be applied to ZIP 226 directly. ZIP 226's Abstract now declares that it is defined relative to the protocol with ZIP 2005 applied; the first-byte domain separator 0x0A for PRF^expand remains reserved by ZIP 2005 for this use. Applied to ZIP 226: - Abstract: add meta-baseline paragraph. - Note Structure and Commitment: leadByte=0x03 rule for § 4.7.3 'Sending Notes (Orchard)' or § 4.8.3 'Dummy Notes (Orchard)' invoked for an OrchardZSA note. - Split Notes: replace the uniform-random sampling of ψ^nf with the deterministic computation ToBase^Orchard(PRF^expand_{rseed_nf}([0x0A] || ρ^old)), using the first-byte domain separator 0x0A for PRF^expand reserved by ZIP 2005. - References: add #protocol-orchardsend; rename ZIP 2005 footnote title to "Orchard Quantum Recoverability". Removed from ZIP 2005: - The "#### ZIP 226" edit block under "Edits to existing ZIPs" (now redundant). A broader review of whether other ZIP 226 / ZIP 227 spec updates need re-statement relative to the post-ZIP-2005 baseline is deferred (the Abstract paragraph provides the meta-baseline). Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --- zips/zip-0226.rst | 13 +++++++++---- zips/zip-2005.md | 21 --------------------- 2 files changed, 9 insertions(+), 25 deletions(-) diff --git a/zips/zip-0226.rst b/zips/zip-0226.rst index 4b42c0057..e05cc8ef3 100644 --- a/zips/zip-0226.rst +++ b/zips/zip-0226.rst @@ -42,6 +42,8 @@ Abstract This ZIP (ZIP 226) proposes the Orchard Zcash Shielded Assets (OrchardZSA) protocol, in conjunction with ZIP 227 [#zip-0227]_. The OrchardZSA protocol is an extension of the Orchard protocol that enables the issuance, transfer and burn of custom Assets on the Zcash chain. The issuance of such Assets is defined in ZIP 227 [#zip-0227]_, while the transfer and burn of such Assets is defined in this ZIP (ZIP 226). While the proposed OrchardZSA protocol is a modification to the Orchard protocol, it has been designed with adaptation to possible future shielded protocols in mind. +This ZIP is defined relative to the Zcash protocol with the changes specified in ZIP 2005 [#zip-2005]_ applied. ZIP 2005 (Orchard Quantum Recoverability) is expected to deploy before any ZSA activation; the references in this document to $\mathsf{H^{rcm,Orchard}}$, $\mathsf{H^{\text{ψ},Orchard}}$, recoverable note plaintexts (lead byte $\mathtt{0x03}$), and related constructs are to be interpreted as defined by ZIP 2005's modifications to the protocol specification. + Motivation ========== @@ -157,6 +159,8 @@ The nullifier is generated in the same manner as in the Orchard protocol §4.16 The OrchardZSA note plaintext also includes the Asset Base $\mathsf{asset\_base} : \mathbb{B}^{[\ell_{\mathbb{P}}]}$ in addition to the components in the Orchard note plaintext [#protocol-notept]_. The explicit encoding of the note plaintext is provided in ZIP 230 [#zip-0230-orchard-note-plaintext]_. +When § 4.7.3 'Sending Notes (Orchard)' [#protocol-orchardsend]_ or § 4.8.3 'Dummy Notes (Orchard)' [#protocol-orcharddummynotes]_ are invoked directly or indirectly in the computation of $\text{ρ}$ and $\text{ψ}$ for an OrchardZSA note, $\mathsf{leadByte}$ MUST be set to $\mathtt{0x03}$. + The explicit order of addition of the note commitments to the note commitment tree is specified in ZIP 227 [#zip-0227-note-commitment-order]_. Rationale for Note Commitment @@ -290,7 +294,7 @@ For Split Notes, the nullifier is generated as follows: .. math:: \mathsf{nf_{old}} = \mathsf{Extract}_{\mathbb{P}} ([(\mathsf{PRF^{nfOrchard}_{nk}} (\text{ρ}^{\mathsf{old}}) + \text{ψ}^{\mathsf{nf}}) \bmod q_{\mathbb{P}}]\,\mathcal{K}^\mathsf{Orchard} + \mathsf{cm^{old}} + \mathcal{L}^\mathsf{Orchard}) -where $\text{ψ}^{\mathsf{nf}}$ is sampled uniformly at random on $\mathbb{F}_{q_{\mathbb{P}}}$, $\mathcal{K}^{\mathsf{Orchard}}$ is the Orchard Nullifier Base as defined in §4.16 ‘Computing ρ values and Nullifiers’ [#protocol-rhoandnullifiers]_, and $\mathcal{L}^{\mathsf{Orchard}} := \mathsf{GroupHash^{\mathbb{P}}}(\texttt{“z.cash:Orchard”}, \texttt{“L”})$. +where $\text{ψ}^{\mathsf{nf}}$ is computed as $\mathsf{ToBase^{Orchard}}\big(\mathsf{PRF^{expand}_{rseed\_nf}}([\mathtt{0x0A}] \,||\, \underline{\text{ρ}^{\mathsf{old}}})\kern-0.1em\big)$ for $\mathsf{rseed\_nf}$ sampled uniformly at random on $\mathbb{B}^{{\kern-0.1em\tiny\mathbb{Y}}[32]}$, $\mathcal{K}^{\mathsf{Orchard}}$ is the Orchard Nullifier Base as defined in §4.16 ‘Computing ρ values and Nullifiers’ [#protocol-rhoandnullifiers]_, and $\mathcal{L}^{\mathsf{Orchard}} := \mathsf{GroupHash^{\mathbb{P}}}(\texttt{“z.cash:Orchard”}, \texttt{“L”})$. The first-byte domain separator $\mathtt{0x0A}$ for $\mathsf{PRF^{expand}}$ is reserved by ZIP 2005 [#zip-2005]_ for this use. Rationale for Split Notes ````````````````````````` @@ -388,8 +392,8 @@ The following requirements on wallets are specified and motivated in ZIP 230 ZEC asset. For other consequences see ZIP 230. * *All* wallets should be ready to receive funds in outputs of v6 transactions as soon - as ZSAs activate — in particular to support decrypting note plaintexts with lead-byte - $\mathtt{0x03}$ [#zip-0230-note-plaintexts]_. The consequence of not doing so would + as ZSAs activate — in particular to support decrypting recoverable note plaintexts + (lead byte $\mathtt{0x03}$) [#zip-0230-note-plaintexts]_. The consequence of not doing so would be that funds sent to Orchard addresses of a wallet without this support could be temporarily inaccessible, until the wallet is upgraded to fully support v6 and to rescan outputs since v6 activation. @@ -459,11 +463,12 @@ References .. [#zip-0244] `ZIP 244: Transaction Identifier Non-Malleability <zip-0244.rst>`_ .. [#zip-0246] `ZIP 246: Digests for the Version 6 Transaction Format <zip-0246.rst>`_ .. [#zip-0307] `ZIP 307: Light Client Protocol for Payment Detection <zip-0307.rst>`_ -.. [#zip-2005] `ZIP 2005: Quantum Recoverability <zip-2005.md>`_ +.. [#zip-2005] `ZIP 2005: Orchard Quantum Recoverability <zip-2005.md>`_ .. [#protocol] `Zcash Protocol Specification, Version 2025.6.2 [NU6.1] or later. <protocol/protocol.pdf>`_ .. [#protocol-notes] `Zcash Protocol Specification, Version 2025.6.2 [NU6.1]. Section 3.2: Notes <protocol/protocol.pdf#notes>`_ .. [#protocol-actions] `Zcash Protocol Specification, Version 2025.6.2 [NU6.1]. Section 3.7: Action Transfers and their Descriptions <protocol/protocol.pdf#actions>`_ .. [#protocol-abstractcommit] `Zcash Protocol Specification, Version 2025.6.2 [NU6.1]. Section 4.1.8: Commitment <protocol/protocol.pdf#abstractcommit>`_ +.. [#protocol-orchardsend] `Zcash Protocol Specification, Version 2025.6.2 [NU6.1]. Section 4.7.3: Sending Notes (Orchard) <protocol/protocol.pdf#orchardsend>`_ .. [#protocol-orcharddummynotes] `Zcash Protocol Specification, Version 2025.6.2 [NU6.1]. Section 4.8.3: Dummy Notes (Orchard) <protocol/protocol.pdf#orcharddummynotes>`_ .. [#protocol-orchardbalance] `Zcash Protocol Specification, Version 2025.6.2 [NU6.1]. Section 4.14: Balance and Binding Signature (Orchard) <protocol/protocol.pdf#orchardbalance>`_ .. [#protocol-rhoandnullifiers] `Zcash Protocol Specification, Version 2025.6.2 [NU6.1]. Section 4.16: Computing ρ values and Nullifiers <protocol/protocol.pdf#rhoandnullifiers>`_ diff --git a/zips/zip-2005.md b/zips/zip-2005.md index f95057400..130e22d38 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -834,27 +834,6 @@ 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 [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)’ -> are invoked directly or indirectly in the computation of $\text{ρ}$ and -> $\text{ψ}$ for an OrchardZSA note, $\mathsf{leadByte}$ MUST be set to -> $\mathtt{0x03}$. - -In section [Split Notes](https://zips.z.cash/zip-0226#split-notes), change: - -> where $\text{ψ}^{\mathsf{nf}}$ is sampled uniformly at random on -> $\mathbb{F}_{q_{\mathbb{P}}}$, ... - -to - -> where $\text{ψ}^{\mathsf{nf}}$ is computed as -> $\mathsf{H^{\text{ψ},Orchard}_{rseed\_nf}}(\underline{\text{ρ}}, 1) = \mathsf{ToBase^{Orchard}}\big(\mathsf{PRF^{expand}_{rseed\_nf}}([\mathtt{0x0A}] \,||\, \underline{\text{ρ}})\kern-0.1em\big)$ -> for $\mathsf{rseed\_nf}$ sampled uniformly at random on $\mathbb{B}^{{\kern-0.1em\tiny\mathbb{Y}}[32]}$, ... - - # Rationale ## Cryptographic background From 1fc349626bcaed41d1c3c9f7d65f147e35d8bc10 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Sun, 26 Apr 2026 00:54:15 +0100 Subject: [PATCH 028/115] =?UTF-8?q?ZIP=202005:=20strip=20split=5Fflag=20fr?= =?UTF-8?q?om=20H^=CF=88;=20reserve=200x0A=20for=20split=20notes=20in=20ZI?= =?UTF-8?q?P=20226?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ZSAs (and therefore split_flag) will not deploy at the same time as Orchard Quantum Recoverability. The split_flag-related complications can be removed from this ZIP, with the first-byte domain separator 0x0A for PRF^expand reserved for use by split notes in ZIP 226, keeping the path open for re-introducing split_flag later. The removal is cleanly revertable. Changes: - H^{ψ,Orchard} now takes a single argument ρ and uses the hardcoded first-byte domain separator 0x09 for PRF^expand; the split_domain case analysis is dropped from both the protocol-spec edit block in § 4.7.3 'Sending Notes (Orchard)' and the Rationale section's dup. - Add a reservation note pointing 0x0A at split notes in ZIP 226. - Drop the four "If this proposal is to be deployed without ZSAs..." conditionals (§ 4.7.3, § 4.8.3, § 4.20.2/4.20.3); the without-ZSAs branch is now the only branch. - All H^{ψ,Orchard} call sites drop the second arg (split_flag or 0). - Recovery circuit's ψ derivation drops split_flag. - Flow diagram: drop split_flag/rsplit nodes; rseed flows directly to H^ψ. - Spendability argument: drop "split_flag = false" qualifiers, drop the adversary's split_flag/rsplit inputs, drop the "TODO split_flag = true" stub and the "Also it is incomplete because it does not consider split notes" caveat. split_flag support is preserved in git history; this commit can be reverted later (with conflict resolution) to bring it back. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --- zips/zip-2005.md | 67 +++++++++++++----------------------------------- 1 file changed, 18 insertions(+), 49 deletions(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index 130e22d38..41c2e21a3 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -244,11 +244,7 @@ graph BT Commitivk ---> ivk([ivk]) gd ---> ivkmul[[ivk]g<sub>d</sub> ]:::func ivk --> ivkmul - split_flag([split_flag]) --> Hpsi - rsplit([rsplit]) -->|split_flag| rpsi{{rψ}} - rsplit ~~~ split_flag - rseed -->|¬split_flag| rpsi - rpsi --> Hpsi[H<sup>ψ</sup>]:::func + rseed --> Hpsi[H<sup>ψ</sup>]:::func rho --> Hpsi leadByte([leadByte]) ==> pre_rcm v([v, AssetBase]) ===> pre_rcm([pre_rcm]) @@ -614,15 +610,11 @@ Replace the lines deriving $\mathsf{rcm}$ and $\mathsf{esk}$ with #### § 4.7.3 ‘Sending Notes (Orchard)’ -If this proposal is to be deployed without ZSAs, add after the definition of -$\mathsf{leadByte}$: +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. - 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) =$ @@ -637,14 +629,9 @@ Add before "For each Action description": > > Define $\mathsf{H^{esk,Orchard}_{rseed}}(\underline{\text{ρ}}) = \mathsf{ToScalar^{Orchard}}\big(\mathsf{PRF^{expand}_{rseed}}([\mathtt{0x04}] \,||\, \underline{\text{ρ}})\kern-0.1em\big)$. > -> 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 $\mathsf{H^{\text{ψ},Orchard}_{rseed}}(\underline{\text{ρ}}) = \mathsf{ToBase^{Orchard}}\big(\mathsf{PRF^{expand}_{rseed}}([\mathtt{0x09}] \,||\, \underline{\text{ρ}})\kern-0.1em\big)$. -If this proposal is to be deployed without ZSAs, replace $\mathsf{split\_domain}$ with -$\mathtt{0x09}$ above and elide its definition. +The first-byte domain separator $\mathtt{0x0A}$ for $\mathsf{PRF^{expand}}$ is reserved by this ZIP for use by split notes in ZIP 226 [^zip-0226-split-notes]. Insert before the derivation of $\mathsf{esk}$: @@ -661,7 +648,7 @@ with > 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})$ +> Derive $\text{ψ} = \mathsf{H^{\text{ψ},Orchard}_{rseed}}(\underline{\text{ρ}})$ #### § 4.8.2 ‘Dummy Notes (Sapling)’ @@ -676,8 +663,7 @@ 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}$: +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)’. @@ -695,7 +681,7 @@ Replace the lines deriving $\mathsf{rcm}$ and $\text{ψ}$ with > > 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)$ +> Derive $\text{ψ} = \mathsf{H^{\text{ψ},Orchard}_{rseed}}(\underline{\text{ρ}})$ and use $\mathsf{g}\star_{\mathsf{d}}$, $\mathsf{pk}\star_{\mathsf{d}}$, and $\mathsf{AssetBase}\kern0.05em\star$ in the inputs to @@ -703,15 +689,11 @@ $\mathsf{NoteCommit^{Orchard}}$. #### § 4.20.2 and § 4.20.3 ‘Decryption using an Incoming/Full Viewing Key (Sapling and Orchard)’ -If this proposal is to be deployed without ZSAs, add after the definition of -$\mathsf{leadByte}$: +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^{esk,Sapling}}$ @@ -766,7 +748,7 @@ with > > $\hspace{1.0em}$ let $\mathsf{pk_d} = \mathsf{KA.DerivePublic}(\mathsf{ivk}, \mathsf{g_d})$ <br> > $\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})$ <br> -> $\hspace{1.0em}$ let $\text{ψ} = \mathsf{H^{\text{ψ},Orchard}_{rseed}}(\underline{\text{ρ}}, 0)$ for Orchard or $\bot$ for Sapling <br> +> $\hspace{1.0em}$ let $\text{ψ} = \mathsf{H^{\text{ψ},Orchard}_{rseed}}(\underline{\text{ρ}})$ for Orchard or $\bot$ for Sapling <br> > $\hspace{1.0em}$ let $\mathsf{rcm} = \begin{cases} > \mathsf{LEOS2IP}_{256}(\mathsf{rseed}),&\!\!\!\text{if } \mathsf{leadByte} = \mathtt{0x01} \\ > \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} @@ -792,7 +774,7 @@ with > $\hspace{1.0em}$ let $\mathsf{g_d} = \mathsf{DiversifyHash}(\mathsf{d})$. if (for Sapling) $\mathsf{g_d} = \bot$, return $\bot$ <br> > $\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})$ <br> -> $\hspace{1.0em}$ let $\text{ψ} = \mathsf{H^{\text{ψ},Orchard}_{rseed}}(\underline{\text{ρ}}, 0)$ for Orchard or $\bot$ for Sapling <br> +> $\hspace{1.0em}$ let $\text{ψ} = \mathsf{H^{\text{ψ},Orchard}_{rseed}}(\underline{\text{ρ}})$ for Orchard or $\bot$ for Sapling <br> > $\hspace{1.0em}$ let $\mathsf{rcm} = \begin{cases} > \mathsf{LEOS2IP}_{256}(\mathsf{rseed}),&\!\!\!\text{if } \mathsf{leadByte} = \mathtt{0x01} \\ > \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} @@ -880,11 +862,7 @@ Import these definitions from § 4.7.3 ‘Sending Notes (Orchard)’ [^protocol > \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 $\mathsf{H^{\text{ψ},Orchard}_{rseed}}(\underline{\text{ρ}}) = \mathsf{ToBase^{Orchard}}\big(\mathsf{PRF^{expand}_{rseed}}([\mathtt{0x09}] \,||\, \underline{\text{ρ}})\kern-0.1em\big)$. Import this definition from § 5.4.7.1 ‘Spend Authorization Signature (Sapling and Orchard)’ [^protocol-concretespendauthsig]: @@ -943,7 +921,7 @@ $\begin{array}{l} \wedge\; \text{let } \mathsf{ivk} = \mathsf{Commit^{ivk}_{rivk}}(\mathsf{ak}, \mathsf{nk}) \\ \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 } \text{ψ} = \mathsf{H}^{\text{ψ}}_{\mathsf{r}\text{ψ}}(\underline{\text{ρ}}) \\ \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}) \\ @@ -957,10 +935,6 @@ $\begin{array}{l} and $\mathsf{nf}$ is the revealed nullifier. -TODO: finish extending this to ZSAs. We need to add $\text{ψ}^{\mathsf{nf}}$, -and enforce $\mathsf{rseed\_nf} = \mathsf{rseed\_old}$ only if this is a -non-split note. - (We don't need to check the derivation of $\mathsf{g_d}$ from $\mathsf{d}$.) ### Cost @@ -1244,15 +1218,14 @@ Recovery circuit? As it turns out, no, but the argument is somewhat involved. TODO: this argument is too handwavy and depends on the ROM; it needs -further work for a quantum adversary. Also it is incomplete because -it does not consider split notes. +further work for a quantum adversary. Since each function in the Recovery circuit is deterministic, the free variables that the adversary can control are the sources of the derivation digraph within that circuit and either $\mathsf{SoK^{sk}}$ or $\mathsf{SoK^{qk}}$. That is, the adversary can control: -* $(\text{ρ}, \mathsf{g_d}, \mathsf{split\_flag}, \mathsf{rseed}, \mathsf{rsplit}, \mathsf{is\_internal\_rivk}, \mathsf{use\_qsk})$ and +* $(\text{ρ}, \mathsf{g_d}, \mathsf{rseed}, \mathsf{is\_internal\_rivk}, \mathsf{use\_qsk})$ and * $\mathsf{sk}$, when $\mathsf{use\_qsk} = \mathsf{false}$; * $(\mathsf{nk}, \mathsf{ak}, \mathsf{qsk})$, when $\mathsf{use\_qsk} = \mathsf{true}$. @@ -1266,8 +1239,6 @@ of the values in the Recovery circuit that the adversary can control. We can then analyze $\mathsf{DeriveNullifier}$ in essentially the same way we analyzed $\mathsf{NoteCommit}$. -First consider $\mathsf{split\_flag} = \mathsf{false}$. - Recall that $\mathsf{DeriveNullifier}$ is defined in § 4.16 ‘Computing ρ values and Nullifiers’ as: @@ -1277,8 +1248,7 @@ Also recall from [Repairing note commitments] that we have $$\mathsf{cm} = [\mathsf{H^{rcm,Orchard}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr}) + f(\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})]\, \mathcal{R}.$$ -When $\mathsf{split\_flag} = \mathsf{false}$, $\text{ψ}$ is determined -by $\mathsf{rseed}$. The nullifier corresponding to +$\text{ψ}$ is determined by $\mathsf{rseed}$. The nullifier corresponding to $(\mathsf{nk}, \text{ρ}, \mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})$ is then $$\mathsf{Extract}_{\mathbb{P}}\big([\mathsf{H^{rcm,Orchard}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr}) + f(\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr}) + g(\mathsf{nk}, \text{ρ}, \mathsf{rseed})]\, \mathcal{R}\big)$$ @@ -1296,8 +1266,7 @@ $\mathsf{cm}$ and $\mathsf{nf}$: * because $\mathsf{g_d} \mapsto \mathsf{pk_d} = [\mathsf{ivk}]\, \mathsf{g_d}$ is 1-1, any change to $\mathsf{ivk}$ for a given $\mathsf{g_d}$ results in a change to $\mathsf{pk_d}$, which goes through $\mathsf{H^{rcm}}$; -* when $\mathsf{split\_flag} = \mathsf{false}$, $\mathsf{rseed}$ goes through $\mathsf{H}^{\text{ψ}}$ - and then $\mathsf{H^{rcm}}$; +* $\mathsf{rseed}$ goes through $\mathsf{H}^{\text{ψ}}$ and then $\mathsf{H^{rcm}}$; * $\mathsf{use\_qsk}$ only has two possible values, and therefore can't increase the adversary's advantage by more than a factor of $2$ provided that both alternatives are otherwise secure; * when $\mathsf{use\_qsk} = \mathsf{false}$: @@ -1318,8 +1287,6 @@ oracles on all of their inputs.) But $\mathsf{noterepr}$ includes $\text{ρ}$, a already established that $\mathsf{nk}$ cannot be varied without affecting $\mathsf{pk_d}$. So with a little work we can see that such splitting is not possible. -TODO $\mathsf{split\_flag} = \mathsf{true}$. - An adversary could also attempt to cause a collision in $\mathsf{nf}$ by causing a collision on $\mathsf{Extract}_{\mathbb{P}}$, but this is also not feasible if $\mathsf{H^{rcm,Orchard}}$ can be modelled as a random oracle. @@ -1417,6 +1384,8 @@ manipulate the note selection algorithm to some extent. [^zip-0226]: [ZIP 226: Transfer and Burn of Zcash Shielded Assets](zip-0226.rst) +[^zip-0226-split-notes]: [ZIP 226: Transfer and Burn of Zcash Shielded Assets — Split Notes](zip-0226.rst#split-notes) + [^zip-0227]: [ZIP 227: Issuance of Zcash Shielded Assets](zip-0227.rst) [^zip-0230]: [ZIP 230: Version 6 Transaction Format](zip-0230.rst) From abbe195d911c008e7102f23425cb9b745cf2a961 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Sun, 26 Apr 2026 21:40:43 +0100 Subject: [PATCH 029/115] ZIP 2005: generalize "recoverable note" terminology MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Promote "recoverable note" and "recoverable note plaintext" from project-bound terms ("recoverable Orchard[ZSA] note") to forward- compatible generic terms in the notation block, with "as initially deployed, these are necessarily Orchard or OrchardZSA notes or note plaintexts" anchoring the current scope. Sweep all uses of "pq-recoverable" → "recoverable" and "non-pq-recoverable" → "non-recoverable" through the document for consistency with the new generic-term definition. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --- zips/zip-2005.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index 41c2e21a3..c41880e03 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -39,8 +39,10 @@ The term "Orchard[ZSA]" in this document refers to the Orchard shielded protocol before the deployment of ZSAs, and to the OrchardZSA shielded protocol after the deployment of ZSAs. -The term "recoverable Orchard[ZSA] note" refers to an Orchard or OrchardZSA -note that was created according to this proposal. +The terms "recoverable note" and "recoverable note plaintext" refer to a +note or note plaintext that was created according to this proposal. As +initially deployed, these are necessarily Orchard or OrchardZSA notes or +note plaintexts. The term "Recovery Protocol" refers to a potential new shielded protocol that would allow recovery of funds held in recoverable Orchard[ZSA] notes. @@ -1328,7 +1330,7 @@ any security compromise and use 256-bit cryptovalues for both integrity and randomization, which would otherwise have been difficult. It is suggested to deploy this change with v6 transactions. That is, -every Orchard output of a v6-onward transaction will be a pq-recoverable +every Orchard output of a v6-onward transaction will be a recoverable note. This implies that when the pre-quantum protocol is turned off, v5 and earlier outputs will no longer be spendable. Since v6 already changes the note encryption in order to support memo bundles and ZSAs, @@ -1338,10 +1340,10 @@ wallets were following the old protocol after the Canopy upgrade and sending non-conformant note plaintexts. When a compliant wallet receives an Orchard note in a v5 or earlier -transaction, the associated funds are not pq-recoverable and need to be +transaction, the associated funds are not recoverable and need to be spent to v6 in order to make them so. -Note: if we prioritize spending non-pq-recoverable notes, it is +Note: if we prioritize spending non-recoverable notes, it is conceivable that an adversary could exploit this to improve [arity leakage attacks](https://github.com/zcash/zcash/issues/4332). On the other hand, adversaries can already choose note values to From 286049b68c4fed7695e28951024eccdca1ce0a2d Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Sun, 26 Apr 2026 21:40:43 +0100 Subject: [PATCH 030/115] ZIP 2005: update deployment-ordering language to reflect QR-may-deploy-without-ZSAs The original framing assumed Quantum Recoverability would deploy simultaneously with ZSAs and memo bundles. With the deployment-ordering decision that QR will almost certainly deploy before ZSAs, several places in the document needed to drop the simultaneous-deployment assumption: - Rewording in the "Abstract", "Introduction", "High-level summary of changes", "Usage with Zcash Shielded Assets" sections, and the introductory paragraph of "Specification Updates". - More substantive updates to the "Deployment" section to set out two deployment options. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --- zips/zip-2005.md | 97 +++++++++++++++++++++++++++--------------------- 1 file changed, 55 insertions(+), 42 deletions(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index c41880e03..d86ed36a1 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -52,12 +52,12 @@ many of its design decisions are intentionally left open. # Abstract -This ZIP proposes a change to the construction of Orchard[ZSA] notes -starting with v6 transactions, designed to improve Zcash's long-term -resilience against a significant potential threat to its security from -quantum computers. It does not by itself make the protocol secure against -quantum adversaries, but is intended to support a smoother transition to -future versions of Zcash designed to be so. +This ZIP proposes a change to the construction of Orchard[ZSA] notes, +designed to improve Zcash's long-term resilience against a significant +potential threat to its security from quantum computers. It does not +by itself make the protocol secure against quantum adversaries, but is +intended to support a smoother transition to future versions of Zcash +designed to be so. Specifically, if it were necessary to disable the current Orchard[ZSA] shielded protocol in order to prevent a discrete-log-breaking adversary @@ -114,8 +114,8 @@ Sapling [^zip-0032-sapling-child-key-derivation] [^zip-0032-sapling-internal-key and Orchard [^zip-0032-orchard-child-key-derivation] [^zip-0032-orchard-internal-key-derivation].) This proposal is implementable at low risk, and required changes to existing -libraries and wallets are small. It can be folded into other changes -necessary to implement ZSAs [^zip-0226] and Memo Bundles [^zip-0231]. +libraries and wallets are small. It can optionally be done at the same time +as changes necessary to implement Memo Bundles [^zip-0231] and/or ZSAs [^zip-0226]. # Requirements @@ -165,15 +165,16 @@ necessary to implement ZSAs [^zip-0226] and Memo Bundles [^zip-0231]. This subsection and the flow diagram below are non-normative. -In order to support ZSAs [^zip-0226] [^zip-0227] and memo bundles -[^zip-0231], v6 transactions require in any case a new note plaintext -format, with lead byte $\mathtt{0x03}.$ This gives us an opportunity -to change the way that the $\mathsf{pre\_rcm}$ value is computed for -this new format, by including all of the note fields in $\mathsf{pre\_rcm}$. -The resulting $\mathsf{rcm}$ is essentially a random function of the -note fields — this allows us to argue that the overall commitment -scheme is post-quantum binding, as long as the new derivation of -$\mathsf{rcm}$ is checked in the Recovery Protocol. +The Quantum Recoverability proposal was originally designed to be +deployed alongside ZSAs [^zip-0226] [^zip-0227] and memo bundles +[^zip-0231]. Whether or not that is still the case, we retain the +same approach of defining a new note plaintext format, with lead byte +$\mathtt{0x03}.$ The $\mathsf{pre\_rcm}$ value is computed differently +for this new format, by including all of the note fields in +$\mathsf{pre\_rcm}$. The resulting $\mathsf{rcm}$ is essentially a +random function of the note fields — this allows us to argue that the +overall commitment scheme is post-quantum binding, as long as the new +derivation of $\mathsf{rcm}$ is checked in the Recovery Protocol. Essentially the same technique also needs to be applied to the function $\mathsf{Commit^{ivk}}$ that is used to derive Orchard @@ -282,8 +283,8 @@ graph BT ## 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]. +This proposal has been designed to activate either prior to, or at the same +time as, 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}$. @@ -433,9 +434,10 @@ 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 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]). +specification, and to the contents of ZIPs as of February 2026. If other +changes for v6 transactions (memo bundles [^zip-0231], ZSAs [^zip-0226] +[^zip-0227]) are deployed simultaneously, these changes will need to be +merged with theirs. ### Changes to the Protocol Specification @@ -1298,13 +1300,13 @@ $\mathsf{H^{rcm,Orchard}}$ can be modelled as a random oracle. TBD: explain that such attacks can break Balance and Spendability, including Spendability for transactions after switching to the Recovery Protocol. -Note that we can identify the precise set of note commitments for -recoverable (lead byte $\mathtt{0x03}$) Orchard notes, since they are -the commitments for Orchard outputs of v6 transactions. -However, we cannot identify the precise set of nullifiers for -recoverable notes: an Orchard action in a v6 transaction could be -spending either a recoverable or non-recoverable note, and their -nullifier sets are indistinguishable. +Note that with [Deployment](#deployment) option 2 (deploying at the same time as +v6 transactions), we can identify the precise set of note commitments for +recoverable (lead byte $\mathtt{0x03}$) Orchard notes, since they are exactly +the commitments for Orchard outputs of v6 transactions. However, we cannot +identify the precise set of nullifiers for recoverable notes: an Orchard action +in a v6 transaction could be spending either a recoverable or non-recoverable +note, and their nullifier sets are indistinguishable. On the other hand, within the recovery circuit we know that the note being spent is recoverable. @@ -1329,19 +1331,30 @@ 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. -It is suggested to deploy this change with v6 transactions. That is, -every Orchard output of a v6-onward transaction will be a recoverable -note. This implies that when the pre-quantum protocol is turned off, -v5 and earlier outputs will no longer be spendable. Since v6 already -changes the note encryption in order to support memo bundles and ZSAs, -this approach to deployment reduces the risk of the kind of difficulties -that occurred with [ZIP 212](https://zips.z.cash/zip-0212), where some -wallets were following the old protocol after the Canopy upgrade and -sending non-conformant note plaintexts. - -When a compliant wallet receives an Orchard note in a v5 or earlier -transaction, the associated funds are not recoverable and need to be -spent to v6 in order to make them so. +There are two options for deployment: + +1. Deploy this change prior to the next network upgrade. This would + optimize time-to-deployment. An activation height is still needed + so that wallets do not start sending recoverable note plaintexts + before the receiving wallet can have been expected to upgrade. +2. Deploy this change at the same time as the next network upgrade (NU7), + at the same time as v6 transactions. + +With either option, it is proposed to enforce this change with v6 +transactions. That is, every Orchard output of a v6-onward transaction +will be a recoverable note. This implies that when the pre-quantum +protocol is turned off, v5 and earlier outputs will no longer be spendable. + +Deploying via a transaction-version bump (rather than as a soft addition +within v5) reduces the risk of the kind of difficulties that occurred with +[ZIP 212](https://zips.z.cash/zip-0212), where some wallets were following +the old protocol after the Canopy upgrade and sending non-conformant note +plaintexts. If memo bundles or ZSAs are deployed simultaneously, those +changes share the same version-bump signal. + +When a compliant wallet receives an Orchard note with lead byte +$\mathtt{0x02}$, the associated funds are not recoverable and need to be +spent to a recoverable note in order to make them so. Note: if we prioritize spending non-recoverable notes, it is conceivable that an adversary could exploit this to improve From eb01840a15f4bceab284db516a5f07654332dfc9 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Mon, 27 Apr 2026 08:08:33 +0100 Subject: [PATCH 031/115] Consistently use "discrete logarithm" (rather than "discrete log") and related terms across the protocol specification and ZIP 2005. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --- protocol/protocol.tex | 98 +++++++++++++++++++++---------------------- zips/zip-2005.md | 18 ++++---- 2 files changed, 59 insertions(+), 57 deletions(-) diff --git a/protocol/protocol.tex b/protocol/protocol.tex index 80b64a816..33c529ace 100644 --- a/protocol/protocol.tex +++ b/protocol/protocol.tex @@ -882,10 +882,11 @@ \newcommand{\primeOrderCurve}{\term{prime-order curve}} \newcommand{\primeOrderCurves}{\terms{prime-order curve}} \newcommand{\hashToCurve}{\term{hash-to-curve}} -\newcommand{\xDiscreteLogarithmProblem}{\term{Discrete Logarithm Problem}} -\newcommand{\xDiscreteLogarithm}{\termandindex{Discrete Logarithm}{Discrete Logarithm Problem}} -\newcommand{\xDecisionalDiffieHellmanProblem}{\term{Decisional Diffie--Hellman Problem}} -\newcommand{\xDecisionalDiffieHellman}{\termandindex{Decisional Diffie--Hellman}{Decisional Diffie--Hellman Problem}} +\newcommand{\discreteLogarithm}{\term{discrete logarithm}} +\newcommand{\DiscreteLogarithmProblem}{\term{Discrete Logarithm Problem}} +\newcommand{\DiscreteLogarithmIndependence}{\term{Discrete Logarithm Independence}} +\newcommand{\DecisionalDiffieHellmanProblem}{\term{Decisional Diffie--Hellman Problem}} +\newcommand{\DecisionalDiffieHellmanAssumption}{\termandindex{Decisional Diffie--Hellman assumption}{Decisional Diffie--Hellman Problem}} \newcommand{\partitioningOracleAttack}{\term{partitioning oracle attack}} \newcommand{\partitioningOracleAttacks}{\terms{partitioning oracle attack}} \newcommand{\sideChannel}{\term{side-channel}} @@ -4970,15 +4971,15 @@ a sequence of \emph{distinct} inputs $m_{\alln} \typecolon \typeexp{\SubgroupGHashInput}{n}$ and a sequence of nonzero $x_{\alln} \typecolon \typeexp{\GFstar{\ParamG{r}}}{n}$ such that $\ssum{i = 1}{n}\!\Big(\scalarmult{x_i}{\SubgroupGHash{\URS}(m_i)}\Big) = \ZeroG{}$. - \item Under the \xDiscreteLogarithm assumption on $\SubgroupG{}$, a \randomOracle almost surely satisfies - Discrete Logarithm Independence. Discrete Logarithm Independence implies \collisionResistance\!, - since a collision $(m_1, m_2)$ for $\SubgroupGHash{\URS}$ trivially gives a - discrete logarithm relation with $x_1 = 1$ and $x_2 = -1$. + \item Assuming hardness of the \DiscreteLogarithmProblem on $\SubgroupG{}$, a \randomOracle almost + surely satisfies \DiscreteLogarithmIndependence. \DiscreteLogarithmIndependence implies + \collisionResistance\!, since a collision $(m_1, m_2)$ for $\SubgroupGHash{\URS}$ trivially + gives a \discreteLogarithm relation with $x_1 = 1$ and $x_2 = -1$. \item $\GroupJHash{}$ is used in \crossref{concretediversifyhash} to instantiate $\DiversifyHash{Sapling}$. We do not know how to prove the Unlinkability property defined in that section in the standard model, but in a model where $\GroupJHash{}$ (restricted to inputs for which it does not return $\bot$) is taken as a \randomOracle, - it is implied by the \xDecisionalDiffieHellman assumption on $\SubgroupJ$\nufive{, + it is implied by the \DecisionalDiffieHellmanAssumption on $\SubgroupJ$\nufive{, and similarly for $\GroupPHash$}. \item $\URS$ is a \defining{\uniformRandomString}; we chose it verifiably at random (see \crossref{beacon}), after fixing the concrete group hash algorithm to be used. @@ -6404,7 +6405,7 @@ $\ZeroP$. Allowing the validity check to pass in that case models the fact that incomplete addition is used to implement Sinsemilla in the circuit. As proven in \theoremref{thmsinsemillaex}, a $\bot$ output from $\SinsemillaHash$ yields a - nontrivial discrete logarithm relation. Since we assume finding such a relation to be + nontrivial \discreteLogarithm relation. Since we assume finding such a relation to be infeasible, we can argue that it is safe to allow an adversary to create a proof that passes the Merkle validity check in such a case. } %nufive @@ -6679,7 +6680,7 @@ We now explain why this works. \vspace{1ex} -A \saplingBindingSignature proves knowledge of the discrete logarithm $\BindingPrivate{Sapling}$ +A \saplingBindingSignature proves knowledge of the \discreteLogarithm $\BindingPrivate{Sapling}$ of $\BindingPublic{Sapling}$ with respect to $\ValueCommitRandBase{Sapling}$. That is, $\BindingPublic{Sapling} = \scalarmult{\BindingPrivate{Sapling}}{\ValueCommitRandBase{Sapling}}$. So the value $0$ and randomness $\BindingPrivate{Sapling}$ is an opening of the \xPedersenCommitment @@ -6714,7 +6715,7 @@ Suppose that $\vSum = \vBad \neq 0 \pmod{\ParamJ{r}}$. Then $\BindingPublic{Sapling} = \ValueCommit{Sapling}{\BindingPrivate{Sapling}}(\vBad)$. -If the adversary were able to find the discrete logarithm of this $\BindingPublic{Sapling}$ +If the adversary were able to find the \discreteLogarithm of this $\BindingPublic{Sapling}$ with respect to $\ValueCommitRandBase{Sapling}$, say ${\BindingPrivate{}}'$ (as needed to create a valid \saplingBindingSignature), then $(\vBad, \BindingPrivate{Sapling})$ and $(0, {\BindingPrivate{}}')$ would be distinct openings of $\BindingPublic{Sapling}$ to different @@ -6873,7 +6874,7 @@ value commitments, and a different bound on the net value sum $\vSum$. \vspace{1ex} -An \orchardBindingSignature proves knowledge of the discrete logarithm $\BindingPrivate{Orchard}$ +An \orchardBindingSignature proves knowledge of the \discreteLogarithm $\BindingPrivate{Orchard}$ of $\BindingPublic{Orchard}$ with respect to $\ValueCommitRandBase{Orchard}$. That is, $\BindingPublic{Orchard} = \scalarmult{\BindingPrivate{Orchard}}{\ValueCommitRandBase{Orchard}}$. So the value $0$ and randomness $\BindingPrivate{Orchard}$ is an opening of the \xPedersenCommitment @@ -6904,7 +6905,7 @@ Suppose that $\vSum = \vBad \neq 0 \pmod{\ParamJ{r}}$. Then $\BindingPublic{Orchard} = \ValueCommit{Orchard}{\BindingPrivate{Orchard}}(\vBad)$. -If the adversary were able to find the discrete logarithm of this $\BindingPublic{Orchard}$ +If the adversary were able to find the \discreteLogarithm of this $\BindingPublic{Orchard}$ with respect to $\ValueCommitRandBase{Orchard}$, say ${\BindingPrivate{}}'$ (as needed to create a valid \orchardBindingSignature), then $(\vBad, \BindingPrivate{Orchard})$ and $(0, {\BindingPrivate{}}')$ would be distinct openings of $\BindingPublic{Orchard}$ to different @@ -7682,7 +7683,7 @@ assumed to allow them to control the output. (The formal output of $\SinsemillaHashToPoint$ is $\bot$ in such a case, while the output computed by the circuit would be nondeterministic.) But as proven in \theoremref{thmsinsemillaex}, these exceptional cases allow immediately - finding a nontrivial discrete logarithm relation. If the \xDiscreteLogarithmProblem is hard on the + finding a nontrivial \discreteLogarithm relation. If the \DiscreteLogarithmProblem is hard on the \pallasCurve, then finding such a case is infeasible. \end{nnotes} } %nufive @@ -8891,8 +8892,8 @@ \item Suppose that $\GroupJHash{}$ (restricted to inputs for which it does not return $\bot$) is modelled as a \randomOracle from \diversifiers to points of order $\ParamJ{r}$ on the \jubjubCurve. In this model, Unlinkability - of $\DiversifyHash{Sapling}$ holds under the \xDecisionalDiffieHellman assumption on the - \primeOrderSubgroup of points on the \jubjubCurve. + of $\DiversifyHash{Sapling}$ holds under the \DecisionalDiffieHellmanAssumption + on the \primeOrderSubgroup of points on the \jubjubCurve. To prove this, consider the ElGamal encryption scheme \cite{ElGamal1985} on this \primeOrderSubgroup, restricted to encrypting plaintexts encoded @@ -8911,11 +8912,10 @@ of the candidate \diversifiedPaymentAddresses.) So if ElGamal is \keyPrivate, then $\DiversifyHash{Sapling}$ is Unlinkable under the same conditions. - \cite[Appendix A]{BBDP2001} gives a security proof for \keyPrivacy - (both \nh{IK-CPA} and \nh{IK-CCA}) of ElGamal under the \xDecisionalDiffieHellman - assumption on the relevant group. (In fact the proof needed is the - ``small modification'' described in the last paragraph in which the generator - is chosen at random for each key.) + \cite[Appendix A]{BBDP2001} gives a security proof for \keyPrivacy (both \nh{IK-CPA} + and \nh{IK-CCA}) of ElGamal under the \DecisionalDiffieHellmanAssumption on the + relevant group. (In fact the proof needed is the ``small modification'' described in + the last paragraph in which the generator is chosen at random for each key.) \item It is assumed (also for the security of other uses of the group hash, such as Pedersen hashes and commitments) that the discrete @@ -8969,7 +8969,7 @@ $\PedersenHash$ is an algebraic \hashFunction with \collisionResistance (for fixed input length) derived from assumed hardness of the -\xDiscreteLogarithmProblem on the \jubjubCurve. +\DiscreteLogarithmProblem on the \jubjubCurve. It is based on the work of David Chaum, Ivan Damgård, Jeroen van de Graaf, Jurgen Bos, George Purdy, Eugène van Heijst and Birgit Pfitzmann in \cite{CDvdG1987}, \cite{BCP1988} and \cite{CvHP1991}, @@ -9146,7 +9146,7 @@ \vspace{-2ex} \defining{$\SinsemillaHash$} is an algebraic \hashFunction with \collisionResistance (for fixed input length) derived from assumed hardness -of the \xDiscreteLogarithmProblem. It is designed by Sean Bowe and \nh{Daira-Emma} Hopwood. +of the \DiscreteLogarithmProblem. It is designed by Sean Bowe and \nh{Daira-Emma} Hopwood. The motivation for introducing a new discrete-logarithm-based hash function (rather than using $\PedersenHash$) is to make efficient use of the lookups available in recent proof systems including \HaloTwo. @@ -9266,7 +9266,7 @@ \vspace{-2.5ex} We show a correspondence between Sinsemilla and a vector Pedersen hash, which allows using the security argument from \cite{BGG1995} to show that collision-resistance can be tightly reduced -to the \xDiscreteLogarithmProblem in $\mathbb{P}$. +to the \DiscreteLogarithmProblem in $\mathbb{P}$. \vspace{1ex} Define $\delta(a, b) = \begin{cases} @@ -9300,7 +9300,7 @@ Let $D \typecolon \byteseqs$ be a personalization input, and let $\ell \typecolon \range{0}{k \mult c}$. Finding a collision $M, M' \typecolon \bitseq{\ell}$ with $M \neq M'$ such that $\SinsemillaHashToPoint(D, M) = \SinsemillaHashToPoint(D, M') \neq \bot$ efficiently yields a nontrivial -discrete logarithm relation, and similarly for $\SinsemillaHash(D, M) = \SinsemillaHash(D, M') \neq \bot$. +\discreteLogarithm relation, and similarly for $\SinsemillaHash(D, M) = \SinsemillaHash(D, M') \neq \bot$. \end{theorem} \begin{proof} @@ -9321,9 +9321,9 @@ The fixed offset does not affect \collisionResistance in this context. (See below for why it cannot be eliminated for $\SinsemillaHash$, or when using incomplete addition.) \theoremref{thmsinsemillaex} will prove that a $\bot$ output from $\SinsemillaHashToPoint$ -yields a nontrivial discrete log relation. It follows that the \collisionResistance of +yields a nontrivial \discreteLogarithm relation. It follows that the \collisionResistance of $\SinsemillaHashToPoint$ can be tightly reduced, via the proof in \cite[Appendix A]{BGG1995}, -to the \xDiscreteLogarithmProblem over $\GroupP$. +to the \DiscreteLogarithmProblem over $\GroupP$. Note that \cite{BGG1995} requires for their main scheme that the scalars are nonzero, which is not necessarily the case in our context. However, their proof in Appendix A does not depend @@ -9335,7 +9335,7 @@ Now we consider $\SinsemillaHash$. We want to prove that, for given $D$, if we can find two distinct messages $M$ and $M'$ such that $\ExtractPbot\smash{\big(\SinsemillaHashToPoint(D, M)\kern-0.1em\big)} = \ExtractPbot\smash{\big(\SinsemillaHashToPoint(D, M')\kern-0.1em\big)} \neq \bot$ then we can efficiently -extract a discrete logarithm. +extract a \discreteLogarithm. The inputs to $\ExtractPbot$ are not $\bot$, therefore they are in $\GroupP$. $\ExtractPbot$ maps $P, Q \in \GroupP$ to the same output if and only if $P = \pm Q$. @@ -9351,12 +9351,12 @@ \vspace{1ex} Because $2^{n+1} \leq \ParamP{r}-1$, the coefficients $\!\!\pmod{\ParamP{r}}$ are not all zero, and therefore -this is a nontrivial discrete logarithm relation between independent bases. +this is a nontrivial \discreteLogarithm relation between independent bases. \end{proof} \begin{nnotes} - \item \cite[Lemma 3]{JT2020} proves a tight reduction from finding a nontrivial discrete logarithm - relation in a \primeOrderGroup to solving the \xDiscreteLogarithmProblem in that group. + \item \cite[Lemma 3]{JT2020} proves a tight reduction from finding a nontrivial \discreteLogarithm + relation in a \primeOrderGroup to solving the \DiscreteLogarithmProblem in that group. \item The above theorem easily extends to the case where additional scalar multiplication terms with independent bases may be added to the $\SinsemillaHashToPoint$ output before applying $\ExtractPbot$. This is needed to show security of the $\SinsemillaShortCommitAlg$ \commitmentScheme defined in @@ -9370,7 +9370,7 @@ \introsection \theoremlabel{thmsinsemillaex} -\begin{theorem}[A $\bot$ output from $\SinsemillaHashToPoint$ yields a nontrivial discrete log relation]\end{theorem} +\begin{theorem}[$\SinsemillaHashToPoint(\ldots) = \bot$ yields a nontrivial \discreteLogarithm relation]\end{theorem} \begin{proof} For convenience of reference, we repeat the algorithm for $\SinsemillaHashToPoint$ in terms @@ -9401,7 +9401,7 @@ \vspace{-0.5ex} $\Acc_i$ has a representation $\scalarmult{2^i}{\SinsemillaGenInit(D)} + \ssum{j=0}{2^k - 1} \,\scalarmult{X_{i,j+1}}{\SinsemillaGenBase(j)}$ for some $X_i \typecolon \typeexp{\binaryrange{i}}{2^j}$. -So given $m$ that results in an exceptional case, the nontrivial discrete logarithm relation +So given $m$ that results in an exceptional case, the nontrivial \discreteLogarithm relation $\scalarmult{\alpha \mult 2^i}{\SinsemillaGenInit(D)} + \Big(\ssum{j=0}{\smash{2^k - 1}} \,\scalarmult{\alpha \mult X_{i,j+1}}{\SinsemillaGenBase(j)}\kern-0.15em\Big) + \SinsemillaGenBase(m_i) = \ZeroP$ is easily computable from $m$. The coefficients in this representation do not overflow since $X_{i,j+1} < 2^i$ for all $i \in \range{1}{n}$ and $j \in \binaryrange{k}$; and @@ -9409,10 +9409,10 @@ \end{proof} \vspace{-0.5ex} -Similarly, a $\bot$ output from $\SinsemillaHash$ yields a nontrivial discrete logarithm relation, +Similarly, a $\bot$ output from $\SinsemillaHash$ yields a nontrivial \discreteLogarithm relation, because $\ExtractPbot$ only returns $\bot$ when its input is $\bot$. -Since by assumption it is hard to find a nontrivial discrete logarithm relation, +Since by assumption it is hard to find a nontrivial \discreteLogarithm relation, we can argue that it is safe to use incomplete additions when computing Sinsemilla inside a circuit. } %nufive @@ -9491,7 +9491,7 @@ against a potential discrete-log-breaking adversary. Given the weak assumption that the $\PoseidonHash$ sponge produces output that preserves sufficient entropy from the inputs $\NullifierKey$ and $\NoteUniqueRand$, this nullifier - construction would still be secure under a \xDecisionalDiffieHellman assumption + construction would still be secure under a \DecisionalDiffieHellmanAssumption on the \Pallas curve, even if the $\Poseidon$-based PRF were distinguishable from an ideal PRF. \item The constant $2^{65}$ comes from \cite[section 4.2]{GKRRS2019}: @@ -10464,7 +10464,7 @@ \vspace{-2ex} \securityrequirement{ \nufive{Each instantiation of} $\BindingSig{}$ must be a \nh{SUF-CMA-secure} \keyMonomorphicSignatureScheme -as defined in \crossref{abstractsigmono}. A signature must prove knowledge of the discrete logarithm of +as defined in \crossref{abstractsigmono}. A signature must prove knowledge of the \discreteLogarithm of the \validatingKey with respect to the base $\ValueCommitRandBase{Sapling}$\nufive{ or $\ValueCommitRandBase{Orchard}$}. } %securityrequirement @@ -10724,7 +10724,7 @@ \vspace{1ex} The probability of $\SinsemillaHashToPoint$ returning $\bot$ is insignificant -(and would yield a nontrivial discrete logarithm relation). +(and would yield a nontrivial \discreteLogarithm relation). The \binding property of $\SinsemillaCommitAlg$ follows from \collisionResistance of $\SinsemillaHashToPoint$ proven in \theoremref{thmsinsemillacr}, given that $\GroupPHash\Of{D \bconcat \ascii{-r}, \ascii{}}$ is independent of any of the bases @@ -10803,7 +10803,7 @@ $\NoteCommitAlg{Orchard}$ in this specification, the implementation in the \actionCircuit constrains the result to an unspecified set of values when an input results in an exceptional case for any incomplete addition. If this - occurs then it yields a nontrivial discrete logarithm relation for the + occurs then it yields a nontrivial \discreteLogarithm relation for the \pallasCurve, as proven in \theoremref{thmsinsemillaex}. We can therefore assume that it is infeasible to find such inputs with nonnegligible probability. \item There are also no points in $\GroupP$ with \affineSW $x$-coordinate @@ -14775,7 +14775,7 @@ \crossref{rhoandnullifiers}). Resistance to Faerie Gold attacks, on the other hand, depends entirely on hardness -of the \xDiscreteLogarithmProblem. The $\NoteUniqueRand$ value of a \note created +of the \DiscreteLogarithmProblem. The $\NoteUniqueRand$ value of a \note created in a given \actionTransfer is obtained from the \nullifier of the \note spent in that \actionTransfer; this ensures (without any cryptographic assumption) that all $\NoteUniqueRand$ values of \notes added to the \noteCommitmentTree are unique. @@ -14784,7 +14784,7 @@ that \commitmentScheme ensures that \Orchard \nullifiers will be unique. (Specifically, this is a Sinsemilla commitment with an additional term having base $\NullifierBaseOrchard$, truncated to its $x$-coordinate. The $x$-coordinate truncation cannot harm -\collisionResistance because, assuming hardness of the \xDiscreteLogarithmProblem +\collisionResistance because, assuming hardness of the \DiscreteLogarithmProblem on the \pallasCurve, \crossref{sinsemillasecurity} covers the case where the additional term is added.) Roadblock attacks are not possible because $\NoteUniqueRand$ does not repeat for \notes in the \noteCommitmentTree, and by a corresponding argument @@ -14863,7 +14863,7 @@ These commitments are statistically \hiding, and so ``everlasting anonymity'' is supported for \SaplingAndOrchard notes under the same conditions as in \Zerocash (by the protocol, not necessarily by \zcashd). Note that -\diversifiedPaymentAddresses can be linked if the \xDecisionalDiffieHellmanProblem +\diversifiedPaymentAddresses can be linked if the \DecisionalDiffieHellmanProblem on the \jubjubCurve\nufive{ or the \pallasCurve} can be broken. } %saplingonward @@ -15688,7 +15688,7 @@ \crossref{inbandrationale}:\!\! \begin{itemize} \item The argument for decryption with an \incomingViewingKey does not need to - depend on the \xDecisionalDiffieHellmanProblem, since $\DiversifiedTransmitBase$ + depend on the \DecisionalDiffieHellmanProblem, since $\DiversifiedTransmitBase$ is committed to by the \noteCommitment as well as $\DiversifiedTransmitPublic$. \item It is necessary to say that the \noteCommitment is always checked for a successful decryption. @@ -15997,8 +15997,8 @@ \item Clarify the distinction between \Orchard \incomingViewingKeys and $\KA{Orchard}$ \privateKeys. \item Add a note in \crossref{concretesinsemillahash} that \cite[Lemma 3]{JT2020} proves - a tight reduction from finding a nontrivial discrete logarithm relation to the - \xDiscreteLogarithmProblem. + a tight reduction from finding a nontrivial \discreteLogarithm relation to the + \DiscreteLogarithmProblem. } %nufive \sapling{ \item Add a note to \crossref{merklepath} clarifying the encoding of $\rt{Sapling}$ @@ -16033,8 +16033,8 @@ a non-null $\prevoutField$ field. \item Caveat how the result of \cite{GG2015} applies to analysis of $\PRFnf{Orchard}{}$ in \crossref{concreteprfs}. - \item Unlinkability of \diversifiedPaymentAddresses depends on the \xDecisionalDiffieHellmanProblem, - not the \xDiscreteLogarithmProblem. + \item Unlinkability of \diversifiedPaymentAddresses depends on the \DecisionalDiffieHellmanProblem, + not the \DiscreteLogarithmProblem. \item Add a paragraph to \crossref{truncation} covering \Orchard. \item Clarify the definition of $\pad$ in \crossref{concretesinsemillahash} by disambiguating $\Mpieces$ from $\Mpadded$. @@ -18521,7 +18521,7 @@ The specification of the \xPedersenHashes used in \Sapling is given in \crossref{concretepedersenhash}. It is based on the scheme from \cite[section 5.2]{CvHP1991} --for which a tighter security reduction to -the \xDiscreteLogarithmProblem was given in \cite{BGG1995}-- but tailored +the \DiscreteLogarithmProblem was given in \cite{BGG1995}-- but tailored to allow several optimizations in the circuit implementation. \xPedersenHashes are the single most commonly used primitive in the diff --git a/zips/zip-2005.md b/zips/zip-2005.md index d86ed36a1..92f78dbd8 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -987,8 +987,9 @@ post-quantum knowledge-sound. $\mathsf{MerkleCRH^{Orchard}}$ is instantiated using $\mathsf{SinsimillaHash}$ [^protocol-concretesinsemillahash]. -Its collision resistance depends on the discrete log relation problem -on the Pallas curve [^protocol-sinsemillasecurity], and so it is not +Its collision resistance depends on the Discrete Logarithm Relation +Problem on the Pallas curve [^protocol-sinsemillasecurity], and so it +is not post-quantum collision-resistant or collapsing. However, because the note commitment tree is public, it is possible to re-hash all of its leaves to construct a new Merkle tree using a collapsing hash function. @@ -1008,9 +1009,10 @@ note. ### Attacks against binding of note commitments We still face the problem that $\mathsf{NoteCommit^{Orchard}}$ is not -binding against a discrete-log-breaking adversary: given the discrete log -relations between bases, we can easily write a linear equation in the -scalar field with multiple solutions of the inputs for a given commitment. +binding against a discrete-log-breaking adversary: given the discrete +logarithm relations between bases, we can easily write a linear equation +in the scalar field with multiple solutions of the inputs for a given +commitment. This allows an adversary to find two distinct notes corresponding to openings of $\mathsf{NoteCommit^{Orchard}}$ on the same commitment. @@ -1116,9 +1118,9 @@ note fields. Note that the argument associated with [Theorem 5.4.4](https://zips.z.cash/protocol/protocol.pdf#thmsinsemillaex) -in the protocol specification ("A $\bot$ output from -$\mathsf{SinsemillaHashToPoint}$ yields a nontrivial discrete log relation." -and "Since by assumption it is hard to find a nontrivial discrete logarithm +in the protocol specification ("$\mathsf{SinsemillaHashToPoint}(\ldots) = \bot$ +yields a nontrivial discrete logarithm relation." and +"Since by assumption it is hard to find a nontrivial discrete logarithm relation, we can argue that it is safe to use incomplete additions when computing Sinsemilla inside a circuit.") is not applicable when it is necessary to defend against a discrete-log-breaking or quantum adversary. From ed409fa998c895b15f9ea3a25879e65541bf7d7f Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Mon, 27 Apr 2026 12:47:22 +0100 Subject: [PATCH 032/115] CSS: make nested ordered lists in Markdown ZIPs numbered then alphabetic then lower-roman. Markdown source cannot specify `<ol type="...">` directly, so nested ordered lists in Markdown ZIPs would otherwise render all levels as numbered by default; now they are rendered as 1. a. i. The `:not([type])` qualifier preserves explicit type attributes emitted by the RST renderer or inline HTML, which can be semantically significant. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --- static/css/style.css | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/static/css/style.css b/static/css/style.css index 51d038e56..8ffef858c 100644 --- a/static/css/style.css +++ b/static/css/style.css @@ -422,6 +422,21 @@ li ol { margin-top: 0.25ex; } +/* +Default nested-ordered-list numbering for Markdown ZIPs (which have no way +to set `<ol type="...">` from source): ordered list levels are numeric, then +alphabetic, then lower-roman (e.g. 1. a. i.). The `:not([type])` qualifier +preserves explicit type attributes emitted by the RST renderer or inline HTML, +which can be semantically significant. +*/ +li ol:not([type]) { + list-style-type: lower-alpha; +} + +li ol:not([type]) li ol:not([type]) { + list-style-type: lower-roman; +} + li ul { margin-top: 0.25ex; } From 28460604cb7cc2728a199ba6de2c3c0e42c3eec5 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Mon, 27 Apr 2026 13:43:41 +0100 Subject: [PATCH 033/115] =?UTF-8?q?ZIP=202005:=20rename=20"Recovery=20circ?= =?UTF-8?q?uit=20/=20Recovery=20Protocol"=20=E2=86=92=20"Recovery=20Statem?= =?UTF-8?q?ent",=20and=20add=20anchored=20section=20header.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The recovery statement is the abstract object enforced by the proof; "circuit" is one possible implementation. Naming the section explicitly so other parts of the ZIP can link to it (`#proposedrecoverystatement`). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --- zips/zip-2005.md | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index 92f78dbd8..183a79314 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -220,8 +220,8 @@ graph BT The bold lines are changes introduced by this ZIP, which all take the form of additional inputs to derivation functions or alternative derivations. -The derivations shown in the box labelled "Potential recovery circuit" are, -roughly speaking, those enforced by the [Proposed Recovery Protocol]. +The derivations shown in the box labelled [Proposed Recovery Statement](#proposedrecoverystatement) +are, roughly speaking, those enforced by the section of that name. ```mermaid graph BT @@ -234,7 +234,7 @@ graph BT classDef spacer opacity:0; PostQC:::circuit - subgraph PostQC[<div style="margin:1.1em;font-size:20px"><b>Potential recovery circuit</b></div>] + subgraph PostQC[<div style="margin:1.1em;font-size:20px"><b>Proposed Recovery Statement</b></div>] direction BT rivk_ext([rivk_ext]) --> Hrivk_int[H<sup>rivk_int</sup>]:::func ak([ak]) --> Hrivk_int[H<sup>rivk_int</sup>]:::func @@ -845,6 +845,8 @@ 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. +### Proposed Recovery Statement + Import this definition from § 4.2.3 ‘Orchard Key Components’ [^protocol-orchardkeycomponents]: > 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)$. @@ -872,7 +874,7 @@ Import this definition from § 5.4.7.1 ‘Spend Authorization Signature (Saplin > 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: +A valid instance of a Recovery Statement assures that given a primary input: $\begin{array}{rl} \hspace{4.1em} ( \mathsf{rt^{Orchard}} \!\!\!\!&{\small ⦂}\; \{ 0\,..\,q_{\mathbb{P}}-1 \}, \\ @@ -955,7 +957,7 @@ So, supporting "$\mathsf{use\_qsk}$" in addition to "not $\mathsf{use\_qsk}$" costs very little extra. All of the operations below need to be implemented with complete additions, -even if they are incomplete in the current Orchard[ZSA] circuit. +even if they are incomplete in the current Orchard[ZSA] statement/circuit. * 7 BLAKE2b-512 compressions: * 3 multiplexed between $\mathsf{H^{rivk\_ext}}$ when $\mathsf{use\_qsk}$ is true (1 compression), @@ -1112,9 +1114,9 @@ TODO: discuss [^CBHSU2017] (sponge security), [^Unruh2015] [^Unruh2016] (collapse-binding property). The above security argument means that provided we also check the uses of -$\mathsf{H^{rcm}}$ and $\mathsf{H}^{\text{ψ}}$ in the post-quantum recovery -circuit, Orchard note commitments can be considered binding on all of the -note fields. +$\mathsf{H^{rcm}}$ and $\mathsf{H}^{\text{ψ}}$ in the post-quantum +[Recovery Statement](#proposedrecoverystatement), Orchard note commitments +can be considered binding on all of the note fields. Note that the argument associated with [Theorem 5.4.4](https://zips.z.cash/protocol/protocol.pdf#thmsinsemillaex) @@ -1124,8 +1126,8 @@ yields a nontrivial discrete logarithm relation." and relation, we can argue that it is safe to use incomplete additions when computing Sinsemilla inside a circuit.") is not applicable when it is necessary to defend against a discrete-log-breaking or quantum adversary. -Therefore, the post-quantum recovery circuit will need to use complete -curve additions to implement Sinsemilla. +Therefore, the post-quantum [Recovery Statement](#proposedrecoverystatement) +will need to use complete curve additions to implement Sinsemilla. ### Attacks against binding of ivk @@ -1220,15 +1222,15 @@ that hash, which would not hold against a discrete-log-breaking adversary. Does this mean it is possible to break Spendability for the given -Recovery circuit? As it turns out, no, but the argument is somewhat +Recovery Statement? As it turns out, no, but the argument is somewhat involved. TODO: this argument is too handwavy and depends on the ROM; it needs further work for a quantum adversary. -Since each function in the Recovery circuit is deterministic, the +Since each function in the Recovery Statement is deterministic, the free variables that the adversary can control are the sources of the -derivation digraph within that circuit and either $\mathsf{SoK^{sk}}$ +derivation digraph within that statement and either $\mathsf{SoK^{sk}}$ or $\mathsf{SoK^{qk}}$. That is, the adversary can control: * $(\text{ρ}, \mathsf{g_d}, \mathsf{rseed}, \mathsf{is\_internal\_rivk}, \mathsf{use\_qsk})$ and @@ -1240,7 +1242,7 @@ $\mathsf{rcm}$ binds $\mathsf{rseed}$ and $\mathsf{pre\_rcm}$, and all of the other inputs to $\mathsf{NoteCommit}$ are also included in $\mathsf{pre\_rcm}$. Therefore, given the independence assumption between $\mathsf{H^{rcm}}$ and $f$ described earlier, $\mathsf{cm}$ binds all -of the values in the Recovery circuit that the adversary can control. +of the values in the Recovery Statement that the adversary can control. We can then analyze $\mathsf{DeriveNullifier}$ in essentially the same way we analyzed $\mathsf{NoteCommit}$. @@ -1310,7 +1312,7 @@ identify the precise set of nullifiers for recoverable notes: an Orchard action in a v6 transaction could be spending either a recoverable or non-recoverable note, and their nullifier sets are indistinguishable. -On the other hand, within the recovery circuit we know that the +On the other hand, within the Recovery Statement we know that the note being spent is recoverable. # Deployment From e0c11c71e709448d80fafc10d2146a9d03989891 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Mon, 27 Apr 2026 13:44:38 +0100 Subject: [PATCH 034/115] ZIP 2005: restructure "Usage with hardware wallets", and add Threat model + Choosing-between-Options-A-and-B subsections. Reorganizes the existing two-paragraph treatment of the qsk-on-h/w vs qsk-exported-to-host trade-off into: - An introductory paragraph defining "host wallet" and listing the two qsk-storage options (A: qsk on hardware wallet, SoK^qsk produced on-device; B: qsk exported to host wallet as a fallback when on-device proving is infeasible). - A "Threat model" subsection enumerating the cases under which spend authorization is broken: (1) qsk possession + a discrete-log break on Pallas, in three variants 1.a/1.b/1.c keyed to where qsk was obtained; and (2) cryptographic break of any underlying primitive or scheme. - A "Choosing between Options A and B" subsection comparing the qsk attack surface under each option, plus a note on ZIP 32 hierarchical derivation making separate qsk backup unnecessary. Adds a footnote pointing at ZIP 312's Threat Model section. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --- zips/zip-2005.md | 120 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 98 insertions(+), 22 deletions(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index 183a79314..002638260 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -407,29 +407,101 @@ graph BT ``` When $\mathsf{use\_qsk}$ is used, on the other hand, it is possible for -the Recovery Protocol to support spend authorization using a much smaller -circuit that only uses $\mathsf{H^{qk}}$ and a commitment scheme. -For example, for some hiding and collapse binding commitment -$c = \mathsf{LinkCommit}_r(\mathsf{qk}, \mathsf{sighash}),$ +the Recovery Protocol to support spend authorization using a simpler +statement that only uses $\mathsf{H^{qk}}$ and a commitment scheme. +For example, for some hiding and collapse-binding commitment +$$\mathsf{c_{link}} = \mathsf{LinkCommit}_r(\mathsf{qk}, \mathsf{sighash})$$ the hardware wallet could prove knowledge of $(\mathsf{qsk}, r)$ such that -$c = \mathsf{LinkCommit}_r(\mathsf{H^{qk}}(\mathsf{qsk}), \mathsf{sighash}).$ -This circuit is relatively small and it might be feasible to do the proof in -quite constrained hardware. - -The host wallet would be given $\mathsf{nk},$ $\mathsf{ak},$ and $\mathsf{qk}$ -for use in the main Recovery circuit (discussed later). The commitment $c$ would -be a public input opened to $(\mathsf{qk}, \mathsf{sighash})$ in that circuit, -ensuring that the hardware wallet has authorized the spend for the correct key. -Because $\mathsf{LinkCommit}$ is hiding and the proofs are zero knowledge, no -information is leaked about which $\mathsf{qk}$ is being used. - -Alternatively, if the hardware wallet is unable to support making proofs at -all, it could be updated to permit exporting $\mathsf{qsk}$. This is less -secure against a quantum adversary that is able to obtain $\mathsf{qsk}$, but -it allows the funds to be transferred to another key or protocol. A quantum -adversary would have to break RedDSA in order to steal funds even if it were -to obtain $\mathsf{qsk}$, since $\mathsf{ask}$ would remain on the hardware -wallet. +$$\mathsf{c_{link}} = \mathsf{LinkCommit}_r(\mathsf{H^{qk}}(\mathsf{qsk}), \mathsf{sighash}).$$ +This statement, labelled as $\mathsf{SoK^{qsk}}$ in the diagram, can be +implemented in a much smaller circuit, so it might be feasible to do the +proof in quite constrained hardware. + +The commitment $\mathsf{c_{link}}$ would be a public input opened to +$(\mathsf{qk}, \mathsf{sighash})$ in the [Recovery Statement](#proposedrecoverystatement), +ensuring that the hardware wallet has authorized the spend for the correct +key. Because $\mathsf{LinkCommit}$ is hiding and the proofs are zero knowledge, +no information is leaked about which $\mathsf{qk}$ is being used. + +### Key storage options and analysis + +By *host wallet*, we mean the device that builds the spend transaction and +produces the rest of the Recovery Statement proof. In a multi-signer FROST +setup, this would be the Coordinator [^zip-0312-threat-model]. The host wallet +is given $\mathsf{nk},$ $\mathsf{ak},$ and (assuming $\mathsf{use\_qsk}$ is true) +$\mathsf{qk}$, for use in the Recovery Statement. Then two options are possible +for storage of $\mathsf{qsk}$: + +**Option A** — The $\mathsf{SoK^{qsk}}$ proof is produced inside the hardware +wallet, and $\mathsf{qsk}$ is retained there. + +**Option B** — Alternatively, if the hardware wallet is unable to support +proving $\mathsf{SoK^{qsk}}$, it could be updated to permit exporting +$\mathsf{qsk}$ to the host wallet, and the $\mathsf{SoK^{qsk}}$ proof would be +produced there. + +In either option, $\mathsf{ask}$ would remain on the hardware wallet which +would continue to produce RedDSA spend authorization signatures (or its part +of the FROST multi-signing protocol). + +#### Threat model + +The [Recovery Statement](#proposedrecoverystatement) is assumed below to +require both of: + +* an $\mathsf{SoK^{qsk}}$ proof verifying knowledge of $\mathsf{qsk}$ + such that $\mathsf{H^{qk}}(\mathsf{qsk}) = \mathsf{qk}$ for the + spent note's $\mathsf{qk}$; and +* a RedDSA signature on $\mathsf{ak}$, which under FROST is + constructed by cooperation of $t$-of-$n$ hardware-wallet signers, + each contributing using its share of $\mathsf{ask}$. + +Under this assumed structure, with FROST + hardware-wallet deployment, +spend authorization is broken only by either: + +1. **$\mathsf{qsk}$ possession + finding discrete logarithms on the + Pallas curve.** The variants differ only in *how* $\mathsf{qsk}$ + is obtained: + + <!-- rendered as a., b., c. --> + 1. the adversary is an authorized FROST signer — they hold a copy + of $\mathsf{qsk}$ by construction; + 2. $\mathsf{qsk}$ is extracted from a hardware wallet, defeating + Option A by a physical-device or side-channel attack; + 3. $\mathsf{qsk}$ is obtained after export to the host wallet, by + compromising the host wallet or intercepting it during export. + +2. **Breaking a primitive or scheme.** RedDSA, FROST, the DKG, or the + proving system has a cryptographic weakness or implementation flaw. + +#### Choosing between Options A and B + +Option A is preferred where the target hardware wallet is capable of +proving $\mathsf{SoK^{qsk}}$ on-device. Option B is a fallback for +cases where it cannot — for instance, due to memory or secure-element +constraints, uncertainty about the proof system that will be chosen +and what will be tractable on small devices, or the device having been +obsoleted before firmware support could be added. + +Under Option A, the host wallet holds only the full viewing key +($\mathsf{ak}$, $\mathsf{nk}$) —which the pre-Quantum-Recoverability +protocol already entrusted to it— plus $\mathsf{qk}$. The $\mathsf{qsk}$ +attack surface is then 1.a. or 1.b. only. + +Option B additionally places $\mathsf{qsk}$ on the host wallet, admitting +case 1.c. as well. This has the disadvantage that host-wallet compromise +is a substantially larger attack surface than hardware-wallet extraction. +However, even with $\mathsf{qsk}$ in hand, an adversary would still need +to break RedDSA or find discrete logarithms on the Pallas curve to steal +funds. + +Note: with ZIP 32 hierarchical derivation, $\mathsf{qsk}$ need not be +backed up separately from the seed phrase. When $\mathsf{use\_qsk}$ is +true, $\mathsf{qsk} = \mathsf{H^{qsk}}(\mathsf{sk})$ where $\mathsf{sk}$ +is the HD-derived spending key, and so $\mathsf{qsk}$ can be re-derived +from the seed phrase (with or without SLIP 39 Shamir backup [^slip-0039]). +A deployment that does not use ZIP 32 is responsible for the security of +its own backup arrangements. ## Specification Updates @@ -1399,6 +1471,8 @@ manipulate the note selection algorithm to some extent. [^zip-0032-orchard-internal-key-derivation]: [ZIP 32: Shielded Hierarchical Deterministic Wallets — Orchard internal key derivation](zip-0032.rst#orchard-internal-key-derivation) +[^slip-0039]: [SLIP-0039: Shamir's Secret-Sharing for Mnemonic Codes](https://github.com/satoshilabs/slips/blob/master/slip-0039.md) + [^zip-0200]: [ZIP 200: Network Upgrade Mechanism](zip-0200.rst) [^zip-0226]: [ZIP 226: Transfer and Burn of Zcash Shielded Assets](zip-0226.rst) @@ -1415,6 +1489,8 @@ manipulate the note selection algorithm to some extent. [^zip-0312-key-generation]: [ZIP 312: FROST for Spend Authorization Multisignatures — Key Generation](zip-0312.rst#key-generation) +[^zip-0312-threat-model]: [ZIP 312: FROST for Spend Authorization Multisignatures — Threat Model](zip-0312.rst#threat-model) + [^zcash-security]: Understanding Zcash Security ([video](https://www.youtube.com/watch?v=f6UToqiIdeY), [slides](https://raw.githubusercontent.com/daira/zcash-security/main/zcash-security.pdf)). Presentation by Daira-Emma Hopwood at Zcon3. [^pq-zcash]: Post-Quantum Zcash ([video](https://www.youtube.com/watch?v=T2B5f297d-Y), [slides](https://docs.google.com/presentation/d/1BHBiSOEO5zt40KWBbRXVMGIIuAcT2hfPWZQ3pT_8tm8/edit?slide=id.g335164f3026_0_113#slide=id.g335164f3026_0_113)). Presentation by Daira-Emma Hopwood at ZconVI. From 4b67094f0ae90759e52ff4d3e23df970580af2f2 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Mon, 27 Apr 2026 13:45:25 +0100 Subject: [PATCH 035/115] ZIP 2005: editorial polish in Requirements, Note Plaintexts (rcm derivation), Spend Authorization, and Informal Security Argument. Several orthogonal prose improvements: - Requirements: drop the "(This is motivated by the fact that there is likely to be a period during which quantum attacks may be possible but very difficult.)" parenthetical from the pre-quantum-security bullet. The qualification was over-confident given recent quantum progress, and is not load-bearing for the requirement itself. - Note Plaintexts subsection: surface the ROM heuristic explicitly when arguing that the new rcm derivation makes the commitment scheme post-quantum binding ("an adversary constrained to treat the PRF as a random oracle ..."), rather than asserting that rcm "is essentially a random function of the note fields". - Spend Authorization treatment: replace the "most likely eventuality is that attacks will be difficult for some years after the current Orchard protocol is disabled" timeline-speculation with a precise conditional ("during any period in which the adversary cannot find discrete logarithms on the Pallas curve"); restructure the FROST- advantage clause as a surrounding-em-dash aside. - Informal Security Argument: minor improvements to the wording of the first paragraph. - Make the spellings of is_internal_rivk and noterepr consistent. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --- zips/zip-2005.md | 77 ++++++++++++++++++++++++------------------------ 1 file changed, 39 insertions(+), 38 deletions(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index 002638260..e5c83a3c9 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -137,9 +137,7 @@ as changes necessary to implement Memo Bundles [^zip-0231] and/or ZSAs [^zip-022 of that protocol's pre-quantum security. * The Recovery Protocol should ensure no loss of security against pre-quantum adversaries — including when FROST multisignatures and/or - hardware wallets are used. (This is motivated by the fact that there - is likely to be a period during which quantum attacks may be possible - but very difficult.) + hardware wallets are used. * Recovery of funds from hardware wallets that support this protocol should not require exposing the pre-quantum spend authorizing key $\mathsf{ask}$ to theft. @@ -171,9 +169,11 @@ deployed alongside ZSAs [^zip-0226] [^zip-0227] and memo bundles same approach of defining a new note plaintext format, with lead byte $\mathtt{0x03}.$ The $\mathsf{pre\_rcm}$ value is computed differently for this new format, by including all of the note fields in -$\mathsf{pre\_rcm}$. The resulting $\mathsf{rcm}$ is essentially a -random function of the note fields — this allows us to argue that the -overall commitment scheme is post-quantum binding, as long as the new +$\mathsf{pre\_rcm}$. This means that an adversary constrained to treat +the PRF used to derive $\mathsf{rcm}$ from $\mathsf{pre\_rcm}$ as a +random oracle, could not vary any note field without producing a +different $\mathsf{rcm}$. This lets us argue that the overall +commitment scheme is post-quantum binding, as long as the new derivation of $\mathsf{rcm}$ is checked in the Recovery Protocol. Essentially the same technique also needs to be applied to the @@ -345,33 +345,31 @@ and when the current Orchard protocol is disabled. The Recovery Protocol will still require a RedDSA signature verifiable by the Spend validating key $\mathsf{ak}$, in addition to knowledge of -$\mathsf{qsk}$. Although RedDSA is not secure in the long term against a -quantum or discrete-log-breaking adversary, the most likely eventuality is -that attacks against it will be difficult for some years after the current -Orchard protocol is disabled. During this period, checking this RedDSA -signature in the Recovery Protocol will ensure that spend authorization by -a $t$-of-$n$ threshold of participants continues to be needed against -classical adversaries. This retains the usual advantage of FROST that the -parties can sign using their shares *without* reconstructing the Spend -authorizing key $\mathsf{ask}$. Coalitions of fewer than $t$ of the -participants will be unable to authorize spends as long as they do not -have access to a sufficiently powerful quantum computer. +$\mathsf{qsk}$. RedDSA is not secure in the long term against a quantum +or discrete-log-breaking adversary. However, during any period in which +the adversary cannot find discrete logarithms on the Pallas curve, +checking this RedDSA signature will ensure that spend authorization +continues to require a $t$-of-$n$ threshold of participants. +An important advantage of FROST —that the parties can sign using their +shares *without* reconstructing $\mathsf{ask}$, the Spend authorizing +key— is retained. Note that a quantum adversary may be able to steal the funds with only -access to $\mathsf{qsk}$, which is held by every participant. Therefore, -it is RECOMMENDED that as soon as a fully post-quantum protocol that -supports multisignatures is available, all funds held under FROST keys +access to $\mathsf{qsk}$, which is held by every participant (see below +for more detail on [Key storage options](#keystorageoptionsandanalysis)). +Therefore, it is RECOMMENDED that as soon as a fully post-quantum protocol +that supports multisignatures is available, all funds held under FROST keys be transferred into that protocol's shielded pool. ## Usage with hardware wallets The same $\mathsf{use\_qsk}$ option can help to improve the efficiency of -using the Recovery Protocol with hardware wallets. If the keys -$\mathsf{rivk\_ext},$ $\mathsf{nk},$ and $\mathsf{ak}$ are generated from -$\mathsf{sk},$ then the circuit for the Recovery Protocol will need to -prove their correct derivation using $\mathsf{H^{rivk\_legacy}},$ -$\mathsf{H^{nk}},$ $\mathsf{H^{ask}},$ and $\mathsf{DerivePublic}$ as -shown in the $\mathsf{SoK^{sk}}$ box of the diagram below. +using the [Recovery Protocol](#proposedrecoveryprotocol) with hardware +wallets. If the keys $\mathsf{rivk\_ext},$ $\mathsf{nk},$ and $\mathsf{ak}$ +are generated from $\mathsf{sk},$ then the circuit for the Recovery Protocol +will need to prove their correct derivation using $\mathsf{H^{rivk\_legacy}},$ +$\mathsf{H^{nk}},$ $\mathsf{H^{ask}},$ and $\mathsf{DerivePublic}$ as shown +in the $\mathsf{SoK^{sk}}$ box of the diagram below. ```mermaid graph BT @@ -993,16 +991,16 @@ $\begin{array}{l} \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 \\ -\mathsf{H^{rivk\_int}_{rivk\_ext}}(\mathsf{ak}, \mathsf{nk})&\text{if } \mathsf{is\_rivk\_internal} = 1 \end{cases} \\ +\mathsf{rivk\_ext},&\text{if not } \mathsf{is\_internal\_rivk} \\ +\mathsf{H^{rivk\_int}_{rivk\_ext}}(\mathsf{ak}, \mathsf{nk}),&\text{if } \mathsf{is\_internal\_rivk} \end{cases} \\ \wedge\; \mathsf{ak} = \mathsf{Extract}_{\mathbb{P}}(\mathsf{ak}^{\mathbb{P}}) \\ \wedge\; \text{let } \mathsf{ivk} = \mathsf{Commit^{ivk}_{rivk}}(\mathsf{ak}, \mathsf{nk}) \\ \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{ρ}}) \\ -\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\; \text{let } \mathsf{noterepr} = \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{noterepr}\big) \\ +\wedge\; \text{let } \mathsf{cm} = \mathsf{NoteCommit^{Orchard}_{rcm}}(\mathsf{noterepr}) \\ \wedge\; \mathsf{cm} \neq \bot \\ \wedge\; \text{let } \mathsf{cm}_x = \mathsf{Extract}_{\mathbb{P}}(\mathsf{cm}) \\ \wedge\; \text{let } \mathsf{leaf} = \mathsf{MerkleCRH}(\mathsf{cm}_x, \text{ρ}) \\ @@ -1230,13 +1228,16 @@ desirable to switch to new addresses. ## Informal Security Argument -The argument is that if $\mathsf{H^{rcm}}$ and $\mathsf{H^{\text{φ}}}$ are -random oracles, $\mathsf{rcm}$ is an unpredictable function of the note fields. -There are two values of $\mathsf{cm}$ that match $\mathsf{cm}_x$ in their -$x$-coordinate. Because the output of $\mathsf{NoteCommit^{Orchard}}$ is of -the form $\mathsf{cm} = F(\mathsf{note}) + [\mathsf{rcm}]\, \mathcal{R}$, -for any given note we have exactly two values of $\mathsf{rcm}$ that will -pass the commitment check. +The informal security argument that we can only spend valid notes goes as +follows: + +If $\mathsf{H^{rcm}}$ and $\mathsf{H^{\text{φ}}}$ are treated as random oracles, +$\mathsf{rcm}$ is an unpredictable function of the note fields. There are two +values of $\mathsf{cm}$ that match $\mathsf{cm}_x$ in their $x$-coordinate. +Because the output of $\mathsf{NoteCommit^{Orchard}_{rcm}}(\mathsf{noterepr})$ is +of the form $\mathsf{cm} = F(\mathsf{noterepr}) + [\mathsf{rcm}]\, \mathcal{R}$, +for any given note we have exactly two values of $\mathsf{rcm}$ that will pass +the commitment check. Suppose there are $N$ legitimate notes in the tree. The adversary is trying to find (possibly using a Grover search) a note that will pass the commitment From 944cefb09bb3a99689cb2cfc4114b3d9d5c3b764 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Tue, 28 Apr 2026 14:41:33 +0100 Subject: [PATCH 036/115] =?UTF-8?q?ZIP=202005:=20=C2=A7=204.2.3=20derivati?= =?UTF-8?q?on=20algorithm=20and=20notes=20accommodate=20FROST.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous wording of the use_qsk=true branch said "generate ask : F*_{r_P} and corresponding SpendAuthSig public key ak^P : P* using any suitably secure method...", which implied a single ask scalar. Under FROST, the spend- authorization material is t-of-n shared and never exists as a single value. Reworded to lead with ak^P and treat the underlying material as implementation-specific (single ask via H^ask(sk), or FROST DKG, or other secure methods). The accompanying recovery note bifurcated by use_qsk and required retaining (ak, nk, rivk, qsk, ask-signing-capability) in the use_qsk=true case. With sk being sufficient to re-derive nk, qsk, qk, and rivk (modulo knowing use_qsk), the bifurcation collapses: in all cases sk is sufficient, with FROST adding the requirement to retain the group verifying key ak and the t-of-n spend-authorization material. Also clarifies the use_qsk flag definition (it controls whether qsk/qk are generated and used in rivk derivation; it does not control how ask is derived) and standardizes "rivk_{internal}" → "rivk\_internal" (leftover from a previous naming convention). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --- zips/zip-2005.md | 54 ++++++++++++++++++++++-------------------------- 1 file changed, 25 insertions(+), 29 deletions(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index e5c83a3c9..fb756ff99 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -597,12 +597,12 @@ in the algorithm with: > [[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 -> $\mathsf{ask}$ is derived directly from $\mathsf{sk}$. (In cases where -> it is desired for the generation of key components to match versions of -> this specification prior to {{ fill in version }}, $\mathsf{use\_qsk}$ -> needs to be set to false.) +> Let $\mathsf{use\_qsk} \;{\small ⦂}\; \mathbb{B}$ be a flag indicating +> whether $\mathsf{qsk}$ and $\mathsf{qk}$ are generated and used in the +> derivation of $\mathsf{rivk}$. (In cases where it is desired for the +> generation of key components to match versions of this specification +> prior to {{ fill in version }}, $\mathsf{use\_qsk}$ needs to be set to +> false.) > > Define: > * $\mathsf{H^{ask}}(\mathsf{sk}) = \mathsf{ToScalar^{Orchard}}\big(\mathsf{PRF^{expand}_{sk}}([\mathtt{0x06}])\kern-0.1em\big)$ @@ -625,9 +625,12 @@ in the algorithm with: > > $\hspace{1.0em}$ let $\mathsf{nk} = \mathsf{H^{nk}}(\mathsf{sk})$ <br> > $\hspace{1.0em}$ if $\mathsf{use\_qsk}$: <br> -> $\hspace{2.5em}$ generate $\mathsf{ask} \;{\small ⦂}\; \mathbb{F}^{*}_{r_{\mathbb{P}}}$ and corresponding $\mathsf{SpendAuthSig^{Orchard}}$ public key $\mathsf{ak}^{\mathbb{P}} \;{\small ⦂}\; \mathbb{P}^*$ <br> -> $\hspace{3.5em}$ using any suitably secure method that ensures the last bit of $\mathsf{repr}_{\mathbb{P}}(\mathsf{ak}_{\mathbb{P}})$ is $0$. <br> -> $\hspace{2.5em}$ let $\mathsf{ak} = \mathsf{Extract}_{\mathbb{P}}(\mathsf{ak}_{\mathbb{P}})$ <br> +> $\hspace{2.5em}$ obtain a $\mathsf{SpendAuthSig^{Orchard}}$ public key $\mathsf{ak}^{\mathbb{P}} \;{\small ⦂}\; \mathbb{P}^*$ by any suitably secure method <br> +> $\hspace{3.5em}$ that ensures the last bit of $\mathsf{repr}_{\mathbb{P}}(\mathsf{ak}^{\mathbb{P}})$ is $0$. Possible methods include direct generation <br> +> $\hspace{3.5em}$ of an Orchard spend-authorizing key $\mathsf{ask} \;{\small ⦂}\; \mathbb{F}^{*}_{r_{\mathbb{P}}}$ followed by $\mathsf{ak}^{\mathbb{P}} = \mathsf{SpendAuthSig^{Orchard}.DerivePublic}(\mathsf{ask})$, <br> +> $\hspace{3.5em}$ or FROST distributed key generation [^zip-0312-key-generation] in which the corresponding spend-authorization <br> +> $\hspace{3.5em}$ material is $t$-of-$n$ shared among the participants. <br> +> $\hspace{2.5em}$ let $\mathsf{ak} = \mathsf{Extract}_{\mathbb{P}}(\mathsf{ak}^{\mathbb{P}})$ <br> > $\hspace{2.5em}$ let $\mathsf{qsk} = \mathsf{H^{qsk}}(\mathsf{sk})$ <br> > $\hspace{2.5em}$ let $\mathsf{qk} = \mathsf{H^{qk}}(\mathsf{qsk})$ <br> > $\hspace{2.5em}$ let $\mathsf{rivk} = \mathsf{H}^{\mathsf{rivk\_ext}}_{\mathsf{qk}}(\mathsf{ak}, \mathsf{nk})$ <br> @@ -644,26 +647,19 @@ in the algorithm with: 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 [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 $\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}$. +> $\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 +> [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 $\mathsf{sk}$, and also to know whether $\mathsf{use\_qsk}$ +> was used to derive the $\mathsf{ivk}$ and addresses. When FROST is being +> used, it is also necessary to retain the group verifying key $\mathsf{ak}$ +> and (collectively among the signers) the key material needed to make +> spend authorization signatures that can be verified using $\mathsf{ak}$. > -> 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}$. +> See [[ZIP 2005, Key storage options and analysis]](#keystorageoptionsandanalysis) +> for further discussion of storage requirements for $\mathsf{sk}$ and +> $\mathsf{qsk}$. #### § 4.7.2 ‘Sending Notes (Sapling)’ @@ -876,7 +872,7 @@ in the diagram in section ‘Orchard internal key derivation’ > the diagram are not the only possibility. For further detail see > § 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 +> 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 > [ZIP 2005] in the event that attacks using quantum computers become > practical. From 3eb0761bace1a68a5c0183bc7dc32163da791a13 Mon Sep 17 00:00:00 2001 From: evan-forbes <evan.samuel.forbes@gmail.com> Date: Tue, 5 May 2026 12:31:14 -0500 Subject: [PATCH 037/115] Summarize Zebra-only devnet block time reduction results Replace placeholder note about pending experiments in the Stale block rate section with a summary of the devnet test (99 geographically distributed Zebra nodes, 2MB blocks, 25s target spacing): 4.86% stale-height rate and 0.37% fork rate, both below the 5% safety threshold, with the caveat that the devnet was more decentralized than mainnet and that nodes used tuned TCP configuration. --- zips/draft-valargroup-blocktime-reduction.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/zips/draft-valargroup-blocktime-reduction.md b/zips/draft-valargroup-blocktime-reduction.md index 8781258aa..b4f81f336 100644 --- a/zips/draft-valargroup-blocktime-reduction.md +++ b/zips/draft-valargroup-blocktime-reduction.md @@ -146,7 +146,7 @@ when it operated under proof-of-work. [^forum-proposal] rate and block time as a poisson process. The 3.9% is taken from noticing that current p90 block propagation between EU and US nodes is 700ms, and then rounding that up to 1s. This needs to be combined with measuring latencies when the blocks are full, yet it is hard to see how this could risk approaching 2s.) -@evan-forbes is working on experiments to further show the block propagation delay, under different network and hardware configurations. +A devnet experiment with 99 geographically-distributed Zebra nodes producing 2MB blocks (full for the majority of the test) at 25-second target spacing measured a stale-height rate of 4.86% and a fork rate of 0.37% — both below the 5% safety threshold — when nodes used tuned TCP configuration. The devnet's node distribution was significantly more decentralized than today's mainnet, so these figures represent a near-worst-case scenario. This indicates that 25-second target spacing can be deployed safely provided that node TCP configuration is tuned for low-latency propagation. [^devnet-blocktime-test] ## Block processing time @@ -591,3 +591,5 @@ activation heights and consensus branch IDs. [^slowfastblocks]: [On Slow and Fast Block Times](https://blog.ethereum.org/2015/09/14/on-slow-and-fast-block-times/) [^forum-proposal]: [Forum: Proposal — Lower Zcash Block Target Spacing to 25s](https://forum.zcashcommunity.com/t/proposal-lower-zcash-block-target-spacing-to-25s/54577) + +[^devnet-blocktime-test]: [Forum: Zcash Block Time Reduction Appears Safe for NU7 w/ Zebra-only Devnet](https://forum.zcashcommunity.com/t/zcash-block-time-reduction-appears-safe-for-nu7-w-zebra-only-devnet/55586) From b80b75f90b98c6d9c9b55e8dd2754dfafbca7d6c Mon Sep 17 00:00:00 2001 From: evan-forbes <evan.samuel.forbes@gmail.com> Date: Tue, 5 May 2026 15:07:39 -0500 Subject: [PATCH 038/115] docs: clarify note on experiments --- zips/draft-valargroup-blocktime-reduction.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zips/draft-valargroup-blocktime-reduction.md b/zips/draft-valargroup-blocktime-reduction.md index b4f81f336..d6c44cb3a 100644 --- a/zips/draft-valargroup-blocktime-reduction.md +++ b/zips/draft-valargroup-blocktime-reduction.md @@ -146,7 +146,7 @@ when it operated under proof-of-work. [^forum-proposal] rate and block time as a poisson process. The 3.9% is taken from noticing that current p90 block propagation between EU and US nodes is 700ms, and then rounding that up to 1s. This needs to be combined with measuring latencies when the blocks are full, yet it is hard to see how this could risk approaching 2s.) -A devnet experiment with 99 geographically-distributed Zebra nodes producing 2MB blocks (full for the majority of the test) at 25-second target spacing measured a stale-height rate of 4.86% and a fork rate of 0.37% — both below the 5% safety threshold — when nodes used tuned TCP configuration. The devnet's node distribution was significantly more decentralized than today's mainnet, so these figures represent a near-worst-case scenario. This indicates that 25-second target spacing can be deployed safely provided that node TCP configuration is tuned for low-latency propagation. [^devnet-blocktime-test] +A devnet experiment with 99 geographically-distributed Zebra nodes producing 2MB blocks at 25-second target spacing measured a stale block rate of 4.86% and a fork rate of 0.37%. Both below the safety threshold of 5% set via Ethereum's historical proof-of-work stale rate. The only modification required to get these low rates was to tune TCP configuration (more details in the linked footnote). The devnet's node distribution was significantly more decentralized than today's mainnet, so these figures represent a near worst-case scenario. This indicates that 25-second target spacing can be deployed safely with no gossip or p2p changes. [^devnet-blocktime-test] ## Block processing time From 2aa8dde4d0de71740ee514bcfd2606ee512af232 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Wed, 29 Apr 2026 01:02:24 +0100 Subject: [PATCH 039/115] ZIP 2005: Remove duplication in the informal security argument. Signed-off-by: Daira-Emma Hopwood <daira@jacaranda.org> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --- zips/zip-2005.md | 190 ++++++++++++++++++++++------------------------- 1 file changed, 89 insertions(+), 101 deletions(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index fb756ff99..b0dd52324 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -1100,8 +1100,9 @@ $\mathsf{rcm} = \mathsf{H^{rcm,Orchard}_{rseed}}(\mathsf{leadByte}, \mathsf{note $\text{where } \mathsf{pre\_rcm} = [\mathtt{0x0B}, \mathsf{leadByte}] \,||\, \mathsf{encode}(\mathsf{noterepr})$ -Then we view the output of -$\mathsf{NoteCommit^{Orchard}_{rcm}}(\mathsf{noterepr})$ +### Informal security argument for binding of note commitments + +We can view the output of $\mathsf{NoteCommit^{Orchard}_{rcm}}(\mathsf{noterepr})$ as the point addition of a randomization term $[\mathsf{H^{rcm,Orchard}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr})]\, \mathcal{R}$, and some other function of $\mathsf{rseed}$, $\mathsf{leadByte}$, and @@ -1115,11 +1116,11 @@ $\mathcal{C}_j = \mathcal{Q}(D) \text{ or } \mathcal{S}(j)$ used by as $\mathcal{C}_j = [c_j]\, \mathcal{R}$ for some $c_j$. That is, $$\mathsf{NoteCommit^{Orchard}_{rcm}}(\mathsf{noterepr}) = [\mathsf{H^{rcm,Orchard}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr}) + f(\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})]\, \mathcal{R}.$$ -First we informally argue security in the classical ROM. We will model -$\mathsf{H^{rcm}}$ as a random oracle independent of $f$ with uniform -output on $\mathbb{F}_{r_{\mathbb{P}}}$. This is reasonable because +We will model $\mathsf{H^{rcm}}$ as a random oracle independent of $f$ with +uniform output on $\mathbb{F}_{r_{\mathbb{P}}}.$ This is reasonable because $\mathsf{H^{rcm}}$ cannot depend on any of the $c_j$, and in any case it is -likely to be a conventional hash function not related to the Pallas curve. +instantiated using BLAKE2b, a conventional hash function not related to the +Pallas curve. > The fact that $\mathsf{NoteCommit^{Orchard}}$ has > $\text{ψ} = \mathsf{H}^{\text{ψ}}(\mathsf{rseed}, \text{ρ})$ as an @@ -1130,54 +1131,81 @@ likely to be a conventional hash function not related to the Pallas curve. > as BLAKE2b-512 can be modelled as a random oracle. Note that since the > input to $\mathsf{H^{rcm}}$ needs more than one BLAKE2b input block, we > require that a HAIFA sponge can be modelled as a random oracle which is -> justified by [^ACMT2025]. +> justified by [^ACMT2025]. It is possible that there could be +> better-than-generic quantum attacks against BLAKE2b-512, but none have +> been published to our knowledge. In practice, we consider it reasonable to +> assume that BLAKE2b-512 has the properties needed for $\mathsf{H^{rcm}}$ +> to be collapsing. Taking the 512-bit BLAKE2b output modulo +> $r_{\mathbb{P}} \approx 2^{254}$ cannot introduce a problem. For each $\mathsf{H^{rcm}}$ oracle query the adversary chooses $\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr}$ and obtains a "random" -$\mathsf{rcm} = \mathsf{H^{rcm,Orchard}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr})$, -such that the distribution of -$\mathsf{rcm} + [f(\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})]\, \mathcal{R}$ -is computationally indistinguishable from the uniform distribution on -$\mathbb{F}_{r_\mathbb{P}}$. -Therefore $\mathsf{cm}_x = \mathsf{Extract}_{\mathbb{P}}([\mathsf{H^{rcm,Orchard}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr}) + f(\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})]\, \mathcal{R})$ -is computationally indistinguishable from an output of -$\mathsf{Extract}_{\mathbb{P}}$ applied to uniformly distributed -Pallas curve points. The number of such outputs is -$(\mathbb{F}_{r_\mathbb{P}} + 1)/2$ (one for each possible -$x$-coordinate of Pallas curve points, plus one for the zero point -$\mathcal{O}_{\mathbb{P}}$ which is mapped to $0$). +$\mathsf{rcm} = \mathsf{H^{rcm,Orchard}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr})$. + +We have $\mathsf{cm}_x = \mathsf{Extract}_{\mathbb{P}}([\mathsf{H^{rcm,Orchard}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr}) + f(\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})]\, \mathcal{R})$. + +Over all Pallas curve points $P$, the number of outputs of +$\mathsf{Extract}_{\mathbb{P}}(P)$ is $(\mathbb{F}_{r_\mathbb{P}} + 1)/2 \approx 2^{253}$ — +one for each possible $x$-coordinate of Pallas curve points, plus one for the +zero point $\mathcal{O}_{\mathbb{P}}$ which is mapped to $0$. > Only one point maps to $0$, as opposed to two points mapping to every > other possible output of $\mathsf{Extract}_{\mathbb{P}}$, but that has > negligible effect. -The number of queries needed to find a collision therefore follows a -distribution negligibly far from that expected for a collision attack on -an ideal hash function mapping from the input domain to a set of size -$(\mathbb{F}_{r_\mathbb{P}} + 1)/2 \approx 2^{253}$. +There are two values of $\mathsf{cm}$ that match $\mathsf{cm}_x$ in their $x$-coordinate. +Because the output of $\mathsf{NoteCommit^{Orchard}_{rcm}}(\mathsf{noterepr})$ is +of the form $\mathsf{cm} = F(\mathsf{noterepr}) + [\mathsf{rcm}]\, \mathcal{R}$, +for any given note we have exactly two values of $\mathsf{rcm}$ that will pass +the commitment check. -In order to adapt this argument to the quantum setting, we need to consider -*collapsing* hash functions as defined in [^Unruh2015] [^Unruh2016]. +Suppose there are $N$ legitimate notes in the tree. The adversary is trying +to find a note that will pass the commitment check without actually being a +note in the tree. As argued above, the distribution of $\mathsf{rcm}$ is +indistinguishable from uniform-random on $\mathbb{F}_{r_\mathbb{P}}$. The +success probability for each attempt in a classical search is therefore +$2N/r_{\mathbb{P}}$ where $r_{\mathbb{P}}$ is the order of the Pallas curve, +and that is negligible because $N \leq 2^{32} \ll r_{\mathbb{P}}$. This is +also infeasible for a quantum adversary using a Grover search. -TODO: $\mathsf{Extract}_{\mathbb{P}}$ is not collapsing. -Is $\mathsf{Extract}_{\mathbb{P}}([\mathsf{H^{rcm,Orchard}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr}) + f(\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})]\, \mathcal{R})$ collapsing? +We're not finished yet because we also have to prove that the nullifier is +computed deterministically for a given note. -By the argument in [^Bernstein2009], the best known *generic* quantum -attack on a hash function is simply the classical attack of [^vOW1999]. -(In particular, the Brassard–Høyer–Tapp algorithm [^BHT1997] is entirely -unimplementable for a 253-bit output size: to achieve the claimed speed-up, -it would require running Grover's algorithm with a quantum circuit that -does random accesses to a $2^{92.3}$-bit quantum memory.) Therefore, an -output size of 253 bits does not exclude a hash function from being -post-quantum collision-resistant. It is possible that there could be -better-than-generic quantum attacks against BLAKE2b, but none have been -published to our knowledge. In practice, we consider it reasonable to -assume that BLAKE2b-512 has the properties needed for $\mathsf{H^{rcm}}$ -to be post-quantum collision-resistant. +All of the inputs to $\mathsf{DeriveNullifier}$ are things we committed to +in the protocol so far *except* $\mathsf{nk}$. By the same argument used +pre-quantumly, there is only one $\mathsf{ivk}$ for a given +$(\mathsf{g_d}, \mathsf{pk_d})$. So in order to just use the existing +protocol for this part, we would need to prove that there is only one +$\mathsf{nk}$ (that is feasible to find) such that +$\mathsf{Commit^{ivk}_{rivk}}(\mathsf{ak}, \mathsf{nk}) = \mathsf{ivk}$. +Unfortunately that's not true; $\mathsf{Commit^{ivk}}$ is instantiated by +$\mathsf{SinsemillaShortCommit}$ which is not post-quantum binding. -TODO: discuss [^CBHSU2017] (sponge security), [^Unruh2015] [^Unruh2016] -(collapse-binding property). +There are two cases depending on $\mathsf{use\_qsk}$ (the adversary can +choose to attack either): + +* Case $\text{not } \mathsf{use\_qsk}$: The spender must prove knowledge of + $\mathsf{sk}$, and that $\mathsf{ak}$, $\mathsf{nk}$, and $\mathsf{rivk}$ + are derived correctly from $\mathsf{sk}$. This works because the + derivations use post-quantum hashes (and $\mathsf{ask} \rightarrow \mathsf{ak}$ + is deterministic). <br> + In particular, $\mathsf{ivk}$ is an essentially random function of + $\mathsf{sk}$, and so we expect that an adversary has no better attack + 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)), + 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 + $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}$: 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 $\text{not } \mathsf{use\_qsk}$. The above security argument means that provided we also check the uses of $\mathsf{H^{rcm}}$ and $\mathsf{H}^{\text{ψ}}$ in the post-quantum @@ -1195,7 +1223,26 @@ necessary to defend against a discrete-log-breaking or quantum adversary. Therefore, the post-quantum [Recovery Statement](#proposedrecoverystatement) will need to use complete curve additions to implement Sinsemilla. -### Attacks against binding of ivk +### Adaptation to the quantum setting + +In order to adapt this argument to the quantum setting, we need to consider +*collapsing* hash functions as defined in [^Unruh2015] [^Unruh2016]. + +TODO: $\mathsf{Extract}_{\mathbb{P}}$ is not collapsing. +Is $\mathsf{Extract}_{\mathbb{P}}([\mathsf{H^{rcm,Orchard}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr}) + f(\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})]\, \mathcal{R})$ collapsing? + +By the argument in [^Bernstein2009], the best known *generic* quantum +attack on a hash function is simply the classical attack of [^vOW1999]. +(In particular, the Brassard–Høyer–Tapp algorithm [^BHT1997] is entirely +unimplementable for a 253-bit output size: to achieve the claimed speed-up, +it would require running Grover's algorithm with a quantum circuit that +does random accesses to a $2^{92.3}$-bit quantum memory.) Therefore, an +output size of 253 bits does not exclude a hash function from being collapsing. + +TODO: discuss [^CBHSU2017] (sponge security), [^Unruh2015] [^Unruh2016] +(collapse-binding property). + +### Informal security argument for binding of ivk The security of Orchard against double-spending also depends on the binding property of $\mathsf{Commit^{ivk}}$. Informally, the security argument is @@ -1222,65 +1269,6 @@ There is a complication: contrary to the situation with note commitments, addresses may be used over the long term and it may not be feasible or desirable to switch to new addresses. -## Informal Security Argument - -The informal security argument that we can only spend valid notes goes as -follows: - -If $\mathsf{H^{rcm}}$ and $\mathsf{H^{\text{φ}}}$ are treated as random oracles, -$\mathsf{rcm}$ is an unpredictable function of the note fields. There are two -values of $\mathsf{cm}$ that match $\mathsf{cm}_x$ in their $x$-coordinate. -Because the output of $\mathsf{NoteCommit^{Orchard}_{rcm}}(\mathsf{noterepr})$ is -of the form $\mathsf{cm} = F(\mathsf{noterepr}) + [\mathsf{rcm}]\, \mathcal{R}$, -for any given note we have exactly two values of $\mathsf{rcm}$ that will pass -the commitment check. - -Suppose there are $N$ legitimate notes in the tree. The adversary is trying -to find (possibly using a Grover search) a note that will pass the commitment -check without actually being a note in the tree. The success probability for -each attempt in a classical search is $2N/r_{\mathbb{P}}$ where $r_{\mathbb{P}}$ -is the order of the Pallas curve, and that is negligible because -$N \leq 2^{32} \ll r_{\mathbb{P}}$. This is also infeasible for a quantum -adversary using a Grover search. - -We're not finished yet because we also have to prove that the nullifier is -computed deterministically for a given note. - -All of the inputs to $\mathsf{DeriveNullifier}$ are things we committed to -in the protocol so far *except* $\mathsf{nk}$. By the same argument used -pre-quantumly, there is only one $\mathsf{ivk}$ for a given -$(\mathsf{g_d}, \mathsf{pk_d})$. So in order to just use the existing -protocol for this part, we would need to prove that there is only one -$\mathsf{nk}$ (that is feasible to find) such that -$\mathsf{Commit^{ivk}_{rivk}}(\mathsf{ak}, \mathsf{nk}) = \mathsf{ivk}$. -Unfortunately that's not true; $\mathsf{Commit^{ivk}}$ is instantiated by -$\mathsf{SinsemillaShortCommit}$ which is not post-quantum binding. - -There are two cases depending on $\mathsf{use\_qsk}$ (the adversary can -choose to attack either): - -* Case $\text{not } \mathsf{use\_qsk}$: The spender must prove knowledge of - $\mathsf{sk}$, and that $\mathsf{ak}$, $\mathsf{nk}$, and $\mathsf{rivk}$ - are derived correctly from $\mathsf{sk}$. This works because the - derivations use post-quantum hashes (and $\mathsf{ask} \rightarrow \mathsf{ak}$ - is deterministic). <br> - In particular, $\mathsf{ivk}$ is an essentially random function of - $\mathsf{sk}$, and so we expect that an adversary has no better attack - 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)), - 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 - $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}$: 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 $\text{not } \mathsf{use\_qsk}$. - ## Security argument for Spendability DeriveNullifier is based on a Pedersen hash. In the current Orchard From 76ce52e401376b6cb9c79fc38eba19080ec9aed2 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Wed, 29 Apr 2026 01:03:13 +0100 Subject: [PATCH 040/115] ZIP 2005: Cosmetics. Signed-off-by: Daira-Emma Hopwood <daira@jacaranda.org> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --- zips/zip-2005.md | 43 ++++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index b0dd52324..95cf57a06 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -439,8 +439,8 @@ $\mathsf{qsk}$ to the host wallet, and the $\mathsf{SoK^{qsk}}$ proof would be produced there. In either option, $\mathsf{ask}$ would remain on the hardware wallet which -would continue to produce RedDSA spend authorization signatures (or its part -of the FROST multi-signing protocol). +would continue to produce RedDSA spend authorization signatures (or perform +its part of the FROST multi-signing protocol). #### Threat model @@ -625,11 +625,8 @@ in the algorithm with: > > $\hspace{1.0em}$ let $\mathsf{nk} = \mathsf{H^{nk}}(\mathsf{sk})$ <br> > $\hspace{1.0em}$ if $\mathsf{use\_qsk}$: <br> -> $\hspace{2.5em}$ obtain a $\mathsf{SpendAuthSig^{Orchard}}$ public key $\mathsf{ak}^{\mathbb{P}} \;{\small ⦂}\; \mathbb{P}^*$ by any suitably secure method <br> -> $\hspace{3.5em}$ that ensures the last bit of $\mathsf{repr}_{\mathbb{P}}(\mathsf{ak}^{\mathbb{P}})$ is $0$. Possible methods include direct generation <br> -> $\hspace{3.5em}$ of an Orchard spend-authorizing key $\mathsf{ask} \;{\small ⦂}\; \mathbb{F}^{*}_{r_{\mathbb{P}}}$ followed by $\mathsf{ak}^{\mathbb{P}} = \mathsf{SpendAuthSig^{Orchard}.DerivePublic}(\mathsf{ask})$, <br> -> $\hspace{3.5em}$ or FROST distributed key generation [^zip-0312-key-generation] in which the corresponding spend-authorization <br> -> $\hspace{3.5em}$ material is $t$-of-$n$ shared among the participants. <br> +> $\hspace{2.5em}$ obtain a $\mathsf{SpendAuthSig^{Orchard}}$ public key $\mathsf{ak}^{\mathbb{P}} \;{\small ⦂}\; \mathbb{P}^*$ by any suitably secure <br> +> $\hspace{3.5em}$ method that ensures the last bit of $\mathsf{repr}_{\mathbb{P}}(\mathsf{ak}^{\mathbb{P}})$ is $0$ (see below). <br> > $\hspace{2.5em}$ let $\mathsf{ak} = \mathsf{Extract}_{\mathbb{P}}(\mathsf{ak}^{\mathbb{P}})$ <br> > $\hspace{2.5em}$ let $\mathsf{qsk} = \mathsf{H^{qsk}}(\mathsf{sk})$ <br> > $\hspace{2.5em}$ let $\mathsf{qk} = \mathsf{H^{qk}}(\mathsf{qsk})$ <br> @@ -644,6 +641,16 @@ in the algorithm with: > $\hspace{2.5em}$ let $\mathsf{qsk} = \mathsf{qk} = \bot$ (there are no quantum spending/intermediate keys in this case) <br> > $\hspace{2.5em}$ let $\mathsf{rivk} = \mathsf{H^{rivk}}(\mathsf{sk})$ +Add before "As explained in § 3.1": + +> When $\mathsf{use\_qsk}$ is true, possible methods of generating +> $\mathsf{ak}^{\mathbb{P}}$ include direct generation of an Orchard Spend +> authorizing key $\mathsf{ask} \;{\small ⦂}\; \mathbb{F}^{*}_{r_{\mathbb{P}}}$ followed by +> $\mathsf{ak}^{\mathbb{P}} = \mathsf{SpendAuthSig^{Orchard}.DerivePublic}(\mathsf{ask})$, +> or FROST distributed key generation [^zip-0312-key-generation] in which the +> corresponding spend-authorization material is $t$-of-$n$ shared among the +> participants. + Add the following notes: > * If $\mathsf{ask}$, $\mathsf{ak}$, $\mathsf{nk}$, $\mathsf{rivk}$, and @@ -1011,6 +1018,9 @@ and $\mathsf{nf}$ is the revealed nullifier. ### Cost +From here on, we abbreviate $\mathsf{H^{rcm,Orchard}}$ to $\mathsf{H^{rcm}}$, +etc. + Note that in the "$\mathsf{use\_qsk}$" case, one BLAKE2b compression is required to compute $\mathsf{rivk\_ext}$ (provided $\ell_{\mathsf{qk}} \leq 504$ bits, so that the input $\mathsf{qk} \,||\, [\mathtt{0x0D}] \,||\, \mathsf{ak} \,||\, \mathsf{nk}$ @@ -1055,9 +1065,8 @@ post-quantum knowledge-sound. $\mathsf{MerkleCRH^{Orchard}}$ is instantiated using $\mathsf{SinsimillaHash}$ [^protocol-concretesinsemillahash]. -Its collision resistance depends on the Discrete Logarithm Relation -Problem on the Pallas curve [^protocol-sinsemillasecurity], and so it -is not +Its collision resistance depends on the Discrete Logarithm Relation Problem +on the Pallas curve [^protocol-sinsemillasecurity], and so it is not post-quantum collision-resistant or collapsing. However, because the note commitment tree is public, it is possible to re-hash all of its leaves to construct a new Merkle tree using a collapsing hash function. @@ -1096,7 +1105,7 @@ $\mathsf{noterepr} = (\mathsf{g}\star_{\mathsf{d}}, \mathsf{pk}\star_{\mathsf{d} as detailed in the [Specification] section. Specifically, when $\mathsf{leadByte} = \mathtt{0x03}$ we have: -$\mathsf{rcm} = \mathsf{H^{rcm,Orchard}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr}) = \mathsf{ToScalar^{Orchard}}(\mathsf{PRF^{expand}_{rseed}}(\mathsf{pre\_rcm}))$ +$\mathsf{rcm} = \mathsf{H^{rcm}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr}) = \mathsf{ToScalar^{Orchard}}(\mathsf{PRF^{expand}_{rseed}}(\mathsf{pre\_rcm}))$ $\text{where } \mathsf{pre\_rcm} = [\mathtt{0x0B}, \mathsf{leadByte}] \,||\, \mathsf{encode}(\mathsf{noterepr})$ @@ -1104,7 +1113,7 @@ $\text{where } \mathsf{pre\_rcm} = [\mathtt{0x0B}, \mathsf{leadByte}] \,||\, \ma We can view the output of $\mathsf{NoteCommit^{Orchard}_{rcm}}(\mathsf{noterepr})$ as the point addition of a randomization term -$[\mathsf{H^{rcm,Orchard}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr})]\, \mathcal{R}$, +$[\mathsf{H^{rcm}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr})]\, \mathcal{R}$, and some other function of $\mathsf{rseed}$, $\mathsf{leadByte}$, and $\mathsf{noterepr}$. @@ -1114,7 +1123,7 @@ by expanding each of the Sinemilla bases $\mathcal{C}_j = \mathcal{Q}(D) \text{ or } \mathcal{S}(j)$ used by [$\mathsf{HashToSinsimillaPoint}$](https://zips.z.cash/protocol/protocol.pdf#concretesinsemillahash) as $\mathcal{C}_j = [c_j]\, \mathcal{R}$ for some $c_j$. That is, -$$\mathsf{NoteCommit^{Orchard}_{rcm}}(\mathsf{noterepr}) = [\mathsf{H^{rcm,Orchard}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr}) + f(\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})]\, \mathcal{R}.$$ +$$\mathsf{NoteCommit^{Orchard}_{rcm}}(\mathsf{noterepr}) = [\mathsf{H^{rcm}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr}) + f(\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})]\, \mathcal{R}.$$ We will model $\mathsf{H^{rcm}}$ as a random oracle independent of $f$ with uniform output on $\mathbb{F}_{r_{\mathbb{P}}}.$ This is reasonable because @@ -1141,9 +1150,9 @@ Pallas curve. For each $\mathsf{H^{rcm}}$ oracle query the adversary chooses $\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr}$ and obtains a "random" -$\mathsf{rcm} = \mathsf{H^{rcm,Orchard}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr})$. +$\mathsf{rcm} = \mathsf{H^{rcm}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr})$. -We have $\mathsf{cm}_x = \mathsf{Extract}_{\mathbb{P}}([\mathsf{H^{rcm,Orchard}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr}) + f(\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})]\, \mathcal{R})$. +We have $\mathsf{cm}_x = \mathsf{Extract}_{\mathbb{P}}([\mathsf{H^{rcm}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr}) + f(\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})]\, \mathcal{R})$. Over all Pallas curve points $P$, the number of outputs of $\mathsf{Extract}_{\mathbb{P}}(P)$ is $(\mathbb{F}_{r_\mathbb{P}} + 1)/2 \approx 2^{253}$ — @@ -1229,7 +1238,7 @@ In order to adapt this argument to the quantum setting, we need to consider *collapsing* hash functions as defined in [^Unruh2015] [^Unruh2016]. TODO: $\mathsf{Extract}_{\mathbb{P}}$ is not collapsing. -Is $\mathsf{Extract}_{\mathbb{P}}([\mathsf{H^{rcm,Orchard}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr}) + f(\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})]\, \mathcal{R})$ collapsing? +Is $\mathsf{Extract}_{\mathbb{P}}([\mathsf{H^{rcm}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr}) + f(\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})]\, \mathcal{R})$ collapsing? By the argument in [^Bernstein2009], the best known *generic* quantum attack on a hash function is simply the classical attack of [^vOW1999]. @@ -1274,7 +1283,7 @@ desirable to switch to new addresses. DeriveNullifier is based on a Pedersen hash. In the current Orchard protocol, the property that it is infeasible to find two distinct Orchard notes with the same nullifier (including possible nullfiers -of split OrchardZSA notes), depends on the collision-resistance of +of split OrchardZSA notes), depends on the collision resistance of that hash, which would not hold against a discrete-log-breaking adversary. From ab43ce21efe1e2c5ddd41f827739d8a8b0e9ffee Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Wed, 29 Apr 2026 01:35:25 +0100 Subject: [PATCH 041/115] ZIP 2005: Repair the informal security argument for binding of ivk. Signed-off-by: Daira-Emma Hopwood <daira@jacaranda.org> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --- zips/zip-2005.md | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index 95cf57a06..026763185 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -1265,18 +1265,23 @@ the security arguments for the Balance and Spend Authorization properties, because we can no longer infer that $\mathsf{nk}$ and $\mathsf{ak}$ are the correct values. -Fortunately, the Orchard protocol specified $\mathsf{rivk}$ to be -derived from $\mathsf{sk}$. - -(There is a complication in that $\mathsf{rivk}$ is derived differently -for an "internal IVK".) - -We use essentially the same fix as for $\mathsf{NoteCommit^{Orchard}}$, -with $\mathsf{rivk}$ in place of $\mathsf{rcm}$. - There is a complication: contrary to the situation with note commitments, addresses may be used over the long term and it may not be feasible or -desirable to switch to new addresses. +desirable to switch to new addresses. Fortunately, the Orchard protocol +specified each of $\mathsf{ak}$, $\mathsf{nk}$, and $\mathsf{rivk}$ to be +derived from $\mathsf{sk}$ via $\mathsf{PRF^{expand}}$. ($\mathsf{rivk}$ +is derived differently for an "internal IVK", but that is also via +$\mathsf{PRF^{expand}}$.) + +We use essentially the same fix as for $\mathsf{NoteCommit^{Orchard}}$, +with $\mathsf{rivk}$ in place of $\mathsf{rcm}$. We check the derivation +of all of $\mathsf{ak}$, $\mathsf{nk}$, and $\mathsf{rivk}$ from $\mathsf{sk}$. +Looking carefully at the structure of the derivations relative to the +ones for $\mathsf{NoteCommit^{Orchard}}$, we can see that $\mathsf{sk}$ +is in a roughly similar position to $\mathsf{rseed}$, and +$(\mathsf{ak}, \mathsf{nk})$ to $\text{ψ}$. Because these are the only +inputs to the commitment, the checks are sufficient to ensure they are +all bound by it. ## Security argument for Spendability From 06575980f4cbbdfc71ebe72e60c6704663b83209 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Fri, 1 May 2026 18:55:46 +0100 Subject: [PATCH 042/115] ZIP 2005: Establish H^{rcm} abbreviation convention in Terminology. Add a Terminology entry stating that in this ZIP's discussion sections we abbreviate H^{rcm,Orchard} as H^{rcm} (and similarly for other Orchard- specific hash function names). Spec changes and references to other ZIPs use the full forms. Drop the now-redundant local abbreviation sentence at the start of the Cost section, since the convention is established globally in Terminology. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --- zips/zip-2005.md | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index 026763185..9f88b2706 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -32,6 +32,11 @@ $\underline{\mathsf{underlined}}$ variable indicates a byte sequence, and a variable suffixed with $\star$ indicates a bit-sequence encoding of an elliptic curve point. +For brevity, in the discussion sections of this ZIP we abbreviate +$\mathsf{H^{rcm,Orchard}}$ as $\mathsf{H^{rcm}}$ (and similarly for other +Orchard-specific hash function names). The changes to the protocol +specification and to other ZIPs use the full forms. + The term "Zcash Shielded Assets" or "ZSAs" refers to the extension to the Orchard shielded protocol described in ZIPs 226 and 227 [^zip-0226] [^zip-0227]. @@ -1018,19 +1023,15 @@ and $\mathsf{nf}$ is the revealed nullifier. ### Cost -From here on, we abbreviate $\mathsf{H^{rcm,Orchard}}$ to $\mathsf{H^{rcm}}$, -etc. - -Note that in the "$\mathsf{use\_qsk}$" case, one BLAKE2b compression -is required to compute $\mathsf{rivk\_ext}$ (provided $\ell_{\mathsf{qk}} \leq 504$ -bits, so that the input $\mathsf{qk} \,||\, [\mathtt{0x0D}] \,||\, \mathsf{ak} \,||\, \mathsf{nk}$ -fits in a single 128-byte BLAKE2b block), and in the -"not $\mathsf{use\_qsk}$" case, three BLAKE2b compressions in total -are required to compute $\mathsf{H^{ask}}$, $\mathsf{H^{nk}}$, and -$\mathsf{H^{rivk\_legacy}}$. Since these cases are mutually exclusive, -it is possible to multiplex the same three compression function instances. -So, supporting "$\mathsf{use\_qsk}$" in addition to -"not $\mathsf{use\_qsk}$" costs very little extra. +Note that in the "$\mathsf{use\_qsk}$" case, one BLAKE2b compression is required +to compute $\mathsf{rivk\_ext}$ (provided $\ell_{\mathsf{qk}} \leq 504$ bits, so +that the input $\mathsf{qk} \,||\, [\mathtt{0x0D}] \,||\, \mathsf{ak} \,||\, \mathsf{nk}$ +fits in a single 128-byte BLAKE2b block), and in the "not $\mathsf{use\_qsk}$" +case, three BLAKE2b compressions in total are required to compute $\mathsf{H^{ask}}$, +$\mathsf{H^{nk}}$, and $\mathsf{H^{rivk\_legacy}}$. Since these cases are mutually +exclusive, it is possible to multiplex the same three compression function instances. +So, supporting "$\mathsf{use\_qsk}$" in addition to "not $\mathsf{use\_qsk}$" costs +very little extra. All of the operations below need to be implemented with complete additions, even if they are incomplete in the current Orchard[ZSA] statement/circuit. From 96e4987e2932ceec0013e5cdd4d4ff8945fcf33d Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Fri, 1 May 2026 18:56:49 +0100 Subject: [PATCH 043/115] ZIP 2005: Rewrite informal Spendability argument as a classical-ROM reduction. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous argument enumerated specific attack classes (a per-input bullet list of "this input goes through this hash") and incorrectly modelled f and g — the Sinsemilla-base lift and the K^Orchard-linear g — as random oracles. f and g are deterministic functions of their inputs. Replace with a reduction-based argument: any classical adversary that finds two valid Recovery Statement witnesses for distinct underlying notes with colliding nullifiers succeeds with probability bounded by q(q-1)/r_P (≤ 2^-94 for Pallas with q ≤ 2^80). The reduction simulates H^{rcm} as a lazily-sampled random oracle, extracts the algebraic identity H_1 + f_1 + g_1 ≡ ±(H_2 + f_2 + g_2) (mod r_P), and bounds the probability that two independent uniform RO outputs satisfy a fixed linear constraint. The argument does not assume Commit^{ivk}-binding (which would not hold against a discrete-log-breaking adversary on Pallas) or collision- resistance of the key-derivation hashes; it uses only H^{rcm}-as-RO plus the structural fact that f and g are deterministic. Also: replace "pq-collision-resistant" with "collapsing" in the rehashed-commitment-tree discussion — the precise post-quantum binding notion per Unruh 2016. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --- zips/zip-2005.md | 144 +++++++++++++++++++++++++++++------------------ 1 file changed, 88 insertions(+), 56 deletions(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index 9f88b2706..535836a3c 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -1080,9 +1080,8 @@ Suppose this has been done. Note: when we rehash the commitment tree, we could include both $\text{ρ}$ and $\mathsf{cm}_x$ for each note (i.e. what is currently the leaf layer becomes $\mathsf{MerkleCRH}(\text{ρ}, \mathsf{cm}_x)$ where $\mathsf{MerkleCRH}$ -is pq-collision-resistant). This change might not be necessary; it just -removes potential complications due to duplicate commitments for the same -note. +is collapsing). This change might not be necessary; it just removes potential +complications due to duplicate commitments for the same note. ### Attacks against binding of note commitments @@ -1297,9 +1296,6 @@ Does this mean it is possible to break Spendability for the given Recovery Statement? As it turns out, no, but the argument is somewhat involved. -TODO: this argument is too handwavy and depends on the ROM; it needs -further work for a quantum adversary. - Since each function in the Recovery Statement is deterministic, the free variables that the adversary can control are the sources of the derivation digraph within that statement and either $\mathsf{SoK^{sk}}$ @@ -1309,67 +1305,103 @@ or $\mathsf{SoK^{qk}}$. That is, the adversary can control: * $\mathsf{sk}$, when $\mathsf{use\_qsk} = \mathsf{false}$; * $(\mathsf{nk}, \mathsf{ak}, \mathsf{qsk})$, when $\mathsf{use\_qsk} = \mathsf{true}$. -As we argued earlier in section [Repairing note commitments], -$\mathsf{rcm}$ binds $\mathsf{rseed}$ and $\mathsf{pre\_rcm}$, and all -of the other inputs to $\mathsf{NoteCommit}$ are also included in -$\mathsf{pre\_rcm}$. Therefore, given the independence assumption between -$\mathsf{H^{rcm}}$ and $f$ described earlier, $\mathsf{cm}$ binds all -of the values in the Recovery Statement that the adversary can control. - -We can then analyze $\mathsf{DeriveNullifier}$ in essentially the same -way we analyzed $\mathsf{NoteCommit}$. - -Recall that $\mathsf{DeriveNullifier}$ is defined in +We analyze $\mathsf{DeriveNullifier}$ as a function of these +controllable inputs. Recall that $\mathsf{DeriveNullifier}$ is defined in § 4.16 ‘Computing ρ values and Nullifiers’ as: $$\mathsf{DeriveNullifier_{nk}}(\text{ρ}, \text{ψ}, \mathsf{cm}) = \mathsf{Extract}_{\mathbb{P}}\big(\big[\mathsf{PRF^{nfOrchard}_{nk}}(\text{ρ}) + \text{ψ}) \bmod q_{\mathbb{P}}\big]\, \mathcal{K}^{\mathsf{Orchard}} + \mathsf{cm}\big)$$ Also recall from [Repairing note commitments] that we have -$$\mathsf{cm} = [\mathsf{H^{rcm,Orchard}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr}) + f(\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})]\, \mathcal{R}.$$ +$$\mathsf{cm} = [\mathsf{H^{rcm}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr}) + f(\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})]\, \mathcal{R}.$$ $\text{ψ}$ is determined by $\mathsf{rseed}$. The nullifier corresponding to -$(\mathsf{nk}, \text{ρ}, \mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})$ is -then -$$\mathsf{Extract}_{\mathbb{P}}\big([\mathsf{H^{rcm,Orchard}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr}) + f(\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr}) + g(\mathsf{nk}, \text{ρ}, \mathsf{rseed})]\, \mathcal{R}\big)$$ +$(\mathsf{nk}, \text{ρ}, \mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})$ +is then +$$\mathsf{Extract}_{\mathbb{P}}\big([\mathsf{H^{rcm}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr}) + f(\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr}) + g(\mathsf{nk}, \text{ρ}, \mathsf{rseed})]\, \mathcal{R}\big)$$ for some $g$ depending on the discrete logarithm of $\mathcal{K}^{\mathsf{Orchard}}$ wrt $\mathcal{R}$. -The intuition is that an adversary cannot vary any of the inputs it controls without causing an -unpredictable change to both $\mathsf{cm}$ and $\mathsf{nf}$. This is because every such input -goes through a function that can be modelled as a random oracle on the way to deriving -$\mathsf{cm}$ and $\mathsf{nf}$: - -* $\text{ρ}$ goes through $\mathsf{H}^{\text{ψ}}$ to derive $\text{ψ}$, and through - $\mathsf{PRF^{nfOrchard}_{nk}}$ which is instantiated as Poseidon to derive $\mathsf{nf}$; -* $\mathsf{g_d}$ goes through $\mathsf{H^{rcm}}$; -* because $\mathsf{g_d} \mapsto \mathsf{pk_d} = [\mathsf{ivk}]\, \mathsf{g_d}$ is 1-1, any - change to $\mathsf{ivk}$ for a given $\mathsf{g_d}$ results in a change to $\mathsf{pk_d}$, - which goes through $\mathsf{H^{rcm}}$; -* $\mathsf{rseed}$ goes through $\mathsf{H}^{\text{ψ}}$ and then $\mathsf{H^{rcm}}$; -* $\mathsf{use\_qsk}$ only has two possible values, and therefore can't increase the adversary's - advantage by more than a factor of $2$ provided that both alternatives are otherwise secure; -* when $\mathsf{use\_qsk} = \mathsf{false}$: - * $\mathsf{sk}$ goes through $\mathsf{H^{rivk\_legacy}}$; - * $\mathsf{nk}$ goes through $\mathsf{H^{nk}}$; - * $\mathsf{ak}$ goes through $\mathsf{H^{ask}}$; -* when $\mathsf{use\_qsk} = \mathsf{true}$: - * $\mathsf{qsk}$ goes through $\mathsf{H^{qk}}$ and $\mathsf{H^{rivk\_ext}}$; - * $\mathsf{nk}$ goes through $\mathsf{H^{rivk\_ext}}$; - * $\mathsf{ak}$ goes through $\mathsf{H^{rivk\_ext}}$; - -Note that while $f$ and $g$ are individually random oracles on their inputs, their -sum modulo $q_{\mathbb{P}}$ could potentially be subject to a meet-in-the-middle attack. -This might be possible if the inputs that the adversary can control could be split so -that some affect only $\mathsf{H^{rcm,Orchard}}$ and $f$, and others affect only $g$. -(Note that $\mathsf{H^{rcm,Orchard}}$ and $f$ have the same inputs and are each random -oracles on all of their inputs.) But $\mathsf{noterepr}$ includes $\text{ρ}$, and we have -already established that $\mathsf{nk}$ cannot be varied without affecting $\mathsf{pk_d}$. -So with a little work we can see that such splitting is not possible. - -An adversary could also attempt to cause a collision in $\mathsf{nf}$ by causing a -collision on $\mathsf{Extract}_{\mathbb{P}}$, but this is also not feasible if -$\mathsf{H^{rcm,Orchard}}$ can be modelled as a random oracle. +We give a reduction-based argument that any classical adversary in the +Random Oracle Model who finds two valid Recovery Statement witnesses for +distinct underlying notes with colliding nullifiers, succeeds with +probability bounded by $q(q-1)/r_{\mathbb{P}}$, where $q$ is the number +of $\mathsf{H^{rcm}}$ queries the adversary makes. The bound depends only +on the query count, not on running time, and applies to any adversary +regardless of attack strategy. + +We model $\mathsf{H^{rcm}}$ as a random oracle with output uniform +on $\mathbb{F}_{r_{\mathbb{P}}}$. The functions $f$ and $g$ are deterministic +functions of their inputs — a structural property of the algebraic +decomposition derived above. $f$ depends on +$(\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})$ via the Sinsemilla +bases $\mathcal{C}_j = [c_j]\, \mathcal{R}$; $g$ depends on +$(\mathsf{nk}, \text{ρ}, \mathsf{rseed})$ via $\mathsf{PRF^{nfOrchard}}$, +$\mathsf{H}^{\text{ψ}}$, and the discrete logarithm of +$\mathcal{K}^{\mathsf{Orchard}}$ wrt $\mathcal{R}$. Neither is modelled as +a random oracle. + +We are *not* assuming $\mathsf{Commit^{ivk}}$ is binding, nor that any +of the key-derivation hashes are collision-resistant. The argument here +covers only $\mathsf{NoteCommit}$ binding — it argues that $\mathsf{nf}$ +binds the underlying note ($\mathsf{noterepr}$, plus $\mathsf{rseed}$ and +$\mathsf{leadByte}$) under $\mathsf{H^{rcm}}$-as-random-oracle +alone. + +**Theorem (distinct-note Spendability, classical ROM).** <a id="thm-spendability"></a> +Let $\mathcal{A}$ be a classical adversary with oracle access to +$\mathsf{H^{rcm}}$ modelled as a random oracle with output uniform on +$\mathbb{F}_{r_{\mathbb{P}}}$, making at most $q$ oracle queries. The +*Spendability-collision* game has $\mathcal{A}$ output two Recovery +Statement witnesses $\mathsf{w}_1, \mathsf{w}_2$ satisfying: + +<a id="thm-spendability-validity"></a>**Validity of witnesses** +: both witnesses satisfy the + [Proposed Recovery Statement](#proposedrecoverystatement). + +<a id="thm-spendability-distinct"></a>**Distinct underlying notes** +: the $\mathsf{H^{rcm}}$-input tuples + $r_i := (\mathsf{rseed}_i, \mathsf{leadByte}_i, \mathsf{noterepr}_i)$ + satisfy $r_1 \neq r_2$. + +<a id="thm-spendability-collide"></a>**Colliding nullifiers** +: $\mathsf{nf}_1 = \mathsf{nf}_2$. + +Then $\mathcal{A}$ wins this game with probability at most +$\binom{q}{2} \cdot 2/r_{\mathbb{P}} = q(q-1)/r_{\mathbb{P}}$, taken over +the random oracle's responses and any internal randomness of $\mathcal{A}$. + +For the Pallas curve we have $r_{\mathbb{P}} \approx 2^{254}$, so any +adversary making at most $q \le 2^{80}$ random-oracle queries wins with +probability at most approximately $2^{-94}$. + +**Reduction.** We construct a simulated environment in which +$\mathsf{H^{rcm}}$ is replaced by a lazily-sampled random oracle. +The simulation maintains a table +$T : \mathsf{H^{rcm}}\text{-input} \to \mathbb{F}_{r_{\mathbb{P}}}$, +initially empty. On each query +$r = (\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})$ from +$\mathcal{A}$, the simulation returns $T[r]$ if defined, or otherwise +samples a fresh $h \leftarrow \mathbb{F}_{r_{\mathbb{P}}}$, records +$T[r] := h$, and returns $h$. After at most $q$ such queries, +$\mathcal{A}$ outputs $(\mathsf{w}_1, \mathsf{w}_2)$ satisfying +[(validity)](#thm-spendability-validity), +[(distinct underlying notes)](#thm-spendability-distinct), and +[(colliding nullifiers)](#thm-spendability-collide). + +The collision $\mathsf{nf}_1 = \mathsf{nf}_2$ implies that +$[H_1 + f_1 + g_1]\, \mathcal{R}$ and $[H_2 + f_2 + g_2]\, \mathcal{R}$ +share an $x$-coordinate, hence are either equal or each other's +negation: + +$$H_1 + f_1 + g_1 \equiv \pm(H_2 + f_2 + g_2) \pmod{r_{\mathbb{P}}},$$ + +where $H_i := \mathsf{H^{rcm}}(r_i)$. By +[(distinct underlying notes)](#thm-spendability-distinct) we have +$r_1 \neq r_2$, so $T[r_1]$ and $T[r_2]$ are sampled independently and +uniformly from $\mathbb{F}_{r_{\mathbb{P}}}$. + +TODO: Probability bound (step 5) and QROM follow-up (step 6) go here. ## Effects of discrete-log-breaking attacks before the switch to the Recovery Protocol From bae778a4918e874c11fdd3ff2717e749281e6586 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Mon, 4 May 2026 08:35:36 +0100 Subject: [PATCH 044/115] ZIP 2005: Cosmetics, and drop unnecessary Orchard superscripts. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Signed-off-by: Daira-Emma Hopwood <daira@jacaranda.org> --- zips/zip-2005.md | 86 ++++++++++++++++++++++++++---------------------- 1 file changed, 46 insertions(+), 40 deletions(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index 535836a3c..27461796d 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -33,9 +33,11 @@ and a variable suffixed with $\star$ indicates a bit-sequence encoding of an elliptic curve point. For brevity, in the discussion sections of this ZIP we abbreviate -$\mathsf{H^{rcm,Orchard}}$ as $\mathsf{H^{rcm}}$ (and similarly for other -Orchard-specific hash function names). The changes to the protocol -specification and to other ZIPs use the full forms. +$\mathsf{H^{rcm,Orchard}}$ as $\mathsf{H^{rcm}}$, +$\mathsf{PRF^{nfOrchard}}$ as $\mathsf{PRF^{nf}}$, +$\mathcal{K}^{\mathsf{Orchard}}$ as $\mathcal{K}$, +and similarly for other Orchard-specific hash function names. The changes +to the protocol specification and to other ZIPs use the full forms. The term "Zcash Shielded Assets" or "ZSAs" refers to the extension to the Orchard shielded protocol described in ZIPs 226 and 227 [^zip-0226] [^zip-0227]. @@ -931,8 +933,7 @@ Import this definition from § 4.2.3 ‘Orchard Key Components’ [^protocol-or 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})))$ +> $\mathsf{H^{rivk\_int}_{rivk\_ext}}(\mathsf{ak}, \mathsf{nk}) = \mathsf{ToScalar^{Orchard}}\big(\mathsf{PRF^{expand}_{rivk\_ext}}\big([\mathtt{0x83}] \,||\, \mathsf{I2LEOSP}_{256}(\mathsf{ak}) \,||\, \mathsf{I2LEOSP}_{256}(\mathsf{nk})\kern-0.1em\big)\kern-0.15em\big)$ Import these definitions from § 4.7.3 ‘Sending Notes (Orchard)’ [^protocol-orchardsend], specialized to $\mathsf{leadByte} = \mathtt{0x03}$: @@ -1002,18 +1003,18 @@ $\begin{array}{l} \mathsf{rivk\_ext},&\text{if not } \mathsf{is\_internal\_rivk} \\ \mathsf{H^{rivk\_int}_{rivk\_ext}}(\mathsf{ak}, \mathsf{nk}),&\text{if } \mathsf{is\_internal\_rivk} \end{cases} \\ \wedge\; \mathsf{ak} = \mathsf{Extract}_{\mathbb{P}}(\mathsf{ak}^{\mathbb{P}}) \\ -\wedge\; \text{let } \mathsf{ivk} = \mathsf{Commit^{ivk}_{rivk}}(\mathsf{ak}, \mathsf{nk}) \\ -\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{ρ}}) \\ -\wedge\; \text{let } \mathsf{noterepr} = \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{noterepr}\big) \\ -\wedge\; \text{let } \mathsf{cm} = \mathsf{NoteCommit^{Orchard}_{rcm}}(\mathsf{noterepr}) \\ -\wedge\; \mathsf{cm} \neq \bot \\ -\wedge\; \text{let } \mathsf{cm}_x = \mathsf{Extract}_{\mathbb{P}}(\mathsf{cm}) \\ -\wedge\; \text{let } \mathsf{leaf} = \mathsf{MerkleCRH}(\mathsf{cm}_x, \text{ρ}) \\ -\wedge\; \mathsf{path} \text{ is a path to } \mathsf{leaf} \text{ in the rehashed commitment tree} \\ -\wedge\; \mathsf{nf} = \mathsf{DeriveNullifier_{nk}}(\text{ρ}, \text{ψ}, \mathsf{cm}) \\ +\wedge\; \text{let } \mathsf{ivk} = \mathsf{Commit^{ivk}_{rivk}}(\mathsf{ak}, \mathsf{nk}) \vphantom{\big(}\\ +\wedge\; \mathsf{ivk} \not\in \{0, \bot\} \vphantom{\Big(}\\ +\wedge\; \text{let } \mathsf{pk_d} = [\mathsf{ivk}]\, \mathsf{g_d} \vphantom{\big(}\\ +\wedge\; \text{let } \text{ψ} = \mathsf{H}^{\text{ψ}}_{\mathsf{r}\text{ψ}}(\underline{\text{ρ}}) \vphantom{\Big(}\\ +\wedge\; \text{let } \mathsf{noterepr} = \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) \vphantom{\big(}\\ +\wedge\; \text{let } \mathsf{rcm} = \mathsf{H^{rcm,Orchard}_{rseed}}\big(\mathtt{0x03}, \mathsf{noterepr}\big) \vphantom{\Big(}\\ +\wedge\; \text{let } \mathsf{cm} = \mathsf{NoteCommit^{Orchard}_{rcm}}(\mathsf{noterepr}) \vphantom{\big(}\\ +\wedge\; \mathsf{cm} \neq \bot \vphantom{\Big(}\\ +\wedge\; \text{let } \mathsf{cm}_x = \mathsf{Extract}_{\mathbb{P}}(\mathsf{cm}) \vphantom{\big(}\\ +\wedge\; \text{let } \mathsf{leaf} = \mathsf{MerkleCRH}(\mathsf{cm}_x, \text{ρ}) \vphantom{\Big(}\\ +\wedge\; \mathsf{path} \text{ is a path to } \mathsf{leaf} \text{ in the rehashed commitment tree} \vphantom{\big(}\\ +\wedge\; \mathsf{nf} = \mathsf{DeriveNullifier_{nk}}(\text{ρ}, \text{ψ}, \mathsf{cm}) \vphantom{\Big(}\\ \} \end{array}$ @@ -1037,15 +1038,15 @@ All of the operations below need to be implemented with complete additions, even if they are incomplete in the current Orchard[ZSA] statement/circuit. * 7 BLAKE2b-512 compressions: - * 3 multiplexed between $\mathsf{H^{rivk\_ext}}$ when $\mathsf{use\_qsk}$ is true (1 compression), + * 3 multiplexed between $\mathsf{H^{rivk\_ext}}$ when $\mathsf{use\_qsk}$ is true (1 compression), and $\mathsf{H^{ask}}$ + $\mathsf{H^{nk}}$ + $\mathsf{H^{rivk\_legacy}}$ when $\mathsf{use\_qsk}$ is false (3 compressions) - * 1 to compute $\mathsf{H^{rivk\_int}}$ - * 1 to compute $\mathsf{H^{\text{ψ}}}$ - * 2 to compute $\mathsf{H^{rcm}}$ - * we could potentially save these two by using Poseidon to implement $\mathsf{H^{rcm}}$, but it seems not worth it. + * 1 to compute $\mathsf{H^{rivk\_int}}$ + * 1 to compute $\mathsf{H^{\text{ψ}}}$ + * 2 to compute $\mathsf{H^{rcm}}$ + * we could potentially save these two by using Poseidon to implement $\mathsf{H^{rcm}}$, but it seems not worth it. * 1 use of $\mathsf{H^{qk}}$ * 1 use of $\mathsf{Commit^{ivk}}$ ($\mathsf{SinsemillaShortCommit}$) -* 1 use of $\mathsf{NoteCommit^{Orchard}}$ ($\mathsf{SinsemillaCommit}$) +* 1 use of $\mathsf{NoteCommit}$ ($\mathsf{SinsemillaCommit}$) * 1 full-width fixed-base Pallas scalar multiplication, $[\mathsf{ask}]\, \mathcal{G}^{\mathsf{Orchard}}$ * 1 full-width variable-base Pallas scalar multiplication, $[\mathsf{ivk}]\, \mathsf{g_d}$ * 1 Merkle tree path check @@ -1064,7 +1065,7 @@ post-quantum knowledge-sound. ### Repairing the note commitment Merkle tree -$\mathsf{MerkleCRH^{Orchard}}$ is instantiated using +$\mathsf{MerkleCRH}$ is instantiated using $\mathsf{SinsimillaHash}$ [^protocol-concretesinsemillahash]. Its collision resistance depends on the Discrete Logarithm Relation Problem on the Pallas curve [^protocol-sinsemillasecurity], and so it is not @@ -1085,53 +1086,53 @@ complications due to duplicate commitments for the same note. ### Attacks against binding of note commitments -We still face the problem that $\mathsf{NoteCommit^{Orchard}}$ is not +We still face the problem that $\mathsf{NoteCommit}$ is not binding against a discrete-log-breaking adversary: given the discrete logarithm relations between bases, we can easily write a linear equation in the scalar field with multiple solutions of the inputs for a given commitment. This allows an adversary to find two distinct notes corresponding to -openings of $\mathsf{NoteCommit^{Orchard}}$ on the same commitment. +openings of $\mathsf{NoteCommit}$ on the same commitment. They create one note as an output and spend the other note — which may have a greater value, or a value in a different ZSA asset, breaking the Balance property. ### Repairing note commitments -We prefer to fix this without changing $\mathsf{NoteCommit^{Orchard}}$ itself. +We prefer to fix this without changing $\mathsf{NoteCommit}$ 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.05em\star)$, as detailed in the [Specification] section. Specifically, when $\mathsf{leadByte} = \mathtt{0x03}$ we have: -$\mathsf{rcm} = \mathsf{H^{rcm}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr}) = \mathsf{ToScalar^{Orchard}}(\mathsf{PRF^{expand}_{rseed}}(\mathsf{pre\_rcm}))$ +$\hspace{2em}\mathsf{rcm} = \mathsf{H^{rcm}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr}) = \mathsf{ToScalar}(\mathsf{PRF^{expand}_{rseed}}(\mathsf{pre\_rcm}))$ $\text{where } \mathsf{pre\_rcm} = [\mathtt{0x0B}, \mathsf{leadByte}] \,||\, \mathsf{encode}(\mathsf{noterepr})$ ### Informal security argument for binding of note commitments -We can view the output of $\mathsf{NoteCommit^{Orchard}_{rcm}}(\mathsf{noterepr})$ +We can view the output of $\mathsf{NoteCommit_{rcm}}(\mathsf{noterepr})$ as the point addition of a randomization term $[\mathsf{H^{rcm}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr})]\, \mathcal{R}$, and some other function of $\mathsf{rseed}$, $\mathsf{leadByte}$, and $\mathsf{noterepr}$. Without loss of generality, we can write that function as -$[f(\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})]\, \mathcal{R}$, +$[\mathsf{f}(\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})]\, \mathcal{R}$, by expanding each of the Sinemilla bases $\mathcal{C}_j = \mathcal{Q}(D) \text{ or } \mathcal{S}(j)$ used by [$\mathsf{HashToSinsimillaPoint}$](https://zips.z.cash/protocol/protocol.pdf#concretesinsemillahash) as $\mathcal{C}_j = [c_j]\, \mathcal{R}$ for some $c_j$. That is, -$$\mathsf{NoteCommit^{Orchard}_{rcm}}(\mathsf{noterepr}) = [\mathsf{H^{rcm}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr}) + f(\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})]\, \mathcal{R}.$$ +$$\mathsf{NoteCommit_{rcm}}(\mathsf{noterepr}) = [\mathsf{H^{rcm}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr}) + \mathsf{f}(\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})]\, \mathcal{R}.$$ -We will model $\mathsf{H^{rcm}}$ as a random oracle independent of $f$ with +We will model $\mathsf{H^{rcm}}$ as a random oracle independent of $\mathsf{f}$ with uniform output on $\mathbb{F}_{r_{\mathbb{P}}}.$ This is reasonable because $\mathsf{H^{rcm}}$ cannot depend on any of the $c_j$, and in any case it is instantiated using BLAKE2b, a conventional hash function not related to the Pallas curve. -> The fact that $\mathsf{NoteCommit^{Orchard}}$ has +> The fact that $\mathsf{NoteCommit}$ has > $\text{ψ} = \mathsf{H}^{\text{ψ}}(\mathsf{rseed}, \text{ρ})$ as an > input does not affect the analysis provided that $\mathsf{H^{rcm}}$ and > $\mathsf{H}^{\text{ψ}}$ can be treated as independent. In practice both @@ -1152,7 +1153,7 @@ $\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr}$ and obtains a "random" $\mathsf{rcm} = \mathsf{H^{rcm}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr})$. -We have $\mathsf{cm}_x = \mathsf{Extract}_{\mathbb{P}}([\mathsf{H^{rcm}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr}) + f(\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})]\, \mathcal{R})$. +We have $\mathsf{cm}_x = \mathsf{Extract}_{\mathbb{P}}([\mathsf{H^{rcm}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr}) + \mathsf{f}(\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})]\, \mathcal{R})$. Over all Pallas curve points $P$, the number of outputs of $\mathsf{Extract}_{\mathbb{P}}(P)$ is $(\mathbb{F}_{r_\mathbb{P}} + 1)/2 \approx 2^{253}$ — @@ -1164,7 +1165,7 @@ zero point $\mathcal{O}_{\mathbb{P}}$ which is mapped to $0$. > negligible effect. There are two values of $\mathsf{cm}$ that match $\mathsf{cm}_x$ in their $x$-coordinate. -Because the output of $\mathsf{NoteCommit^{Orchard}_{rcm}}(\mathsf{noterepr})$ is +Because the output of $\mathsf{NoteCommit_{rcm}}(\mathsf{noterepr})$ is of the form $\mathsf{cm} = F(\mathsf{noterepr}) + [\mathsf{rcm}]\, \mathcal{R}$, for any given note we have exactly two values of $\mathsf{rcm}$ that will pass the commitment check. @@ -1197,7 +1198,7 @@ choose to attack either): * Case $\text{not } \mathsf{use\_qsk}$: The spender must prove knowledge of $\mathsf{sk}$, and that $\mathsf{ak}$, $\mathsf{nk}$, and $\mathsf{rivk}$ are derived correctly from $\mathsf{sk}$. This works because the - derivations use post-quantum hashes (and $\mathsf{ask} \rightarrow \mathsf{ak}$ + derivations use post-quantum hashes (and $\mathsf{ask} \mapsto \mathsf{ak}$ is deterministic). <br> In particular, $\mathsf{ivk}$ is an essentially random function of $\mathsf{sk}$, and so we expect that an adversary has no better attack @@ -1306,14 +1307,19 @@ or $\mathsf{SoK^{qk}}$. That is, the adversary can control: * $(\mathsf{nk}, \mathsf{ak}, \mathsf{qsk})$, when $\mathsf{use\_qsk} = \mathsf{true}$. We analyze $\mathsf{DeriveNullifier}$ as a function of these -controllable inputs. Recall that $\mathsf{DeriveNullifier}$ is defined in -§ 4.16 ‘Computing ρ values and Nullifiers’ as: +controllable inputs. Recall that $\mathsf{DeriveNullifier}$ is defined +in § 4.16 ‘Computing ρ values and Nullifiers’ as: -$$\mathsf{DeriveNullifier_{nk}}(\text{ρ}, \text{ψ}, \mathsf{cm}) = \mathsf{Extract}_{\mathbb{P}}\big(\big[\mathsf{PRF^{nfOrchard}_{nk}}(\text{ρ}) + \text{ψ}) \bmod q_{\mathbb{P}}\big]\, \mathcal{K}^{\mathsf{Orchard}} + \mathsf{cm}\big)$$ +$$\mathsf{DeriveNullifier_{nk}}(\text{ρ}, \text{ψ}, \mathsf{cm}) := + \mathsf{Extract}_{\mathbb{P}}\Big( + \big[(\mathsf{PRF^{nf}_{nk}}(\text{ρ}) + \text{ψ}) \bmod q_{\mathbb{P}}\big]\, \mathcal{K} + + \mathsf{cm} + \Big)$$ Also recall from [Repairing note commitments] that we have -$$\mathsf{cm} = [\mathsf{H^{rcm}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr}) + f(\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})]\, \mathcal{R}.$$ +$$\mathsf{cm} = [\mathsf{H^{rcm}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr}) + + \mathsf{f}(\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})]\, \mathcal{R}.$$ $\text{ψ}$ is determined by $\mathsf{rseed}$. The nullifier corresponding to $(\mathsf{nk}, \text{ρ}, \mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})$ From 5ef25b1338b5dcdf89f189ce30dad2e81e0127a5 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Mon, 4 May 2026 10:24:49 +0100 Subject: [PATCH 045/115] ZIP 2005: Tighten key-binding argument; lift use_qsk to witness structure; Spendability-proof refinements. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **Make the key-binding argument rigorous** (to support the ε_kb term in the Spendability proof): hoist the binding-break definition, ε_kb advantage, and a formal theorem statement into a Security argument for key binding section, with a proof sketch that mirrors the Spendability reduction structurally. **Lift flags out of the Recovery Statement and key-binding witness.** The use_qsk and is_internal_rivk flag information is now encoded in the witness's null structure: (sk = ⊥) ≠ (qk = ⊥) replaces the use_qsk flag, and rivk ∈ {rivk_ext, H^{rivk_int}_{rivk_ext}(ak, nk)} replaces the is_internal_rivk flag. The witness-structure form is strictly stronger than flag-based: cross-branch attacks (e.g., w_1 with qk ≠ ⊥ and w_2 with sk ≠ ⊥, both opening the same ivk) are now in scope. Co-nullable witness components are grouped as tuples — (qk, σ_qsk) is a single (T_1 × T_2) ∪ {(⊥, ⊥)} field rather than two independently- nullable fields with a separate consistency constraint. **Fix a pre-existing bug:** rk = SpendAuthSig.RandomizePublic(α, ak^P) was conditioned on use_qsk = true in the original Recovery Statement; it should hold unconditionally. **Spendability-proof tightening:** * Split the pinning lemma into ivk-pinning (unconditional, per-witness, via discrete-log on prime-order Pallas) and PRF^{nf}-pinning (pair- conditional, via key-binding break absence). * Make F's partiality explicit: F is defined under the no-key-binding- break conditioning, with (rseed, ρ, ψ) as fields of notetuple and PRF^{nf}_{nk}(ρ) pinned via the PRF^{nf}-pinning lemma. * Handle the F_i = 0 (identity) case via § 5.4.9.7 convention Extract_P(O) = 0, citing the new protocol-concreteextractorpallas reference. * Justify K_R being well-defined and nonzero. * State the non-querying constraint where it does work: deterministic shifts in F are independent of H^{rcm} oracle responses. * Add a tightness paragraph citing Maurer's classical-RO collision bound k(k-1)/(2N), with the factor-of-2 derivation for the ±-equivalence in our win condition. * Drop "or extracts from internal state" from the ε_{kb} definition. * Rename ε_{Commit^{ivk}}(A) to ε_{kb}(A, q_{kb}) — parameterized by query count, scoped to "key-binding" rather than just Commit^{ivk}. * Add the substituted concrete bound: by the key-binding theorem, ε_{kb}(A, q_{kb}) ≤ q_{kb}(q_{kb}-1)/r_P, so the overall Spendability bound is at most (q_{rcm}(q_{rcm}-1) + q_{kb}(q_{kb}-1))/r_P. **Notation cleanup:** * F → \mathsf{F} (function names sans-serif; F_1, F_2 stay italic as values). * q → q_{rcm} / q_{kb} (subscripted by which RO is being counted). Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Signed-off-by: Daira-Emma Hopwood <daira@jacaranda.org> --- zips/zip-2005.md | 525 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 397 insertions(+), 128 deletions(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index 27461796d..20ba96150 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -965,18 +965,16 @@ $\begin{array}{rl} the prover knows an auxiliary input: $\begin{array}{rl} - \hspace{4em} ( \mathsf{use\_qsk} \!\!\!\!&{\small ⦂}\; \mathbb{B}, \\ - \mathsf{is\_internal\_rivk} \!\!\!\!&{\small ⦂}\; \mathbb{B}, \\ - \mathsf{path} \!\!\!\!&{\small ⦂}\; \{ 0\,..\,q_{\mathbb{P}}-1 \}^{[\mathsf{MerkleDepth^{Orchard}}]}, \\ + \hspace{4em} ( \mathsf{path} \!\!\!\!&{\small ⦂}\; \{ 0\,..\,q_{\mathbb{P}}-1 \}^{[\mathsf{MerkleDepth^{Orchard}}]}, \\ \mathsf{pos} \!\!\!\!&{\small ⦂}\; \{ 0\,..\,2^{\mathsf{MerkleDepth^{Orchard}}}-1 \}, \\ K \!\!\!\!&{\small ⦂}\; \mathbb{B}^{[\ell_{\mathsf{sk}}]}, \\ \mathsf{\alpha} \!\!\!\!&{\small ⦂}\; \mathbb{F}_{r_{\mathbb{P}}}, \\ \mathsf{ak}^{\mathbb{P}} \!\!\!\!&{\small ⦂}\; \mathbb{P}^*, \\ \mathsf{nk} \!\!\!\!&{\small ⦂}\; \mathbb{F}_{q_{\mathbb{P}}}, \\ - \mathsf{qk} \!\!\!\!&{\small ⦂}\; \mathbb{B}^{{\kern-0.1em\tiny\mathbb{Y}}[\ell_{\mathsf{qk}}/8]}, \\ - \sigma_{\mathsf{qsk}} \!\!\!\!&{\small ⦂}\; \mathsf{SoK^{qsk}}\big((\mathsf{qk}), \mathsf{SigHash}\big), \\ + \mathsf{rivk\_ext} \!\!\!\!&{\small ⦂}\; \mathbb{F}_{r_{\mathbb{P}}}, \\ \mathsf{rivk} \!\!\!\!&{\small ⦂}\; \mathbb{F}_{r_{\mathbb{P}}}, \\ - \sigma_{\mathsf{sk}} \!\!\!\!&{\small ⦂}\; \mathsf{SoK^{sk}}\big((\mathsf{ak}^{\mathbb{P}}, \mathsf{nk}, \mathsf{rivk\_ext}), \mathsf{SigHash}\big), \\ + (\mathsf{qk}, \sigma_{\mathsf{qsk}}) \!\!\!\!&{\small ⦂}\; \big(\mathbb{B}^{{\kern-0.1em\tiny\mathbb{Y}}[\ell_{\mathsf{qk}}/8]} \times \mathsf{SoK^{qsk}}\big((\mathsf{qk}), \mathsf{SigHash}\big)\big) \cup \{(\bot, \bot)\}, \\ + \sigma_{\mathsf{sk}} \!\!\!\!&{\small ⦂}\; \mathsf{SoK^{sk}}\big((\mathsf{ak}^{\mathbb{P}}, \mathsf{nk}, \mathsf{rivk\_ext}), \mathsf{SigHash}\big) \cup \{\bot\}, \\ \mathsf{rseed} \!\!\!\!&{\small ⦂}\; \mathbb{B}^{{\kern-0.1em\tiny\mathbb{Y}}[32]}, \\ \mathsf{g_d} \!\!\!\!&{\small ⦂}\; \mathbb{P}^*, \\ \mathsf{v} \!\!\!\!&{\small ⦂}\; \{ 0\,..\,2^{\ell_{\mathsf{value}}}-1 \}, \\ @@ -986,23 +984,28 @@ $\begin{array}{rl} where $\begin{array}{rll} - \hspace{1em}\mathsf{SoK^{qsk}.Statement} \!\!\!\!&=\, \big\{\,\mathsf{qsk} \;{\small ⦂}\; \mathbb{B}^{{\kern-0.1em\tiny\mathbb{Y}}[\ell_{\mathsf{qsk}}/8]} &\!\!\!\!|\;\, \mathsf{qk} = \mathsf{H^{qk}}(\mathsf{qsk})\,\big\} \\ - \hspace{1em}\mathsf{SoK^{sk}.Statement} \!\!\!\!&=\, \big\{\,\mathsf{sk} \;{\small ⦂}\; \mathbb{B}^{[\ell_{\mathsf{sk}}]} &\!\!\!\!|\;\, \mathsf{ak}^{\mathbb{P}} = [\mathsf{H^{ask}}(\mathsf{sk})]\, \mathcal{G}^{\mathsf{Orchard}} \\ - && \;\wedge\; \mathsf{nk} = \mathsf{H^{nk}} \\ - && \;\wedge\; \mathsf{rivk\_ext} = \mathsf{H^{rivk\_legacy}}(\mathsf{sk})\,\big\} + \hspace{1em}\mathsf{BindKeys^{sk}}(\mathsf{sk}, \mathsf{ak}^{\mathbb{P}}, \mathsf{nk}, \mathsf{rivk\_ext}) = + \big(&\!\!\!\! \mathsf{ak}^{\mathbb{P}} = [\mathsf{H^{ask}}(\mathsf{sk})]\, \mathcal{G}^{\mathsf{Orchard}} \\ + &\!\!\!\! \wedge\; \mathsf{nk} = \mathsf{H^{nk}}(\mathsf{sk}) \\ + &\!\!\!\! \wedge\; \mathsf{rivk\_ext} = \mathsf{H^{rivk\_legacy}}(\mathsf{sk}) \,\big) +\end{array}$ + +and + +$\begin{array}{rll} + \hspace{1em}\mathsf{SoK^{qsk}.Statement} \!\!\!&=\, \big\{\,\mathsf{qsk} \;{\small ⦂}\; \mathbb{B}^{{\kern-0.1em\tiny\mathbb{Y}}[\ell_{\mathsf{qsk}}/8]} &\!\!\!\!|\;\, \mathsf{qk} = \mathsf{H^{qk}}(\mathsf{qsk}) \,\big\} \\ + \hspace{1em}\mathsf{SoK^{sk}.Statement} \!\!\!&=\, \big\{\,\mathsf{sk} \;{\small ⦂}\; \mathbb{B}^{[\ell_{\mathsf{sk}}]} &\!\!\!\!|\;\, \mathsf{BindKeys^{sk}}(\mathsf{sk}, \mathsf{ak}^{\mathbb{P}}, \mathsf{nk}, \mathsf{rivk\_ext}) \,\big\} \end{array}$ 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) \\ -\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 not } \mathsf{is\_internal\_rivk} \\ -\mathsf{H^{rivk\_int}_{rivk\_ext}}(\mathsf{ak}, \mathsf{nk}),&\text{if } \mathsf{is\_internal\_rivk} \end{cases} \\ -\wedge\; \mathsf{ak} = \mathsf{Extract}_{\mathbb{P}}(\mathsf{ak}^{\mathbb{P}}) \\ +\{\;\, \mathsf{rk} = \mathsf{SpendAuthSig^{Orchard}.RandomizePublic}(\alpha, \mathsf{ak}^{\mathbb{P}}) \vphantom{\big(}\\ +\wedge\; \mathsf{ak} = \mathsf{Extract}_{\mathbb{P}}(\mathsf{ak}^{\mathbb{P}}) \vphantom{\Big(}\\ +\wedge\; \big((\mathsf{qk}, \sigma_{\mathsf{qsk}}) = (\bot, \bot)\big) \neq \big(\sigma_{\mathsf{sk}} = \bot\big) \vphantom{\big(}\\ +\wedge\; (\mathsf{qk}, \sigma_{\mathsf{qsk}}) \neq (\bot, \bot) \Rightarrow \big(\, \mathsf{SoK^{qsk}.Validate}\big((\mathsf{qk}), \mathsf{SigHash}, \sigma_{\mathsf{qsk}}\big) \kern0.05em\wedge\, \mathsf{rivk\_ext} = \mathsf{H^{rivk\_ext}_{qk}}(\mathsf{ak}, \mathsf{nk})\kern0.05em\big) \vphantom{\Big(}\\ +\wedge\; \sigma_{\mathsf{sk}} \neq \bot \Rightarrow \mathsf{SoK^{sk}.Validate}\big((\mathsf{ak}^{\mathbb{P}}, \mathsf{nk}, \mathsf{rivk\_ext}), \mathsf{SigHash}, \sigma_{\mathsf{sk}}\big) \vphantom{\big(}\\ +\wedge\; \mathsf{rivk} \in \big\{\, \mathsf{rivk\_ext},\, \mathsf{H^{rivk\_int}_{rivk\_ext}}(\mathsf{ak}, \mathsf{nk}) \,\big\} \vphantom{\Big(}\\ \wedge\; \text{let } \mathsf{ivk} = \mathsf{Commit^{ivk}_{rivk}}(\mathsf{ak}, \mathsf{nk}) \vphantom{\big(}\\ \wedge\; \mathsf{ivk} \not\in \{0, \bot\} \vphantom{\Big(}\\ \wedge\; \text{let } \mathsf{pk_d} = [\mathsf{ivk}]\, \mathsf{g_d} \vphantom{\big(}\\ @@ -1192,10 +1195,10 @@ $\mathsf{Commit^{ivk}_{rivk}}(\mathsf{ak}, \mathsf{nk}) = \mathsf{ivk}$. Unfortunately that's not true; $\mathsf{Commit^{ivk}}$ is instantiated by $\mathsf{SinsemillaShortCommit}$ which is not post-quantum binding. -There are two cases depending on $\mathsf{use\_qsk}$ (the adversary can -choose to attack either): +There are two cases depending on which witness branch the adversary +uses (they can choose to attack either, or both simultaneously): -* Case $\text{not } \mathsf{use\_qsk}$: The spender must prove knowledge of +* Case $\mathsf{sk} \neq \bot$: The spender must prove knowledge of $\mathsf{sk}$, and that $\mathsf{ak}$, $\mathsf{nk}$, and $\mathsf{rivk}$ are derived correctly from $\mathsf{sk}$. This works because the derivations use post-quantum hashes (and $\mathsf{ask} \mapsto \mathsf{ak}$ @@ -1212,10 +1215,11 @@ 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}$: This case is almost the same except that +* Case $\mathsf{qk} \neq \bot$: 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 $\text{not } \mathsf{use\_qsk}$. + in terms of $T$ is also the same as for the $\mathsf{sk} \neq \bot$ + case. The above security argument means that provided we also check the uses of $\mathsf{H^{rcm}}$ and $\mathsf{H}^{\text{ψ}}$ in the post-quantum @@ -1238,8 +1242,8 @@ will need to use complete curve additions to implement Sinsemilla. In order to adapt this argument to the quantum setting, we need to consider *collapsing* hash functions as defined in [^Unruh2015] [^Unruh2016]. -TODO: $\mathsf{Extract}_{\mathbb{P}}$ is not collapsing. -Is $\mathsf{Extract}_{\mathbb{P}}([\mathsf{H^{rcm}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr}) + f(\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})]\, \mathcal{R})$ collapsing? +TODO: does $\mathsf{Extract}_{\mathbb{P}}$ cause any difficulty for lifting +to QROM? By the argument in [^Bernstein2009], the best known *generic* quantum attack on a hash function is simply the classical attack of [^vOW1999]. @@ -1252,37 +1256,169 @@ output size of 253 bits does not exclude a hash function from being collapsing. TODO: discuss [^CBHSU2017] (sponge security), [^Unruh2015] [^Unruh2016] (collapse-binding property). -### Informal security argument for binding of ivk - -The security of Orchard against double-spending also depends on the binding -property of $\mathsf{Commit^{ivk}}$. Informally, the security argument is -that there is only one value of $\mathsf{ivk}$ corresponding to a given -$(\mathsf{g_d}, \mathsf{pk_d})$ (which are committed to by the note -commitment), and so this binds $\mathsf{nk}$ and $\mathsf{ak}$ to the -correct values for the committed note. - -If the binding property of $\mathsf{Commit^{ivk}}$ fails, then so do -the security arguments for the Balance and Spend Authorization properties, -because we can no longer infer that $\mathsf{nk}$ and $\mathsf{ak}$ are the -correct values. - -There is a complication: contrary to the situation with note commitments, -addresses may be used over the long term and it may not be feasible or -desirable to switch to new addresses. Fortunately, the Orchard protocol -specified each of $\mathsf{ak}$, $\mathsf{nk}$, and $\mathsf{rivk}$ to be -derived from $\mathsf{sk}$ via $\mathsf{PRF^{expand}}$. ($\mathsf{rivk}$ -is derived differently for an "internal IVK", but that is also via -$\mathsf{PRF^{expand}}$.) - -We use essentially the same fix as for $\mathsf{NoteCommit^{Orchard}}$, -with $\mathsf{rivk}$ in place of $\mathsf{rcm}$. We check the derivation -of all of $\mathsf{ak}$, $\mathsf{nk}$, and $\mathsf{rivk}$ from $\mathsf{sk}$. -Looking carefully at the structure of the derivations relative to the -ones for $\mathsf{NoteCommit^{Orchard}}$, we can see that $\mathsf{sk}$ -is in a roughly similar position to $\mathsf{rseed}$, and -$(\mathsf{ak}, \mathsf{nk})$ to $\text{ψ}$. Because these are the only -inputs to the commitment, the checks are sufficient to ensure they are -all bound by it. +### Security argument for key binding + +The security of Orchard against several attacks depends on cryptographic +keys being bound to a recoverable note's $\mathsf{ivk}$. Different +Orchard properties need different components of the key witness pinned: + +* **Nullifier-binding** (used by the Balance argument and by the + [Spendability argument](#securityargumentforspendability) below + — the latter via the + [$\mathsf{PRF^{nf}}$-pinning lemma](#lemma-prf-nf-pinning)): + $\mathsf{nk}$ uniquely determined by $\mathsf{ivk}$. +* **Spend Authorization**: $\mathsf{qk}$ uniquely determined by + $\mathsf{ivk}$ when $\mathsf{qk} \neq \bot$ (i.e., when + $\mathsf{use\_qsk} = \mathsf{true}$). + +The formal key-binding condition stated below covers both of these +uniformly: a key-binding break is a pair of distinct witnesses sharing +the same $\mathsf{ivk}$, where each witness carries the full key tuple +— $(\mathsf{ak}, \mathsf{nk}, \mathsf{rivk})$ plus whichever of +$\mathsf{qk}$ or $\mathsf{sk}$ is in use. If key binding fails, the +Balance, Spendability, and Spend Authorization arguments each lose +their corresponding pinning step. + +Relative to the situation with note commitments where it was reasonable +to only obtain quantum recoverability for newly output Orchard notes, +there is a complication. Addresses may be used over the long term and +it may not be desirable to switch to new addresses, or to avoid funds +being sent to old ones. Fortunately, the Orchard protocol specified each +of $\mathsf{ak}$, $\mathsf{nk}$, and $\mathsf{rivk}$ to be derived from +$\mathsf{sk}$ via $\mathsf{PRF^{expand}}$, which is assumed collapsing. +($\mathsf{rivk}$ is derived differently for an "internal IVK", but that +is also via $\mathsf{PRF^{expand}}$.) + +Classically, the binding of $\mathsf{Commit^{ivk}}$ —instantiated via +Sinsemilla— fails against a discrete-log-breaking adversary, similarly +to $\mathsf{NoteCommit}$. We use essentially the same fix as for +$\mathsf{NoteCommit}$, with the $\mathsf{rivk}$-derivation hashes +playing the role of $\mathsf{H^{rcm}}$. The Recovery Statement checks +the derivation of $\mathsf{rivk}$: + +* When $\mathsf{qk} \neq \bot$, + $\mathsf{rivk\_ext} = \mathsf{H^{rivk\_ext}_{qk}}(\mathsf{ak}, \mathsf{nk})$. +* When $\mathsf{sk} \neq \bot$, + $\mathsf{rivk\_ext} = \mathsf{H^{rivk\_legacy}}(\mathsf{sk})$, with + $\mathsf{ak}$ and $\mathsf{nk}$ also derived from $\mathsf{sk}$ via + $\mathsf{H^{ask}}$ and $\mathsf{H^{nk}}$. + +Exactly one of $\mathsf{qk}$ and $\mathsf{sk}$ is non-$\bot$ per +witness; this is equivalent to case-splitting by $\mathsf{use\_qsk}$. + +In either case, $\mathsf{rivk}$ is then either $\mathsf{rivk\_ext}$ +directly (external IVK) or +$\mathsf{H^{rivk\_int}_{rivk\_ext}}(\mathsf{ak}, \mathsf{nk})$ (internal +IVK). All of these hashes are modelled as independent random oracles for +the key-binding argument. + +As in the [Recovery Statement](#proposedrecoverystatement), we have: + +$\begin{array}{rll} + \hspace{1em}\mathsf{BindKeys^{sk}}(\mathsf{sk}, \mathsf{ak}^{\mathbb{P}}, \mathsf{nk}, \mathsf{rivk\_ext}) = + \big(&\!\!\!\! \mathsf{ak}^{\mathbb{P}} = [\mathsf{H^{ask}}(\mathsf{sk})]\, \mathcal{G}^{\mathsf{Orchard}} \\ + &\!\!\!\! \wedge\; \mathsf{nk} = \mathsf{H^{nk}}(\mathsf{sk}) \\ + &\!\!\!\! \wedge\; \mathsf{rivk\_ext} = \mathsf{H^{rivk\_legacy}}(\mathsf{sk}) \,\big) +\end{array}$ + +Let the key-binding condition on a witness +$w = (\mathsf{ivk}, \mathsf{qk}, \mathsf{sk}, \mathsf{ak}^{\mathbb{P}}, \mathsf{nk}, \mathsf{rivk\_ext}, \mathsf{rivk})$ be: + +$\begin{array}{l} +\;\;\; (\mathsf{sk} = \bot) \neq (\mathsf{qk} = \bot) \\ +\wedge\; \mathsf{qk} \neq \bot \Rightarrow \big(\; \mathsf{rivk\_ext} = \mathsf{H^{rivk\_ext}_{qk}}(\mathsf{ak}, \mathsf{nk}) \,\big) \\ +\wedge\; \mathsf{sk} \neq \bot \Rightarrow \mathsf{BindKeys^{sk}}(\mathsf{sk}, \mathsf{ak}^{\mathbb{P}}, \mathsf{nk}, \mathsf{rivk\_ext}) \\ +\wedge\; \mathsf{rivk} \in \big\{\, \mathsf{rivk\_ext},\, \mathsf{H^{rivk\_int}_{rivk\_ext}}(\mathsf{ak}, \mathsf{nk}) \,\big\} \\ +\wedge\; \mathsf{ivk} = \mathsf{Commit^{ivk}_{rivk}}(\mathsf{ak}, \mathsf{nk}) \\ +\wedge\; \mathsf{ivk} \not\in \{0, \bot\} +\end{array}$ + +where $\mathsf{ak} = \mathsf{Extract}_{\mathbb{P}}(\mathsf{ak}^{\mathbb{P}}).$ + +The flags $\mathsf{use\_qsk}$ and $\mathsf{is\_internal\_rivk}$ that +appear in the protocol diagram do not appear in this witness — nor in +the formal Recovery Statement above. Their roles are absorbed into the +witness's structural form: + +* $\mathsf{use\_qsk}$ is encoded in + $(\mathsf{sk} = \bot) \neq (\mathsf{qk} = \bot)$: exactly one of + $\mathsf{sk}$ and $\mathsf{qk}$ is non-$\bot$, and the branch-specific + constraints apply to whichever is present. +* $\mathsf{is\_internal\_rivk}$ is encoded in + $\mathsf{rivk} \in \big\{\mathsf{rivk\_ext},\, \mathsf{H^{rivk\_int}_{rivk\_ext}}(\mathsf{ak}, \mathsf{nk})\big\}$: + both $\mathsf{rivk}$ derivations are admitted simultaneously. + +This formulation is strictly stronger than a flag-conditioned one: a +key-binding break can have $w_1$ and $w_2$ in different branches across +either flag (e.g., $w_1$ with $\mathsf{qk} \neq \bot$ and $w_2$ with +$\mathsf{sk} \neq \bot$, or $w_1$ with external $\mathsf{rivk}$ and +$w_2$ with internal $\mathsf{rivk}$), provided both produce the same +$\mathsf{ivk}$. A flag-based formulation would forbid only same-branch +breaks. + +A **key-binding break** is a pair of distinct witnesses $(w_1, w_2)$ with shared +$\mathsf{ivk}$ satifying the key-binding condition. + +The random oracles used in the key-binding condition are $\mathsf{H^{rivk\_ext}}$, +$\mathsf{H^{rivk\_legacy}}$, $\mathsf{H^{rivk\_int}}$, $\mathsf{H^{ask}}$, and +$\mathsf{H^{nk}}$. + +Let $\varepsilon_{\mathsf{kb}}(\mathcal{A}, q_{\mathsf{kb}})$ +be the probability, over $\mathcal{A}$'s randomness and at most $q_{\mathsf{kb}}$ +queries in total to these random oracles, that $\mathcal{A}$ outputs a +key-binding break. + +**Theorem (key-binding, classical ROM).** <a id="thm-key-binding-rom"></a> +Let $\mathcal{A}$ be a classical adversary making at most $q_{\mathsf{kb}}$ +total queries to the random oracles used in the key-binding condition. Then +$\varepsilon_{\mathsf{kb}}(\mathcal{A}, q_{\mathsf{kb}}) \leq \frac{q_{\mathsf{kb}}(q_{\mathsf{kb}}-1)}{r_{\mathbb{P}}}$. + +**Proof sketch.** +$\mathsf{Commit^{ivk}_{rivk}}(\mathsf{ak}, \mathsf{nk})$ is a Sinsemilla +short commitment, of the form +$\mathsf{ShortHash}\big([h(\mathsf{ak}, \mathsf{nk}) + \mathsf{rivk}] \cdot \mathcal{S}\big)$ +for a Pedersen-like deterministic hash $h$ and a Sinsemilla base +$\mathcal{S}$. As in the Spendability proof, $h$ does not query +$\mathsf{H^{rivk\_ext}}$, $\mathsf{H^{rivk\_legacy}}$, or +$\mathsf{H^{rivk\_int}}$: it is determined by fixed Sinsemilla bases +and depends only on $(\mathsf{ak}, \mathsf{nk})$. By the same $y^2 = f(x)$ +argument used in Spendability (using § 5.4.9.7 for the +$\mathsf{Extract}_{\mathbb{P}}$-style $x$-coordinate convention), a +key-binding break implies +$$h(\mathsf{ak}, \mathsf{nk}) + \mathsf{rivk} \equiv \pm\big(h(\mathsf{ak}', \mathsf{nk}') + \mathsf{rivk}'\big) \pmod{r_{\mathbb{P}}}.$$ + +Under the random-oracle modelling, $\mathsf{rivk}$ in each case is a +fresh, uniform $\mathbb{F}_{r_{\mathbb{P}}}$-valued random-oracle output +keyed by deterministic inputs: + +* When $\mathsf{qk} \neq \bot$: $\mathsf{rivk\_ext}$ comes from + $\mathsf{H^{rivk\_ext}_{qk}}(\mathsf{ak}, \mathsf{nk})$. +* When $\mathsf{sk} \neq \bot$: $\mathsf{rivk\_ext}$ comes from + $\mathsf{H^{rivk\_legacy}}(\mathsf{sk})$. +* $\mathsf{rivk}$ is either $\mathsf{rivk\_ext}$ (external IVK), or +* $\mathsf{H^{rivk\_int}_{rivk\_ext}}(\mathsf{ak}, \mathsf{nk})$ (internal IVK). + +In every case, the value +$\mathsf{G}(\mathsf{ak}, \mathsf{nk}, \mathsf{rivk}) := h(\mathsf{ak}, \mathsf{nk}) + \mathsf{rivk} \pmod{r_{\mathbb{P}}}$ +is a translate of an independent uniform random-oracle output by a +deterministic shift. For distinct triples, $\mathsf{G}$ outputs are +each independent and uniform on $\mathbb{F}_{r_{\mathbb{P}}}$. + +The break condition $G_1 \equiv \pm G_2 \pmod{r_{\mathbb{P}}}$ +is then a linear constraint on a pair of independent uniform variables, +satisfied with probability at most $2/r_{\mathbb{P}}$. Taking a union +bound over the at most ${q_{\mathsf{kb}} \choose 2}$ pairs of distinct +random-oracle queries and the two sign cases gives +$\varepsilon_{\mathsf{kb}}(\mathcal{A}, q_{\mathsf{kb}}) \leq \frac{q_{\mathsf{kb}}(q_{\mathsf{kb}}-1)}{r_{\mathbb{P}}}$. + +(TODO: verify the exact form of $h$ and $\mathcal{S}$ from § 5.4.1.10 +'Sinsemilla Commit Function'; verify that the $\mathsf{qk} \neq \bot$ +branch pins $\mathsf{qk}$, and that the $\mathsf{sk} \neq \bot$ branch +pins $(\mathsf{ak}, \mathsf{nk})$, via the random-oracle inputs, so +that distinct witnesses necessarily correspond to distinct +random-oracle queries; verify the internal-IVK case's keying does not +introduce a dependency that breaks the "independent uniform" claim +above.) ## Security argument for Spendability @@ -1300,11 +1436,12 @@ involved. Since each function in the Recovery Statement is deterministic, the free variables that the adversary can control are the sources of the derivation digraph within that statement and either $\mathsf{SoK^{sk}}$ -or $\mathsf{SoK^{qk}}$. That is, the adversary can control: - -* $(\text{ρ}, \mathsf{g_d}, \mathsf{rseed}, \mathsf{is\_internal\_rivk}, \mathsf{use\_qsk})$ and - * $\mathsf{sk}$, when $\mathsf{use\_qsk} = \mathsf{false}$; - * $(\mathsf{nk}, \mathsf{ak}, \mathsf{qsk})$, when $\mathsf{use\_qsk} = \mathsf{true}$. +or $\mathsf{SoK^{qk}}$. That is, the adversary can control all of +$$(\text{ρ}, \mathsf{g_d}, \mathsf{rseed}, \mathsf{sk}, \mathsf{nk}, \mathsf{ak}, \mathsf{qk}, \mathsf{qsk}, \mathsf{rivk})$$ +subject to $(\mathsf{sk} = \bot) \neq (\mathsf{qk} = \bot)$. The +choice between external and internal IVK is encoded in +$\mathsf{rivk}$'s value (either $\mathsf{rivk\_ext}$ or +$\mathsf{H^{rivk\_int}_{rivk\_ext}}(\mathsf{ak}, \mathsf{nk})$). We analyze $\mathsf{DeriveNullifier}$ as a function of these controllable inputs. Recall that $\mathsf{DeriveNullifier}$ is defined @@ -1321,45 +1458,99 @@ Also recall from [Repairing note commitments] that we have $$\mathsf{cm} = [\mathsf{H^{rcm}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr}) + \mathsf{f}(\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})]\, \mathcal{R}.$$ -$\text{ψ}$ is determined by $\mathsf{rseed}$. The nullifier corresponding to +Let $K_{\kern-.08em\mathcal{R}}$ denote the discrete logarithm of +$\mathcal{K}$ with respect to $\mathcal{R}$. This is well-defined and +nonzero: $\mathcal{R}$ generates the prime-order Pallas group, so any +non-identity Pallas point has a unique nonzero discrete logarithm with +respect to it; and $\mathcal{K}$ is non-identity by construction. + +Recall that $\text{ψ}$ is determined by $\mathsf{rseed}$ via +$\text{ψ} = \mathsf{H}^{\text{ψ}}_{\mathsf{rseed}}(\text{ρ})$. +The nullifier corresponding to $(\mathsf{nk}, \text{ρ}, \mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})$ is then -$$\mathsf{Extract}_{\mathbb{P}}\big([\mathsf{H^{rcm}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr}) + f(\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr}) + g(\mathsf{nk}, \text{ρ}, \mathsf{rseed})]\, \mathcal{R}\big)$$ - -for some $g$ depending on the discrete logarithm of $\mathcal{K}^{\mathsf{Orchard}}$ wrt $\mathcal{R}$. - -We give a reduction-based argument that any classical adversary in the -Random Oracle Model who finds two valid Recovery Statement witnesses for -distinct underlying notes with colliding nullifiers, succeeds with -probability bounded by $q(q-1)/r_{\mathbb{P}}$, where $q$ is the number -of $\mathsf{H^{rcm}}$ queries the adversary makes. The bound depends only -on the query count, not on running time, and applies to any adversary -regardless of attack strategy. - -We model $\mathsf{H^{rcm}}$ as a random oracle with output uniform -on $\mathbb{F}_{r_{\mathbb{P}}}$. The functions $f$ and $g$ are deterministic -functions of their inputs — a structural property of the algebraic -decomposition derived above. $f$ depends on -$(\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})$ via the Sinsemilla -bases $\mathcal{C}_j = [c_j]\, \mathcal{R}$; $g$ depends on -$(\mathsf{nk}, \text{ρ}, \mathsf{rseed})$ via $\mathsf{PRF^{nfOrchard}}$, -$\mathsf{H}^{\text{ψ}}$, and the discrete logarithm of -$\mathcal{K}^{\mathsf{Orchard}}$ wrt $\mathcal{R}$. Neither is modelled as -a random oracle. - -We are *not* assuming $\mathsf{Commit^{ivk}}$ is binding, nor that any -of the key-derivation hashes are collision-resistant. The argument here -covers only $\mathsf{NoteCommit}$ binding — it argues that $\mathsf{nf}$ +$$\mathsf{Extract}_{\mathbb{P}}\Big( + \big[ + \big((\mathsf{PRF^{nf}_{nk}}(\text{ρ}) + \text{ψ}) \bmod q_{\mathbb{P}}\big) \cdot K_{\kern-.08em\mathcal{R}} + + \mathsf{H^{rcm}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr}) + \mathsf{f}(\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr}) + \big]\, \mathcal{R} + \Big).$$ + +We model $\mathsf{H^{rcm}}$ as a random oracle with output uniform on +$\mathbb{F}_{r_{\mathbb{P}}}$. The functions $\mathsf{f}$, +$\mathsf{H}^{\text{ψ}}$, and $\mathsf{PRF^{nf}}$ are deterministic +functions of $\mathsf{notetuple}$ that **do not query $\mathsf{H^{rcm}}$**: +$\mathsf{f}(\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})$ is the +Sinsemilla-base lift; $\mathsf{H}^{\text{ψ}}$ and $\mathsf{PRF^{nf}}$ are +conventional hash functions. + +> The non-querying constraint rules out trivializing instantiations such +> as $\mathsf{f}({\small •}) = -\mathsf{H^{rcm}}({\small •})$. +> In the concrete protocol, it reflects that $\mathsf{f}$ depends only on +> fixed Sinsemilla bases; and that the hashes $\mathsf{H}^{\text{ψ}}$, +> $\mathsf{PRF^{nf}}$, and $\mathsf{H^{rcm}}$ use distinct domain +> separators, so can be considered unrelated to each other. + +A key-binding break is as defined above in the +[Security argument for key binding](#securityargumentforkeybinding). + +Let $\varepsilon_{\mathsf{kb}}(\mathcal{A}, q_{\mathsf{kb}})$ +be the probability, over $\mathcal{A}$'s randomness and at most +$q_{\mathsf{kb}}$ queries to the random oracles used in the +key-binding argument, that $\mathcal{A}$ outputs a key-binding break. +$\varepsilon_{\mathsf{kb}}(\mathcal{A}, q_{\mathsf{kb}})$ is +bounded separately by that argument; the bound below is unconditional, +but is only useful to the extent that +$\varepsilon_{\mathsf{kb}}(\mathcal{A}, q_{\mathsf{kb}})$ is +small. + +We give a reduction-based argument that any classical adversary +$\mathcal{A}$ in the Random Oracle Model attempting to find two valid +[Recovery Statement](#proposedrecoverystatement) witnesses for distinct +underlying notes that have colliding nullifiers, succeeds with probability at most +$\frac{q_{\mathsf{rcm}}(q_{\mathsf{rcm}}-1)}{r_{\mathbb{P}}} + \varepsilon_{\mathsf{kb}}(\mathcal{A}, q_{\mathsf{kb}})$, +where $q_{\mathsf{rcm}}$ is the number of queries $\mathcal{A}$ makes +to $\mathsf{H^{rcm}}$, and $q_{\mathsf{kb}}$ is as defined above. +The bound depends only on $q_{\mathsf{rcm}}$ and on +$\varepsilon_{\mathsf{kb}}(\mathcal{A}, q_{\mathsf{kb}})$, +not on running time. + +The components $\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr}$ +are fields of $\mathsf{notetuple}$ by definition; and $\text{ρ}$, +$\mathsf{g_d}$, $\mathsf{pk_d}$, and $\text{ψ}$ are fields of +$\mathsf{noterepr}$, hence of $\mathsf{notetuple}$. + +**$\mathsf{ivk}$-pinning lemma.** <a id="lemma-ivk-pinning"></a> +For any valid Recovery Statement witness $w$ with +$\mathsf{notetuple} = (\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})$, +the value $\mathsf{ivk} = \log_{\mathsf{g_d}}(\mathsf{pk_d})$ is +well-defined, since $\mathsf{g_d} \neq \mathcal{O}_{\mathbb{P}}$ on the +prime-order Pallas curve and +$\mathsf{ivk} \in [0, q_{\mathbb{P}}) \subseteq [0, r_{\mathbb{P}})$; +$\mathsf{ivk}$ is therefore uniquely determined by $\mathsf{notetuple}$. + +**$\mathsf{PRF^{nf}}$-pinning lemma.** <a id="lemma-prf-nf-pinning"></a> +Suppose $\mathcal{A}$'s output $(w_1, w_2)$ does not contain a +key-binding break. Then for each $i \in \{1, 2\}$, +$\mathsf{PRF^{nf}_{\mathsf{nk}_i}}(\text{ρ}_i)$ is uniquely determined +by $\mathsf{notetuple}_i$: by the conditioning, +$(\mathsf{ak}_i, \mathsf{nk}_i, \mathsf{rivk}_i)$ is the only opening of +$\mathsf{ivk}_i$ appearing in $\mathcal{A}$'s output, so $\mathsf{nk}_i$ +is a function of $\mathsf{ivk}_i$, which is in turn a function of +$\mathsf{notetuple}_i$ by the $\mathsf{ivk}$-pinning lemma; and +$\text{ρ}_i$ is a field of $\mathsf{notetuple}_i$. + +The argument here covers nullifier-binding — it argues that $\mathsf{nf}$ binds the underlying note ($\mathsf{noterepr}$, plus $\mathsf{rseed}$ and -$\mathsf{leadByte}$) under $\mathsf{H^{rcm}}$-as-random-oracle -alone. +$\mathsf{leadByte}$) under $\mathsf{H^{rcm}}$ modelled as a random oracle +and the [key-binding theorem](#thm-key-binding-rom). **Theorem (distinct-note Spendability, classical ROM).** <a id="thm-spendability"></a> Let $\mathcal{A}$ be a classical adversary with oracle access to -$\mathsf{H^{rcm}}$ modelled as a random oracle with output uniform on -$\mathbb{F}_{r_{\mathbb{P}}}$, making at most $q$ oracle queries. The -*Spendability-collision* game has $\mathcal{A}$ output two Recovery -Statement witnesses $\mathsf{w}_1, \mathsf{w}_2$ satisfying: +$\mathsf{H^{rcm}}$ having output uniform on $\mathbb{F}_{r_{\mathbb{P}}}$, +making at most $q_{\mathsf{rcm}}$ oracle queries. The *Spendability-collision* +game has $\mathcal{A}$ output two Recovery Statement witnesses $w_1, w_2$ +satisfying: <a id="thm-spendability-validity"></a>**Validity of witnesses** : both witnesses satisfy the @@ -1367,47 +1558,121 @@ Statement witnesses $\mathsf{w}_1, \mathsf{w}_2$ satisfying: <a id="thm-spendability-distinct"></a>**Distinct underlying notes** : the $\mathsf{H^{rcm}}$-input tuples - $r_i := (\mathsf{rseed}_i, \mathsf{leadByte}_i, \mathsf{noterepr}_i)$ - satisfy $r_1 \neq r_2$. + $\mathsf{notetuple}_i := (\mathsf{rseed}_i, \mathsf{leadByte}_i, \mathsf{noterepr}_i)$ + satisfy $\mathsf{notetuple}_1 \neq \mathsf{notetuple}_2$. <a id="thm-spendability-collide"></a>**Colliding nullifiers** : $\mathsf{nf}_1 = \mathsf{nf}_2$. Then $\mathcal{A}$ wins this game with probability at most -$\binom{q}{2} \cdot 2/r_{\mathbb{P}} = q(q-1)/r_{\mathbb{P}}$, taken over -the random oracle's responses and any internal randomness of $\mathcal{A}$. - -For the Pallas curve we have $r_{\mathbb{P}} \approx 2^{254}$, so any -adversary making at most $q \le 2^{80}$ random-oracle queries wins with -probability at most approximately $2^{-94}$. +$$\Big({\textstyle{q_{\mathsf{rcm}}} \atop \textstyle{2}}\Big) \cdot \frac{2}{r_{\mathbb{P}}} + + \varepsilon_{\mathsf{kb}}(\mathcal{A}, q_{\mathsf{kb}}) + = \frac{q_{\mathsf{rcm}}(q_{\mathsf{rcm}}-1)}{r_{\mathbb{P}}} + \varepsilon_{\mathsf{kb}}(\mathcal{A}, q_{\mathsf{kb}}),$$ +taken over the random oracle's responses and any internal randomness of +$\mathcal{A}$. + +This bound is essentially tight against classical generic adversaries. +Maurer [^Maurer2002] (Section 2, p. 5) establishes a matching upper +bound of ${k \choose 2}/N$ on the success probability of any +classical algorithm in finding a collision against a random oracle with +an $N$-element output space using $k$ queries. Maurer's bound applies +to the *equality* event $F_i = F_j$; our win condition allows +$F_i = \pm F_j$ (two winning configurations per pair instead of one). +Applying Maurer with $N = r_{\mathbb{P}}$ (the $\mathsf{H^{rcm}}$ +output space) gives ${q_{\mathsf{rcm}} \choose 2}/r_{\mathbb{P}}$ for +the equality event; doubling for the sign relaxation gives our +$\frac{q_{\mathsf{rcm}}(q_{\mathsf{rcm}}-1)}{r_{\mathbb{P}}}$ bound. +Classical parallel collision search [^Bernstein2009] (top of p. 8) +achieves the equality-event regime up to a constant factor; the same +adversaries achieve a constant fraction of the doubled bound for the +$\pm$-equivalence event. **Reduction.** We construct a simulated environment in which -$\mathsf{H^{rcm}}$ is replaced by a lazily-sampled random oracle. -The simulation maintains a table -$T : \mathsf{H^{rcm}}\text{-input} \to \mathbb{F}_{r_{\mathbb{P}}}$, -initially empty. On each query -$r = (\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})$ from -$\mathcal{A}$, the simulation returns $T[r]$ if defined, or otherwise -samples a fresh $h \leftarrow \mathbb{F}_{r_{\mathbb{P}}}$, records -$T[r] := h$, and returns $h$. After at most $q$ such queries, -$\mathcal{A}$ outputs $(\mathsf{w}_1, \mathsf{w}_2)$ satisfying -[(validity)](#thm-spendability-validity), -[(distinct underlying notes)](#thm-spendability-distinct), and -[(colliding nullifiers)](#thm-spendability-collide). - -The collision $\mathsf{nf}_1 = \mathsf{nf}_2$ implies that -$[H_1 + f_1 + g_1]\, \mathcal{R}$ and $[H_2 + f_2 + g_2]\, \mathcal{R}$ -share an $x$-coordinate, hence are either equal or each other's -negation: - -$$H_1 + f_1 + g_1 \equiv \pm(H_2 + f_2 + g_2) \pmod{r_{\mathbb{P}}},$$ - -where $H_i := \mathsf{H^{rcm}}(r_i)$. By -[(distinct underlying notes)](#thm-spendability-distinct) we have -$r_1 \neq r_2$, so $T[r_1]$ and $T[r_2]$ are sampled independently and -uniformly from $\mathbb{F}_{r_{\mathbb{P}}}$. - -TODO: Probability bound (step 5) and QROM follow-up (step 6) go here. +$\mathsf{H^{rcm}}$ is replaced by a lazily-sampled random oracle. The +simulation maintains a table +$T : \mathsf{NoteTuple} \to \mathbb{F}_{r_{\mathbb{P}}}$, initially empty. +On each query $\mathsf{notetuple}$ from $\mathcal{A}$, the simulation +returns $T[\mathsf{notetuple}]$ if defined, or otherwise samples a fresh +$h \leftarrow \mathbb{F}_{r_{\mathbb{P}}}$, records +$T[\mathsf{notetuple}] := h$, and returns $h$. After at most $q$ such +queries, $\mathcal{A}$ outputs $(w_1, w_2)$ satisfying +[**Validity of witnesses**](#thm-spendability-validity), +[**Distinct underlying notes**](#thm-spendability-distinct), and +[**Colliding nullifiers**](#thm-spendability-collide). + +$\mathsf{rseed}_i$, $\mathsf{leadByte}_i$, $\mathsf{noterepr}_i$, +$\text{ρ}_i$, $\text{ψ}_i$ are fields of $\mathsf{notetuple}_i$ +(directly or via $\mathsf{noterepr}_i$). The probability that +$(w_1, w_2)$ contains a key-binding break is at most +$\varepsilon_{\mathsf{kb}}(\mathcal{A}, q_{\mathsf{kb}})$; for the rest +of the analysis we condition on the complement. + +Under this conditioning, define +$$\mathsf{F}(\mathsf{notetuple}) := \mathsf{H^{rcm}}(\mathsf{notetuple}) + +\mathsf{f}(\mathsf{notetuple}) + \big((\mathsf{PRF^{nf}_{nk}}(\text{ρ}) + +\text{ψ}) \bmod q_{\mathbb{P}}\big) \cdot K_{\kern-.08em\mathcal{R}} +\pmod{r_{\mathbb{P}}},$$ + +where $\mathsf{rseed}, \text{ρ}, \text{ψ}$ are fields of +$\mathsf{notetuple}$ and $\mathsf{PRF^{nf}_{nk}}(\text{ρ})$ is +determined by $\mathsf{notetuple}$ via the +[$\mathsf{PRF^{nf}}$-pinning lemma](#lemma-prf-nf-pinning). + +The collision $\mathsf{nf}_1 = \mathsf{nf}_2$ holds iff +$$\mathsf{Extract}_{\mathbb{P}}\big([\mathsf{F}(\mathsf{notetuple}_1)]\, \mathcal{R}\big) += \mathsf{Extract}_{\mathbb{P}}\big([\mathsf{F}(\mathsf{notetuple}_2)]\, \mathcal{R}\big).$$ +$\mathsf{Extract}_{\mathbb{P}}$ is defined in § 5.4.9.7 'Coordinate Extractor +for Pallas' [^protocol-concreteextractorpallas] as the $x$-coordinate of its +argument for non-identity points, with the identity mapping to 0. Since Pallas is +a short-Weierstrass curve and no Pallas point has $x$-coordinate 0, two Pallas +points have equal $\mathsf{Extract}_{\mathbb{P}}$ values iff they are equal or +each other's negation: +$$\mathsf{F}(\mathsf{notetuple}_1) \equiv \pm \mathsf{F}(\mathsf{notetuple}_2) \pmod{r_{\mathbb{P}}}.$$ + +By [**Distinct underlying notes**](#thm-spendability-distinct), +$\mathsf{notetuple}_1 \neq \mathsf{notetuple}_2$, so $T[\mathsf{notetuple}_1]$ and +$T[\mathsf{notetuple}_2]$ are sampled independently and uniformly from +$\mathbb{F}_{r_{\mathbb{P}}}$. The remaining terms in $\mathsf{F}(\mathsf{notetuple})$ +($\mathsf{f}$ and the $\mathsf{PRF^{nf}}$ contribution scaled by +$K_{\kern-.08em\mathcal{R}}$) are deterministic functions of $\mathsf{notetuple}$ +that do not query $\mathsf{H^{rcm}}$. +Since the non-querying constraint makes the deterministic shifts +independent of the $\mathsf{H^{rcm}}$ oracle's responses, and +$T[\mathsf{notetuple}_1]$, $T[\mathsf{notetuple}_2]$ are independently +uniform on $\mathbb{F}_{r_{\mathbb{P}}}$, +$\mathsf{F}(\mathsf{notetuple}_1)$ and $\mathsf{F}(\mathsf{notetuple}_2)$ +are each independent and uniform on $\mathbb{F}_{r_{\mathbb{P}}}$. + +The win condition $F_1 \equiv \pm F_2$ is then a linear constraint on a +pair of independent uniform variables, satisfied with probability at most +$2/r_{\mathbb{P}}$ (each sign contributes $1/r_{\mathbb{P}}$). + +Taking a union bound over the at most ${q_{\mathsf{rcm}} \choose 2}$ pairs of +distinct $\mathsf{H^{rcm}}$ queries and the two sign cases gives +a winning probability, conditional on $(w_1, w_2)$ not constituting +a key-binding break, of at most +${q_{\mathsf{rcm}} \choose 2} \cdot \frac{2}{r_{\mathbb{P}}} = \frac{q_{\mathsf{rcm}}(q_{\mathsf{rcm}}-1)}{r_{\mathbb{P}}}$. +Decomposing on whether such a break occurs (probability at most +$\varepsilon_{\mathsf{kb}}(\mathcal{A}, q_{\mathsf{kb}})$) and applying +$\Pr[\text{win}] \leq \Pr[\text{win} \mid \neg\,\text{break}] + \Pr[\text{break}]$ +gives the theorem's overall claim of +$\frac{q_{\mathsf{rcm}}(q_{\mathsf{rcm}}-1)}{r_{\mathbb{P}}} + \varepsilon_{\mathsf{kb}}(\mathcal{A}, q_{\mathsf{kb}})$. +This completes the classical-ROM proof. + +The [key-binding theorem](#thm-key-binding-rom) bounds +$\varepsilon_{\mathsf{kb}}(\mathcal{A}, q_{\mathsf{kb}}) \leq \frac{q_{\mathsf{kb}}(q_{\mathsf{kb}}-1)}{r_{\mathbb{P}}}$. +Substituting, an adversary $\mathcal{A}$ that makes at most +$q_{\mathsf{rcm}}$ queries to $\mathsf{H^{rcm}}$ and at most +$q_{\mathsf{kb}}$ queries to the key-binding random oracles +wins the Spendability-collision game with probability at most +$\frac{q_{\mathsf{rcm}}(q_{\mathsf{rcm}}-1) \;+\; q_{\mathsf{kb}}(q_{\mathsf{kb}}-1)}{r_{\mathbb{P}}}$. + +TODO (QROM lift): The reduction is straight-line and does not adaptively +reprogram $\mathsf{H^{rcm}}$ on inputs the adversary may have queried in +superposition, so we expect a clean lift to the quantum random-oracle +model via standard QROM techniques [^Unruh2015] [^Unruh2016] [^CMSZ2021] +[^CDDGS2025], with at most a small loss factor. The technical conditions +have not yet been verified. ## Effects of discrete-log-breaking attacks before the switch to the Recovery Protocol @@ -1501,6 +1766,8 @@ manipulate the note selection algorithm to some extent. [^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) +[^protocol-concreteextractorpallas]: [Zcash Protocol Specification, Version 2025.6.2 [NU6.1]. Section 5.4.9.7: Coordinate Extractor for Pallas](protocol/protocol.pdf#concreteextractorpallas) + [^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) @@ -1539,6 +1806,8 @@ manipulate the note selection algorithm to some extent. [^Bernstein2009]: [Cost analysis of hash collisions: Will quantum computers make SHARCS obsolete? Daniel J. Bernstein.](https://cr.yp.to/hash/collisioncost-20090517.pdf) +[^Maurer2002]: [Indistinguishability of Random Systems. Ueli Maurer.](https://crypto.ethz.ch/publications/files/Maurer02.pdf) Advances in Cryptology — EUROCRYPT 2002, LNCS vol. 2332, pp. 110–132. + [^Unruh2015]: [Computationally binding quantum commitments. Dominique Unruh.](https://eprint.iacr.org/2015/361) [^Unruh2016]: [Collapse-binding quantum commitments without random oracles. Dominique Unruh.](https://eprint.iacr.org/2016/508) From af7a14083017ae9e844d481dfce22700bfafc479 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Tue, 5 May 2026 20:56:35 +0100 Subject: [PATCH 046/115] ZIP 2005: Restructure key-binding proof sketch and correct bound. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Restructure the key-binding theorem's proof sketch around a "final random oracle" formulation, absorbing the previous internal-IVK case into the others; tighten each case's WLOG step to derive distinctness from predicate determinism rather than from a vague witness-distinctness claim. Correct the bound to 3 q_kb(q_kb-1)/(2 r_P) to account for the upstream-RO collision residual in the both-internal sub-case, which the previous bound q_kb(q_kb-1)/r_P missed; propagate the corrected constant to the Spendability theorem's combined bound. Update G notation (function mathsf, output values italic) to match the F convention. Update the high-level summary's binding-argument paragraph to describe both branches symmetrically, matching the lifted formal statement. Define the break event at the projection level (distinct (qk, sk, ak, nk, rivk)), making explicit that the y-sign of ak^P is intentionally not part of the binding equivalence class — consistent with Orchard's existing design choice to use ak as a single F_{q_P} element. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --- zips/zip-2005.md | 204 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 148 insertions(+), 56 deletions(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index 20ba96150..331e5d93e 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -185,17 +185,32 @@ derivation of $\mathsf{rcm}$ is checked in the Recovery Protocol. Essentially the same technique also needs to be applied to the function $\mathsf{Commit^{ivk}}$ that is used to derive Orchard -incoming viewing keys. In order to support existing keys, we have -the Recovery Protocol check the derivations of $\mathsf{nk}$, -$\mathsf{ak}$, and $\mathsf{rivk}$ from the secret key $\mathsf{sk}$. - -Since this derivation of (at least) $\mathsf{ak}$ from $\mathsf{sk}$ -cannot be used in the case of FROST key generation, we also provide an -alternative way to derive $\mathsf{rivk}$ which is to be used in that -case. This alternative derivation, using a new "quantum spending key" -$\mathsf{qsk}$ and "quantum intermediate key" $\mathsf{qk}$, also -supports more efficient use of hardware wallets in the Recovery Protocol. -It is described in sections [Usage with FROST] and [Usage with Hardware Wallets]. +incoming viewing keys. The randomness $\mathsf{rivk}$ in +$\mathsf{Commit^{ivk}}$ is derived from one of two random oracles, +depending on which key material the user holds: + +* For existing Orchard keys, $\mathsf{rivk\_ext}$ is derived from + the secret key $\mathsf{sk}$ via $\mathsf{H^{rivk\_legacy}}(\mathsf{sk})$, + with $\mathsf{ak}$ and $\mathsf{nk}$ also derived from $\mathsf{sk}$. + The Recovery Protocol checks all three derivations. +* For keys generated via FROST distributed key generation, or for + hardware wallets where exporting $\mathsf{sk}$ is undesirable, an + alternative "quantum spending key" $\mathsf{qsk}$ and "quantum + intermediate key" $\mathsf{qk}$ are used, with + $\mathsf{rivk\_ext} = \mathsf{H^{rivk\_ext}_{qk}}(\mathsf{ak}, \mathsf{nk})$. + The Recovery Protocol checks this derivation together with a + $\mathsf{SoK^{qsk}}$ proof of knowledge of $\mathsf{qsk}$ such that + $\mathsf{H^{qk}}(\mathsf{qsk}) = \mathsf{qk}$. + +Both branches are covered uniformly by the +[Security argument for key binding](#securityargumentforkeybinding): +each binds the keys $(\mathsf{ak}, \mathsf{nk}, \mathsf{rivk})$ — and, +when in use, $\mathsf{qk}$ — to the incoming-viewing key $\mathsf{ivk}$ +post-quantumly, up to a small advantage against collision-finding in +the random oracles used for $\mathsf{rivk}$ derivation. The FROST and +hardware-wallet use cases are described in +[Usage with FROST](#usagewithfrost) and +[Usage with hardware wallets](#usagewithhardwarewallets). ## Flow diagram for the Orchard and OrchardZSA protocols @@ -1335,6 +1350,15 @@ $\begin{array}{l} where $\mathsf{ak} = \mathsf{Extract}_{\mathbb{P}}(\mathsf{ak}^{\mathbb{P}}).$ +The predicate intentionally does not constrain the $y$-sign of +$\mathsf{ak}^{\mathbb{P}}$. This is consistent with Orchard's design +choice to use $\mathsf{ak}$ as a single $\mathbb{F}_{q_{\mathbb{P}}}$ +element (the $x$-coordinate $\mathsf{Extract}_{\mathbb{P}}(\mathsf{ak}^{\mathbb{P}})$), +which avoids point-decompression in places that consume $\mathsf{ak}$, +in exchange for a factor-of-2 reduction in concrete binding security. +Accordingly, the break event below identifies witnesses up to the +$y$-sign of $\mathsf{ak}^{\mathbb{P}}$. + The flags $\mathsf{use\_qsk}$ and $\mathsf{is\_internal\_rivk}$ that appear in the protocol diagram do not appear in this witness — nor in the formal Recovery Statement above. Their roles are absorbed into the @@ -1356,8 +1380,11 @@ $w_2$ with internal $\mathsf{rivk}$), provided both produce the same $\mathsf{ivk}$. A flag-based formulation would forbid only same-branch breaks. -A **key-binding break** is a pair of distinct witnesses $(w_1, w_2)$ with shared -$\mathsf{ivk}$ satifying the key-binding condition. +A **key-binding break** is a pair of witnesses $(w_1, w_2)$ with +shared $\mathsf{ivk}$ satisfying the key-binding condition, whose +$(\mathsf{qk}, \mathsf{sk}, \mathsf{ak}, \mathsf{nk}, \mathsf{rivk})$ +projections differ — i.e., $w_1$ and $w_2$ differ in some component +other than the $y$-sign of $\mathsf{ak}^{\mathbb{P}}$. The random oracles used in the key-binding condition are $\mathsf{H^{rivk\_ext}}$, $\mathsf{H^{rivk\_legacy}}$, $\mathsf{H^{rivk\_int}}$, $\mathsf{H^{ask}}$, and @@ -1371,54 +1398,119 @@ key-binding break. **Theorem (key-binding, classical ROM).** <a id="thm-key-binding-rom"></a> Let $\mathcal{A}$ be a classical adversary making at most $q_{\mathsf{kb}}$ total queries to the random oracles used in the key-binding condition. Then -$\varepsilon_{\mathsf{kb}}(\mathcal{A}, q_{\mathsf{kb}}) \leq \frac{q_{\mathsf{kb}}(q_{\mathsf{kb}}-1)}{r_{\mathbb{P}}}$. +$\varepsilon_{\mathsf{kb}}(\mathcal{A}, q_{\mathsf{kb}}) \leq \frac{3\, q_{\mathsf{kb}}(q_{\mathsf{kb}}-1)}{2\, r_{\mathbb{P}}}$. **Proof sketch.** + +*Algebraic setup.* $\mathsf{Commit^{ivk}_{rivk}}(\mathsf{ak}, \mathsf{nk})$ is a Sinsemilla short commitment, of the form $\mathsf{ShortHash}\big([h(\mathsf{ak}, \mathsf{nk}) + \mathsf{rivk}] \cdot \mathcal{S}\big)$ for a Pedersen-like deterministic hash $h$ and a Sinsemilla base -$\mathcal{S}$. As in the Spendability proof, $h$ does not query -$\mathsf{H^{rivk\_ext}}$, $\mathsf{H^{rivk\_legacy}}$, or -$\mathsf{H^{rivk\_int}}$: it is determined by fixed Sinsemilla bases -and depends only on $(\mathsf{ak}, \mathsf{nk})$. By the same $y^2 = f(x)$ -argument used in Spendability (using § 5.4.9.7 for the -$\mathsf{Extract}_{\mathbb{P}}$-style $x$-coordinate convention), a -key-binding break implies +$\mathcal{S}$ (TODO: verify the exact form of $h$ and $\mathcal{S}$ +from § 5.4.1.10 'Sinsemilla Commit Function'). Domain separation in +the protocol's BLAKE2b instantiations ensures $h$ does not query +$\mathsf{H^{rivk\_ext}}$, $\mathsf{H^{rivk\_legacy}}$, +$\mathsf{H^{rivk\_int}}$, $\mathsf{H^{ask}}$, or $\mathsf{H^{nk}}$: +$h$ depends only on fixed Sinsemilla bases and on $(\mathsf{ak}, \mathsf{nk})$. + +By the same $y^2 = f(x)$ argument used in the Spendability proof +(using § 5.4.9.7 for the $\mathsf{Extract}_{\mathbb{P}}$-style +$x$-coordinate convention), a key-binding break implies $$h(\mathsf{ak}, \mathsf{nk}) + \mathsf{rivk} \equiv \pm\big(h(\mathsf{ak}', \mathsf{nk}') + \mathsf{rivk}'\big) \pmod{r_{\mathbb{P}}}.$$ - -Under the random-oracle modelling, $\mathsf{rivk}$ in each case is a -fresh, uniform $\mathbb{F}_{r_{\mathbb{P}}}$-valued random-oracle output -keyed by deterministic inputs: - -* When $\mathsf{qk} \neq \bot$: $\mathsf{rivk\_ext}$ comes from - $\mathsf{H^{rivk\_ext}_{qk}}(\mathsf{ak}, \mathsf{nk})$. -* When $\mathsf{sk} \neq \bot$: $\mathsf{rivk\_ext}$ comes from - $\mathsf{H^{rivk\_legacy}}(\mathsf{sk})$. -* $\mathsf{rivk}$ is either $\mathsf{rivk\_ext}$ (external IVK), or -* $\mathsf{H^{rivk\_int}_{rivk\_ext}}(\mathsf{ak}, \mathsf{nk})$ (internal IVK). - -In every case, the value -$\mathsf{G}(\mathsf{ak}, \mathsf{nk}, \mathsf{rivk}) := h(\mathsf{ak}, \mathsf{nk}) + \mathsf{rivk} \pmod{r_{\mathbb{P}}}$ -is a translate of an independent uniform random-oracle output by a -deterministic shift. For distinct triples, $\mathsf{G}$ outputs are -each independent and uniform on $\mathbb{F}_{r_{\mathbb{P}}}$. - -The break condition $G_1 \equiv \pm G_2 \pmod{r_{\mathbb{P}}}$ -is then a linear constraint on a pair of independent uniform variables, -satisfied with probability at most $2/r_{\mathbb{P}}$. Taking a union -bound over the at most ${q_{\mathsf{kb}} \choose 2}$ pairs of distinct -random-oracle queries and the two sign cases gives -$\varepsilon_{\mathsf{kb}}(\mathcal{A}, q_{\mathsf{kb}}) \leq \frac{q_{\mathsf{kb}}(q_{\mathsf{kb}}-1)}{r_{\mathbb{P}}}$. - -(TODO: verify the exact form of $h$ and $\mathcal{S}$ from § 5.4.1.10 -'Sinsemilla Commit Function'; verify that the $\mathsf{qk} \neq \bot$ -branch pins $\mathsf{qk}$, and that the $\mathsf{sk} \neq \bot$ branch -pins $(\mathsf{ak}, \mathsf{nk})$, via the random-oracle inputs, so -that distinct witnesses necessarily correspond to distinct -random-oracle queries; verify the internal-IVK case's keying does not -introduce a dependency that breaks the "independent uniform" claim -above.) +Define $\mathsf{G}(w) := h(\mathsf{ak}, \mathsf{nk}) + \mathsf{rivk} \pmod{r_{\mathbb{P}}}$ +for a witness $w$, and let $G_i := \mathsf{G}(w_i)$ for $i \in \{1, 2\}$. +The break condition is +$G_1 \equiv \pm G_2 \pmod{r_{\mathbb{P}}}$. + +*Final-random-oracle structure.* +For each witness $w_i$ satisfying the key-binding condition, +$\mathsf{rivk}_i$ is the output of a *final random oracle* +$O_i \in \{\mathsf{H^{rivk\_ext}}, \mathsf{H^{rivk\_legacy}}, \mathsf{H^{rivk\_int}}\}$ +at a *final input* $x_i$, determined by the witness's branch and +IVK choice: + +* qk-branch, external IVK: $O_i = \mathsf{H^{rivk\_ext}}$, + $x_i = (\mathsf{qk}_i, \mathsf{ak}_i, \mathsf{nk}_i)$. +* sk-branch, external IVK: $O_i = \mathsf{H^{rivk\_legacy}}$, + $x_i = \mathsf{sk}_i$. +* qk-branch, internal IVK: $O_i = \mathsf{H^{rivk\_int}}$, + $x_i = (\mathsf{rivk\_ext}_i, \mathsf{ak}_i, \mathsf{nk}_i)$ where + $\mathsf{rivk\_ext}_i = \mathsf{H^{rivk\_ext}_{qk_i}}(\mathsf{ak}_i, \mathsf{nk}_i)$. +* sk-branch, internal IVK: $O_i = \mathsf{H^{rivk\_int}}$, + $x_i = (\mathsf{rivk\_ext}_i, \mathsf{ak}_i, \mathsf{nk}_i)$ where + $\mathsf{rivk\_ext}_i = \mathsf{H^{rivk\_legacy}}(\mathsf{sk}_i)$. + +In each case +$G_i = h(\mathsf{ak}_i, \mathsf{nk}_i) + O_i(x_i) \pmod{r_{\mathbb{P}}}$, +with the deterministic shift $h$ independent of $O_i$'s responses +(by non-querying). + +*Independence claim per pair.* +For distinct witnesses $w_1, w_2$ both satisfying the key-binding +condition, $G_1$ and $G_2$ are independent uniform on +$\mathbb{F}_{r_{\mathbb{P}}}$, except for a residual event of +probability at most $1/r_{\mathbb{P}}$ per pair (accounting for +upstream-RO collisions in the both-internal sub-case). By case on +$(O_1, O_2)$: + +**$O_1 \neq O_2$.** The two random oracles are domain-separated +(independent BLAKE2b instantiations), so $O_1$'s outputs are +independent of $O_2$'s outputs. Each $G_i$ is uniform on +$\mathbb{F}_{r_{\mathbb{P}}}$ marginally; the pair is independent. + +**$O_1 = O_2 \in \{\mathsf{H^{rivk\_ext}}, \mathsf{H^{rivk\_legacy}}\}$.** +Both witnesses are in the same branch and external IVK. If +$x_1 = x_2$, the predicate's functional determinations +($\mathsf{rivk\_ext}_i$ from $x_i$; $\mathsf{rivk}_i = \mathsf{rivk\_ext}_i$; +$\mathsf{ivk}_i = \mathsf{Commit^{ivk}}(\mathsf{ak}_i, \mathsf{nk}_i, \mathsf{rivk}_i)$; +in the sk-branch additionally $\mathsf{ak}_i, \mathsf{nk}_i$ from +$\mathsf{sk}_i$ via $\mathsf{H^{ask}}, \mathsf{H^{nk}}$) force the +witnesses to coincide on all fields constrained by the key-binding +condition, contradicting distinctness. Hence WLOG $x_1 \neq x_2$, so +the two RO outputs at $x_1, x_2$ are independent uniform. + +**$O_1 = O_2 = \mathsf{H^{rivk\_int}}$.** Both witnesses are +internal IVK. If $x_1 = x_2$ as $\mathsf{H^{rivk\_int}}$ inputs, then +$\mathsf{rivk}_1 = \mathsf{rivk}_2$ and $\mathsf{ivk}_1 = \mathsf{ivk}_2$. +Sub-cases on the upstream branches: + +* same upstream branch (qk×qk or sk×sk): + $\mathsf{rivk\_ext}_1 = \mathsf{rivk\_ext}_2$ either forces upstream + input coincidence (and hence witness coincidence on all constrained + fields, contradicting distinctness) or requires an upstream-RO + collision — probability at most $1/r_{\mathbb{P}}$ per pair of + upstream queries. +* cross upstream branch (qk×sk): + $\mathsf{rivk\_ext}_1 = \mathsf{rivk\_ext}_2$ requires a cross-RO + collision between $\mathsf{H^{rivk\_ext}}$ and + $\mathsf{H^{rivk\_legacy}}$, which by domain separation is + probability at most $1/r_{\mathbb{P}}$ per pair of upstream queries. + +In every sub-case the residual $x_1 = x_2$ event has probability at +most $1/r_{\mathbb{P}}$ per pair. Conditional on $x_1 \neq x_2$, +$\mathsf{H^{rivk\_int}}$'s outputs at $x_1, x_2$ are independent +uniform. + +*Bounding the break probability.* +For any pair of distinct witnesses, the break condition +$G_1 \equiv \pm G_2 \pmod{r_{\mathbb{P}}}$ holds with probability +at most $2/r_{\mathbb{P}}$ when $G_1, G_2$ are independent uniform +(one per sign), plus at most $1/r_{\mathbb{P}}$ residual for +upstream collisions in the both-internal sub-case — total at most +$3/r_{\mathbb{P}}$ per pair. + +Treating the five rivk-derivation random oracles +($\mathsf{H^{rivk\_ext}}$, $\mathsf{H^{rivk\_legacy}}$, +$\mathsf{H^{rivk\_int}}$, $\mathsf{H^{ask}}$, $\mathsf{H^{nk}}$) as a +single combined uniform random oracle on the joint query domain (each +RO contributes its outputs independently of the others), and +union-bounding over the at most $\binom{q_{\mathsf{kb}}}{2}$ pairs +of distinct witnesses, +$$\varepsilon_{\mathsf{kb}}(\mathcal{A}, q_{\mathsf{kb}}) \leq \frac{3 q_{\mathsf{kb}}(q_{\mathsf{kb}}-1)}{2 r_{\mathbb{P}}}.$$ + +(TODO: verify the exact form of $h$ and $\mathcal{S}$ from +§ 5.4.1.10 'Sinsemilla Commit Function'.) ## Security argument for Spendability @@ -1660,12 +1752,12 @@ $\frac{q_{\mathsf{rcm}}(q_{\mathsf{rcm}}-1)}{r_{\mathbb{P}}} + \varepsilon_{\mat This completes the classical-ROM proof. The [key-binding theorem](#thm-key-binding-rom) bounds -$\varepsilon_{\mathsf{kb}}(\mathcal{A}, q_{\mathsf{kb}}) \leq \frac{q_{\mathsf{kb}}(q_{\mathsf{kb}}-1)}{r_{\mathbb{P}}}$. +$\varepsilon_{\mathsf{kb}}(\mathcal{A}, q_{\mathsf{kb}}) \leq \frac{3\, q_{\mathsf{kb}}(q_{\mathsf{kb}}-1)}{2\, r_{\mathbb{P}}}$. Substituting, an adversary $\mathcal{A}$ that makes at most $q_{\mathsf{rcm}}$ queries to $\mathsf{H^{rcm}}$ and at most $q_{\mathsf{kb}}$ queries to the key-binding random oracles wins the Spendability-collision game with probability at most -$\frac{q_{\mathsf{rcm}}(q_{\mathsf{rcm}}-1) \;+\; q_{\mathsf{kb}}(q_{\mathsf{kb}}-1)}{r_{\mathbb{P}}}$. +$\frac{q_{\mathsf{rcm}}(q_{\mathsf{rcm}}-1)}{r_{\mathbb{P}}} \;+\; \frac{3\, q_{\mathsf{kb}}(q_{\mathsf{kb}}-1)}{2\, r_{\mathbb{P}}}$. TODO (QROM lift): The reduction is straight-line and does not adaptively reprogram $\mathsf{H^{rcm}}$ on inputs the adversary may have queried in From ce4b2dafcab42c4feb28f2883182638b147351bb Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Tue, 5 May 2026 21:10:25 +0100 Subject: [PATCH 047/115] ZIP 2005: Switch H^{qk} from BLAKE2s-256 to BLAKE3.derive_key. Use BLAKE3.derive_key with context string "Zcash ZIP 2005 qk-derivation v1" and 32-byte output. Requires one BLAKE3 compression in the SoK^{qsk} circuit, with the derive_key context key precomputed as a constant. Add a BLAKE3 reference. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --- zips/zip-2005.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index 331e5d93e..fa0d49dd3 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -631,7 +631,7 @@ in the algorithm with: > * $\mathsf{H^{nk}}(\mathsf{sk}) = \mathsf{ToBase^{Orchard}}\big(\mathsf{PRF^{expand}_{sk}}([\mathtt{0x07}])\kern-0.1em\big)$ > * $\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^{qk}}(\mathsf{qsk}) = \mathsf{BLAKE3.derive\_key}(\texttt{“Zcash ZIP 2005 qk-derivation v1”}, \mathsf{qsk}, 32)$ [^BLAKE3]. > * $\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}}}$, @@ -1062,7 +1062,7 @@ even if they are incomplete in the current Orchard[ZSA] statement/circuit. * 1 to compute $\mathsf{H^{\text{ψ}}}$ * 2 to compute $\mathsf{H^{rcm}}$ * we could potentially save these two by using Poseidon to implement $\mathsf{H^{rcm}}$, but it seems not worth it. -* 1 use of $\mathsf{H^{qk}}$ +* 1 BLAKE3 compression for $\mathsf{H^{qk}}$ (with the $\mathsf{derive\_key}$ context key precomputed as a constant) * 1 use of $\mathsf{Commit^{ivk}}$ ($\mathsf{SinsemillaShortCommit}$) * 1 use of $\mathsf{NoteCommit}$ ($\mathsf{SinsemillaCommit}$) * 1 full-width fixed-base Pallas scalar multiplication, $[\mathsf{ask}]\, \mathcal{G}^{\mathsf{Orchard}}$ @@ -1898,6 +1898,8 @@ manipulate the note selection algorithm to some extent. [^Bernstein2009]: [Cost analysis of hash collisions: Will quantum computers make SHARCS obsolete? Daniel J. Bernstein.](https://cr.yp.to/hash/collisioncost-20090517.pdf) +[^BLAKE3]: [BLAKE3: One Function, Fast Everywhere. Jack O'Connor, Jean-Philippe Aumasson, Samuel Neves, and Zooko Wilcox-O'Hearn, 2020.](https://github.com/BLAKE3-team/BLAKE3-specs/blob/master/blake3.pdf) See § 2.1.2 for the `derive_key` mode. + [^Maurer2002]: [Indistinguishability of Random Systems. Ueli Maurer.](https://crypto.ethz.ch/publications/files/Maurer02.pdf) Advances in Cryptology — EUROCRYPT 2002, LNCS vol. 2332, pp. 110–132. [^Unruh2015]: [Computationally binding quantum commitments. Dominique Unruh.](https://eprint.iacr.org/2015/361) From a9cbab6caec113ef9584402ef9b0b652913d85a2 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Wed, 6 May 2026 03:06:28 +0100 Subject: [PATCH 048/115] ZIP 2005: Harmonize Spendability-proof style with key-binding proof. Apply the conciseness improvements that landed in the key-binding proof: italic subsection labels (Algebraic setup / Independence claim per pair / Bounding the win probability), F_i := F(notetuple_i) shorthand for output values, RO model used directly without an explicit lazy-sampling table, single union-bound paragraph instead of three. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --- zips/zip-2005.md | 93 +++++++++++++++++++----------------------------- 1 file changed, 36 insertions(+), 57 deletions(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index fa0d49dd3..ae302ba6d 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -1679,76 +1679,55 @@ achieves the equality-event regime up to a constant factor; the same adversaries achieve a constant fraction of the doubled bound for the $\pm$-equivalence event. -**Reduction.** We construct a simulated environment in which -$\mathsf{H^{rcm}}$ is replaced by a lazily-sampled random oracle. The -simulation maintains a table -$T : \mathsf{NoteTuple} \to \mathbb{F}_{r_{\mathbb{P}}}$, initially empty. -On each query $\mathsf{notetuple}$ from $\mathcal{A}$, the simulation -returns $T[\mathsf{notetuple}]$ if defined, or otherwise samples a fresh -$h \leftarrow \mathbb{F}_{r_{\mathbb{P}}}$, records -$T[\mathsf{notetuple}] := h$, and returns $h$. After at most $q$ such -queries, $\mathcal{A}$ outputs $(w_1, w_2)$ satisfying +**Proof sketch.** +$\mathcal{A}$ makes at most $q_{\mathsf{rcm}}$ queries to +$\mathsf{H^{rcm}}$ before outputting $(w_1, w_2)$ satisfying [**Validity of witnesses**](#thm-spendability-validity), [**Distinct underlying notes**](#thm-spendability-distinct), and -[**Colliding nullifiers**](#thm-spendability-collide). - -$\mathsf{rseed}_i$, $\mathsf{leadByte}_i$, $\mathsf{noterepr}_i$, -$\text{ρ}_i$, $\text{ψ}_i$ are fields of $\mathsf{notetuple}_i$ -(directly or via $\mathsf{noterepr}_i$). The probability that -$(w_1, w_2)$ contains a key-binding break is at most -$\varepsilon_{\mathsf{kb}}(\mathcal{A}, q_{\mathsf{kb}})$; for the rest -of the analysis we condition on the complement. +[**Colliding nullifiers**](#thm-spendability-collide). The probability +that $(w_1, w_2)$ contains a key-binding break is at most +$\varepsilon_{\mathsf{kb}}(\mathcal{A}, q_{\mathsf{kb}})$; condition on +the complement. +*Algebraic setup.* Under this conditioning, define $$\mathsf{F}(\mathsf{notetuple}) := \mathsf{H^{rcm}}(\mathsf{notetuple}) + \mathsf{f}(\mathsf{notetuple}) + \big((\mathsf{PRF^{nf}_{nk}}(\text{ρ}) + \text{ψ}) \bmod q_{\mathbb{P}}\big) \cdot K_{\kern-.08em\mathcal{R}} \pmod{r_{\mathbb{P}}},$$ - where $\mathsf{rseed}, \text{ρ}, \text{ψ}$ are fields of $\mathsf{notetuple}$ and $\mathsf{PRF^{nf}_{nk}}(\text{ρ})$ is determined by $\mathsf{notetuple}$ via the -[$\mathsf{PRF^{nf}}$-pinning lemma](#lemma-prf-nf-pinning). - -The collision $\mathsf{nf}_1 = \mathsf{nf}_2$ holds iff -$$\mathsf{Extract}_{\mathbb{P}}\big([\mathsf{F}(\mathsf{notetuple}_1)]\, \mathcal{R}\big) -= \mathsf{Extract}_{\mathbb{P}}\big([\mathsf{F}(\mathsf{notetuple}_2)]\, \mathcal{R}\big).$$ -$\mathsf{Extract}_{\mathbb{P}}$ is defined in § 5.4.9.7 'Coordinate Extractor -for Pallas' [^protocol-concreteextractorpallas] as the $x$-coordinate of its -argument for non-identity points, with the identity mapping to 0. Since Pallas is -a short-Weierstrass curve and no Pallas point has $x$-coordinate 0, two Pallas -points have equal $\mathsf{Extract}_{\mathbb{P}}$ values iff they are equal or -each other's negation: -$$\mathsf{F}(\mathsf{notetuple}_1) \equiv \pm \mathsf{F}(\mathsf{notetuple}_2) \pmod{r_{\mathbb{P}}}.$$ +[$\mathsf{PRF^{nf}}$-pinning lemma](#lemma-prf-nf-pinning), and let +$F_i := \mathsf{F}(\mathsf{notetuple}_i)$ for $i \in \{1, 2\}$. + +$\mathsf{Extract}_{\mathbb{P}}$ (§ 5.4.9.7 'Coordinate Extractor for +Pallas' [^protocol-concreteextractorpallas]) is the $x$-coordinate of +its argument for non-identity points, with the identity mapping to $0$. +Since Pallas has the form $y^2 = f(x)$ and no Pallas point has +$x$-coordinate $0$, the collision $\mathsf{nf}_1 = \mathsf{nf}_2$ +holds iff $F_1 \equiv \pm F_2 \pmod{r_{\mathbb{P}}}$. +*Independence claim per pair.* By [**Distinct underlying notes**](#thm-spendability-distinct), -$\mathsf{notetuple}_1 \neq \mathsf{notetuple}_2$, so $T[\mathsf{notetuple}_1]$ and -$T[\mathsf{notetuple}_2]$ are sampled independently and uniformly from -$\mathbb{F}_{r_{\mathbb{P}}}$. The remaining terms in $\mathsf{F}(\mathsf{notetuple})$ -($\mathsf{f}$ and the $\mathsf{PRF^{nf}}$ contribution scaled by -$K_{\kern-.08em\mathcal{R}}$) are deterministic functions of $\mathsf{notetuple}$ -that do not query $\mathsf{H^{rcm}}$. -Since the non-querying constraint makes the deterministic shifts -independent of the $\mathsf{H^{rcm}}$ oracle's responses, and -$T[\mathsf{notetuple}_1]$, $T[\mathsf{notetuple}_2]$ are independently -uniform on $\mathbb{F}_{r_{\mathbb{P}}}$, -$\mathsf{F}(\mathsf{notetuple}_1)$ and $\mathsf{F}(\mathsf{notetuple}_2)$ -are each independent and uniform on $\mathbb{F}_{r_{\mathbb{P}}}$. - -The win condition $F_1 \equiv \pm F_2$ is then a linear constraint on a -pair of independent uniform variables, satisfied with probability at most -$2/r_{\mathbb{P}}$ (each sign contributes $1/r_{\mathbb{P}}$). - -Taking a union bound over the at most ${q_{\mathsf{rcm}} \choose 2}$ pairs of -distinct $\mathsf{H^{rcm}}$ queries and the two sign cases gives -a winning probability, conditional on $(w_1, w_2)$ not constituting -a key-binding break, of at most -${q_{\mathsf{rcm}} \choose 2} \cdot \frac{2}{r_{\mathbb{P}}} = \frac{q_{\mathsf{rcm}}(q_{\mathsf{rcm}}-1)}{r_{\mathbb{P}}}$. -Decomposing on whether such a break occurs (probability at most -$\varepsilon_{\mathsf{kb}}(\mathcal{A}, q_{\mathsf{kb}})$) and applying -$\Pr[\text{win}] \leq \Pr[\text{win} \mid \neg\,\text{break}] + \Pr[\text{break}]$ -gives the theorem's overall claim of -$\frac{q_{\mathsf{rcm}}(q_{\mathsf{rcm}}-1)}{r_{\mathbb{P}}} + \varepsilon_{\mathsf{kb}}(\mathcal{A}, q_{\mathsf{kb}})$. +$\mathsf{notetuple}_1 \neq \mathsf{notetuple}_2$, so the +$\mathsf{H^{rcm}}$ outputs at $\mathsf{notetuple}_1, \mathsf{notetuple}_2$ +are independent uniform on $\mathbb{F}_{r_{\mathbb{P}}}$. The +deterministic shifts ($\mathsf{f}$ and the $\mathsf{PRF^{nf}}$ +contribution scaled by $K_{\kern-.08em\mathcal{R}}$) do not query +$\mathsf{H^{rcm}}$, so they are independent of its responses. Hence +$F_1$ and $F_2$ are independent uniform on $\mathbb{F}_{r_{\mathbb{P}}}$. + +*Bounding the win probability.* +The win condition $F_1 \equiv \pm F_2$ is a linear constraint on a +pair of independent uniform variables, satisfied with probability at +most $2/r_{\mathbb{P}}$ (one per sign). Union-bounding over the at +most $\binom{q_{\mathsf{rcm}}}{2}$ pairs of distinct +$\mathsf{H^{rcm}}$ queries: +$$\Pr[\text{win} \mid \neg\,\text{break}] \leq \frac{q_{\mathsf{rcm}}(q_{\mathsf{rcm}}-1)}{r_{\mathbb{P}}}.$$ +Decomposing on whether a key-binding break occurs and applying +$\Pr[\text{win}] \leq \Pr[\text{win} \mid \neg\,\text{break}] + \Pr[\text{break}]$: +$$\Pr[\text{win}] \leq \frac{q_{\mathsf{rcm}}(q_{\mathsf{rcm}}-1)}{r_{\mathbb{P}}} + \varepsilon_{\mathsf{kb}}(\mathcal{A}, q_{\mathsf{kb}}).$$ This completes the classical-ROM proof. The [key-binding theorem](#thm-key-binding-rom) bounds From e9486acd13bc47285318668bee6145b75a756a77 Mon Sep 17 00:00:00 2001 From: Evan Forbes <42654277+evan-forbes@users.noreply.github.com> Date: Tue, 5 May 2026 23:30:14 -0500 Subject: [PATCH 049/115] Apply suggestions from code review Co-authored-by: Kris Nuttycombe <kris@nutty.land> Co-authored-by: Daira-Emma Hopwood <daira@jacaranda.org> --- zips/draft-valargroup-blocktime-reduction.md | 53 +++++++++----------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/zips/draft-valargroup-blocktime-reduction.md b/zips/draft-valargroup-blocktime-reduction.md index d6c44cb3a..2edeee864 100644 --- a/zips/draft-valargroup-blocktime-reduction.md +++ b/zips/draft-valargroup-blocktime-reduction.md @@ -41,7 +41,7 @@ the Sapling and Orchard shielded protocols. This solves three problems. - Significantly improves the UX for actors who need 1 or 2 conf's. (Near Intents, small payments) The user-latency goes down 3x. - Increases consensus bandwidth, which amplifies the scaling impact of a future shielded pool which does not require shielded sync. -- Introduces action limits, which short term more than doubles the Orchard TPS (2.9 → 6.1 TPS), while lowering the impact a DoS attacker can impose on wallets for shielded sync by 42% (270.5 → 156.83 MB/day). +- Introduces action limits, which short term more than doubles the Orchard TPS (2.9 → 6.1 TPS), while lowering the impact a DoS attacker can impose on wallets; for example, maximum shielded sync bandwidth for light clients is reduced by 42% (270.5 → 156.83 MB/day). The action limits significantly decrease the number of Sprout and Sapling pool outputs available per block, to lower the maximum shielded sync burden under @@ -88,22 +88,22 @@ stale rates have not significantly increased. See [^slowfastblocks] for analysis in various attack models. As this proposal meets the constraint of keeping stale rates low, this should under the "X% of hashpower is byzantine" threat model improve user confirmation times by a factor slightly under 3x. -Under the posts "Economic" threat model, where the user requires the block +Under the post's "Economic" threat model, where the user requires the block rewards built on-top of their payment to exceed the value of the payment, this -significantly improves the variance in confirmation latency. (But makes the -mean latency a bit higher due to stale rate) As noted there, this attack model -is not applied at sizable transactions. Its only potentially applied for small -value ones, where actually the granularity of block times likely lowers time -until sufficient finality. We do not argue for reducing wall-clock block -confirmation counts aside from exisitng 1-2 confirmation users in this ZIP. -However, we do expect many classes of users to be able to wall-clock lower -theirs under consistent threat modelling of what they choose today. - -However, Zcash uniquely has a second cost on scaling, the shielded sync. Every +significantly improves the variance in confirmation latency (but makes the +mean latency a bit higher due to stale rate). As noted there, this attack model +is not applied at sizable transactions. It is only potentially applied for small-valued +transactions, where the granularity of block times likely lowers time +until sufficient finality. We do not argue for reducing block confirmation counts in this ZIP. +However, we do expect many classes of users to be able to reduce their expected +time until funds are considered to have been received under threat modelling +consistent with block confirmation counts they choose today. + +Zcash has a second cost imposed by scaling, the shielded sync. Every shielded transaction induces a bandwidth overhead for every wallet and an extra trial decryption, so we must carefully understand the impact a DOS -attacker can cause. Today the worst case DOS attack can induce 270.5 -MB of wallet sync download to clients per day, and 4.8M trial decrypts per +attacker can cause. Today the worst-case DoS attack can induce 270.5 +MB of wallet sync download to clients per day, and 4.8M trial decryptions per day. We propose introducing action limits in Orchard (306 actions per block), and (input+output) limits for Sapling (300 per block). With these limits, the worst case becomes 156.83 MB bandwidth and 2.1M trial decrypts per day. This @@ -127,7 +127,7 @@ current distribution of shielded funds across pools. As of March 2026: The vast majority of shielded activity is already in Orchard, and this trend is expected to continue. The Sapling and Sprout limits are set generously relative to their current usage while substantially reducing -their potential for DOS abuse. +their potential for DoS. ## Stale block rate @@ -151,11 +151,11 @@ A devnet experiment with 99 geographically-distributed Zebra nodes producing 2MB ## Block processing time -A prerequisite for shorter block times is that block validation and -propagation remain small relative to the target spacing. The per-pool +A prerequisite for reducing the target block spacing is that block validation and +propagation must remain small relative to the target spacing. The per-pool action limits introduced by this proposal ensure that worst-case block processing time is *lower* per block than today's. The increase in consensus -bandwidth, and Orchard TPS does mean that full node sync will increase in net +bandwidth and Orchard TPS does mean that full node sync will increase in net time. We accept this trade-off (TODO: be concrete with timing increases, and remark that more CPU cores fixes this) @@ -165,15 +165,15 @@ packed Orchard block requires verifying all action proofs and spend authorization signatures for those ~617 actions. **Proposed worst case:** With the action limits, a block contains at -most 306 Orchard actions or 300 Sapling IOs. This is roughly half the +most 306 Orchard actions and a maximum of 300 Sapling input or output items. This is roughly half the current Orchard worst case and a fraction of the Sapling worst case. The per-block verification work is therefore substantially reduced. **Batch verification.** Orchard transaction verification benefits from batch validation, where proof and signature verification is amortized -across multiple transactions. In current node implementations, Orchard +across multiple transactions. In Zebra, Orchard transactions are batch-verified in groups of up to 64 transactions -(each worst case being 2 actions). Zebra has performed batch +(each worst case being a single action). Zebra has performed batch verification during live network syncing since version 3.0.0. With the action limits, a worst-case block's Orchard bundle can be fully batch-verified in a small number of batches. @@ -262,7 +262,7 @@ $$ \mathsf{BlockSubsidy}(\mathsf{height}) := \begin{cases} \ldots &\text{(prior cases unchanged)} \\\\[1ex] - \left\lfloor \dfrac{\mathsf{MaxBlockSubsidy}}{\mathsf{BlossomPoWTargetSpacingRatio} \cdot \mathsf{NU7PoWTargetSpacingRatio} \cdot 2^{\mathsf{Halving}(\mathsf{height})}} \right\rfloor, + \mathsf{floor}\left(\dfrac{\mathsf{MaxBlockSubsidy}}{\mathsf{BlossomPoWTargetSpacingRatio} \cdot \mathsf{NU7PoWTargetSpacingRatio} \cdot 2^{\mathsf{Halving}(\mathsf{height})}}\right), &\text{if } \mathsf{IsNU7Activated}(\mathsf{height}) \end{cases} $$ @@ -273,11 +273,11 @@ clock time remains the same. Note: the current post-Blossom block subsidy of 1.5625 ZEC does not divide evenly by 3. The post-NU7 subsidy is -$\lfloor 156250000 / 6 \rfloor = 26041666$ zatoshi (0.26041666 ZEC), +$\mathsf{floor}(156250000 / 6) = 26041666$ zatoshi (0.26041666 ZEC), losing approximately 0.33 zatoshi per block to rounding. Over a full halving interval of 5,040,000 blocks this amounts to less than 0.017 ZEC of total underpaid issuance, a negligible amount. Should any of the NSM ZIP's -be accepted, the difference can be credited to the NSM, else it will just be +be accepted, the difference can be credited to the NSM, otherwise it will just be under-minted from supply. ### Shielded pool action limits @@ -322,15 +322,12 @@ JoinSplit produces 2 shielded outputs. This global budget ensures that the worst-case shielded sync bandwidth per block is bounded regardless of which combination of pools is used. -If a block's Orchard actions reach the limit of 306, no Sapling or -Sprout shielded outputs may be included. If both pools are used, their -combined cost must stay within the budget. These limits do not apply to the transparent components of transactions. The overall 2 MB block size limit continues to apply as before. -#### Compact sync bandwidth per action +#### Rationale: Compact sync bandwidth per action The limits above are chosen to bound the worst-case bandwidth that lightweight wallets must download for shielded sync. The compact From 32373f6b687912c8df7c9e49768b88f61d3795c2 Mon Sep 17 00:00:00 2001 From: evan-forbes <evan.samuel.forbes@gmail.com> Date: Wed, 6 May 2026 00:32:51 -0500 Subject: [PATCH 050/115] chore: address reviewer feedback on blossom activated height --- zips/draft-valargroup-blocktime-reduction.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/zips/draft-valargroup-blocktime-reduction.md b/zips/draft-valargroup-blocktime-reduction.md index d6c44cb3a..05e780972 100644 --- a/zips/draft-valargroup-blocktime-reduction.md +++ b/zips/draft-valargroup-blocktime-reduction.md @@ -256,12 +256,15 @@ $$ $$ Redefine $\mathsf{BlockSubsidy}$ to add a case for post-activation -heights: +heights. The prior Blossom case in § 7.8 'Calculation of Block Subsidy +and Founders' Reward', currently written as "otherwise", must be +amended to "if $\mathsf{IsBlossomActivated}(\mathsf{height})$ and not +$\mathsf{IsNU7Activated}(\mathsf{height})$": $$ \mathsf{BlockSubsidy}(\mathsf{height}) := \begin{cases} - \ldots &\text{(prior cases unchanged)} \\\\[1ex] + \ldots &\text{(prior cases, with the Blossom case amended as above)} \\\\[1ex] \left\lfloor \dfrac{\mathsf{MaxBlockSubsidy}}{\mathsf{BlossomPoWTargetSpacingRatio} \cdot \mathsf{NU7PoWTargetSpacingRatio} \cdot 2^{\mathsf{Halving}(\mathsf{height})}} \right\rfloor, &\text{if } \mathsf{IsNU7Activated}(\mathsf{height}) \end{cases} From 4067d2d26722b7c14ab170c97030ebd6f00bde0c Mon Sep 17 00:00:00 2001 From: Evan Forbes <42654277+evan-forbes@users.noreply.github.com> Date: Wed, 6 May 2026 00:52:17 -0500 Subject: [PATCH 051/115] Apply suggestions from code review Co-authored-by: Daira-Emma Hopwood <daira@jacaranda.org> --- zips/draft-valargroup-blocktime-reduction.md | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/zips/draft-valargroup-blocktime-reduction.md b/zips/draft-valargroup-blocktime-reduction.md index 2edeee864..e6c0fa7e8 100644 --- a/zips/draft-valargroup-blocktime-reduction.md +++ b/zips/draft-valargroup-blocktime-reduction.md @@ -153,11 +153,14 @@ A devnet experiment with 99 geographically-distributed Zebra nodes producing 2MB A prerequisite for reducing the target block spacing is that block validation and propagation must remain small relative to the target spacing. The per-pool -action limits introduced by this proposal ensure that worst-case block -processing time is *lower* per block than today's. The increase in consensus -bandwidth and Orchard TPS does mean that full node sync will increase in net -time. We accept this trade-off (TODO: be concrete with timing increases, and -remark that more CPU cores fixes this) +propagation remain small relative to the target spacing. The per-pool +action limits introduced by this proposal ensure that worst-case +*per-block* processing time is lower than today's. The fact that there +are three times as many blocks in unit time does mean that the *overall* +worst-case proportion of time taken for processing, and the cost of +sync after a given time offline (for both full nodes and light clients) +will increase. We accept this trade-off. (TODO: be concrete with timing +increases, and the effect of parallelism.) **Current worst case:** A full 2 MB block today can contain up to ~617 Orchard actions or ~2,090 Sapling outputs, with no per-pool limits. A fully @@ -276,9 +279,8 @@ divide evenly by 3. The post-NU7 subsidy is $\mathsf{floor}(156250000 / 6) = 26041666$ zatoshi (0.26041666 ZEC), losing approximately 0.33 zatoshi per block to rounding. Over a full halving interval of 5,040,000 blocks this amounts to less than 0.017 ZEC -of total underpaid issuance, a negligible amount. Should any of the NSM ZIP's -be accepted, the difference can be credited to the NSM, otherwise it will just be -under-minted from supply. +of total underpaid issuance, a negligible amount. Should ZIP 234 be accepted, +the difference will eventually be reissued. ### Shielded pool action limits From 996b80e70ac0107b4794b223e0461995999ea5fd Mon Sep 17 00:00:00 2001 From: evan-forbes <evan.samuel.forbes@gmail.com> Date: Wed, 6 May 2026 01:04:07 -0500 Subject: [PATCH 052/115] review feedback and fill in todos --- zips/draft-valargroup-blocktime-reduction.md | 42 +++++++++++--------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/zips/draft-valargroup-blocktime-reduction.md b/zips/draft-valargroup-blocktime-reduction.md index 05e780972..7621f3e5c 100644 --- a/zips/draft-valargroup-blocktime-reduction.md +++ b/zips/draft-valargroup-blocktime-reduction.md @@ -136,17 +136,17 @@ mining centralization risk, block propagation delay, and block verification times. Today the stale rate is 0.4%, but this may be lower than what pure block propagation delay may imply due to hashpower centralization in mining pools. -At 25-second block target spacing, the projected stale (orphan) block -rate is approximately 1.3% using theoretical models, or approximately -3.9% using significantly rounded-up estimates of Zcash network propagation -delays. Both figures are well below Ethereum's historical stale rate of 5.4% -when it operated under proof-of-work. [^forum-proposal] - -(TODO: Refine above numbers and expand on them. The 1.3% is derived from a very straightforward method, of estimating propagation delay using the current uncle -rate and block time as a poisson process. The 3.9% is taken from noticing that current p90 block propagation between EU and US nodes is 700ms, and then -rounding that up to 1s. This needs to be combined with measuring latencies when the blocks are full, yet it is hard to see how this could risk approaching 2s.) - -A devnet experiment with 99 geographically-distributed Zebra nodes producing 2MB blocks at 25-second target spacing measured a stale block rate of 4.86% and a fork rate of 0.37%. Both below the safety threshold of 5% set via Ethereum's historical proof-of-work stale rate. The only modification required to get these low rates was to tune TCP configuration (more details in the linked footnote). The devnet's node distribution was significantly more decentralized than today's mainnet, so these figures represent a near worst-case scenario. This indicates that 25-second target spacing can be deployed safely with no gossip or p2p changes. [^devnet-blocktime-test] +At 25-second block target spacing, the theoretical stale block rate is +approximately 3.26%, derived from measured Zcash network propagation +delays. A devnet experiment with 99 geographically-distributed Zebra +nodes producing 2MB blocks at 25-second target spacing measured a stale +block rate of 4.86% and a fork rate of 0.37%. Both observed figures are +below the 5% safety threshold set by Ethereum's historical proof-of-work +stale rate. [^forum-proposal] The only modification required to achieve +these rates was tuning TCP configuration (more details in the linked +footnote). The devnet's node distribution was significantly more +decentralized than today's mainnet, so these figures represent a +near worst-case scenario. [^devnet-blocktime-test] ## Block processing time @@ -178,10 +178,13 @@ verification during live network syncing since version 3.0.0. With the action limits, a worst-case block's Orchard bundle can be fully batch-verified in a small number of batches. -**Estimated timing.** On a typical 4-core machine, worst-case full -block verification (including proof verification for all shielded -components) is estimated at under 500ms for a block at the -action limits. (TODO: Refine with easily citeable benchmarks) +**Estimated timing.** In local benchmarks limited to 4 threads, on +an AMD Ryzen AI 9 HX 370 (12 cores, 24 threads, 2.0 GHz base clock, +up to 5.1 GHz boost clock, 28 W default TDP, 15--54 W configurable +TDP), availability verification for an Orchard-heavy block at the +action limits completed in 529.00--554.30 ms, and availability +verification for a Sapling-heavy block at the action limits completed +in 1.1017--1.1329 s. [^amd-ryzen-ai-hx-370] When transactions have already been pre-verified upon entering the mempool, which is the typical case for a node that has been online, block validation reduces to checking signatures and @@ -413,9 +416,10 @@ used both before and after activation. ### Block-count-based constants The following constants, measured in number of blocks, were reviewed. -Implementations SHOULD scale these by -$\mathsf{NU7PoWTargetSpacingRatio}$ where they represent -a time duration: +Implementations SHOULD scale by $\mathsf{NU7PoWTargetSpacingRatio}$ +those constants that represent a time duration (marked "Scale by 3" +below), and SHOULD NOT scale those whose semantics are intrinsically +measured in blocks (marked "No change"): | Constant | Current | Post-activation | Notes | |---------------------------------------------|---------|-----------------|-------| @@ -596,3 +600,5 @@ activation heights and consensus branch IDs. [^forum-proposal]: [Forum: Proposal — Lower Zcash Block Target Spacing to 25s](https://forum.zcashcommunity.com/t/proposal-lower-zcash-block-target-spacing-to-25s/54577) [^devnet-blocktime-test]: [Forum: Zcash Block Time Reduction Appears Safe for NU7 w/ Zebra-only Devnet](https://forum.zcashcommunity.com/t/zcash-block-time-reduction-appears-safe-for-nu7-w-zebra-only-devnet/55586) + +[^amd-ryzen-ai-hx-370]: [AMD Ryzen AI 9 HX 370 specifications](https://www.amd.com/en/support/downloads/drivers.html/processors/ryzen/ryzen-ai-300-series/amd-ryzen-ai-9-hx-370.html#specifications) From ac13907ed4b27e051bb052027d84f56c47b8202f Mon Sep 17 00:00:00 2001 From: evan-forbes <evan.samuel.forbes@gmail.com> Date: Wed, 6 May 2026 01:17:28 -0500 Subject: [PATCH 053/115] Trim CPU model details from estimated timing block --- zips/draft-valargroup-blocktime-reduction.md | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/zips/draft-valargroup-blocktime-reduction.md b/zips/draft-valargroup-blocktime-reduction.md index 242982504..54c7dceac 100644 --- a/zips/draft-valargroup-blocktime-reduction.md +++ b/zips/draft-valargroup-blocktime-reduction.md @@ -181,13 +181,11 @@ verification during live network syncing since version 3.0.0. With the action limits, a worst-case block's Orchard bundle can be fully batch-verified in a small number of batches. -**Estimated timing.** In local benchmarks limited to 4 threads, on -an AMD Ryzen AI 9 HX 370 (12 cores, 24 threads, 2.0 GHz base clock, -up to 5.1 GHz boost clock, 28 W default TDP, 15--54 W configurable -TDP), availability verification for an Orchard-heavy block at the -action limits completed in 529.00--554.30 ms, and availability -verification for a Sapling-heavy block at the action limits completed -in 1.1017--1.1329 s. [^amd-ryzen-ai-hx-370] +**Estimated timing.** In local benchmarks on a modern AMD laptop CPU +limited to 4 threads, availability verification for an Orchard-heavy +block at the action limits completed in 529.00--554.30 ms, and +availability verification for a Sapling-heavy block at the action +limits completed in 1.1017--1.1329 s. When transactions have already been pre-verified upon entering the mempool, which is the typical case for a node that has been online, block validation reduces to checking signatures and @@ -599,5 +597,3 @@ activation heights and consensus branch IDs. [^forum-proposal]: [Forum: Proposal — Lower Zcash Block Target Spacing to 25s](https://forum.zcashcommunity.com/t/proposal-lower-zcash-block-target-spacing-to-25s/54577) [^devnet-blocktime-test]: [Forum: Zcash Block Time Reduction Appears Safe for NU7 w/ Zebra-only Devnet](https://forum.zcashcommunity.com/t/zcash-block-time-reduction-appears-safe-for-nu7-w-zebra-only-devnet/55586) - -[^amd-ryzen-ai-hx-370]: [AMD Ryzen AI 9 HX 370 specifications](https://www.amd.com/en/support/downloads/drivers.html/processors/ryzen/ryzen-ai-300-series/amd-ryzen-ai-9-hx-370.html#specifications) From 0d21232f0350b1623cdeed647aebf36f4717e1bd Mon Sep 17 00:00:00 2001 From: evan-forbes <evan.samuel.forbes@gmail.com> Date: Wed, 6 May 2026 01:26:16 -0500 Subject: [PATCH 054/115] Apply daira suggestion: Sapling IOs -> inputs+outputs --- zips/draft-valargroup-blocktime-reduction.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zips/draft-valargroup-blocktime-reduction.md b/zips/draft-valargroup-blocktime-reduction.md index 54c7dceac..a23645530 100644 --- a/zips/draft-valargroup-blocktime-reduction.md +++ b/zips/draft-valargroup-blocktime-reduction.md @@ -168,7 +168,7 @@ packed Orchard block requires verifying all action proofs and spend authorization signatures for those ~617 actions. **Proposed worst case:** With the action limits, a block contains at -most 306 Orchard actions and a maximum of 300 Sapling input or output items. This is roughly half the +most 306 Orchard actions and a maximum of 300 Sapling inputs+outputs. This is roughly half the current Orchard worst case and a fraction of the Sapling worst case. The per-block verification work is therefore substantially reduced. From 85c6111262906438647a33b2804eb8e815a380a7 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe <kris@nutty.land> Date: Thu, 7 May 2026 10:39:03 -0600 Subject: [PATCH 055/115] Apply suggestion from @nuttycom The CHANGELOG notes that `app-id` is now deprecated. --- .github/workflows/publish.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index df53b6cb6..15424a96c 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -29,7 +29,7 @@ jobs: id: app-token uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1 with: - app-id: ${{ secrets.APP_ID }} + client-id: ${{ secrets.APP_ID }} private-key: ${{ secrets.APP_PRIVATE_KEY }} - name: Checkout repository From ddbe286248f6a3465fed8641800019802f6f3246 Mon Sep 17 00:00:00 2001 From: Dev Ojha <dojha@berkeley.edu> Date: Fri, 8 May 2026 16:56:26 +0800 Subject: [PATCH 056/115] Update for anchor block hegiht reduction --- zips/draft-valargroup-blocktime-reduction.md | 56 +++++++++++++------- 1 file changed, 38 insertions(+), 18 deletions(-) diff --git a/zips/draft-valargroup-blocktime-reduction.md b/zips/draft-valargroup-blocktime-reduction.md index a23645530..56f6241e1 100644 --- a/zips/draft-valargroup-blocktime-reduction.md +++ b/zips/draft-valargroup-blocktime-reduction.md @@ -1,7 +1,8 @@ ZIP: Unassigned Title: Shorter Block Target Spacing - Owners: ValarDragon <dojha@berkeley.edu> + Owners: Dev Ojha <dev@valargroup.dev> + Evan Forbes <evan@valargroup.dev> Status: Draft Category: Consensus Created: 2026-03-13 @@ -41,7 +42,7 @@ the Sapling and Orchard shielded protocols. This solves three problems. - Significantly improves the UX for actors who need 1 or 2 conf's. (Near Intents, small payments) The user-latency goes down 3x. - Increases consensus bandwidth, which amplifies the scaling impact of a future shielded pool which does not require shielded sync. -- Introduces action limits, which short term more than doubles the Orchard TPS (2.9 → 6.1 TPS), while lowering the impact a DoS attacker can impose on wallets; for example, maximum shielded sync bandwidth for light clients is reduced by 42% (270.5 → 156.83 MB/day). +- Introduces action limits. These provide limits of the number of actions that can go into a block. There is a global limit across all pools, and per pool limits. It is configured to more than double the Orchard TPS (2.9 → 6.1 TPS), while lowering the impact a DoS attacker can impose on wallets; for example, maximum shielded sync bandwidth for light clients is reduced by 42% (270.5 → 156.83 MB/day). The action limits significantly decrease the number of Sprout and Sapling pool outputs available per block, to lower the maximum shielded sync burden under @@ -75,7 +76,7 @@ The motivations for decreasing the block target spacing are: gadget is also deployed. The throughput goal on its own could be achieved via a block size increase. -However the main goal of this proposal is to foremost improve the transaction +However the goal of this proposal is to foremost improve the transaction latency. It is estimated that this reduction in blocktime would increase the stale rate from today's 0.4% to 1.3%. For reference, Ethereum operated at 5.4% stale rate. @@ -104,9 +105,17 @@ shielded transaction induces a bandwidth overhead for every wallet and an extra trial decryption, so we must carefully understand the impact a DOS attacker can cause. Today the worst-case DoS attack can induce 270.5 MB of wallet sync download to clients per day, and 4.8M trial decryptions per -day. We propose introducing action limits in Orchard (306 actions per block), -and (input+output) limits for Sapling (300 per block). With these limits, the -worst case becomes 156.83 MB bandwidth and 2.1M trial decrypts per day. This +day. We propose introducing global action limits and per-pool action limits as follows: + +- A maximum of 306 actions per block across all pools + +- A maximum of 306 Orchard actions per block + +- A maximum of 300 Sapling inputs + outputs. (Total inputs + outputs < 300) + +- A maximum of 25 Sprout JoinSplits per block. + +With these limits, the worst case becomes 156.83 MB bandwidth and 2.1M trial decrypts per day. This is a 42% improvement in worst case wallet sync bandwidth despite 3x more blocks. This yields a 2x in Orchard TPS, and keeps Sapling TPS at a higher level than today's Orchard TPS. @@ -141,7 +150,7 @@ approximately 3.26%, derived from measured Zcash network propagation delays. A devnet experiment with 99 geographically-distributed Zebra nodes producing 2MB blocks at 25-second target spacing measured a stale block rate of 4.86% and a fork rate of 0.37%. Both observed figures are -below the 5% safety threshold set by Ethereum's historical proof-of-work +below the 5.4% safety threshold set by Ethereum's historical proof-of-work stale rate. [^forum-proposal] The only modification required to achieve these rates was tuning TCP configuration (more details in the linked footnote). The devnet's node distribution was significantly more @@ -168,9 +177,13 @@ packed Orchard block requires verifying all action proofs and spend authorization signatures for those ~617 actions. **Proposed worst case:** With the action limits, a block contains at -most 306 Orchard actions and a maximum of 300 Sapling inputs+outputs. This is roughly half the -current Orchard worst case and a fraction of the Sapling worst case. -The per-block verification work is therefore substantially reduced. +most 306 actions across pools. There is separately, limits per pool. We propose per-pool limits of: + +- 306 Orchard actions +- 300 Sapling inputs+outputs. +- 25 Sprout JoinSplits. + +This means the new worst case block processing time, if Orchard dominant, would be half of today's worst case, and Sapling's would be one sixth. The per-block verification work is therefore substantially reduced. **Batch verification.** Orchard transaction verification benefits from batch validation, where proof and signature verification is amortized @@ -430,18 +443,25 @@ measured in blocks (marked "No change"): ### Anchor selection depth -ZIP 213 [^zip-0213] recommends selecting an anchor 10 blocks back from +ZIP 315 [^zip-0315], recommends selecting an anchor 3 blocks back from the chain tip when constructing shielded transactions. The recommended -anchor depth SHOULD remain at 10 blocks after activation, reducing the -wall-clock anchor delay from ~12.5 minutes to ~4.2 minutes. This +anchor depth SHOULD remain at 3 blocks after activation, reducing the average +wall-clock anchor delay from ~3.75 minutes to ~1.25 minutes. This follows the same precedent set by the Blossom upgrade (ZIP 208 -[^zip-0208]), which halved the anchor delay from ~25 minutes to ~12.5 -minutes without changing the 10-block depth. +[^zip-0208]), which did not update the anchor depth and therefore halved delay. | Parameter | Current | Post-activation | Notes | |-----------|---------|-----------------|-------| -| Recommended anchor depth | 10 blocks (~12.5 min) | 10 blocks (~4.2 min) | No change; follows Blossom precedent | +| Recommended anchor depth | 3 blocks (~3.75 min) | 3 blocks (~1.25 min) | No change; follows Blossom precedent | +The increased likelihood of forking due to block time reduction should not be +concerning here. For an issue to occur when anchor depth is 3 blocks back, you +must have a 4 block re-org. In the many years of Ethereum PoW, a 4 block re-org +has never been observed [^lovejoy-reorg]. So we are not practically at risk of +inherent randomness causing a re-org. In other POW chains, re-orgs of 4+ +blocks resulted from a consensus split of some form, including the recent +Litecoin attack, or an attack from a surge in hashpower. +Anchor height depth is not intended to protect against those two vectors. # Rationale @@ -584,8 +604,6 @@ activation heights and consensus branch IDs. [^zip-0208]: [ZIP 208: Shorter Block Target Spacing](zip-0208.rst) -[^zip-0213]: [ZIP 213: Shielded Coinbase](zip-0213.rst) - [^zip-0315]: [ZIP 315: Best Practices for Wallet Implementations](zip-0315.rst) [^zip-0317]: [ZIP 317: Proportional Transfer Fee Mechanism](zip-0317.rst) @@ -594,6 +612,8 @@ activation heights and consensus branch IDs. [^slowfastblocks]: [On Slow and Fast Block Times](https://blog.ethereum.org/2015/09/14/on-slow-and-fast-block-times/) +[^lovejoy-reorg]: [Lovejoy, James P. (2020). *An Empirical Analysis of Chain Reorganizations and Double-Spend Attacks on Proof-of-Work Cryptocurrencies.* M.Eng. thesis, Massachusetts Institute of Technology, Department of Electrical Engineering and Computer Science.](https://static1.squarespace.com/static/6675a0d5fc9e317c60db9b37/t/66eb3560532516773c4f7ece/1726690657755/LovejoyJamesP-meng-eecs-2020+%281%29.pdf) + [^forum-proposal]: [Forum: Proposal — Lower Zcash Block Target Spacing to 25s](https://forum.zcashcommunity.com/t/proposal-lower-zcash-block-target-spacing-to-25s/54577) [^devnet-blocktime-test]: [Forum: Zcash Block Time Reduction Appears Safe for NU7 w/ Zebra-only Devnet](https://forum.zcashcommunity.com/t/zcash-block-time-reduction-appears-safe-for-nu7-w-zebra-only-devnet/55586) From dd3b22c83e4a336bfe3b7662bc3d270585eaf577 Mon Sep 17 00:00:00 2001 From: Dev Ojha <dojha@berkeley.edu> Date: Fri, 8 May 2026 17:18:58 +0800 Subject: [PATCH 057/115] Resolve last TODO --- zips/draft-valargroup-blocktime-reduction.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/zips/draft-valargroup-blocktime-reduction.md b/zips/draft-valargroup-blocktime-reduction.md index 56f6241e1..2491da1f1 100644 --- a/zips/draft-valargroup-blocktime-reduction.md +++ b/zips/draft-valargroup-blocktime-reduction.md @@ -160,16 +160,15 @@ near worst-case scenario. [^devnet-blocktime-test] ## Block processing time -A prerequisite for reducing the target block spacing is that block validation and -propagation must remain small relative to the target spacing. The per-pool +A prerequisite for reducing the target block spacing is that block validation +and propagation must remain small relative to the target spacing. The per-pool propagation remain small relative to the target spacing. The per-pool action limits introduced by this proposal ensure that worst-case *per-block* processing time is lower than today's. The fact that there are three times as many blocks in unit time does mean that the *overall* -worst-case proportion of time taken for processing, and the cost of -sync after a given time offline (for both full nodes and light clients) -will increase. We accept this trade-off. (TODO: be concrete with timing -increases, and the effect of parallelism.) +worst-case proportion of time taken for processing, and the worst cost of +sync after a given time offline for full nodes will increase. We accept this +trade-off. These computational limits parallelize well. The max bandwidth requirement from the chain is 655kbps, so syncing with 10mbps bandwidth still has a 15x advantage factor over full blocks on mainnet. **Current worst case:** A full 2 MB block today can contain up to ~617 Orchard actions or ~2,090 Sapling outputs, with no per-pool limits. A fully From e538977cf944e6543fbaf0786a6cebd6c59bbb5a Mon Sep 17 00:00:00 2001 From: Dev Ojha <dojha@berkeley.edu> Date: Fri, 8 May 2026 22:24:07 +0800 Subject: [PATCH 058/115] ZIP 213: align anchor-depth rationale with ZIP 315 Update ZIP 213's Rationale to reference an anchor 3 blocks back from the chain tip, matching the recommendation in ZIP 315, instead of the older "10 blocks" guidance. Removes conflicting advice that confuses new implementers. Closes #1265 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --- zips/zip-0213.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/zips/zip-0213.rst b/zips/zip-0213.rst index e4a3b6e19..e1d46159e 100644 --- a/zips/zip-0213.rst +++ b/zips/zip-0213.rst @@ -130,9 +130,9 @@ be shielded immediately. Enforcing coinbase maturity at the consensus level for Sapling outputs would incur significant complexity in the consensus rules, because it would require special-casing coinbase note commitments in the Sapling commitment tree. The standard recommendation when -spending a note is to select an anchor 10 blocks back from the current chain tip, which -acts as a de-facto 10-block maturity on all notes, coinbase included. This might be -proposed as a consensus rule in future. +spending a note is to select an anchor 3 blocks back from the current chain tip (see ZIP +315 [#zip-0315]_), which acts as a de-facto 3-block maturity on all notes, coinbase +included. This might be proposed as a consensus rule in future. There is another reason for shielded coinbase maturity being unnecessary: shielded coinbase outputs have the same effect on economic activity as regular shielded outputs. @@ -205,3 +205,4 @@ References .. [#zip-0207] `ZIP 207: Funding Streams <zip-0207.rst>`_ .. [#zip-0250] `ZIP 250: Deployment of the Heartwood Network Upgrade <zip-0250.rst>`_ .. [#zip-0252] `ZIP 252: Deployment of the NU5 Network Upgrade <zip-0252.rst>`_ +.. [#zip-0315] `ZIP 315: Best Practices for Wallet Implementations <zip-0315.rst>`_ From 4a6f6aa72b1c2c2700cdc2f5e2ad916f80a7bd03 Mon Sep 17 00:00:00 2001 From: Dev Ojha <ValarDragon@users.noreply.github.com> Date: Wed, 13 May 2026 05:52:58 +0900 Subject: [PATCH 059/115] Apply suggestion from @nuttycom Co-authored-by: Kris Nuttycombe <kris@nutty.land> --- zips/draft-valargroup-blocktime-reduction.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zips/draft-valargroup-blocktime-reduction.md b/zips/draft-valargroup-blocktime-reduction.md index 2491da1f1..eeded335f 100644 --- a/zips/draft-valargroup-blocktime-reduction.md +++ b/zips/draft-valargroup-blocktime-reduction.md @@ -1,6 +1,6 @@ ZIP: Unassigned - Title: Shorter Block Target Spacing + Title: 25-second Block Target Spacing Owners: Dev Ojha <dev@valargroup.dev> Evan Forbes <evan@valargroup.dev> Status: Draft From 6feea430335faa42c1ff287e0ba92da4f0c17621 Mon Sep 17 00:00:00 2001 From: Sean Bowe <ewillbefull@gmail.com> Date: Wed, 13 May 2026 09:02:35 -0600 Subject: [PATCH 060/115] Add Sean Bowe as ZIP editor --- zips/zip-0000.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/zips/zip-0000.rst b/zips/zip-0000.rst index efbe05be1..2ef158f53 100644 --- a/zips/zip-0000.rst +++ b/zips/zip-0000.rst @@ -8,6 +8,7 @@ Arya <arya@zfnd.org> Kris Nuttycombe <kris@nutty.land> Sam H. Smith <sam@shieldedlabs.net> + Sean Bowe <sean@bowe.tech> Original-Authors: Josh Cincinnati George Tankersley Deirdre Connolly @@ -190,6 +191,7 @@ The current ZIP Editors are: capacities. * Arya, associated with the Zcash Foundation. * Mark Henderson and Sam H. Smith, associated with Shielded Labs. +* Sean Bowe, associated with Project Tachyon. All can be reached at zips@z.cash. The current design of the ZIP Process dictates that there are always at least two ZIP Editors, including at least From deacf490dddab474ec8044b04d737111c264d425 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 13 May 2026 16:04:26 +0000 Subject: [PATCH 061/115] Bump actions/create-github-app-token from 3.1.1 to 3.2.0 Bumps [actions/create-github-app-token](https://github.com/actions/create-github-app-token) from 3.1.1 to 3.2.0. - [Release notes](https://github.com/actions/create-github-app-token/releases) - [Changelog](https://github.com/actions/create-github-app-token/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/create-github-app-token/compare/1b10c78c7865c340bc4f6099eb2f838309f1e8c3...bcd2ba49218906704ab6c1aa796996da409d3eb1) --- updated-dependencies: - dependency-name: actions/create-github-app-token dependency-version: 3.2.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> --- .github/workflows/publish.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index e6a552bc7..aa1f935c0 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -27,7 +27,7 @@ jobs: steps: - name: Generate app token id: app-token - uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1 + uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 with: client-id: ${{ secrets.APP_ID }} private-key: ${{ secrets.APP_PRIVATE_KEY }} From dba57899079449ea5a9b57f24a253f645e17402a Mon Sep 17 00:00:00 2001 From: Sean Bowe <ewillbefull@gmail.com> Date: Wed, 13 May 2026 11:49:05 -0600 Subject: [PATCH 062/115] Replace Znewco placeholder with Zcash Open Development Lab Znewco was a stand-in for the actual company name, which has since been decided as Zcash Open Development Lab. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --- zips/zip-0000.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/zips/zip-0000.rst b/zips/zip-0000.rst index 2ef158f53..b246f1ea6 100644 --- a/zips/zip-0000.rst +++ b/zips/zip-0000.rst @@ -201,8 +201,9 @@ ZIP Editors MUST declare any potential or perceived conflict of interest they have relating to their responsibilities as ZIP Editors. Daira-Emma Hopwood declares a conflict of interest in acting as a ZIP Editor -and as Head of Research and Assurance at Znewco, Inc., and will endeavour -to minimize the downsides of that confluence of roles as far as possible. +and as Head of Research and Assurance at Zcash Open Development Lab, and +will endeavour to minimize the downsides of that confluence of roles as far +as possible. In particular, ze commits to stepping down from the ZIP Editor role after the deployment of Zcash Shielded Assets, assuming ze is still in a management role at a company primarily involved with the development of From 15958941a6d069c3ecb9d9e2816c9e395e10cac9 Mon Sep 17 00:00:00 2001 From: Dev Ojha <dojha@berkeley.edu> Date: Thu, 14 May 2026 10:57:41 +0900 Subject: [PATCH 063/115] Add ZIP number 218 --- README.rst | 3 +++ README.template | 1 + zips/{draft-valargroup-blocktime-reduction.md => zip-0218.md} | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) rename zips/{draft-valargroup-blocktime-reduction.md => zip-0218.md} (99%) diff --git a/README.rst b/README.rst index 739b6a21f..29b16ff90 100644 --- a/README.rst +++ b/README.rst @@ -62,6 +62,7 @@ NU7 Candidate ZIPs The following ZIPs are under consideration for deployment in NU7: +- `ZIP 218: 25-second Block Target Spacing <zips/zip-0218.md>`__ - `ZIP 226: Transfer and Burn of Zcash Shielded Assets <zips/zip-0226.rst>`__ - `ZIP 227: Issuance of Zcash Shielded Assets <zips/zip-0227.rst>`__ - `ZIP 230: Version 6 Transaction Format <zips/zip-0230.rst>`__ @@ -169,6 +170,7 @@ written. <tr> <td><span class="reserved">129</span></td> <td class="left"><a class="reserved" href="zips/zip-0129.md">Zcash Transparent Multisig Setup</a></td> <td>Reserved</td> <td class="left"><a href="https://github.com/zcash/zips/issues/1060">zips#1060</a></td> <tr> <td>204</td> <td class="left"><a href="zips/zip-0204.rst">Zcash P2P Network Protocol</a></td> <td>Draft</td> <td class="left"><a href="https://github.com/zcash/zips/issues/352">zips#352</a></td> <tr> <td><span class="reserved">217</span></td> <td class="left"><a class="reserved" href="zips/zip-0217.rst">Aggregate Signatures</a></td> <td>Reserved</td> <td class="left"><a href="https://github.com/zcash/zips/issues/1137">zips#1137</a></td> + <tr> <td>218</td> <td class="left"><a href="zips/zip-0218.md">25-second Block Target Spacing</a></td> <td>Draft</td> <td class="left"><a href="https://forum.zcashcommunity.com/t/proposal-lower-zcash-block-target-spacing-to-25s/54577">https://forum.zcashcommunity.com/t/proposal-lower-zcash-block-target-spacing-to-25s/54577</a></td> <tr> <td><span class="reserved">219</span></td> <td class="left"><a class="reserved" href="zips/zip-0219.rst">Disabling Addition of New Value to the Sapling Chain Value Pool</a></td> <td>Reserved</td> <td class="left"><a href="https://github.com/zcash/zips/issues/428">zips#428</a></td> <tr> <td>222</td> <td class="left"><a href="zips/zip-0222.rst">Transparent Zcash Extensions</a></td> <td>Draft</td> <td class="left"><a href="https://github.com/zcash/zips/issues/1231">zips#1231</a></td> <tr> <td>226</td> <td class="left"><a href="zips/zip-0226.rst">Transfer and Burn of Zcash Shielded Assets</a></td> <td>Draft</td> <td class="left"><a href="https://github.com/zcash/zips/issues/618">zips#618</a></td> @@ -304,6 +306,7 @@ Index of ZIPs <tr> <td>215</td> <td class="left"><a href="zips/zip-0215.rst">Explicitly Defining and Modifying Ed25519 Validation Rules</a></td> <td>Final</td> <tr> <td>216</td> <td class="left"><a href="zips/zip-0216.rst">Require Canonical Jubjub Point Encodings</a></td> <td>Final</td> <tr> <td><span class="reserved">217</span></td> <td class="left"><a class="reserved" href="zips/zip-0217.rst">Aggregate Signatures</a></td> <td>Reserved</td> + <tr> <td>218</td> <td class="left"><a href="zips/zip-0218.md">25-second Block Target Spacing</a></td> <td>Draft</td> <tr> <td><span class="reserved">219</span></td> <td class="left"><a class="reserved" href="zips/zip-0219.rst">Disabling Addition of New Value to the Sapling Chain Value Pool</a></td> <td>Reserved</td> <tr> <td><strike>220</strike></td> <td class="left"><strike><a href="zips/zip-0220.rst">Zcash Shielded Assets</a></strike></td> <td>Withdrawn</td> <tr> <td>221</td> <td class="left"><a href="zips/zip-0221.rst">FlyClient - Consensus-Layer Changes</a></td> <td>Final</td> diff --git a/README.template b/README.template index 111eb1a22..4f078629e 100644 --- a/README.template +++ b/README.template @@ -62,6 +62,7 @@ NU7 Candidate ZIPs The following ZIPs are under consideration for deployment in NU7: +- `ZIP 218: 25-second Block Target Spacing <zips/zip-0218.md>`__ - `ZIP 226: Transfer and Burn of Zcash Shielded Assets <zips/zip-0226.rst>`__ - `ZIP 227: Issuance of Zcash Shielded Assets <zips/zip-0227.rst>`__ - `ZIP 230: Version 6 Transaction Format <zips/zip-0230.rst>`__ diff --git a/zips/draft-valargroup-blocktime-reduction.md b/zips/zip-0218.md similarity index 99% rename from zips/draft-valargroup-blocktime-reduction.md rename to zips/zip-0218.md index eeded335f..9492341a4 100644 --- a/zips/draft-valargroup-blocktime-reduction.md +++ b/zips/zip-0218.md @@ -1,5 +1,5 @@ - ZIP: Unassigned + ZIP: 218 Title: 25-second Block Target Spacing Owners: Dev Ojha <dev@valargroup.dev> Evan Forbes <evan@valargroup.dev> From af430f58ce52517befcb4624ae919d1c35456069 Mon Sep 17 00:00:00 2001 From: Dev Ojha <dojha@berkeley.edu> Date: Sun, 17 May 2026 03:27:27 +0900 Subject: [PATCH 064/115] Add Dev Ojha as ZIP editor Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --- zips/zip-0000.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/zips/zip-0000.rst b/zips/zip-0000.rst index b246f1ea6..d5115cd1a 100644 --- a/zips/zip-0000.rst +++ b/zips/zip-0000.rst @@ -9,6 +9,7 @@ Kris Nuttycombe <kris@nutty.land> Sam H. Smith <sam@shieldedlabs.net> Sean Bowe <sean@bowe.tech> + Dev Ojha <dev@valargroup.dev> Original-Authors: Josh Cincinnati George Tankersley Deirdre Connolly @@ -192,6 +193,7 @@ The current ZIP Editors are: * Arya, associated with the Zcash Foundation. * Mark Henderson and Sam H. Smith, associated with Shielded Labs. * Sean Bowe, associated with Project Tachyon. +* Dev Ojha, associated with Valar Group. All can be reached at zips@z.cash. The current design of the ZIP Process dictates that there are always at least two ZIP Editors, including at least From ded9707a69759f9d20af6defe2c568d24b4a9292 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Fri, 15 May 2026 22:27:47 +0100 Subject: [PATCH 065/115] ZIP 2005: Use note-tuple terminology consistently in Spendability arguments. * Adopt notetuple, which is currently (rseed, leadByte, noterepr), as the named tuple feeding H^{rcm} and f, replacing "underlying note" or "note fields" framings in the binding and Spendability arguments. * Rename the Spendability theorem and its "Distinct ..." condition to use "note tuple(s)" instead of "underlying notes". * Fix an error where NoteCommit^rcm(noterepr) was defined in terms of leadByte, which it can't be because noterepr does not contain leadByte. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --- zips/zip-2005.md | 44 +++++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index ae302ba6d..49e99c4e5 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -1130,19 +1130,20 @@ $\text{where } \mathsf{pre\_rcm} = [\mathtt{0x0B}, \mathsf{leadByte}] \,||\, \ma ### Informal security argument for binding of note commitments -We can view the output of $\mathsf{NoteCommit_{rcm}}(\mathsf{noterepr})$ +We can view the output of $\mathsf{NoteCommit_{rcm}}$ for +$\mathsf{notetuple} = (\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})$ as the point addition of a randomization term $[\mathsf{H^{rcm}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr})]\, \mathcal{R}$, -and some other function of $\mathsf{rseed}$, $\mathsf{leadByte}$, and -$\mathsf{noterepr}$. +and some other function of $\mathsf{notetuple}$. Without loss of generality, we can write that function as -$[\mathsf{f}(\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})]\, \mathcal{R}$, +$[\mathsf{f}(\mathsf{notetuple})]\, \mathcal{R}$, by expanding each of the Sinemilla bases $\mathcal{C}_j = \mathcal{Q}(D) \text{ or } \mathcal{S}(j)$ used by [$\mathsf{HashToSinsimillaPoint}$](https://zips.z.cash/protocol/protocol.pdf#concretesinsemillahash) as $\mathcal{C}_j = [c_j]\, \mathcal{R}$ for some $c_j$. That is, -$$\mathsf{NoteCommit_{rcm}}(\mathsf{noterepr}) = [\mathsf{H^{rcm}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr}) + \mathsf{f}(\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})]\, \mathcal{R}.$$ +the note commitment for $\mathsf{notetuple}$ is +$$[\mathsf{H^{rcm}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr}) + \mathsf{f}(\mathsf{notetuple})]\, \mathcal{R}.$$ We will model $\mathsf{H^{rcm}}$ as a random oracle independent of $\mathsf{f}$ with uniform output on $\mathbb{F}_{r_{\mathbb{P}}}.$ This is reasonable because @@ -1167,11 +1168,11 @@ Pallas curve. > $r_{\mathbb{P}} \approx 2^{254}$ cannot introduce a problem. For each $\mathsf{H^{rcm}}$ oracle query the adversary chooses -$\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr}$ +$\mathsf{notetuple} = (\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})$ and obtains a "random" $\mathsf{rcm} = \mathsf{H^{rcm}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr})$. -We have $\mathsf{cm}_x = \mathsf{Extract}_{\mathbb{P}}([\mathsf{H^{rcm}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr}) + \mathsf{f}(\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})]\, \mathcal{R})$. +We have $\mathsf{cm}_x = \mathsf{Extract}_{\mathbb{P}}([\mathsf{H^{rcm}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr}) + \mathsf{f}(\mathsf{notetuple})]\, \mathcal{R})$. Over all Pallas curve points $P$, the number of outputs of $\mathsf{Extract}_{\mathbb{P}}(P)$ is $(\mathbb{F}_{r_\mathbb{P}} + 1)/2 \approx 2^{253}$ — @@ -1183,8 +1184,8 @@ zero point $\mathcal{O}_{\mathbb{P}}$ which is mapped to $0$. > negligible effect. There are two values of $\mathsf{cm}$ that match $\mathsf{cm}_x$ in their $x$-coordinate. -Because the output of $\mathsf{NoteCommit_{rcm}}(\mathsf{noterepr})$ is -of the form $\mathsf{cm} = F(\mathsf{noterepr}) + [\mathsf{rcm}]\, \mathcal{R}$, +Because the output of $\mathsf{NoteCommit_{rcm}}$ for $\mathsf{notetuple}$ is +of the form $\mathsf{cm} = [\mathsf{f}(\mathsf{notetuple}) + \mathsf{rcm}]\, \mathcal{R}$, for any given note we have exactly two values of $\mathsf{rcm}$ that will pass the commitment check. @@ -1239,7 +1240,8 @@ uses (they can choose to attack either, or both simultaneously): The above security argument means that provided we also check the uses of $\mathsf{H^{rcm}}$ and $\mathsf{H}^{\text{ψ}}$ in the post-quantum [Recovery Statement](#proposedrecoverystatement), Orchard note commitments -can be considered binding on all of the note fields. +can be considered binding on the note tuple +$(\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})$. Note that the argument associated with [Theorem 5.4.4](https://zips.z.cash/protocol/protocol.pdf#thmsinsemillaex) @@ -1571,9 +1573,9 @@ $$\mathsf{Extract}_{\mathbb{P}}\Big( We model $\mathsf{H^{rcm}}$ as a random oracle with output uniform on $\mathbb{F}_{r_{\mathbb{P}}}$. The functions $\mathsf{f}$, $\mathsf{H}^{\text{ψ}}$, and $\mathsf{PRF^{nf}}$ are deterministic -functions of $\mathsf{notetuple}$ that **do not query $\mathsf{H^{rcm}}$**: -$\mathsf{f}(\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})$ is the -Sinsemilla-base lift; $\mathsf{H}^{\text{ψ}}$ and $\mathsf{PRF^{nf}}$ are +functions of $\mathsf{notetuple} = (\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})$ +that **do not query $\mathsf{H^{rcm}}$**: $\mathsf{f}(\mathsf{notetuple})$ +is the Sinsemilla-base lift; $\mathsf{H}^{\text{ψ}}$ and $\mathsf{PRF^{nf}}$ are conventional hash functions. > The non-querying constraint rules out trivializing instantiations such @@ -1598,8 +1600,8 @@ small. We give a reduction-based argument that any classical adversary $\mathcal{A}$ in the Random Oracle Model attempting to find two valid -[Recovery Statement](#proposedrecoverystatement) witnesses for distinct -underlying notes that have colliding nullifiers, succeeds with probability at most +[Recovery Statement](#proposedrecoverystatement) witnesses with distinct +note tuples that have colliding nullifiers, succeeds with probability at most $\frac{q_{\mathsf{rcm}}(q_{\mathsf{rcm}}-1)}{r_{\mathbb{P}}} + \varepsilon_{\mathsf{kb}}(\mathcal{A}, q_{\mathsf{kb}})$, where $q_{\mathsf{rcm}}$ is the number of queries $\mathcal{A}$ makes to $\mathsf{H^{rcm}}$, and $q_{\mathsf{kb}}$ is as defined above. @@ -1633,11 +1635,11 @@ $\mathsf{notetuple}_i$ by the $\mathsf{ivk}$-pinning lemma; and $\text{ρ}_i$ is a field of $\mathsf{notetuple}_i$. The argument here covers nullifier-binding — it argues that $\mathsf{nf}$ -binds the underlying note ($\mathsf{noterepr}$, plus $\mathsf{rseed}$ and -$\mathsf{leadByte}$) under $\mathsf{H^{rcm}}$ modelled as a random oracle +binds the note tuple $(\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})$ +under $\mathsf{H^{rcm}}$ modelled as a random oracle and the [key-binding theorem](#thm-key-binding-rom). -**Theorem (distinct-note Spendability, classical ROM).** <a id="thm-spendability"></a> +**Theorem (distinct-notetuple Spendability, classical ROM).** <a id="thm-spendability"></a> Let $\mathcal{A}$ be a classical adversary with oracle access to $\mathsf{H^{rcm}}$ having output uniform on $\mathbb{F}_{r_{\mathbb{P}}}$, making at most $q_{\mathsf{rcm}}$ oracle queries. The *Spendability-collision* @@ -1648,7 +1650,7 @@ satisfying: : both witnesses satisfy the [Proposed Recovery Statement](#proposedrecoverystatement). -<a id="thm-spendability-distinct"></a>**Distinct underlying notes** +<a id="thm-spendability-distinct"></a>**Distinct note tuples** : the $\mathsf{H^{rcm}}$-input tuples $\mathsf{notetuple}_i := (\mathsf{rseed}_i, \mathsf{leadByte}_i, \mathsf{noterepr}_i)$ satisfy $\mathsf{notetuple}_1 \neq \mathsf{notetuple}_2$. @@ -1683,7 +1685,7 @@ $\pm$-equivalence event. $\mathcal{A}$ makes at most $q_{\mathsf{rcm}}$ queries to $\mathsf{H^{rcm}}$ before outputting $(w_1, w_2)$ satisfying [**Validity of witnesses**](#thm-spendability-validity), -[**Distinct underlying notes**](#thm-spendability-distinct), and +[**Distinct note tuples**](#thm-spendability-distinct), and [**Colliding nullifiers**](#thm-spendability-collide). The probability that $(w_1, w_2)$ contains a key-binding break is at most $\varepsilon_{\mathsf{kb}}(\mathcal{A}, q_{\mathsf{kb}})$; condition on @@ -1709,7 +1711,7 @@ $x$-coordinate $0$, the collision $\mathsf{nf}_1 = \mathsf{nf}_2$ holds iff $F_1 \equiv \pm F_2 \pmod{r_{\mathbb{P}}}$. *Independence claim per pair.* -By [**Distinct underlying notes**](#thm-spendability-distinct), +By [**Distinct note tuples**](#thm-spendability-distinct), $\mathsf{notetuple}_1 \neq \mathsf{notetuple}_2$, so the $\mathsf{H^{rcm}}$ outputs at $\mathsf{notetuple}_1, \mathsf{notetuple}_2$ are independent uniform on $\mathbb{F}_{r_{\mathbb{P}}}$. The From f380c4096dc4f91d399bffae576bf97b1ff91e17 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Sat, 16 May 2026 00:05:35 +0100 Subject: [PATCH 066/115] ZIP 2005: Drop leadByte from H^{rcm,Orchard}'s input. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit leadByte versions the note plaintext, not the note. The previous design took leadByte as a parameter of H^{rcm,Orchard} (with internal dispatch on its value), which created a layering violation between the handling of note plaintexts vs notes. * Redefine H^{rcm,Orchard} to take only (rseed, noterepr) and define it only for the recoverable-note (leadByte = 0x03) case. The leadByte = 0x02 case uses the existing derivation rcm = ToScalar^{Orchard}(PRF^{expand}_{rseed}([0x05] || ρ)) unchanged. * Drop the leadByte byte from the hashed prefix: pre_rcm = [0x0B] || ... instead of [0x0B, leadByte] || .... * At each call site (§4.7.3 Sending Notes, §4.8.3 Dummy Notes, §4.20.2/§4.20.3 Decryption), dispatch on leadByte explicitly to choose between the legacy and recoverable derivations. * Simplify the Spendability proof's notetuple to (rseed, noterepr); drop the leadByte_i index from notetuple_i in the theorem's "Distinct note tuples" condition. * Add a sentence before the flow diagram noting that it shows the recoverable-note case (leadByte = 0x03) and that the legacy case uses the existing simpler derivation. Drop the leadByte → pre_rcm edge. * Update the rationale and the specialised import in the Spendability setup to match the new signature. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --- zips/zip-2005.md | 96 ++++++++++++++++++++++++++---------------------- 1 file changed, 52 insertions(+), 44 deletions(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index 49e99c4e5..38ac3de6c 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -243,7 +243,12 @@ graph BT The bold lines are changes introduced by this ZIP, which all take the form of additional inputs to derivation functions or alternative derivations. The derivations shown in the box labelled [Proposed Recovery Statement](#proposedrecoverystatement) -are, roughly speaking, those enforced by the section of that name. +are, roughly speaking, those enforced by the section of that name. The +diagram shows the recoverable-note case ($\mathsf{leadByte} = \mathtt{0x03}$); +for $\mathsf{leadByte} = \mathtt{0x02}$ the existing Orchard derivation +$\mathsf{rcm} = \mathsf{ToScalar^{Orchard}}\big(\mathsf{PRF^{expand}_{rseed}}([\mathtt{0x05}] \,||\, \underline{\text{ρ}})\kern-0.1em\big)$ +applies, and the additional fields feeding into $\mathsf{pre\_rcm}$ +are absent. ```mermaid graph BT @@ -271,8 +276,7 @@ graph BT ivk --> ivkmul rseed --> Hpsi[H<sup>ψ</sup>]:::func rho --> Hpsi - leadByte([leadByte]) ==> pre_rcm - v([v, AssetBase]) ===> pre_rcm([pre_rcm]) + v([v, AssetBase]) ==> pre_rcm([pre_rcm]) pkd ====> pre_rcm gd ==> pre_rcm psi ===> pre_rcm @@ -285,8 +289,8 @@ graph BT Hpsi --> psi([#8239;ψ#8239;]) gd --> NoteCommit:::func pkd --> NoteCommit - v --> NoteCommit psi --> NoteCommit + v --> NoteCommit rcm --> NoteCommit rho --> NoteCommit cm --> DeriveNullifier:::func @@ -716,15 +720,14 @@ Add after the definition of $\mathsf{leadByte}$: 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) =$ +> Define $\mathsf{H^{rcm,Orchard}_{rseed}}(\mathsf{g}\star_{\mathsf{d}}, \mathsf{pk}\star_{\mathsf{d}}, \mathsf{v}, \underline{\text{ρ}}, \text{ψ}, \mathsf{AssetBase}\kern0.05em\star) =$ > $\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.05em\star),&\!\!\!\text{if } \mathsf{leadByte} = \mathtt{0x03} -> \end{cases}$ +> where $\mathsf{pre\_rcm} = [\mathtt{0x0B}] \,||\, \mathsf{LEBS2OSP}_{256}(\mathsf{g}\star_{\mathsf{d}}) \,||\, \mathsf{LEBS2OSP}_{256}(\mathsf{pk}\star_{\mathsf{d}}) \,||\, \mathsf{I2LEOSP}_{64}(\mathsf{v}) \,||\, \underline{\text{ρ}} \,||\, \mathsf{I2LEOSP}_{256}(\text{ψ}) \,||\, \mathsf{LEBS2OSP}_{256}(\mathsf{AssetBase}\kern0.05em\star)$. +> +> ($\mathsf{H^{rcm,Orchard}}$ is defined only for the $\mathsf{leadByte} = \mathtt{0x03}$ case; the existing +> derivation $\mathsf{rcm} = \mathsf{ToScalar^{Orchard}}(\mathsf{PRF^{expand}_{rseed}}([\mathtt{0x05}] \,||\, \underline{\text{ρ}}))$ +> from the protocol specification continues to apply when $\mathsf{leadByte} = \mathtt{0x02}$.) > > Define $\mathsf{H^{esk,Orchard}_{rseed}}(\underline{\text{ρ}}) = \mathsf{ToScalar^{Orchard}}\big(\mathsf{PRF^{expand}_{rseed}}([\mathtt{0x04}] \,||\, \underline{\text{ρ}})\kern-0.1em\big)$. > @@ -745,7 +748,10 @@ with > Derive $\mathsf{esk} = \mathsf{H^{esk,Orchard}_{rseed}}(\underline{\text{ρ}})$ -> 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 $\mathsf{rcm} = \begin{cases} +> \mathsf{ToScalar^{Orchard}}\big(\mathsf{PRF^{expand}_{rseed}}([\mathtt{0x05}] \,||\, \underline{\text{ρ}})\kern-0.1em\big),&\!\!\!\text{if } \mathsf{leadByte} = \mathtt{0x02} \\ +> \mathsf{H^{rcm,Orchard}_{rseed}}(\mathsf{g}\star_{\mathsf{d}}, \mathsf{pk}\star_{\mathsf{d}}, \mathsf{v}, \underline{\text{ρ}}, \text{ψ}, \mathsf{AssetBase}\kern0.05em\star),&\!\!\!\text{if } \mathsf{leadByte} = \mathtt{0x03} +> \end{cases}$ > Derive $\text{ψ} = \mathsf{H^{\text{ψ},Orchard}_{rseed}}(\underline{\text{ρ}})$ @@ -778,7 +784,10 @@ Replace the lines deriving $\mathsf{rcm}$ and $\text{ψ}$ with > $\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}}\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 $\mathsf{rcm} = \begin{cases} +> \mathsf{ToScalar^{Orchard}}\big(\mathsf{PRF^{expand}_{rseed}}([\mathtt{0x05}] \,||\, \underline{\text{ρ}})\kern-0.1em\big),&\!\!\!\text{if } \mathsf{leadByte} = \mathtt{0x02} \\ +> \mathsf{H^{rcm,Orchard}_{rseed}}(\mathsf{g}\star_{\mathsf{d}}, \mathsf{pk}\star_{\mathsf{d}}, \mathsf{v}, \underline{\text{ρ}}, \text{ψ}, \mathsf{AssetBase}\kern0.05em\star),&\!\!\!\text{if } \mathsf{leadByte} = \mathtt{0x03} +> \end{cases}$ > > Derive $\text{ψ} = \mathsf{H^{\text{ψ},Orchard}_{rseed}}(\underline{\text{ρ}})$ @@ -850,7 +859,9 @@ with > $\hspace{1.0em}$ let $\text{ψ} = \mathsf{H^{\text{ψ},Orchard}_{rseed}}(\underline{\text{ρ}})$ for Orchard or $\bot$ for Sapling <br> > $\hspace{1.0em}$ let $\mathsf{rcm} = \begin{cases} > \mathsf{LEOS2IP}_{256}(\mathsf{rseed}),&\!\!\!\text{if } \mathsf{leadByte} = \mathtt{0x01} \\ -> \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} +> \mathsf{H^{rcm,Sapling}_{rseed}}(\bot, \bot),&\!\!\!\text{if Sapling and } \mathsf{leadByte} = \mathtt{0x02} \\ +> \mathsf{ToScalar^{Orchard}}\big(\mathsf{PRF^{expand}_{rseed}}([\mathtt{0x05}] \,||\, \underline{\text{ρ}})\kern-0.1em\big),&\!\!\!\text{if Orchard and } \mathsf{leadByte} = \mathtt{0x02} \\ +> \mathsf{H^{rcm,Orchard}_{rseed}}(\mathsf{g}\star_{\mathsf{d}}, \mathsf{pk}\star_{\mathsf{d}}, \mathsf{v}, \underline{\text{ρ}}, \text{ψ}, \mathsf{AssetBase}\kern0.05em\star),&\!\!\!\text{if Orchard and } \mathsf{leadByte} = \mathtt{0x03} > \end{cases}$ <br> > $\hspace{1.0em}$ if $\mathsf{rcm} \geq r_{\mathbb{G}}$, return $\bot$ @@ -858,7 +869,7 @@ 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 -define $\mathsf{H^{rcm,protocol}}$. +define $\mathsf{H^{rcm,Sapling}}$ and $\mathsf{H^{rcm,Orchard}}$ respectively. For § 4.20.3, replace @@ -876,7 +887,9 @@ with > $\hspace{1.0em}$ let $\text{ψ} = \mathsf{H^{\text{ψ},Orchard}_{rseed}}(\underline{\text{ρ}})$ for Orchard or $\bot$ for Sapling <br> > $\hspace{1.0em}$ let $\mathsf{rcm} = \begin{cases} > \mathsf{LEOS2IP}_{256}(\mathsf{rseed}),&\!\!\!\text{if } \mathsf{leadByte} = \mathtt{0x01} \\ -> \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} +> \mathsf{H^{rcm,Sapling}_{rseed}}(\bot, \bot),&\!\!\!\text{if Sapling and } \mathsf{leadByte} = \mathtt{0x02} \\ +> \mathsf{ToScalar^{Orchard}}\big(\mathsf{PRF^{expand}_{rseed}}([\mathtt{0x05}] \,||\, \underline{\text{ρ}})\kern-0.1em\big),&\!\!\!\text{if Orchard and } \mathsf{leadByte} = \mathtt{0x02} \\ +> \mathsf{H^{rcm,Orchard}_{rseed}}(\mathsf{g}\star_{\mathsf{d}}, \mathsf{pk}\star_{\mathsf{d}}, \mathsf{v}, \underline{\text{ρ}}, \text{ψ}, \mathsf{AssetBase}\kern0.05em\star),&\!\!\!\text{if Orchard and } \mathsf{leadByte} = \mathtt{0x03} > \end{cases}$ <br> > $\hspace{1.0em}$ if $\mathsf{rcm} \geq r_{\mathbb{G}}$, return $\bot$ @@ -950,17 +963,12 @@ 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}}\big(\mathsf{PRF^{expand}_{rivk\_ext}}\big([\mathtt{0x83}] \,||\, \mathsf{I2LEOSP}_{256}(\mathsf{ak}) \,||\, \mathsf{I2LEOSP}_{256}(\mathsf{nk})\kern-0.1em\big)\kern-0.15em\big)$ -Import these definitions from § 4.7.3 ‘Sending Notes (Orchard)’ [^protocol-orchardsend], specialized to $\mathsf{leadByte} = \mathtt{0x03}$: +Import these definitions from § 4.7.3 ‘Sending Notes (Orchard)’ [^protocol-orchardsend]: -> 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) =$ +> Define $\mathsf{H^{rcm,Orchard}_{rseed}}(\mathsf{g}\star_{\mathsf{d}}, \mathsf{pk}\star_{\mathsf{d}}, \mathsf{v}, \underline{\text{ρ}}, \text{ψ}, \mathsf{AssetBase}\kern0.05em\star) =$ > $\mathsf{ToScalar^{Orchard}}\big(\mathsf{PRF^{expand}_{rseed}}(\mathsf{pre\_rcm})\kern-0.1em\big)$ > -> where $\mathsf{pre\_rcm} = \begin{cases} -> \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.05em\star),&\!\!\!\text{if } \mathsf{leadByte} = \mathtt{0x03} -> \end{cases}$ +> where $\mathsf{pre\_rcm} = [\mathtt{0x0B}] \,||\, \mathsf{LEBS2OSP}_{256}(\mathsf{g}\star_{\mathsf{d}}) \,||\, \mathsf{LEBS2OSP}_{256}(\mathsf{pk}\star_{\mathsf{d}}) \,||\, \mathsf{I2LEOSP}_{64}(\mathsf{v}) \,||\, \underline{\text{ρ}} \,||\, \mathsf{I2LEOSP}_{256}(\text{ψ}) \,||\, \mathsf{LEBS2OSP}_{256}(\mathsf{AssetBase}\kern0.05em\star)$. > > Define $\mathsf{H^{\text{ψ},Orchard}_{rseed}}(\underline{\text{ρ}}) = \mathsf{ToBase^{Orchard}}\big(\mathsf{PRF^{expand}_{rseed}}([\mathtt{0x09}] \,||\, \underline{\text{ρ}})\kern-0.1em\big)$. @@ -1124,16 +1132,16 @@ $\mathsf{noterepr} = (\mathsf{g}\star_{\mathsf{d}}, \mathsf{pk}\star_{\mathsf{d} as detailed in the [Specification] section. Specifically, when $\mathsf{leadByte} = \mathtt{0x03}$ we have: -$\hspace{2em}\mathsf{rcm} = \mathsf{H^{rcm}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr}) = \mathsf{ToScalar}(\mathsf{PRF^{expand}_{rseed}}(\mathsf{pre\_rcm}))$ +$\hspace{2em}\mathsf{rcm} = \mathsf{H^{rcm}_{rseed}}(\mathsf{noterepr}) = \mathsf{ToScalar}(\mathsf{PRF^{expand}_{rseed}}(\mathsf{pre\_rcm}))$ -$\text{where } \mathsf{pre\_rcm} = [\mathtt{0x0B}, \mathsf{leadByte}] \,||\, \mathsf{encode}(\mathsf{noterepr})$ +$\text{where } \mathsf{pre\_rcm} = [\mathtt{0x0B}] \,||\, \mathsf{encode}(\mathsf{noterepr})$ ### Informal security argument for binding of note commitments We can view the output of $\mathsf{NoteCommit_{rcm}}$ for -$\mathsf{notetuple} = (\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})$ +$\mathsf{notetuple} = (\mathsf{rseed}, \mathsf{noterepr})$ as the point addition of a randomization term -$[\mathsf{H^{rcm}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr})]\, \mathcal{R}$, +$[\mathsf{H^{rcm}_{rseed}}(\mathsf{noterepr})]\, \mathcal{R}$, and some other function of $\mathsf{notetuple}$. Without loss of generality, we can write that function as @@ -1143,7 +1151,7 @@ $\mathcal{C}_j = \mathcal{Q}(D) \text{ or } \mathcal{S}(j)$ used by [$\mathsf{HashToSinsimillaPoint}$](https://zips.z.cash/protocol/protocol.pdf#concretesinsemillahash) as $\mathcal{C}_j = [c_j]\, \mathcal{R}$ for some $c_j$. That is, the note commitment for $\mathsf{notetuple}$ is -$$[\mathsf{H^{rcm}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr}) + \mathsf{f}(\mathsf{notetuple})]\, \mathcal{R}.$$ +$$[\mathsf{H^{rcm}_{rseed}}(\mathsf{noterepr}) + \mathsf{f}(\mathsf{notetuple})]\, \mathcal{R}.$$ We will model $\mathsf{H^{rcm}}$ as a random oracle independent of $\mathsf{f}$ with uniform output on $\mathbb{F}_{r_{\mathbb{P}}}.$ This is reasonable because @@ -1168,11 +1176,11 @@ Pallas curve. > $r_{\mathbb{P}} \approx 2^{254}$ cannot introduce a problem. For each $\mathsf{H^{rcm}}$ oracle query the adversary chooses -$\mathsf{notetuple} = (\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})$ +$\mathsf{notetuple} = (\mathsf{rseed}, \mathsf{noterepr})$ and obtains a "random" -$\mathsf{rcm} = \mathsf{H^{rcm}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr})$. +$\mathsf{rcm} = \mathsf{H^{rcm}_{rseed}}(\mathsf{noterepr})$. -We have $\mathsf{cm}_x = \mathsf{Extract}_{\mathbb{P}}([\mathsf{H^{rcm}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr}) + \mathsf{f}(\mathsf{notetuple})]\, \mathcal{R})$. +We have $\mathsf{cm}_x = \mathsf{Extract}_{\mathbb{P}}([\mathsf{H^{rcm}_{rseed}}(\mathsf{noterepr}) + \mathsf{f}(\mathsf{notetuple})]\, \mathcal{R})$. Over all Pallas curve points $P$, the number of outputs of $\mathsf{Extract}_{\mathbb{P}}(P)$ is $(\mathbb{F}_{r_\mathbb{P}} + 1)/2 \approx 2^{253}$ — @@ -1241,7 +1249,7 @@ The above security argument means that provided we also check the uses of $\mathsf{H^{rcm}}$ and $\mathsf{H}^{\text{ψ}}$ in the post-quantum [Recovery Statement](#proposedrecoverystatement), Orchard note commitments can be considered binding on the note tuple -$(\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})$. +$(\mathsf{rseed}, \mathsf{noterepr})$. Note that the argument associated with [Theorem 5.4.4](https://zips.z.cash/protocol/protocol.pdf#thmsinsemillaex) @@ -1416,7 +1424,7 @@ $\mathsf{H^{rivk\_ext}}$, $\mathsf{H^{rivk\_legacy}}$, $\mathsf{H^{rivk\_int}}$, $\mathsf{H^{ask}}$, or $\mathsf{H^{nk}}$: $h$ depends only on fixed Sinsemilla bases and on $(\mathsf{ak}, \mathsf{nk})$. -By the same $y^2 = f(x)$ argument used in the Spendability proof +By the same $y^2 = Y(x)$ argument used in the Spendability proof (using § 5.4.9.7 for the $\mathsf{Extract}_{\mathbb{P}}$-style $x$-coordinate convention), a key-binding break implies $$h(\mathsf{ak}, \mathsf{nk}) + \mathsf{rivk} \equiv \pm\big(h(\mathsf{ak}', \mathsf{nk}') + \mathsf{rivk}'\big) \pmod{r_{\mathbb{P}}}.$$ @@ -1549,8 +1557,8 @@ $$\mathsf{DeriveNullifier_{nk}}(\text{ρ}, \text{ψ}, \mathsf{cm}) := Also recall from [Repairing note commitments] that we have -$$\mathsf{cm} = [\mathsf{H^{rcm}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr}) - + \mathsf{f}(\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})]\, \mathcal{R}.$$ +$$\mathsf{cm} = [\mathsf{H^{rcm}_{rseed}}(\mathsf{noterepr}) + + \mathsf{f}(\mathsf{rseed}, \mathsf{noterepr})]\, \mathcal{R}.$$ Let $K_{\kern-.08em\mathcal{R}}$ denote the discrete logarithm of $\mathcal{K}$ with respect to $\mathcal{R}$. This is well-defined and @@ -1561,19 +1569,19 @@ respect to it; and $\mathcal{K}$ is non-identity by construction. Recall that $\text{ψ}$ is determined by $\mathsf{rseed}$ via $\text{ψ} = \mathsf{H}^{\text{ψ}}_{\mathsf{rseed}}(\text{ρ})$. The nullifier corresponding to -$(\mathsf{nk}, \text{ρ}, \mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})$ +$(\mathsf{nk}, \text{ρ}, \mathsf{rseed}, \mathsf{noterepr})$ is then $$\mathsf{Extract}_{\mathbb{P}}\Big( \big[ \big((\mathsf{PRF^{nf}_{nk}}(\text{ρ}) + \text{ψ}) \bmod q_{\mathbb{P}}\big) \cdot K_{\kern-.08em\mathcal{R}} - + \mathsf{H^{rcm}_{rseed}}(\mathsf{leadByte}, \mathsf{noterepr}) + \mathsf{f}(\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr}) + + \mathsf{H^{rcm}_{rseed}}(\mathsf{noterepr}) + \mathsf{f}(\mathsf{rseed}, \mathsf{noterepr}) \big]\, \mathcal{R} \Big).$$ We model $\mathsf{H^{rcm}}$ as a random oracle with output uniform on $\mathbb{F}_{r_{\mathbb{P}}}$. The functions $\mathsf{f}$, $\mathsf{H}^{\text{ψ}}$, and $\mathsf{PRF^{nf}}$ are deterministic -functions of $\mathsf{notetuple} = (\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})$ +functions of $\mathsf{notetuple} = (\mathsf{rseed}, \mathsf{noterepr})$ that **do not query $\mathsf{H^{rcm}}$**: $\mathsf{f}(\mathsf{notetuple})$ is the Sinsemilla-base lift; $\mathsf{H}^{\text{ψ}}$ and $\mathsf{PRF^{nf}}$ are conventional hash functions. @@ -1609,14 +1617,14 @@ The bound depends only on $q_{\mathsf{rcm}}$ and on $\varepsilon_{\mathsf{kb}}(\mathcal{A}, q_{\mathsf{kb}})$, not on running time. -The components $\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr}$ +The components $\mathsf{rseed}, \mathsf{noterepr}$ are fields of $\mathsf{notetuple}$ by definition; and $\text{ρ}$, $\mathsf{g_d}$, $\mathsf{pk_d}$, and $\text{ψ}$ are fields of $\mathsf{noterepr}$, hence of $\mathsf{notetuple}$. **$\mathsf{ivk}$-pinning lemma.** <a id="lemma-ivk-pinning"></a> For any valid Recovery Statement witness $w$ with -$\mathsf{notetuple} = (\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})$, +$\mathsf{notetuple} = (\mathsf{rseed}, \mathsf{noterepr})$, the value $\mathsf{ivk} = \log_{\mathsf{g_d}}(\mathsf{pk_d})$ is well-defined, since $\mathsf{g_d} \neq \mathcal{O}_{\mathbb{P}}$ on the prime-order Pallas curve and @@ -1635,7 +1643,7 @@ $\mathsf{notetuple}_i$ by the $\mathsf{ivk}$-pinning lemma; and $\text{ρ}_i$ is a field of $\mathsf{notetuple}_i$. The argument here covers nullifier-binding — it argues that $\mathsf{nf}$ -binds the note tuple $(\mathsf{rseed}, \mathsf{leadByte}, \mathsf{noterepr})$ +binds the note tuple $(\mathsf{rseed}, \mathsf{noterepr})$ under $\mathsf{H^{rcm}}$ modelled as a random oracle and the [key-binding theorem](#thm-key-binding-rom). @@ -1652,7 +1660,7 @@ satisfying: <a id="thm-spendability-distinct"></a>**Distinct note tuples** : the $\mathsf{H^{rcm}}$-input tuples - $\mathsf{notetuple}_i := (\mathsf{rseed}_i, \mathsf{leadByte}_i, \mathsf{noterepr}_i)$ + $\mathsf{notetuple}_i := (\mathsf{rseed}_i, \mathsf{noterepr}_i)$ satisfy $\mathsf{notetuple}_1 \neq \mathsf{notetuple}_2$. <a id="thm-spendability-collide"></a>**Colliding nullifiers** @@ -1706,7 +1714,7 @@ $F_i := \mathsf{F}(\mathsf{notetuple}_i)$ for $i \in \{1, 2\}$. $\mathsf{Extract}_{\mathbb{P}}$ (§ 5.4.9.7 'Coordinate Extractor for Pallas' [^protocol-concreteextractorpallas]) is the $x$-coordinate of its argument for non-identity points, with the identity mapping to $0$. -Since Pallas has the form $y^2 = f(x)$ and no Pallas point has +Since Pallas has the form $y^2 = Y(x)$ and no Pallas point has $x$-coordinate $0$, the collision $\mathsf{nf}_1 = \mathsf{nf}_2$ holds iff $F_1 \equiv \pm F_2 \pmod{r_{\mathbb{P}}}$. From a2d369c8daa93842d3fe2a191358461597e77cab Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Sat, 16 May 2026 05:45:19 +0100 Subject: [PATCH 067/115] ZIP 2005: "FROST multisignatures" -> "FROST threshold multisignatures" A multisignature scheme is a signature scheme that supports signing by multiple parties with public key aggregation, but does not necessarily support signing by a threshold of parties. Signed-off-by: Daira-Emma Hopwood <daira@jacaranda.org> --- zips/zip-2005.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index 38ac3de6c..5d4873c27 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -133,9 +133,9 @@ as changes necessary to implement Memo Bundles [^zip-0231] and/or ZSAs [^zip-022 discrete-log-breaking and quantum adversaries. * No particular choice of post-quantum proving system or commitment tree hash should be assumed for that alternate protocol. -* The proposed scheme should be fully compatible with FROST - multisignatures [^zip-0312], hardware wallets, and the combination - of both. +* The proposed scheme should be fully compatible with FROST threshold + multisignatures [^zip-0312], hardware wallets, and the combination of + both. * The proposed scheme should not require regeneration of existing non-multisignature keys or addresses. * The changes made to the pre-quantum protocol should not cause a @@ -143,8 +143,8 @@ as changes necessary to implement Memo Bundles [^zip-0231] and/or ZSAs [^zip-022 against any given adversary class, or require significant re-analysis of that protocol's pre-quantum security. * The Recovery Protocol should ensure no loss of security against - pre-quantum adversaries — including when FROST multisignatures and/or - hardware wallets are used. + pre-quantum adversaries — including when FROST threshold multisignatures + and/or hardware wallets are used. * Recovery of funds from hardware wallets that support this protocol should not require exposing the pre-quantum spend authorizing key $\mathsf{ask}$ to theft. @@ -384,8 +384,8 @@ Note that a quantum adversary may be able to steal the funds with only access to $\mathsf{qsk}$, which is held by every participant (see below for more detail on [Key storage options](#keystorageoptionsandanalysis)). Therefore, it is RECOMMENDED that as soon as a fully post-quantum protocol -that supports multisignatures is available, all funds held under FROST keys -be transferred into that protocol's shielded pool. +that supports threshold multisignatures is available, all funds held under +FROST keys be transferred into that protocol's shielded pool. ## Usage with hardware wallets From 04db896880e0c788ff8023c70da0bc507876a894 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Sat, 16 May 2026 08:36:56 +0100 Subject: [PATCH 068/115] Withdraw ZIP 230. Signed-off-by: Daira-Emma Hopwood <daira@jacaranda.org> --- README.rst | 4 ++-- zips/zip-0230.rst | 12 ++++++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/README.rst b/README.rst index 29b16ff90..76a82e575 100644 --- a/README.rst +++ b/README.rst @@ -176,7 +176,6 @@ written. <tr> <td>226</td> <td class="left"><a href="zips/zip-0226.rst">Transfer and Burn of Zcash Shielded Assets</a></td> <td>Draft</td> <td class="left"><a href="https://github.com/zcash/zips/issues/618">zips#618</a></td> <tr> <td>227</td> <td class="left"><a href="zips/zip-0227.rst">Issuance of Zcash Shielded Assets</a></td> <td>Draft</td> <td class="left"><a href="https://github.com/zcash/zips/issues/618">zips#618</a></td> <tr> <td><span class="reserved">228</span></td> <td class="left"><a class="reserved" href="zips/zip-0228.rst">Asset Swaps for Zcash Shielded Assets</a></td> <td>Reserved</td> <td class="left"><a href="https://github.com/zcash/zips/issues/776">zips#776</a></td> - <tr> <td>230</td> <td class="left"><a href="zips/zip-0230.rst">Version 6 Transaction Format</a></td> <td>Draft</td> <td class="left"><a href="https://github.com/zcash/zips/issues/686">zips#686</a></td> <tr> <td>231</td> <td class="left"><a href="zips/zip-0231.md">Memo Bundles</a></td> <td>Draft</td> <td class="left"><a href="https://github.com/zcash/zips/issues/627">zips#627</a></td> <tr> <td>233</td> <td class="left"><a href="zips/zip-0233.md">Network Sustainability Mechanism: Removing Funds From Circulation</a></td> <td>Draft</td> <td class="left"><a href="https://github.com/zcash/zips/issues/922">zips#922</a></td> <tr> <td>234</td> <td class="left"><a href="zips/zip-0234.md">Network Sustainability Mechanism: Issuance Smoothing</a></td> <td>Draft</td> <td class="left"><a href="https://github.com/zcash/zips/issues/923">zips#923</a></td> @@ -250,6 +249,7 @@ Withdrawn, Rejected, or Obsolete ZIPs <tr> <th>ZIP</th> <th>Title</th> <th>Status</th> </tr> <tr> <td><strike>210</strike></td> <td class="left"><strike><a href="zips/zip-0210.rst">Sapling Anchor Deduplication within Transactions</a></strike></td> <td>Withdrawn</td> <tr> <td><strike>220</strike></td> <td class="left"><strike><a href="zips/zip-0220.rst">Zcash Shielded Assets</a></strike></td> <td>Withdrawn</td> + <tr> <td><strike>230</strike></td> <td class="left"><strike><a href="zips/zip-0230.rst">Withdrawn Version 6 Transaction Format</a></strike></td> <td>Withdrawn</td> <tr> <td><strike>254</strike></td> <td class="left"><strike><a href="zips/zip-0254.md">Deployment of the NU7 Network Upgrade (Withdrawn)</a></strike></td> <td>Withdrawn</td> <tr> <td><strike>313</strike></td> <td class="left"><strike><a href="zips/zip-0313.rst">Reduce Conventional Transaction Fee to 1000 zatoshis</a></strike></td> <td>Obsolete</td> <tr> <td><strike>1001</strike></td> <td class="left"><strike><a href="zips/zip-1001.rst">Keep the Block Distribution as Initially Defined — 90% to Miners</a></strike></td> <td>Obsolete</td> @@ -316,7 +316,7 @@ Index of ZIPs <tr> <td>226</td> <td class="left"><a href="zips/zip-0226.rst">Transfer and Burn of Zcash Shielded Assets</a></td> <td>Draft</td> <tr> <td>227</td> <td class="left"><a href="zips/zip-0227.rst">Issuance of Zcash Shielded Assets</a></td> <td>Draft</td> <tr> <td><span class="reserved">228</span></td> <td class="left"><a class="reserved" href="zips/zip-0228.rst">Asset Swaps for Zcash Shielded Assets</a></td> <td>Reserved</td> - <tr> <td>230</td> <td class="left"><a href="zips/zip-0230.rst">Version 6 Transaction Format</a></td> <td>Draft</td> + <tr> <td><strike>230</strike></td> <td class="left"><strike><a href="zips/zip-0230.rst">Withdrawn Version 6 Transaction Format</a></strike></td> <td>Withdrawn</td> <tr> <td>231</td> <td class="left"><a href="zips/zip-0231.md">Memo Bundles</a></td> <td>Draft</td> <tr> <td>233</td> <td class="left"><a href="zips/zip-0233.md">Network Sustainability Mechanism: Removing Funds From Circulation</a></td> <td>Draft</td> <tr> <td>234</td> <td class="left"><a href="zips/zip-0234.md">Network Sustainability Mechanism: Issuance Smoothing</a></td> <td>Draft</td> diff --git a/zips/zip-0230.rst b/zips/zip-0230.rst index 7ad1dcf3a..a036fd218 100644 --- a/zips/zip-0230.rst +++ b/zips/zip-0230.rst @@ -1,7 +1,7 @@ :: ZIP: 230 - Title: Version 6 Transaction Format + Title: Withdrawn Version 6 Transaction Format Owners: Daira-Emma Hopwood <daira@jacaranda.org> Jack Grigg <thestr4d@gmail.com> Sean Bowe <ewillbefull@gmail.com> @@ -11,7 +11,7 @@ Original-Authors: Greg Pfeil Deirdre Connolly Credits: Ying Tong Lai - Status: Draft + Status: Withdrawn Category: Consensus Created: 2023-04-18 License: MIT @@ -35,6 +35,10 @@ The character § is used when referring to sections of the Zcash Protocol Specif Abstract ======== +.. warning:: + This ZIP has been obsoleted by ZIP 248 [#zip-0248]_, and will not be deployed. Transaction + version number 6 is now defined by ZIP 248. + This proposal defines a new Zcash peer-to-peer transaction format, which supports the changes being deployed in Network Upgrade 7 [#draft-arya-deploy-nu7]_. It follows the same design pattern as the v5 transaction format [#zip-0225]_. @@ -46,7 +50,7 @@ Motivation The OrchardZSA protocol requires serialized data elements that are distinct from any previous Zcash transaction. Since ZIP 244 was activated in NU5, the v5 and later serialized transaction formats are not consensus-critical. -Thus, this ZIP defines format that can easily accommodate future extensions, +Thus, this ZIP defines a format that can easily accommodate future extensions, where elements or a given pool are kept separate. @@ -720,5 +724,5 @@ References .. [#zip-0301] `ZIP 301: Zcash Stratum Protocol <zip-0301.rst>`_ .. [#zip-2002-motivation] `ZIP 231: Explicit Fees — Motivation <zip-2002.rst#motivation>`_ .. [#zip-2005] `ZIP 2005: Quantum Recoverability <zip-2005.md>`_ -.. [#zip-2005-security-analysis] `ZIP 2005: Quantum Recoverability — Security Analysis <zip-2005.md#security-analysis>`_ +.. [#zip-2005-security-analysis] `ZIP 2005: Quantum Recoverability — Security Analysis <zip-2005.md#securityanalysis>`_ .. [#draft-arya-deploy-nu7] `draft-arya-deploy-nu7: Deployment of the NU7 Network Upgrade <draft-arya-deploy-nu7.md>`_ From 8418662d138917c573a8a7b4ec2e58601d435423 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Sat, 16 May 2026 08:38:02 +0100 Subject: [PATCH 069/115] ZIPs 226, 230, and 231: remove references to note plaintext lead byte 0x03. Signed-off-by: Daira-Emma Hopwood <daira@jacaranda.org> --- zips/zip-0226.rst | 12 +++++------- zips/zip-0230.rst | 19 ++++++++++++------- zips/zip-0231.md | 7 ++++++- 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/zips/zip-0226.rst b/zips/zip-0226.rst index e05cc8ef3..4c35334a8 100644 --- a/zips/zip-0226.rst +++ b/zips/zip-0226.rst @@ -42,7 +42,7 @@ Abstract This ZIP (ZIP 226) proposes the Orchard Zcash Shielded Assets (OrchardZSA) protocol, in conjunction with ZIP 227 [#zip-0227]_. The OrchardZSA protocol is an extension of the Orchard protocol that enables the issuance, transfer and burn of custom Assets on the Zcash chain. The issuance of such Assets is defined in ZIP 227 [#zip-0227]_, while the transfer and burn of such Assets is defined in this ZIP (ZIP 226). While the proposed OrchardZSA protocol is a modification to the Orchard protocol, it has been designed with adaptation to possible future shielded protocols in mind. -This ZIP is defined relative to the Zcash protocol with the changes specified in ZIP 2005 [#zip-2005]_ applied. ZIP 2005 (Orchard Quantum Recoverability) is expected to deploy before any ZSA activation; the references in this document to $\mathsf{H^{rcm,Orchard}}$, $\mathsf{H^{\text{ψ},Orchard}}$, recoverable note plaintexts (lead byte $\mathtt{0x03}$), and related constructs are to be interpreted as defined by ZIP 2005's modifications to the protocol specification. +This ZIP is defined relative to the Zcash protocol with the changes specified in ZIP 2005 [#zip-2005]_ applied. ZIP 2005 (Orchard Quantum Recoverability) is expected to deploy before any ZSA activation; the references in this document to $\mathsf{H^{rcm,Orchard}}$, $\mathsf{H^{\text{ψ},Orchard}}$, recoverable note plaintexts, and related constructs are to be interpreted as defined by ZIP 2005's modifications to the protocol specification. Motivation ========== @@ -159,7 +159,7 @@ The nullifier is generated in the same manner as in the Orchard protocol §4.16 The OrchardZSA note plaintext also includes the Asset Base $\mathsf{asset\_base} : \mathbb{B}^{[\ell_{\mathbb{P}}]}$ in addition to the components in the Orchard note plaintext [#protocol-notept]_. The explicit encoding of the note plaintext is provided in ZIP 230 [#zip-0230-orchard-note-plaintext]_. -When § 4.7.3 'Sending Notes (Orchard)' [#protocol-orchardsend]_ or § 4.8.3 'Dummy Notes (Orchard)' [#protocol-orcharddummynotes]_ are invoked directly or indirectly in the computation of $\text{ρ}$ and $\text{ψ}$ for an OrchardZSA note, $\mathsf{leadByte}$ MUST be set to $\mathtt{0x03}$. +When § 4.7.3 'Sending Notes (Orchard)' [#protocol-orchardsend]_ or § 4.8.3 'Dummy Notes (Orchard)' [#protocol-orcharddummynotes]_ are invoked directly or indirectly in the computation of $\text{ρ}$ and $\text{ψ}$ for an OrchardZSA note, $\mathsf{leadByte}$ MUST be set to {{ZSALEADBYTE}}. The explicit order of addition of the note commitments to the note commitment tree is specified in ZIP 227 [#zip-0227-note-commitment-order]_. @@ -392,11 +392,9 @@ The following requirements on wallets are specified and motivated in ZIP 230 ZEC asset. For other consequences see ZIP 230. * *All* wallets should be ready to receive funds in outputs of v6 transactions as soon - as ZSAs activate — in particular to support decrypting recoverable note plaintexts - (lead byte $\mathtt{0x03}$) [#zip-0230-note-plaintexts]_. The consequence of not doing so would - be that funds sent to Orchard addresses of a wallet without this support could be - temporarily inaccessible, until the wallet is upgraded to fully support v6 and to - rescan outputs since v6 activation. + as ZSAs activate. The consequence of not doing so would be that funds sent to Orchard + addresses of a wallet without this support could be 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]_ ------------------------------------------------------ diff --git a/zips/zip-0230.rst b/zips/zip-0230.rst index a036fd218..e5c016b1e 100644 --- a/zips/zip-0230.rst +++ b/zips/zip-0230.rst @@ -39,6 +39,11 @@ Abstract This ZIP has been obsoleted by ZIP 248 [#zip-0248]_, and will not be deployed. Transaction version number 6 is now defined by ZIP 248. + Occurrences of the note plaintext lead byte constant it introduced (originally $\mathtt{0x03}$) + have been changed to "{{LEADBYTE}}", to clarify that this ZIP does not reserve that lead byte + value, and to avoid confusion with the different specification of lead byte $\mathtt{0x03}$ in + ZIP 2005 [#zip-2005]_. + This proposal defines a new Zcash peer-to-peer transaction format, which supports the changes being deployed in Network Upgrade 7 [#draft-arya-deploy-nu7]_. It follows the same design pattern as the v5 transaction format [#zip-0225]_. @@ -491,11 +496,11 @@ An issuance note description, ``IssueNoteDescription`` contains the following fi Note Plaintexts --------------- -New note plaintext formats using lead byte $\mathtt{0x03}$ are introduced for +New note plaintext formats using lead byte {{LEADBYTE}} are introduced for Sapling and Orchard, in order to support memo bundles and (for Orchard) ZSAs and quantum recoverability. -The $\mathsf{leadByte}$ MUST be $\mathtt{0x03}$ for all note plaintexts in v6 +The $\mathsf{leadByte}$ MUST be {{LEADBYTE}} for all note plaintexts in v6 transactions. Sapling Note Plaintext @@ -550,8 +555,8 @@ The encodings of $\mathsf{d}$, $\mathsf{v}$, and $\mathsf{rseed}$ remain unchang Non-normative note: The *use* of the $\mathsf{rseed}$ in Orchard note decryption changes, but its type and encoding do not. -Rationale for requiring the lead byte to be 0x03 in v6 -`````````````````````````````````````````````````````` +Rationale for requiring the lead byte to be {{LEADBYTE}} in v6 +`````````````````````````````````````````````````````````````` It was decided to synchronize the changes to note encryption required for quantum recoverability, ZSA support, and memo bundles with a change to the @@ -636,7 +641,7 @@ Support for receiving funds in v6 transactions Zcash wallets MUST support parsing and processing v6 transactions by the time they are allowed on the network (scheduled for NU7 activation). This includes -detecting and decrypting lead-byte $\mathtt{0x03}$ note plaintexts and memo +detecting and decrypting lead-byte {{LEADBYTE}} note plaintexts and memo bundles. The necessary changes to note decryption are specified in ZIP 231 [#zip-0231]_, @@ -652,7 +657,7 @@ once that support is added. Rationale for being ready to receive v6 transactions at their activation ```````````````````````````````````````````````````````````````````````` -Note plaintexts with lead byte $\mathtt{0x03}$, which are required for Orchard +Note plaintexts with lead byte {{LEADBYTE}}, which are required for Orchard notes in v6 transactions, can be sent to any Orchard address. These notes use a different computation of $\mathsf{rcm}$ and $\text{ψ}$ from @@ -664,7 +669,7 @@ attempting to non-conformantly use the note decryption algorithm for lead byte $\mathtt{0x02}$ would compute a different note commitment $\mathsf{cm}_x$ and would reject the note. -If wallets do not support v6 transactions and lead-byte $\mathtt{0x03}$ note +If wallets do not support v6 transactions and lead-byte {{LEADBYTE}} note decryption immediately, then funds may be sent to them that they cannot receive. This affects both the existing Orchard functionality, and receiving non-native ZSA assets. diff --git a/zips/zip-0231.md b/zips/zip-0231.md index 45c8e4a0a..f5b05b61f 100644 --- a/zips/zip-0231.md +++ b/zips/zip-0231.md @@ -487,7 +487,7 @@ In § 5.5 ‘Encodings of Note Plaintexts and Memo Fields’ [^protocol-notepten > > $\begin{array}{|c|c|c|c|c|} \hline \raisebox{0.6ex}{\mathstrut} \text{8-bit } \mathsf{leadByte} & \text{88-bit } \mathsf{d} & \text{64-bit } \mathsf{v} & \text{256-bit } \mathsf{rseed} & \text{32-byte } \mathsf{K^{memo}} \\\hline \end{array}$ > - > * A byte 0x03, indicating this version of the encoding of a v6-onward + > * A byte {{MBLEADBYTE}}, indicating this version of the encoding of a v6-onward > Sapling or Orchard note plaintext. > * 11 bytes specifying $\mathsf{d}$. > * 8 bytes specifying $\mathsf{v}$. @@ -583,6 +583,11 @@ synchronization. TBD +## Note plaintext lead byte assignment + +The lead byte to be used for this proposal, denoted as {{MBLEADBYTE}} above, has +not yet been assigned. + # Rationale From 3f2652d2c03c45f778c7978396e4dd9ee4b111ab Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Sat, 16 May 2026 08:43:17 +0100 Subject: [PATCH 070/115] ZIP 2005: Deployment changes Signed-off-by: Daira-Emma Hopwood <daira@jacaranda.org> --- zips/zip-2005.md | 133 ++++++++++++++++++++++++++++------------------- 1 file changed, 79 insertions(+), 54 deletions(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index 5d4873c27..3c4b65130 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -48,8 +48,7 @@ protocol after the deployment of ZSAs. The terms "recoverable note" and "recoverable note plaintext" refer to a note or note plaintext that was created according to this proposal. As -initially deployed, these are necessarily Orchard or OrchardZSA notes or -note plaintexts. +initially deployed, these are necessarily Orchard notes or note plaintexts. The term "Recovery Protocol" refers to a potential new shielded protocol that would allow recovery of funds held in recoverable Orchard[ZSA] notes. @@ -170,12 +169,9 @@ as changes necessary to implement Memo Bundles [^zip-0231] and/or ZSAs [^zip-022 This subsection and the flow diagram below are non-normative. -The Quantum Recoverability proposal was originally designed to be -deployed alongside ZSAs [^zip-0226] [^zip-0227] and memo bundles -[^zip-0231]. Whether or not that is still the case, we retain the -same approach of defining a new note plaintext format, with lead byte -$\mathtt{0x03}.$ The $\mathsf{pre\_rcm}$ value is computed differently -for this new format, by including all of the note fields in +This proposal defines a new note plaintext format for Orchard notes, +with lead byte $\mathtt{0x03}.$ The $\mathsf{pre\_rcm}$ value is computed +differently for this new format, by including all of the note fields in $\mathsf{pre\_rcm}$. This means that an adversary constrained to treat the PRF used to derive $\mathsf{rcm}$ from $\mathsf{pre\_rcm}$ as a random oracle, could not vary any note field without producing a @@ -307,17 +303,6 @@ graph BT # Specification -## Usage with Zcash Shielded Assets - -This proposal has been designed to activate either prior to, or at the same -time as, 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 @@ -527,13 +512,17 @@ from the seed phrase (with or without SLIP 39 Shamir backup [^slip-0039]). A deployment that does not use ZIP 32 is responsible for the security of its own backup arrangements. +## Usage with other proposals requiring note plaintext format changes + +This proposal was originally designed to be deployed alongside ZSAs [^zip-0226] +[^zip-0227] and memo bundles [^zip-0231], which also defined a new note +plaintext format. Since this proposal now defines lead byte $\mathtt{0x03}$, +those proposals will need to use a new lead byte value or values. + ## 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 as of February 2026. If other -changes for v6 transactions (memo bundles [^zip-0231], ZSAs [^zip-0226] -[^zip-0227]) are deployed simultaneously, these changes will need to be -merged with theirs. +specification, and to the contents of ZIPs as of May 2026. ### Changes to the Protocol Specification @@ -550,17 +539,51 @@ Replace the paragraph with +> Let the constant $\mathsf{ZIP2005ActivationHeight}$ be as defined in +> [[ZIP 2005, Deployment]](#deployment). +> > Define $\mathsf{allowedLeadBytes^{protocol}}(\mathsf{height}, \mathsf{txVersion}) =$ > $\hspace{2em} \begin{cases} > \{ \mathtt{0x01} \},&\!\!\!\text{if } \mathsf{height} < \mathsf{CanopyActivationHeight} \\ > \{ \mathtt{0x01}, \mathtt{0x02} \},&\!\!\!\text{if } \mathsf{CanopyActivationHeight} \leq \mathsf{height} < \mathsf{CanopyActivationHeight} + \mathsf{ZIP212GracePeriod} \\ -> \{ \mathtt{0x02} \},&\!\!\!\text{if } \mathsf{CanopyActivationHeight} + \mathsf{ZIP212GracePeriod} \leq \mathsf{height} \text{ and } \mathsf{txVersion} < 6 \\ +> \{ \mathtt{0x02} \},&\!\!\!\text{if } \mathsf{CanopyActivationHeight} + \mathsf{ZIP212GracePeriod} \leq \mathsf{height} \text{ and } \\ +> &\;\; (\mathsf{height} < \mathsf{ZIP2005ActivationHeight} \text{ or } \mathsf{protocol} \neq \mathsf{Orchard}) \\ +> \{ \mathtt{0x02}, \mathtt{0x03} \},&\!\!\!\text{if } \mathsf{ZIP2005ActivationHeight} \leq \mathsf{height} \text{ and } \mathsf{protocol} = \mathsf{Orchard} \text{ and } \mathsf{txVersion} < 6 \\ > \{ \mathtt{0x03} \},&\!\!\!\text{otherwise.} > \end{cases}$ -and delete "or $\mathsf{txVersion}$" from "It is intentional that the -definition of $\mathsf{allowedLeadBytes}$ does not currently depend on -$\mathsf{protocol}$ or $\mathsf{txVersion}$." +Replace + +> Senders SHOULD choose the highest note plaintext lead byte allowed under this +> condition. + +with + +> $\mathsf{ZIP2005ActivationHeight}$ specifies the first block height at which +> recoverable note plaintexts with lead byte $\mathtt{0x03}$ are allowed to +> occur in Orchard outputs. Orchard note plaintexts sent to *wallet-internal* +> addresses SHOULD use lead byte $\mathtt{0x03}$ starting from this height. +> Orchard note plaintexts in v5 transactions sent to *external* addresses +> SHOULD use lead byte $\mathtt{0x02}$ until wallet support for receiving note +> plaintexts with lead byte $\mathtt{0x03}$ is widespread in the Zcash +> ecosystem. +> +> In other cases, senders SHOULD choose the highest note plaintext lead byte +> allowed according to $\mathsf{allowedLeadBytes}.$ + +Delete the non-normative note: + +> * It is intentional that the definition of $\mathsf{allowedLeadBytes}$ does +> not currently depend on $\mathsf{protocol}$ or $\mathsf{txVersion}.$ It +> might do so in future. + +Add the non-normative note: + +> * For Orchard note plaintexts sent in v6 transactions [^zip-0248], the only +> allowed lead byte value is $\mathtt{0x03}.$ + +It is assumed for these changes that v6 transactions will not activate before +$\mathsf{ZIP2005ActivationHeight}$. #### § 4.1.2 ‘Pseudo Random Functions’ @@ -1760,24 +1783,27 @@ have not yet been verified. TBD: explain that such attacks can break Balance and Spendability, including Spendability for transactions after switching to the Recovery Protocol. -Note that with [Deployment](#deployment) option 2 (deploying at the same time as -v6 transactions), we can identify the precise set of note commitments for -recoverable (lead byte $\mathtt{0x03}$) Orchard notes, since they are exactly -the commitments for Orchard outputs of v6 transactions. However, we cannot -identify the precise set of nullifiers for recoverable notes: an Orchard action -in a v6 transaction could be spending either a recoverable or non-recoverable -note, and their nullifier sets are indistinguishable. +Note that we can precisely identify the set of note commitments for recoverable +Orchard notes in v6 transactions, even if we cannot decrypt them, since only +recoverable notes are allowed in that case. However, Orchard notes in v5 +transactions after $\mathsf{ZIP2005ActivationHeight}$ could be either +recoverable or not. + +We cannot identify the precise set of nullifiers for recoverable notes: an +Orchard action in a v6 transaction could be spending either a recoverable or +non-recoverable note, and their nullifier sets are indistinguishable. On the other hand, within the Recovery Statement we know that the note being spent is recoverable. # Deployment -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’ [^protocol-orchardkeycomponents]. +Let $\mathsf{ZIP2005ActivationHeight}$ be {{TBD}}. + +As far as the author of this ZIP is 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’ [^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 @@ -1791,26 +1817,23 @@ 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. -There are two options for deployment: +Two options were considered for deployment: -1. Deploy this change prior to the next network upgrade. This would - optimize time-to-deployment. An activation height is still needed - so that wallets do not start sending recoverable note plaintexts - before the receiving wallet can have been expected to upgrade. +1. Deploy this change prior to the next network upgrade. This optimizes + time-to-deployment. An activation height is still needed, in order to + identify a height from which wallets must re-scan if they are missing + recoverable notes due to late deployment. 2. Deploy this change at the same time as the next network upgrade (NU7), at the same time as v6 transactions. -With either option, it is proposed to enforce this change with v6 -transactions. That is, every Orchard output of a v6-onward transaction -will be a recoverable note. This implies that when the pre-quantum -protocol is turned off, v5 and earlier outputs will no longer be spendable. +With either option, it is proposed to enforce this change with v6 transactions. +That is, every Orchard output of a v6-onward transaction will be a recoverable +note. -Deploying via a transaction-version bump (rather than as a soft addition -within v5) reduces the risk of the kind of difficulties that occurred with -[ZIP 212](https://zips.z.cash/zip-0212), where some wallets were following -the old protocol after the Canopy upgrade and sending non-conformant note -plaintexts. If memo bundles or ZSAs are deployed simultaneously, those -changes share the same version-bump signal. +This ZIP currently reflects the first option. The risk of some wallets +not having deployed support for receiving the new note plaintext format +is mitigated by initially only using that format for note plaintexts sent +to wallet-internal addresses. When a compliant wallet receives an Orchard note with lead byte $\mathtt{0x02}$, the associated funds are not recoverable and need to be @@ -1871,6 +1894,8 @@ manipulate the note selection algorithm to some extent. [^zip-0231]: [ZIP 231: Memo Bundles](zip-0231.rst) +[^zip-0248]: [ZIP 248: Extensible Transaction Format (PR: zcash/zips#1156)](https://github.com/zcash/zips/pull/1156) + [^zip-0312]: [ZIP 312: FROST for Spend Authorization Multisignatures](zip-0312.rst) [^zip-0312-key-generation]: [ZIP 312: FROST for Spend Authorization Multisignatures — Key Generation](zip-0312.rst#key-generation) From 709de5e5c0a3b5f940a212d153912194645407cf Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Sat, 16 May 2026 12:03:03 +0100 Subject: [PATCH 071/115] ZIP 2005: Add "Proactive movement of funds to recoverable notes" section. Signed-off-by: Daira-Emma Hopwood <daira@jacaranda.org> --- zips/zip-2005.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index 3c4b65130..276986943 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -303,6 +303,18 @@ graph BT # Specification +## Proactive movement of funds to recoverable notes + +Once this proposal is deployed, wallets SHOULD move all of the funds they +control (including transparent, Sprout, and Sapling funds) into recoverable +Orchard notes as soon as practically possible. This does not depend on support +from other wallets for receiving recoverable notes, because wallet-internal +addresses can be used. + +Non-recoverable funds may be received after existing funds have been made +recoverable. Wallets SHOULD therefore treat the movement of funds to +recoverable notes as an ongoing process. + ## Usage with FROST When generating Orchard keys for FROST, $\mathsf{ak}$ will be derived jointly From c523c88a03bb7346b86e26fdcd89175d8531fcb6 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Sat, 16 May 2026 12:25:40 +0100 Subject: [PATCH 072/115] ZIP 2005: Drop AssetBase from H^{rcm,Orchard}. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 0x03 note plaintext format now does not include AssetBase. Drop AssetBase from: * the H^{rcm,Orchard} definition (signature and pre_rcm body) in §4.7.3 and in the specialised import in the Spendability proof; * the Sending Notes (Orchard) and Dummy Notes (Orchard) procedures: drop the "Let AssetBase = V^Orchard" preludes, the "AssetBase★ = ..." inline-let lines, and AssetBase★ from the H^{rcm,Orchard} call sites; also drop AssetBase★ from "use ... in the inputs to NoteCommit"; * the Decryption procedures (§4.20.2 and §4.20.3): drop the "Let AssetBase = V^Orchard" prelude, AssetBase★ from the inline let, and from the H^{rcm,Orchard} call sites; * the Recovery Statement witness's noterepr; * the rationale's "Repairing note commitments" noterepr; * the flow diagram (drop AssetBase from the "v, AssetBase" pre_rcm input). Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --- zips/zip-2005.md | 50 ++++++++++++++++-------------------------------- 1 file changed, 16 insertions(+), 34 deletions(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index 276986943..8318ae728 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -272,7 +272,7 @@ graph BT ivk --> ivkmul rseed --> Hpsi[H<sup>ψ</sup>]:::func rho --> Hpsi - v([v, AssetBase]) ==> pre_rcm([pre_rcm]) + v([#8239;v#8239;]) ==> pre_rcm([pre_rcm]) pkd ====> pre_rcm gd ==> pre_rcm psi ===> pre_rcm @@ -748,17 +748,12 @@ Replace the lines deriving $\mathsf{rcm}$ and $\mathsf{esk}$ with #### § 4.7.3 ‘Sending Notes (Orchard)’ -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)’. - Add before "For each Action description": -> Define $\mathsf{H^{rcm,Orchard}_{rseed}}(\mathsf{g}\star_{\mathsf{d}}, \mathsf{pk}\star_{\mathsf{d}}, \mathsf{v}, \underline{\text{ρ}}, \text{ψ}, \mathsf{AssetBase}\kern0.05em\star) =$ +> Define $\mathsf{H^{rcm,Orchard}_{rseed}}(\mathsf{g}\star_{\mathsf{d}}, \mathsf{pk}\star_{\mathsf{d}}, \mathsf{v}, \underline{\text{ρ}}, \text{ψ}) =$ > $\mathsf{ToScalar^{Orchard}}\big(\mathsf{PRF^{expand}_{rseed}}(\mathsf{pre\_rcm})\kern-0.1em\big)$ > -> where $\mathsf{pre\_rcm} = [\mathtt{0x0B}] \,||\, \mathsf{LEBS2OSP}_{256}(\mathsf{g}\star_{\mathsf{d}}) \,||\, \mathsf{LEBS2OSP}_{256}(\mathsf{pk}\star_{\mathsf{d}}) \,||\, \mathsf{I2LEOSP}_{64}(\mathsf{v}) \,||\, \underline{\text{ρ}} \,||\, \mathsf{I2LEOSP}_{256}(\text{ψ}) \,||\, \mathsf{LEBS2OSP}_{256}(\mathsf{AssetBase}\kern0.05em\star)$. +> where $\mathsf{pre\_rcm} = [\mathtt{0x0B}] \,||\, \mathsf{LEBS2OSP}_{256}(\mathsf{g}\star_{\mathsf{d}}) \,||\, \mathsf{LEBS2OSP}_{256}(\mathsf{pk}\star_{\mathsf{d}}) \,||\, \mathsf{I2LEOSP}_{64}(\mathsf{v}) \,||\, \underline{\text{ρ}} \,||\, \mathsf{I2LEOSP}_{256}(\text{ψ})$. > > ($\mathsf{H^{rcm,Orchard}}$ is defined only for the $\mathsf{leadByte} = \mathtt{0x03}$ case; the existing > derivation $\mathsf{rcm} = \mathsf{ToScalar^{Orchard}}(\mathsf{PRF^{expand}_{rseed}}([\mathtt{0x05}] \,||\, \underline{\text{ρ}}))$ @@ -773,8 +768,7 @@ The first-byte domain separator $\mathtt{0x0A}$ for $\mathsf{PRF^{expand}}$ is r 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.05em\star = \mathsf{repr}_{\mathbb{P}}(\mathsf{AssetBase})$. +> and $\mathsf{pk}\star_{\mathsf{d}} = \mathsf{repr}_{\mathbb{P}}(\mathsf{pk_d})$. and use these in the inputs to $\mathsf{NoteCommit^{Orchard}}$. @@ -785,7 +779,7 @@ with > Derive $\mathsf{rcm} = \begin{cases} > \mathsf{ToScalar^{Orchard}}\big(\mathsf{PRF^{expand}_{rseed}}([\mathtt{0x05}] \,||\, \underline{\text{ρ}})\kern-0.1em\big),&\!\!\!\text{if } \mathsf{leadByte} = \mathtt{0x02} \\ -> \mathsf{H^{rcm,Orchard}_{rseed}}(\mathsf{g}\star_{\mathsf{d}}, \mathsf{pk}\star_{\mathsf{d}}, \mathsf{v}, \underline{\text{ρ}}, \text{ψ}, \mathsf{AssetBase}\kern0.05em\star),&\!\!\!\text{if } \mathsf{leadByte} = \mathtt{0x03} +> \mathsf{H^{rcm,Orchard}_{rseed}}(\mathsf{g}\star_{\mathsf{d}}, \mathsf{pk}\star_{\mathsf{d}}, \mathsf{v}, \underline{\text{ρ}}, \text{ψ}),&\!\!\!\text{if } \mathsf{leadByte} = \mathtt{0x03} > \end{cases}$ > Derive $\text{ψ} = \mathsf{H^{\text{ψ},Orchard}_{rseed}}(\underline{\text{ρ}})$ @@ -803,11 +797,6 @@ Replace the line deriving $\mathsf{rcm}$ with #### § 4.8.3 ‘Dummy Notes (Orchard)’ -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 @@ -816,27 +805,20 @@ 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.05em\star = \mathsf{repr}_{\mathbb{P}}(\mathsf{AssetBase})$. +> and $\mathsf{pk}\star_{\mathsf{d}} = \mathsf{repr}_{\mathbb{P}}(\mathsf{pk_d})$. > > Derive $\mathsf{rcm} = \begin{cases} > \mathsf{ToScalar^{Orchard}}\big(\mathsf{PRF^{expand}_{rseed}}([\mathtt{0x05}] \,||\, \underline{\text{ρ}})\kern-0.1em\big),&\!\!\!\text{if } \mathsf{leadByte} = \mathtt{0x02} \\ -> \mathsf{H^{rcm,Orchard}_{rseed}}(\mathsf{g}\star_{\mathsf{d}}, \mathsf{pk}\star_{\mathsf{d}}, \mathsf{v}, \underline{\text{ρ}}, \text{ψ}, \mathsf{AssetBase}\kern0.05em\star),&\!\!\!\text{if } \mathsf{leadByte} = \mathtt{0x03} +> \mathsf{H^{rcm,Orchard}_{rseed}}(\mathsf{g}\star_{\mathsf{d}}, \mathsf{pk}\star_{\mathsf{d}}, \mathsf{v}, \underline{\text{ρ}}, \text{ψ}),&\!\!\!\text{if } \mathsf{leadByte} = \mathtt{0x03} > \end{cases}$ > > Derive $\text{ψ} = \mathsf{H^{\text{ψ},Orchard}_{rseed}}(\underline{\text{ρ}})$ and use $\mathsf{g}\star_{\mathsf{d}}$, $\mathsf{pk}\star_{\mathsf{d}}$, -and $\mathsf{AssetBase}\kern0.05em\star$ in the inputs to -$\mathsf{NoteCommit^{Orchard}}$. +in the inputs to $\mathsf{NoteCommit^{Orchard}}$. #### § 4.20.2 and § 4.20.3 ‘Decryption using an Incoming/Full Viewing Key (Sapling and Orchard)’ -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)’. - For both § 4.20.2 and § 4.20.3, add before the decryption procedure: > Let $\mathsf{H^{rcm,Sapling}}$ and $\mathsf{H^{esk,Sapling}}$ @@ -890,13 +872,13 @@ with > $\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$ <br> > > $\hspace{1.0em}$ let $\mathsf{pk_d} = \mathsf{KA.DerivePublic}(\mathsf{ivk}, \mathsf{g_d})$ <br> -> $\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})$ <br> +> $\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})$ <br> > $\hspace{1.0em}$ let $\text{ψ} = \mathsf{H^{\text{ψ},Orchard}_{rseed}}(\underline{\text{ρ}})$ for Orchard or $\bot$ for Sapling <br> > $\hspace{1.0em}$ let $\mathsf{rcm} = \begin{cases} > \mathsf{LEOS2IP}_{256}(\mathsf{rseed}),&\!\!\!\text{if } \mathsf{leadByte} = \mathtt{0x01} \\ > \mathsf{H^{rcm,Sapling}_{rseed}}(\bot, \bot),&\!\!\!\text{if Sapling and } \mathsf{leadByte} = \mathtt{0x02} \\ > \mathsf{ToScalar^{Orchard}}\big(\mathsf{PRF^{expand}_{rseed}}([\mathtt{0x05}] \,||\, \underline{\text{ρ}})\kern-0.1em\big),&\!\!\!\text{if Orchard and } \mathsf{leadByte} = \mathtt{0x02} \\ -> \mathsf{H^{rcm,Orchard}_{rseed}}(\mathsf{g}\star_{\mathsf{d}}, \mathsf{pk}\star_{\mathsf{d}}, \mathsf{v}, \underline{\text{ρ}}, \text{ψ}, \mathsf{AssetBase}\kern0.05em\star),&\!\!\!\text{if Orchard and } \mathsf{leadByte} = \mathtt{0x03} +> \mathsf{H^{rcm,Orchard}_{rseed}}(\mathsf{g}\star_{\mathsf{d}}, \mathsf{pk}\star_{\mathsf{d}}, \mathsf{v}, \underline{\text{ρ}}, \text{ψ}),&\!\!\!\text{if Orchard and } \mathsf{leadByte} = \mathtt{0x03} > \end{cases}$ <br> > $\hspace{1.0em}$ if $\mathsf{rcm} \geq r_{\mathbb{G}}$, return $\bot$ @@ -918,13 +900,13 @@ 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$ <br> -> $\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})$ <br> +> $\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})$ <br> > $\hspace{1.0em}$ let $\text{ψ} = \mathsf{H^{\text{ψ},Orchard}_{rseed}}(\underline{\text{ρ}})$ for Orchard or $\bot$ for Sapling <br> > $\hspace{1.0em}$ let $\mathsf{rcm} = \begin{cases} > \mathsf{LEOS2IP}_{256}(\mathsf{rseed}),&\!\!\!\text{if } \mathsf{leadByte} = \mathtt{0x01} \\ > \mathsf{H^{rcm,Sapling}_{rseed}}(\bot, \bot),&\!\!\!\text{if Sapling and } \mathsf{leadByte} = \mathtt{0x02} \\ > \mathsf{ToScalar^{Orchard}}\big(\mathsf{PRF^{expand}_{rseed}}([\mathtt{0x05}] \,||\, \underline{\text{ρ}})\kern-0.1em\big),&\!\!\!\text{if Orchard and } \mathsf{leadByte} = \mathtt{0x02} \\ -> \mathsf{H^{rcm,Orchard}_{rseed}}(\mathsf{g}\star_{\mathsf{d}}, \mathsf{pk}\star_{\mathsf{d}}, \mathsf{v}, \underline{\text{ρ}}, \text{ψ}, \mathsf{AssetBase}\kern0.05em\star),&\!\!\!\text{if Orchard and } \mathsf{leadByte} = \mathtt{0x03} +> \mathsf{H^{rcm,Orchard}_{rseed}}(\mathsf{g}\star_{\mathsf{d}}, \mathsf{pk}\star_{\mathsf{d}}, \mathsf{v}, \underline{\text{ρ}}, \text{ψ}),&\!\!\!\text{if Orchard and } \mathsf{leadByte} = \mathtt{0x03} > \end{cases}$ <br> > $\hspace{1.0em}$ if $\mathsf{rcm} \geq r_{\mathbb{G}}$, return $\bot$ @@ -1000,10 +982,10 @@ Import this definition from ZIP 32 [^zip-0032-orchard-internal-key-derivation]: Import these definitions from § 4.7.3 ‘Sending Notes (Orchard)’ [^protocol-orchardsend]: -> Define $\mathsf{H^{rcm,Orchard}_{rseed}}(\mathsf{g}\star_{\mathsf{d}}, \mathsf{pk}\star_{\mathsf{d}}, \mathsf{v}, \underline{\text{ρ}}, \text{ψ}, \mathsf{AssetBase}\kern0.05em\star) =$ +> Define $\mathsf{H^{rcm,Orchard}_{rseed}}(\mathsf{g}\star_{\mathsf{d}}, \mathsf{pk}\star_{\mathsf{d}}, \mathsf{v}, \underline{\text{ρ}}, \text{ψ}) =$ > $\mathsf{ToScalar^{Orchard}}\big(\mathsf{PRF^{expand}_{rseed}}(\mathsf{pre\_rcm})\kern-0.1em\big)$ > -> where $\mathsf{pre\_rcm} = [\mathtt{0x0B}] \,||\, \mathsf{LEBS2OSP}_{256}(\mathsf{g}\star_{\mathsf{d}}) \,||\, \mathsf{LEBS2OSP}_{256}(\mathsf{pk}\star_{\mathsf{d}}) \,||\, \mathsf{I2LEOSP}_{64}(\mathsf{v}) \,||\, \underline{\text{ρ}} \,||\, \mathsf{I2LEOSP}_{256}(\text{ψ}) \,||\, \mathsf{LEBS2OSP}_{256}(\mathsf{AssetBase}\kern0.05em\star)$. +> where $\mathsf{pre\_rcm} = [\mathtt{0x0B}] \,||\, \mathsf{LEBS2OSP}_{256}(\mathsf{g}\star_{\mathsf{d}}) \,||\, \mathsf{LEBS2OSP}_{256}(\mathsf{pk}\star_{\mathsf{d}}) \,||\, \mathsf{I2LEOSP}_{64}(\mathsf{v}) \,||\, \underline{\text{ρ}} \,||\, \mathsf{I2LEOSP}_{256}(\text{ψ})$. > > Define $\mathsf{H^{\text{ψ},Orchard}_{rseed}}(\underline{\text{ρ}}) = \mathsf{ToBase^{Orchard}}\big(\mathsf{PRF^{expand}_{rseed}}([\mathtt{0x09}] \,||\, \underline{\text{ρ}})\kern-0.1em\big)$. @@ -1068,7 +1050,7 @@ $\begin{array}{l} \wedge\; \mathsf{ivk} \not\in \{0, \bot\} \vphantom{\Big(}\\ \wedge\; \text{let } \mathsf{pk_d} = [\mathsf{ivk}]\, \mathsf{g_d} \vphantom{\big(}\\ \wedge\; \text{let } \text{ψ} = \mathsf{H}^{\text{ψ}}_{\mathsf{r}\text{ψ}}(\underline{\text{ρ}}) \vphantom{\Big(}\\ -\wedge\; \text{let } \mathsf{noterepr} = \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) \vphantom{\big(}\\ +\wedge\; \text{let } \mathsf{noterepr} = \big(\mathsf{repr}_{\mathbb{P}}(\mathsf{g_d}), \mathsf{repr}_{\mathbb{P}}(\mathsf{pk_d}), \mathsf{v}, \underline{\text{ρ}}, \text{ψ}\big) \vphantom{\big(}\\ \wedge\; \text{let } \mathsf{rcm} = \mathsf{H^{rcm,Orchard}_{rseed}}\big(\mathtt{0x03}, \mathsf{noterepr}\big) \vphantom{\Big(}\\ \wedge\; \text{let } \mathsf{cm} = \mathsf{NoteCommit^{Orchard}_{rcm}}(\mathsf{noterepr}) \vphantom{\big(}\\ \wedge\; \mathsf{cm} \neq \bot \vphantom{\Big(}\\ @@ -1163,7 +1145,7 @@ Balance property. We prefer to fix this without changing $\mathsf{NoteCommit}$ 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.05em\star)$, +$\mathsf{noterepr} = (\mathsf{g}\star_{\mathsf{d}}, \mathsf{pk}\star_{\mathsf{d}}, \mathsf{v}, \underline{\text{ρ}}, \text{ψ})$, as detailed in the [Specification] section. Specifically, when $\mathsf{leadByte} = \mathtt{0x03}$ we have: From e559f47ba5a27583f662343276de6359ed4e7221 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Sat, 16 May 2026 15:42:51 +0100 Subject: [PATCH 073/115] ZIP 2005: Decouple from OrchardZSA in framing prose. Per the deployment-option-1 decision (ZIP 2005 deploys Orchard-only, without ZSAs), reframe places that implied ZIP 2005's scope included OrchardZSA: * "It can optionally be done at the same time as changes necessary to implement ... ZSAs" -> "It is compatible with ... ZSAs". * Rename "Flow diagram for the Orchard and OrchardZSA protocols" to "Flow diagram for the Orchard protocol" (the diagram shows the 0x03 recoverable-note case, which is Orchard-only). Update the cross-reference to match. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --- zips/zip-2005.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index 8318ae728..4df52c2c7 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -120,8 +120,8 @@ Sapling [^zip-0032-sapling-child-key-derivation] [^zip-0032-sapling-internal-key and Orchard [^zip-0032-orchard-child-key-derivation] [^zip-0032-orchard-internal-key-derivation].) This proposal is implementable at low risk, and required changes to existing -libraries and wallets are small. It can optionally be done at the same time -as changes necessary to implement Memo Bundles [^zip-0231] and/or ZSAs [^zip-0226]. +libraries and wallets are small. It is compatible with Memo Bundles [^zip-0231] +and/or ZSAs [^zip-0226]. # Requirements @@ -208,7 +208,7 @@ hardware-wallet use cases are described in [Usage with FROST](#usagewithfrost) and [Usage with hardware wallets](#usagewithhardwarewallets). -## Flow diagram for the Orchard and OrchardZSA protocols +## Flow diagram for the Orchard protocol This diagram shows, approximately, the derivation of Orchard keys, addresses, notes, note commitments, and nullifiers. All of the flow @@ -967,8 +967,8 @@ changes to be adopted now are likely to be sufficient to securely support a Recovery Protocol. 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. +derivations given in the [Flow diagram for the Orchard protocol], and we +suggest having that diagram open in another window to refer to it. ### Proposed Recovery Statement @@ -1543,7 +1543,7 @@ $$\varepsilon_{\mathsf{kb}}(\mathcal{A}, q_{\mathsf{kb}}) \leq \frac{3 q_{\maths DeriveNullifier is based on a Pedersen hash. In the current Orchard protocol, the property that it is infeasible to find two distinct -Orchard notes with the same nullifier (including possible nullfiers +Orchard notes with the same nullifier (including possible nullifiers of split OrchardZSA notes), depends on the collision resistance of that hash, which would not hold against a discrete-log-breaking adversary. From 40631175ded262d929ba4eed1d845734f6be2dc4 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Sat, 16 May 2026 16:00:16 +0100 Subject: [PATCH 074/115] ZIP 2005: Update Credits and Pull-Request fields. Signed-off-by: Daira-Emma Hopwood <daira@jacaranda.org> --- zips/zip-2005.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index 4df52c2c7..55179b51c 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -4,12 +4,16 @@ Owners: Daira-Emma Hopwood <daira@jacaranda.org> Jack Grigg <thestr4d@gmail.com> Credits: Sean Bowe + Dev Ojha + Kris Nuttycombe Status: Draft Category: Consensus Created: 2025-03-31 License: MIT Discussions-To: <https://github.com/zcash/zips/issues/1135> Pull-Request: <https://github.com/zcash/zips/pull/1126> + <https://github.com/zcash/zips/pull/1184> + <https://github.com/zcash/zips/pull/1275> # Terminology From 3abd99d170de8965d73a7526b8f46175396a1659 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Sat, 16 May 2026 16:20:52 +0100 Subject: [PATCH 075/115] ZIP 2005: Inline H^{rcm,Sapling}; fix H^{esk,Sapling} arity; protocol-conditionalise dispatch. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three follow-ups to the leadByte case-split refactoring: * Remove the named H^{rcm,Sapling} function (it was a wrapper with two unused args around ToScalar^Sapling(PRF^expand_rseed([0x04]))) and inline the right-hand side at the call sites in §4.7.2, §4.8.2, §4.20.2, and §4.20.3. * Reduce H^{esk,Sapling}'s signature from (_, _) to (_), matching its Canopy-onward call shape H^{esk,protocol}_{rseed}(ρ) at §4.20.2's decryption step. * Replace prose conditions "if Sapling and leadByte = ..." / "if Orchard and leadByte = ..." with "if protocol = Sapling and leadByte = ..." / "if protocol = Orchard and leadByte = ..." in the §4.20.2 and §4.20.3 rcm dispatches. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --- zips/zip-2005.md | 35 +++++++++++++---------------------- 1 file changed, 13 insertions(+), 22 deletions(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index 55179b51c..d69630b90 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -737,18 +737,15 @@ Add the following notes: Add after the definition of $\mathsf{leadByte}$: -> Define $\mathsf{H^{rcm,Sapling}_{rseed}}(\_, \_) = \mathsf{ToScalar^{Sapling}}\big(\mathsf{PRF^{expand}_{rseed}}([\mathtt{0x04}])\kern-0.1em\big)$ +> Define $\mathsf{H^{esk,Sapling}_{rseed}}(\_) = \mathsf{ToScalar^{Sapling}}\big(\mathsf{PRF^{expand}_{rseed}}([\mathtt{0x05}])\kern-0.1em\big)$. > -> Define $\mathsf{H^{esk,Sapling}_{rseed}}(\_, \_) = \mathsf{ToScalar^{Sapling}}\big(\mathsf{PRF^{expand}_{rseed}}([\mathtt{0x05}])\kern-0.1em\big)$. -> -> ($\mathsf{H^{rcm,Sapling}}$ and $\mathsf{H^{esk,Sapling}}$ intentionally -> take arguments that are unused.) +> ($\mathsf{H^{esk,Sapling}}$ intentionally takes an argument that is unused.) Replace the lines deriving $\mathsf{rcm}$ and $\mathsf{esk}$ with -> Derive $\mathsf{rcm} = \mathsf{H^{rcm,Sapling}_{rseed}}(\bot, \bot)$ +> Derive $\mathsf{rcm} = \mathsf{ToScalar^{Sapling}}\big(\mathsf{PRF^{expand}_{rseed}}([\mathtt{0x04}])\kern-0.1em\big)$ > -> Derive $\mathsf{esk} = \mathsf{H^{esk,Sapling}_{rseed}}(\bot, \bot)$ +> Derive $\mathsf{esk} = \mathsf{H^{esk,Sapling}_{rseed}}(\bot)$ #### § 4.7.3 ‘Sending Notes (Orchard)’ @@ -790,14 +787,9 @@ with #### § 4.8.2 ‘Dummy Notes (Sapling)’ -Add - -> Let $\mathsf{H^{rcm,Sapling}}$ be as defined in -> § 4.7.2 ‘Sending Notes (Sapling)’. - Replace the line deriving $\mathsf{rcm}$ with -> Derive $\mathsf{rcm} = \mathsf{H^{rcm,Sapling}_{rseed}}(\bot, \bot)$ +> Derive $\mathsf{rcm} = \mathsf{ToScalar^{Sapling}}\big(\mathsf{PRF^{expand}_{rseed}}([\mathtt{0x04}])\kern-0.1em\big)$ #### § 4.8.3 ‘Dummy Notes (Orchard)’ @@ -825,8 +817,7 @@ in the inputs to $\mathsf{NoteCommit^{Orchard}}$. For both § 4.20.2 and § 4.20.3, add before the decryption procedure: -> Let $\mathsf{H^{rcm,Sapling}}$ and $\mathsf{H^{esk,Sapling}}$ -> be as defined in § 4.7.2 ‘Sending Notes (Sapling)’. +> Let $\mathsf{H^{esk,Sapling}}$ be as defined in § 4.7.2 ‘Sending Notes (Sapling)’. > > Let $\mathsf{H^{rcm,Orchard}}$, $\mathsf{H^{esk,Orchard}}$, > and $\mathsf{H^{\text{ψ},Orchard}}$ be as defined in @@ -880,9 +871,9 @@ with > $\hspace{1.0em}$ let $\text{ψ} = \mathsf{H^{\text{ψ},Orchard}_{rseed}}(\underline{\text{ρ}})$ for Orchard or $\bot$ for Sapling <br> > $\hspace{1.0em}$ let $\mathsf{rcm} = \begin{cases} > \mathsf{LEOS2IP}_{256}(\mathsf{rseed}),&\!\!\!\text{if } \mathsf{leadByte} = \mathtt{0x01} \\ -> \mathsf{H^{rcm,Sapling}_{rseed}}(\bot, \bot),&\!\!\!\text{if Sapling and } \mathsf{leadByte} = \mathtt{0x02} \\ -> \mathsf{ToScalar^{Orchard}}\big(\mathsf{PRF^{expand}_{rseed}}([\mathtt{0x05}] \,||\, \underline{\text{ρ}})\kern-0.1em\big),&\!\!\!\text{if Orchard and } \mathsf{leadByte} = \mathtt{0x02} \\ -> \mathsf{H^{rcm,Orchard}_{rseed}}(\mathsf{g}\star_{\mathsf{d}}, \mathsf{pk}\star_{\mathsf{d}}, \mathsf{v}, \underline{\text{ρ}}, \text{ψ}),&\!\!\!\text{if Orchard and } \mathsf{leadByte} = \mathtt{0x03} +> \mathsf{ToScalar^{Sapling}}\big(\mathsf{PRF^{expand}_{rseed}}([\mathtt{0x04}])\kern-0.1em\big),&\!\!\!\text{if } \mathsf{protocol} = \mathsf{Sapling} \text{ and } \mathsf{leadByte} = \mathtt{0x02} \\ +> \mathsf{ToScalar^{Orchard}}\big(\mathsf{PRF^{expand}_{rseed}}([\mathtt{0x05}] \,||\, \underline{\text{ρ}})\kern-0.1em\big),&\!\!\!\text{if } \mathsf{protocol} = \mathsf{Orchard} \text{ and } \mathsf{leadByte} = \mathtt{0x02} \\ +> \mathsf{H^{rcm,Orchard}_{rseed}}(\mathsf{g}\star_{\mathsf{d}}, \mathsf{pk}\star_{\mathsf{d}}, \mathsf{v}, \underline{\text{ρ}}, \text{ψ}),&\!\!\!\text{if } \mathsf{protocol} = \mathsf{Orchard} \text{ and } \mathsf{leadByte} = \mathtt{0x03} > \end{cases}$ <br> > $\hspace{1.0em}$ if $\mathsf{rcm} \geq r_{\mathbb{G}}$, return $\bot$ @@ -890,7 +881,7 @@ 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 -define $\mathsf{H^{rcm,Sapling}}$ and $\mathsf{H^{rcm,Orchard}}$ respectively. +define $\mathsf{H^{rcm,Orchard}}$. For § 4.20.3, replace @@ -908,9 +899,9 @@ with > $\hspace{1.0em}$ let $\text{ψ} = \mathsf{H^{\text{ψ},Orchard}_{rseed}}(\underline{\text{ρ}})$ for Orchard or $\bot$ for Sapling <br> > $\hspace{1.0em}$ let $\mathsf{rcm} = \begin{cases} > \mathsf{LEOS2IP}_{256}(\mathsf{rseed}),&\!\!\!\text{if } \mathsf{leadByte} = \mathtt{0x01} \\ -> \mathsf{H^{rcm,Sapling}_{rseed}}(\bot, \bot),&\!\!\!\text{if Sapling and } \mathsf{leadByte} = \mathtt{0x02} \\ -> \mathsf{ToScalar^{Orchard}}\big(\mathsf{PRF^{expand}_{rseed}}([\mathtt{0x05}] \,||\, \underline{\text{ρ}})\kern-0.1em\big),&\!\!\!\text{if Orchard and } \mathsf{leadByte} = \mathtt{0x02} \\ -> \mathsf{H^{rcm,Orchard}_{rseed}}(\mathsf{g}\star_{\mathsf{d}}, \mathsf{pk}\star_{\mathsf{d}}, \mathsf{v}, \underline{\text{ρ}}, \text{ψ}),&\!\!\!\text{if Orchard and } \mathsf{leadByte} = \mathtt{0x03} +> \mathsf{ToScalar^{Sapling}}\big(\mathsf{PRF^{expand}_{rseed}}([\mathtt{0x04}])\kern-0.1em\big),&\!\!\!\text{if } \mathsf{protocol} = \mathsf{Sapling} \text{ and } \mathsf{leadByte} = \mathtt{0x02} \\ +> \mathsf{ToScalar^{Orchard}}\big(\mathsf{PRF^{expand}_{rseed}}([\mathtt{0x05}] \,||\, \underline{\text{ρ}})\kern-0.1em\big),&\!\!\!\text{if } \mathsf{protocol} = \mathsf{Orchard} \text{ and } \mathsf{leadByte} = \mathtt{0x02} \\ +> \mathsf{H^{rcm,Orchard}_{rseed}}(\mathsf{g}\star_{\mathsf{d}}, \mathsf{pk}\star_{\mathsf{d}}, \mathsf{v}, \underline{\text{ρ}}, \text{ψ}),&\!\!\!\text{if } \mathsf{protocol} = \mathsf{Orchard} \text{ and } \mathsf{leadByte} = \mathtt{0x03} > \end{cases}$ <br> > $\hspace{1.0em}$ if $\mathsf{rcm} \geq r_{\mathbb{G}}$, return $\bot$ From b2b10868ffa81aa10bef64ac0edefd03fc9398f5 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Sat, 16 May 2026 16:29:08 +0100 Subject: [PATCH 076/115] ZIP 2005: Define Derive_rcm^{Sapling,Orchard} helpers; use at all rcm-derivation sites. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Define protocol-specific helpers that bundle the leadByte case-split for rcm derivation: * Derive_rcm^{Sapling}_{rseed}(leadByte) dispatches between LEOS2IP_{256}(rseed) (leadByte=0x01) and ToScalar^Sapling(PRF^expand_rseed([0x04])) (leadByte=0x02). * Derive_rcm^{Orchard}_{rseed}(leadByte, g★_d, pk★_d, v, ρ, ψ) dispatches between the existing legacy derivation ToScalar^Orchard(PRF^expand_rseed([0x05] || ρ)) (leadByte=0x02) and the new H^{rcm,Orchard}_{rseed}(g★_d, pk★_d, v, ρ, ψ) (leadByte=0x03). Update the call sites in §4.7.2 / §4.7.3 / §4.8.2 / §4.8.3 / §4.20.2 / §4.20.3 to invoke the helpers. The §4.20.2 / §4.20.3 decryption dispatch collapses from a 4-case rcm case-split to a 2-case protocol-conditional call. Drop the now-redundant parenthetical noting that H^{rcm,Orchard} is defined only for the leadByte=0x03 case (H^{rcm,Orchard} is now only referenced inside Derive_rcm^{Orchard}'s definition). Update the "which define ..." cross-reference at the order-of-operations note to name Derive_rcm^{\{Sapling,Orchard\}} rather than H^{rcm,Orchard}, since Derive_rcm is now the primary export of the affected sections. Harmonize the notation for H^ψ in the rationale: ψ = H^ψ(rseed, ρ) becomes ψ = H^ψ_{rseed}(ρ). The two forms are equivalent under the protocol-spec convention; the subscripted form is preferred for consistency. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --- zips/zip-2005.md | 42 +++++++++++++++++++----------------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index d69630b90..975384a8f 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -740,10 +740,15 @@ Add after the definition of $\mathsf{leadByte}$: > Define $\mathsf{H^{esk,Sapling}_{rseed}}(\_) = \mathsf{ToScalar^{Sapling}}\big(\mathsf{PRF^{expand}_{rseed}}([\mathtt{0x05}])\kern-0.1em\big)$. > > ($\mathsf{H^{esk,Sapling}}$ intentionally takes an argument that is unused.) +> +> Define $\mathsf{Derive\_rcm^{Sapling}_{rseed}}(\mathsf{leadByte}) = \begin{cases} +> \mathsf{LEOS2IP}_{256}(\mathsf{rseed}),&\!\!\!\text{if } \mathsf{leadByte} = \mathtt{0x01} \\ +> \mathsf{ToScalar^{Sapling}}\big(\mathsf{PRF^{expand}_{rseed}}([\mathtt{0x04}])\kern-0.1em\big),&\!\!\!\text{if } \mathsf{leadByte} = \mathtt{0x02} +> \end{cases}$ Replace the lines deriving $\mathsf{rcm}$ and $\mathsf{esk}$ with -> Derive $\mathsf{rcm} = \mathsf{ToScalar^{Sapling}}\big(\mathsf{PRF^{expand}_{rseed}}([\mathtt{0x04}])\kern-0.1em\big)$ +> Derive $\mathsf{rcm} = \mathsf{Derive\_rcm^{Sapling}_{rseed}}(\mathsf{leadByte})$ > > Derive $\mathsf{esk} = \mathsf{H^{esk,Sapling}_{rseed}}(\bot)$ @@ -756,9 +761,10 @@ Add before "For each Action description": > > where $\mathsf{pre\_rcm} = [\mathtt{0x0B}] \,||\, \mathsf{LEBS2OSP}_{256}(\mathsf{g}\star_{\mathsf{d}}) \,||\, \mathsf{LEBS2OSP}_{256}(\mathsf{pk}\star_{\mathsf{d}}) \,||\, \mathsf{I2LEOSP}_{64}(\mathsf{v}) \,||\, \underline{\text{ρ}} \,||\, \mathsf{I2LEOSP}_{256}(\text{ψ})$. > -> ($\mathsf{H^{rcm,Orchard}}$ is defined only for the $\mathsf{leadByte} = \mathtt{0x03}$ case; the existing -> derivation $\mathsf{rcm} = \mathsf{ToScalar^{Orchard}}(\mathsf{PRF^{expand}_{rseed}}([\mathtt{0x05}] \,||\, \underline{\text{ρ}}))$ -> from the protocol specification continues to apply when $\mathsf{leadByte} = \mathtt{0x02}$.) +> Define $\mathsf{Derive\_rcm^{Orchard}_{rseed}}(\mathsf{leadByte}, \mathsf{g}\star_{\mathsf{d}}, \mathsf{pk}\star_{\mathsf{d}}, \mathsf{v}, \underline{\text{ρ}}, \text{ψ}) = \begin{cases} +> \mathsf{ToScalar^{Orchard}}\big(\mathsf{PRF^{expand}_{rseed}}([\mathtt{0x05}] \,||\, \underline{\text{ρ}})\kern-0.1em\big),&\!\!\!\text{if } \mathsf{leadByte} = \mathtt{0x02} \\ +> \mathsf{H^{rcm,Orchard}_{rseed}}(\mathsf{g}\star_{\mathsf{d}}, \mathsf{pk}\star_{\mathsf{d}}, \mathsf{v}, \underline{\text{ρ}}, \text{ψ}),&\!\!\!\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)$. > @@ -778,10 +784,7 @@ with > Derive $\mathsf{esk} = \mathsf{H^{esk,Orchard}_{rseed}}(\underline{\text{ρ}})$ -> Derive $\mathsf{rcm} = \begin{cases} -> \mathsf{ToScalar^{Orchard}}\big(\mathsf{PRF^{expand}_{rseed}}([\mathtt{0x05}] \,||\, \underline{\text{ρ}})\kern-0.1em\big),&\!\!\!\text{if } \mathsf{leadByte} = \mathtt{0x02} \\ -> \mathsf{H^{rcm,Orchard}_{rseed}}(\mathsf{g}\star_{\mathsf{d}}, \mathsf{pk}\star_{\mathsf{d}}, \mathsf{v}, \underline{\text{ρ}}, \text{ψ}),&\!\!\!\text{if } \mathsf{leadByte} = \mathtt{0x03} -> \end{cases}$ +> Derive $\mathsf{rcm} = \mathsf{Derive\_rcm^{Orchard}_{rseed}}(\mathsf{leadByte}, \mathsf{g}\star_{\mathsf{d}}, \mathsf{pk}\star_{\mathsf{d}}, \mathsf{v}, \underline{\text{ρ}}, \text{ψ})$ > Derive $\text{ψ} = \mathsf{H^{\text{ψ},Orchard}_{rseed}}(\underline{\text{ρ}})$ @@ -789,7 +792,7 @@ with Replace the line deriving $\mathsf{rcm}$ with -> Derive $\mathsf{rcm} = \mathsf{ToScalar^{Sapling}}\big(\mathsf{PRF^{expand}_{rseed}}([\mathtt{0x04}])\kern-0.1em\big)$ +> Derive $\mathsf{rcm} = \mathsf{Derive\_rcm^{Sapling}_{rseed}}(\mathsf{leadByte})$ #### § 4.8.3 ‘Dummy Notes (Orchard)’ @@ -803,10 +806,7 @@ Replace the lines deriving $\mathsf{rcm}$ and $\text{ψ}$ with > Let $\mathsf{g}\star_{\mathsf{d}} = \mathsf{repr}_{\mathbb{P}}(\mathsf{g_d})$, > and $\mathsf{pk}\star_{\mathsf{d}} = \mathsf{repr}_{\mathbb{P}}(\mathsf{pk_d})$. > -> Derive $\mathsf{rcm} = \begin{cases} -> \mathsf{ToScalar^{Orchard}}\big(\mathsf{PRF^{expand}_{rseed}}([\mathtt{0x05}] \,||\, \underline{\text{ρ}})\kern-0.1em\big),&\!\!\!\text{if } \mathsf{leadByte} = \mathtt{0x02} \\ -> \mathsf{H^{rcm,Orchard}_{rseed}}(\mathsf{g}\star_{\mathsf{d}}, \mathsf{pk}\star_{\mathsf{d}}, \mathsf{v}, \underline{\text{ρ}}, \text{ψ}),&\!\!\!\text{if } \mathsf{leadByte} = \mathtt{0x03} -> \end{cases}$ +> Derive $\mathsf{rcm} = \mathsf{Derive\_rcm^{Orchard}_{rseed}}(\mathsf{leadByte}, \mathsf{g}\star_{\mathsf{d}}, \mathsf{pk}\star_{\mathsf{d}}, \mathsf{v}, \underline{\text{ρ}}, \text{ψ})$ > > Derive $\text{ψ} = \mathsf{H^{\text{ψ},Orchard}_{rseed}}(\underline{\text{ρ}})$ @@ -870,10 +870,8 @@ with > $\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})$ <br> > $\hspace{1.0em}$ let $\text{ψ} = \mathsf{H^{\text{ψ},Orchard}_{rseed}}(\underline{\text{ρ}})$ for Orchard or $\bot$ for Sapling <br> > $\hspace{1.0em}$ let $\mathsf{rcm} = \begin{cases} -> \mathsf{LEOS2IP}_{256}(\mathsf{rseed}),&\!\!\!\text{if } \mathsf{leadByte} = \mathtt{0x01} \\ -> \mathsf{ToScalar^{Sapling}}\big(\mathsf{PRF^{expand}_{rseed}}([\mathtt{0x04}])\kern-0.1em\big),&\!\!\!\text{if } \mathsf{protocol} = \mathsf{Sapling} \text{ and } \mathsf{leadByte} = \mathtt{0x02} \\ -> \mathsf{ToScalar^{Orchard}}\big(\mathsf{PRF^{expand}_{rseed}}([\mathtt{0x05}] \,||\, \underline{\text{ρ}})\kern-0.1em\big),&\!\!\!\text{if } \mathsf{protocol} = \mathsf{Orchard} \text{ and } \mathsf{leadByte} = \mathtt{0x02} \\ -> \mathsf{H^{rcm,Orchard}_{rseed}}(\mathsf{g}\star_{\mathsf{d}}, \mathsf{pk}\star_{\mathsf{d}}, \mathsf{v}, \underline{\text{ρ}}, \text{ψ}),&\!\!\!\text{if } \mathsf{protocol} = \mathsf{Orchard} \text{ and } \mathsf{leadByte} = \mathtt{0x03} +> \mathsf{Derive\_rcm^{Sapling}_{rseed}}(\mathsf{leadByte}),&\!\!\!\text{if } \mathsf{protocol} = \mathsf{Sapling} \\ +> \mathsf{Derive\_rcm^{Orchard}_{rseed}}(\mathsf{leadByte}, \mathsf{g}\star_{\mathsf{d}}, \mathsf{pk}\star_{\mathsf{d}}, \mathsf{v}, \underline{\text{ρ}}, \text{ψ}),&\!\!\!\text{if } \mathsf{protocol} = \mathsf{Orchard} > \end{cases}$ <br> > $\hspace{1.0em}$ if $\mathsf{rcm} \geq r_{\mathbb{G}}$, return $\bot$ @@ -881,7 +879,7 @@ 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 -define $\mathsf{H^{rcm,Orchard}}$. +define $\mathsf{Derive\_rcm^{\{Sapling,Orchard\}}}$. For § 4.20.3, replace @@ -898,10 +896,8 @@ with > $\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})$ <br> > $\hspace{1.0em}$ let $\text{ψ} = \mathsf{H^{\text{ψ},Orchard}_{rseed}}(\underline{\text{ρ}})$ for Orchard or $\bot$ for Sapling <br> > $\hspace{1.0em}$ let $\mathsf{rcm} = \begin{cases} -> \mathsf{LEOS2IP}_{256}(\mathsf{rseed}),&\!\!\!\text{if } \mathsf{leadByte} = \mathtt{0x01} \\ -> \mathsf{ToScalar^{Sapling}}\big(\mathsf{PRF^{expand}_{rseed}}([\mathtt{0x04}])\kern-0.1em\big),&\!\!\!\text{if } \mathsf{protocol} = \mathsf{Sapling} \text{ and } \mathsf{leadByte} = \mathtt{0x02} \\ -> \mathsf{ToScalar^{Orchard}}\big(\mathsf{PRF^{expand}_{rseed}}([\mathtt{0x05}] \,||\, \underline{\text{ρ}})\kern-0.1em\big),&\!\!\!\text{if } \mathsf{protocol} = \mathsf{Orchard} \text{ and } \mathsf{leadByte} = \mathtt{0x02} \\ -> \mathsf{H^{rcm,Orchard}_{rseed}}(\mathsf{g}\star_{\mathsf{d}}, \mathsf{pk}\star_{\mathsf{d}}, \mathsf{v}, \underline{\text{ρ}}, \text{ψ}),&\!\!\!\text{if } \mathsf{protocol} = \mathsf{Orchard} \text{ and } \mathsf{leadByte} = \mathtt{0x03} +> \mathsf{Derive\_rcm^{Sapling}_{rseed}}(\mathsf{leadByte}),&\!\!\!\text{if } \mathsf{protocol} = \mathsf{Sapling} \\ +> \mathsf{Derive\_rcm^{Orchard}_{rseed}}(\mathsf{leadByte}, \mathsf{g}\star_{\mathsf{d}}, \mathsf{pk}\star_{\mathsf{d}}, \mathsf{v}, \underline{\text{ρ}}, \text{ψ}),&\!\!\!\text{if } \mathsf{protocol} = \mathsf{Orchard} > \end{cases}$ <br> > $\hspace{1.0em}$ if $\mathsf{rcm} \geq r_{\mathbb{G}}$, return $\bot$ @@ -1172,7 +1168,7 @@ instantiated using BLAKE2b, a conventional hash function not related to the Pallas curve. > The fact that $\mathsf{NoteCommit}$ has -> $\text{ψ} = \mathsf{H}^{\text{ψ}}(\mathsf{rseed}, \text{ρ})$ as an +> $\text{ψ} = \mathsf{H}^{\text{ψ}}_{\mathsf{rseed}}(\text{ρ})$ as an > input does not affect the analysis provided that $\mathsf{H^{rcm}}$ and > $\mathsf{H}^{\text{ψ}}$ can be treated as independent. In practice both > are defined in terms of $\mathsf{PRF^{expand}}$, but with strict domain From 8f3dcb020c20e1f85184cab76e172de8770711a7 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Sat, 16 May 2026 17:04:42 +0100 Subject: [PATCH 077/115] ZIP 2005: Update BLAKE3 reference to use Zooko Wilcox's current name. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --- 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 975384a8f..ee0938fcb 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -1897,7 +1897,7 @@ manipulate the note selection algorithm to some extent. [^Bernstein2009]: [Cost analysis of hash collisions: Will quantum computers make SHARCS obsolete? Daniel J. Bernstein.](https://cr.yp.to/hash/collisioncost-20090517.pdf) -[^BLAKE3]: [BLAKE3: One Function, Fast Everywhere. Jack O'Connor, Jean-Philippe Aumasson, Samuel Neves, and Zooko Wilcox-O'Hearn, 2020.](https://github.com/BLAKE3-team/BLAKE3-specs/blob/master/blake3.pdf) See § 2.1.2 for the `derive_key` mode. +[^BLAKE3]: [BLAKE3: One Function, Fast Everywhere. Jack O'Connor, Jean-Philippe Aumasson, Samuel Neves, and Zooko Wilcox, 2020.](https://github.com/BLAKE3-team/BLAKE3-specs/blob/master/blake3.pdf) See § 2.1.2 for the `derive_key` mode. [^Maurer2002]: [Indistinguishability of Random Systems. Ueli Maurer.](https://crypto.ethz.ch/publications/files/Maurer02.pdf) Advances in Cryptology — EUROCRYPT 2002, LNCS vol. 2332, pp. 110–132. From 198039e459e3263987597a52cb30713bfc8915ef Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Sat, 16 May 2026 17:47:46 +0100 Subject: [PATCH 078/115] ZIP 2005: Pin ak (in addition to qk) for Spend Authorization key-binding. The Spend Authorization argument needs ak (up to y-sign of ak^P) uniquely determined by ivk, because the verification key rk = ak^P + [alpha] G depends on ak. The formal key-binding predicate already pins ak via ivk = Commit^{ivk}_{rivk}(ak, nk); the motivation enumeration in the key-binding section was incomplete. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --- zips/zip-2005.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index ee0938fcb..392537793 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -1300,9 +1300,10 @@ Orchard properties need different components of the key witness pinned: — the latter via the [$\mathsf{PRF^{nf}}$-pinning lemma](#lemma-prf-nf-pinning)): $\mathsf{nk}$ uniquely determined by $\mathsf{ivk}$. -* **Spend Authorization**: $\mathsf{qk}$ uniquely determined by - $\mathsf{ivk}$ when $\mathsf{qk} \neq \bot$ (i.e., when - $\mathsf{use\_qsk} = \mathsf{true}$). +* **Spend Authorization**: $\mathsf{ak}$ (up to $y$-sign of + $\mathsf{ak}^{\mathbb{P}}$) uniquely determined by $\mathsf{ivk}$; + and $\mathsf{qk}$ uniquely determined by $\mathsf{ivk}$ when + $\mathsf{qk} \neq \bot$ (i.e., when $\mathsf{use\_qsk} = \mathsf{true}$). The formal key-binding condition stated below covers both of these uniformly: a key-binding break is a pair of distinct witnesses sharing From 0fd9533f4758b916a233e9f9b5463ab6b603a054 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Sat, 16 May 2026 17:48:12 +0100 Subject: [PATCH 079/115] =?UTF-8?q?ZIP=202005:=20Make=20key-binding=20alge?= =?UTF-8?q?braic=20setup=20explicit=20per=20=C2=A7=205.4.1.10.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the abstract ShortHash([h(ak,nk)+rivk] S) form with the explicit Sinsemilla-commitment definition from § 5.4.1.10: exhibit S as the rivk-randomization base via GroupHash^P, M' as SinsemillaHashToPoint over LEBSP(ak) || LEBSP(nk), and the WLOG scalar-lift M' = [h(ak,nk)] S using a Pedersen-like deterministic h. Drops two duplicate "verify the exact form" TODOs. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --- zips/zip-2005.md | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index 392537793..fcc225867 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -1422,12 +1422,22 @@ $\varepsilon_{\mathsf{kb}}(\mathcal{A}, q_{\mathsf{kb}}) \leq \frac{3\, q_{\math **Proof sketch.** *Algebraic setup.* -$\mathsf{Commit^{ivk}_{rivk}}(\mathsf{ak}, \mathsf{nk})$ is a Sinsemilla -short commitment, of the form -$\mathsf{ShortHash}\big([h(\mathsf{ak}, \mathsf{nk}) + \mathsf{rivk}] \cdot \mathcal{S}\big)$ -for a Pedersen-like deterministic hash $h$ and a Sinsemilla base -$\mathcal{S}$ (TODO: verify the exact form of $h$ and $\mathcal{S}$ -from § 5.4.1.10 'Sinsemilla Commit Function'). Domain separation in +By § 5.4.1.10 “Sinsemilla commitments”, +$\mathsf{Commit^{ivk}_{rivk}}(\mathsf{ak}, \mathsf{nk}) = +\mathsf{Extract}_{\mathbb{P}}\big(M' + [\mathsf{rivk}]\, \mathcal{S}\big)$, +where +$\mathcal{S} := \mathsf{GroupHash}^{\mathbb{P}}(\texttt{“z.cash:Orchard-CommitIvk-r”}, \texttt{“”})$ +is the rivk-randomization base and +$M' := \mathsf{SinsemillaHashToPoint}\big(\texttt{“z.cash:Orchard-CommitIvk-M”},\, +\mathsf{LEBSP}(\mathsf{ak}) \,\Vert\, \mathsf{LEBSP}(\mathsf{nk})\big)$ +(see § 5.4.1.10 for the exact bit-sequence encoding). +By expanding the Sinsemilla bases used inside $\mathsf{SinsemillaHashToPoint}$ +as scalar multiples of $\mathcal{S}$, without loss of generality we have +$M' = [h(\mathsf{ak}, \mathsf{nk})]\, \mathcal{S}$ for a Pedersen-like +deterministic scalar hash $h$. Therefore +$\mathsf{Commit^{ivk}_{rivk}}(\mathsf{ak}, \mathsf{nk}) = +\mathsf{Extract}_{\mathbb{P}}\big([h(\mathsf{ak}, \mathsf{nk}) + \mathsf{rivk}]\, \mathcal{S}\big)$. +Domain separation in the protocol's BLAKE2b instantiations ensures $h$ does not query $\mathsf{H^{rivk\_ext}}$, $\mathsf{H^{rivk\_legacy}}$, $\mathsf{H^{rivk\_int}}$, $\mathsf{H^{ask}}$, or $\mathsf{H^{nk}}$: @@ -1528,8 +1538,6 @@ union-bounding over the at most $\binom{q_{\mathsf{kb}}}{2}$ pairs of distinct witnesses, $$\varepsilon_{\mathsf{kb}}(\mathcal{A}, q_{\mathsf{kb}}) \leq \frac{3 q_{\mathsf{kb}}(q_{\mathsf{kb}}-1)}{2 r_{\mathbb{P}}}.$$ -(TODO: verify the exact form of $h$ and $\mathcal{S}$ from -§ 5.4.1.10 'Sinsemilla Commit Function'.) ## Security argument for Spendability From d073964ee2c496a31f0dc1e2ffedd25947240f29 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Sat, 16 May 2026 18:10:45 +0100 Subject: [PATCH 080/115] ZIP 2005: Resolve TODO -- Extract_P does not interfere with the QROM lift. Extract_P is a deterministic 2-to-1 map on non-identity Pallas points and does not query any random oracle, so it composes the same way classically and quantumly. The factor of 2 from the 2-to-1 reduction is already absorbed into the break-probability bound. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --- zips/zip-2005.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index fcc225867..e91aa60ac 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -1275,8 +1275,15 @@ will need to use complete curve additions to implement Sinsemilla. In order to adapt this argument to the quantum setting, we need to consider *collapsing* hash functions as defined in [^Unruh2015] [^Unruh2016]. -TODO: does $\mathsf{Extract}_{\mathbb{P}}$ cause any difficulty for lifting -to QROM? +$\mathsf{Extract}_{\mathbb{P}}$ does not interfere with the QROM lift: +it is a deterministic 2-to-1 map on non-identity Pallas points +(sending $P$ and $-P$ to the same $x$-coordinate) and does not query +$\mathsf{H^{rcm}}$ or any other random oracle, so it composes with the +underlying random oracle the same way classically and quantumly. The +factor of 2 from the 2-to-1 reduction is already absorbed into the +break-probability bound (each $\mathsf{cm}_x$ has exactly two valid +$\mathsf{cm}$ values, hence exactly two valid $\mathsf{rcm}$ values, as +stated above). By the argument in [^Bernstein2009], the best known *generic* quantum attack on a hash function is simply the classical attack of [^vOW1999]. From 49f7ae89999c1d15f4d9d69776c5b0df0faf04b6 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Sat, 16 May 2026 18:17:00 +0100 Subject: [PATCH 081/115] ZIP 2005: Harmonize the two stray \binom occurrences to \choose. Both forms render identically; \choose was already the dominant notation in the proofs. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --- zips/zip-2005.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index e91aa60ac..82405f3a0 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -1541,7 +1541,7 @@ Treating the five rivk-derivation random oracles $\mathsf{H^{rivk\_int}}$, $\mathsf{H^{ask}}$, $\mathsf{H^{nk}}$) as a single combined uniform random oracle on the joint query domain (each RO contributes its outputs independently of the others), and -union-bounding over the at most $\binom{q_{\mathsf{kb}}}{2}$ pairs +union-bounding over the at most ${q_{\mathsf{kb}} \choose 2}$ pairs of distinct witnesses, $$\varepsilon_{\mathsf{kb}}(\mathcal{A}, q_{\mathsf{kb}}) \leq \frac{3 q_{\mathsf{kb}}(q_{\mathsf{kb}}-1)}{2 r_{\mathbb{P}}}.$$ @@ -1756,7 +1756,7 @@ $F_1$ and $F_2$ are independent uniform on $\mathbb{F}_{r_{\mathbb{P}}}$. The win condition $F_1 \equiv \pm F_2$ is a linear constraint on a pair of independent uniform variables, satisfied with probability at most $2/r_{\mathbb{P}}$ (one per sign). Union-bounding over the at -most $\binom{q_{\mathsf{rcm}}}{2}$ pairs of distinct +most ${q_{\mathsf{rcm}} \choose 2}$ pairs of distinct $\mathsf{H^{rcm}}$ queries: $$\Pr[\text{win} \mid \neg\,\text{break}] \leq \frac{q_{\mathsf{rcm}}(q_{\mathsf{rcm}}-1)}{r_{\mathbb{P}}}.$$ Decomposing on whether a key-binding break occurs and applying From 78698ec7076614ea628219bfc1d185a8501df189 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Sat, 16 May 2026 18:17:56 +0100 Subject: [PATCH 082/115] ZIP 2005: Define the binomial-coefficient notation in the Terminology section. Readers may be unfamiliar with the stacked-fraction \choose form. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --- zips/zip-2005.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index 82405f3a0..a306d0128 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -36,6 +36,10 @@ $\underline{\mathsf{underlined}}$ variable indicates a byte sequence, and a variable suffixed with $\star$ indicates a bit-sequence encoding of an elliptic curve point. +The notation ${k \choose n}$ denotes the binomial coefficient — the +number of ways of choosing $n$ items from a set of $k$, equal to +$\frac{k!}{n!(k-n)!}$ for $0 \leq n \leq k$. + For brevity, in the discussion sections of this ZIP we abbreviate $\mathsf{H^{rcm,Orchard}}$ as $\mathsf{H^{rcm}}$, $\mathsf{PRF^{nfOrchard}}$ as $\mathsf{PRF^{nf}}$, From ad6495419d9477dbd40997d0e1c71df9445b3977 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Sat, 16 May 2026 18:43:38 +0100 Subject: [PATCH 083/115] ZIP 2005: Address review comments (define-order, explicit imports, displaymath, I2LEBSP). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * In § 4.7.2, define Derive_rcm^Sapling before H^esk,Sapling (rcm-then-esk ordering, matching § 4.7.3). * In § 4.8.2, add an import preamble for Derive_rcm^Sapling. * In § 4.8.3 and § 4.20.2/§ 4.20.3, replace the stale H^{rcm,Orchard} import with Derive_rcm^Orchard (and add Derive_rcm^Sapling to § 4.20.x), since the actual derivation goes through the helpers. * In the key-binding algebraic setup, replace the non-existent LEBSP with I2LEBSP_{l^Orchard} and lift the three named formulas to display math for readability. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --- zips/zip-2005.md | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index a306d0128..ce10078f3 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -741,14 +741,14 @@ Add the following notes: Add after the definition of $\mathsf{leadByte}$: -> Define $\mathsf{H^{esk,Sapling}_{rseed}}(\_) = \mathsf{ToScalar^{Sapling}}\big(\mathsf{PRF^{expand}_{rseed}}([\mathtt{0x05}])\kern-0.1em\big)$. -> -> ($\mathsf{H^{esk,Sapling}}$ intentionally takes an argument that is unused.) -> > Define $\mathsf{Derive\_rcm^{Sapling}_{rseed}}(\mathsf{leadByte}) = \begin{cases} > \mathsf{LEOS2IP}_{256}(\mathsf{rseed}),&\!\!\!\text{if } \mathsf{leadByte} = \mathtt{0x01} \\ > \mathsf{ToScalar^{Sapling}}\big(\mathsf{PRF^{expand}_{rseed}}([\mathtt{0x04}])\kern-0.1em\big),&\!\!\!\text{if } \mathsf{leadByte} = \mathtt{0x02} > \end{cases}$ +> +> Define $\mathsf{H^{esk,Sapling}_{rseed}}(\_) = \mathsf{ToScalar^{Sapling}}\big(\mathsf{PRF^{expand}_{rseed}}([\mathtt{0x05}])\kern-0.1em\big)$. +> +> ($\mathsf{H^{esk,Sapling}}$ intentionally takes an argument that is unused.) Replace the lines deriving $\mathsf{rcm}$ and $\mathsf{esk}$ with @@ -794,6 +794,11 @@ with #### § 4.8.2 ‘Dummy Notes (Sapling)’ +Add + +> Let $\mathsf{Derive\_rcm^{Sapling}}$ be as defined in +> § 4.7.2 ‘Sending Notes (Sapling)’. + Replace the line deriving $\mathsf{rcm}$ with > Derive $\mathsf{rcm} = \mathsf{Derive\_rcm^{Sapling}_{rseed}}(\mathsf{leadByte})$ @@ -802,7 +807,7 @@ Replace the line deriving $\mathsf{rcm}$ with Insert before "The spend-related fields ...": -> Let $\mathsf{H^{rcm,Orchard}}$ and $\mathsf{H^{\text{ψ},Orchard}}$ be +> Let $\mathsf{Derive\_rcm^{Orchard}}$ and $\mathsf{H^{\text{ψ},Orchard}}$ be > as defined in § 4.7.3 ‘Sending Notes (Orchard)’. Replace the lines deriving $\mathsf{rcm}$ and $\text{ψ}$ with @@ -821,9 +826,10 @@ in the inputs to $\mathsf{NoteCommit^{Orchard}}$. For both § 4.20.2 and § 4.20.3, add before the decryption procedure: -> Let $\mathsf{H^{esk,Sapling}}$ be as defined in § 4.7.2 ‘Sending Notes (Sapling)’. +> Let $\mathsf{Derive\_rcm^{Sapling}}$ and $\mathsf{H^{esk,Sapling}}$ be +> as defined in § 4.7.2 ‘Sending Notes (Sapling)’. > -> Let $\mathsf{H^{rcm,Orchard}}$, $\mathsf{H^{esk,Orchard}}$, +> Let $\mathsf{Derive\_rcm^{Orchard}}$, $\mathsf{H^{esk,Orchard}}$, > and $\mathsf{H^{\text{ψ},Orchard}}$ be as defined in > § 4.7.3 ‘Sending Notes (Orchard)’. @@ -1434,20 +1440,20 @@ $\varepsilon_{\mathsf{kb}}(\mathcal{A}, q_{\mathsf{kb}}) \leq \frac{3\, q_{\math *Algebraic setup.* By § 5.4.1.10 “Sinsemilla commitments”, -$\mathsf{Commit^{ivk}_{rivk}}(\mathsf{ak}, \mathsf{nk}) = -\mathsf{Extract}_{\mathbb{P}}\big(M' + [\mathsf{rivk}]\, \mathcal{S}\big)$, -where -$\mathcal{S} := \mathsf{GroupHash}^{\mathbb{P}}(\texttt{“z.cash:Orchard-CommitIvk-r”}, \texttt{“”})$ -is the rivk-randomization base and -$M' := \mathsf{SinsemillaHashToPoint}\big(\texttt{“z.cash:Orchard-CommitIvk-M”},\, -\mathsf{LEBSP}(\mathsf{ak}) \,\Vert\, \mathsf{LEBSP}(\mathsf{nk})\big)$ -(see § 5.4.1.10 for the exact bit-sequence encoding). +$$\mathsf{Commit^{ivk}_{rivk}}(\mathsf{ak}, \mathsf{nk}) = +\mathsf{Extract}_{\mathbb{P}}\big(M' + [\mathsf{rivk}]\, \mathcal{S}\big),$$ +where $\mathcal{S}$ is the rivk-randomization base +$$\mathcal{S} := \mathsf{GroupHash}^{\mathbb{P}}(\texttt{“z.cash:Orchard-CommitIvk-r”}, \texttt{“”}),$$ +and +$$M' := \mathsf{SinsemillaHashToPoint}\big(\texttt{“z.cash:Orchard-CommitIvk-M”},\; +\mathsf{I2LEBSP}_{\ell^{\mathsf{Orchard}}_{\mathsf{base}}}(\mathsf{ak}) \,\Vert\, +\mathsf{I2LEBSP}_{\ell^{\mathsf{Orchard}}_{\mathsf{base}}}(\mathsf{nk})\big).$$ By expanding the Sinsemilla bases used inside $\mathsf{SinsemillaHashToPoint}$ as scalar multiples of $\mathcal{S}$, without loss of generality we have $M' = [h(\mathsf{ak}, \mathsf{nk})]\, \mathcal{S}$ for a Pedersen-like -deterministic scalar hash $h$. Therefore -$\mathsf{Commit^{ivk}_{rivk}}(\mathsf{ak}, \mathsf{nk}) = -\mathsf{Extract}_{\mathbb{P}}\big([h(\mathsf{ak}, \mathsf{nk}) + \mathsf{rivk}]\, \mathcal{S}\big)$. +deterministic scalar hash $h$, so +$$\mathsf{Commit^{ivk}_{rivk}}(\mathsf{ak}, \mathsf{nk}) = +\mathsf{Extract}_{\mathbb{P}}\big([h(\mathsf{ak}, \mathsf{nk}) + \mathsf{rivk}]\, \mathcal{S}\big).$$ Domain separation in the protocol's BLAKE2b instantiations ensures $h$ does not query $\mathsf{H^{rivk\_ext}}$, $\mathsf{H^{rivk\_legacy}}$, From ad5a23eb897816d14c98ac66062a11b514a0b8cc Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Sat, 16 May 2026 21:53:57 +0100 Subject: [PATCH 084/115] ZIP 2005: Fill out "Effects of discrete-log-breaking attacks" sections Cover the threat surface across Zcash's shielded and transparent protocols; split into "before the switch", "after the switch", and "attacks addressed by the Recovery Protocol" subsections; enumerate attack classes (Balance, Spend authentication, Spendability, Privacy). Add ZIP 209 (turnstile), ZIP 2003 (disable v4 transactions), and the Google 2025 paper on quantum attacks against blockchains to the references. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --- zips/zip-2005.md | 113 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 109 insertions(+), 4 deletions(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index ce10078f3..ded1bcaf7 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -1791,8 +1791,107 @@ have not yet been verified. ## Effects of discrete-log-breaking attacks before the switch to the Recovery Protocol -TBD: explain that such attacks can break Balance and Spendability, including -Spendability for transactions after switching to the Recovery Protocol. +A practical discrete-log-breaking attack —either by a sufficiently large quantum +computer running Shor's algorithm, or a major advance in classical cryptanalysis +of the discrete logarithm or Diffie–Hellman problems— would compromise the +cryptographic primitives underlying Zcash's shielded protocols. + +Note and value commitments in Orchard[ZSA] and Sapling are Pedersen-style and +lose binding; the proof systems used in the shielded protocols (Halo 2 over +Vesta in Orchard[ZSA], Groth16 over BLS12-381 in Sapling or Sprout) lose +soundness; and the RedDSA binding and spend authorization signatures in +Orchard[ZSA] and Sapling can be forged. Sprout's note commitments are +SHA-256-based and survive a discrete log break, but the broken proof system is +sufficient to forge JoinSplit statements, and the Ed25519 spend authorization +and JoinSplit signatures can be forged. In addition, the ECDSA signatures used +for transparent spend authentication can be forged. + +The combined effect is severe. An adversary can: + +* break Balance for the Sapling or Orchard pools by forging value-commitment + openings or binding signatures; +* break Balance for the Sprout, Sapling, or Orchard pools by forging Groth16 or + Halo 2 proofs of balanced transactions; +* break Spend authentication (i.e. steal funds, independently of a Balance break) + for the Sprout, Sapling, or Orchard pools by forging alternative note witnesses + for any commitment on chain, or by forging Groth16 or Halo 2 proofs of valid + spends; +* break Spend authentication for the Sapling or Orchard pools by forging RedJubjub + or RedPallas spend authorization signatures, or for the transparent pool by + forging ECDSA-over-secp256k1 signatures used in scripts; +* break Spendability via roadblock or Faerie Gold attacks, preventing users from + spending their own funds; +* break Privacy of note plaintexts by finding the $\mathsf{ivk}$ for a known + Sapling or Orchard address, or the $\mathsf{sk_{enc}}$ for a known Sprout + address, or by breaking the Diffie–Hellman-based note encryption (again only + for a known recipient address). + +Attacks on transparent spend authentication are not addressed by this proposal. +[^Google2025] discusses these attacks in the context of Bitcoin. For Zcash, we +should note that P2PK and legacy P2MS (non-P2SH) scripts have never been +supported by Zcash wallets, but Zcash is vulnerable to "on-spend" attacks in a +similar way to Bitcoin, with the additional consideration that some Zcash +wallets might be more likely to reuse transparent addresses. The discussion of +Segwit is not relevant to Zcash. + +## Effects of discrete-log-breaking attacks after the switch to the Recovery Protocol + +We assume for this section that the legacy Orchard, OrchardZSA (if deployed), +Sapling, and Sprout protocols will be switched off. Any remaining funds in +the Sapling and Sprout pools, as well as funds in non-recoverable Orchard notes, +would be rendered permanently unspendable. + +The Balance, Spend authentication, and Spendability attacks are possible only +*before* the switch to the Recovery Protocol — that is, while legacy Orchard, +Sapling, and (if ZIP 2003 is not deployed first [^zip-2003]) Sprout spends are +still accepted by the consensus rules. + +If a balance violation occurred in any pool before its protocol was switched +off, it would not necessarily be detected. The only constraint on such attacks +is the ZIP 209 turnstile mechanism [^zip-0209]. If there were evidence of +balance violation having occurred, confidence in Zcash as a whole could +potentially be undermined despite the turnstile constraints (especially if the +violation was in the largest pool, currently Orchard). Therefore, it will be +essential to ensure that the pre-quantum protocols are switched off well in +advance of the potential availability of cryptographically relevant quantum +computers. + +If the transparent protocol is not switched off, then the situation with respect +to transparent spend authentication is unchanged. Balance for the transparent +protocol cannot be violated directly by a discrete-log break (but funds created +by a balance violation in a shielded pool can be moved into the transparent pool +up to that shielded pool's turnstile limit). + +The changes made by ZIP 2005 are only intended to address Balance preservation, +Spend authentication, and Spendability for recoverable Orchard[ZSA] notes. The +situation with respect to Privacy is unchanged for any pool. + +In particular, the note encryption for Orchard[ZSA], Sapling, and Sprout pools +is subject to "Harvest Now, Decrypt Later" attacks: that is, a +discrete-log-breaking attack can be performed as long as an adversary has both +the ciphertext (which is published on the block chain) and the recipient +address. Other protocol changes are under consideration to mitigate this risk +for future transfers. + +Due to the zero-knowledge property, Groth16 and Halo 2 proofs do not leak +further information relevant to Privacy when addresses are unknown. The same is +true of Sapling or Orchard[ZSA] spend authentication signatures, due to key +rerandomization. + +## Attacks addressed by the Recovery Protocol + +The Recovery Statement's $\mathsf{BindKeys}$ constraint pins the key witness via +$\mathsf{PRF^{expand}}$ (modelled as collapsing), not via discrete-log hardness. +So (if no mistakes are made in the design or instantiation), fresh Balance, +Spend authentication, or Spendability attacks against the Recovery Protocol +should require breaking post-quantum binding rather than just discrete logs. +Funds in recoverable Orchard notes can therefore be spent through the Recovery +Protocol after the switch. However, if the adversary attacked either +Spendability (e.g. via a roadblock attack) or Spend authorization before the +switch to the Recovery Protocol, then it could affect the legitimate holder's +ability to spend the funds afterward. The window between +$\mathsf{ZIP2005ActivationHeight}$ and the switch is the critical exposure +period for recoverable Orchard funds. Note that we can precisely identify the set of note commitments for recoverable Orchard notes in v6 transactions, even if we cannot decrypt them, since only @@ -1804,8 +1903,8 @@ We cannot identify the precise set of nullifiers for recoverable notes: an Orchard action in a v6 transaction could be spending either a recoverable or non-recoverable note, and their nullifier sets are indistinguishable. -On the other hand, within the Recovery Statement we know that the -note being spent is recoverable. +On the other hand, within the Recovery Statement we know that the note being +spent is recoverable. # Deployment @@ -1895,6 +1994,8 @@ manipulate the note selection algorithm to some extent. [^zip-0200]: [ZIP 200: Network Upgrade Mechanism](zip-0200.rst) +[^zip-0209]: [ZIP 209: Prohibit Negative Shielded Chain Value Pool Balances](zip-0209.rst) + [^zip-0226]: [ZIP 226: Transfer and Burn of Zcash Shielded Assets](zip-0226.rst) [^zip-0226-split-notes]: [ZIP 226: Transfer and Burn of Zcash Shielded Assets — Split Notes](zip-0226.rst#split-notes) @@ -1913,6 +2014,8 @@ manipulate the note selection algorithm to some extent. [^zip-0312-threat-model]: [ZIP 312: FROST for Spend Authorization Multisignatures — Threat Model](zip-0312.rst#threat-model) +[^zip-2003]: [ZIP 2003: Disallow version 4 transactions](zip-2003.rst) + [^zcash-security]: Understanding Zcash Security ([video](https://www.youtube.com/watch?v=f6UToqiIdeY), [slides](https://raw.githubusercontent.com/daira/zcash-security/main/zcash-security.pdf)). Presentation by Daira-Emma Hopwood at Zcon3. [^pq-zcash]: Post-Quantum Zcash ([video](https://www.youtube.com/watch?v=T2B5f297d-Y), [slides](https://docs.google.com/presentation/d/1BHBiSOEO5zt40KWBbRXVMGIIuAcT2hfPWZQ3pT_8tm8/edit?slide=id.g335164f3026_0_113#slide=id.g335164f3026_0_113)). Presentation by Daira-Emma Hopwood at ZconVI. @@ -1938,3 +2041,5 @@ manipulate the note selection algorithm to some extent. [^CDDGS2025]: [Quantum Rewinding for IOP-Based Succinct Arguments. Alessandro Chiesa, Marcel Dall'Agnol, Zijing Di, Ziyi Guan, and Nicholas Spooner.](https://eprint.iacr.org/2025/947) [^ACMT2025]: [The Sponge is Quantum Indifferentiable. Gorjan Alagic, Joseph Carolan, Christian Majenz, and Saliha Tokat.](https://eprint.iacr.org/2025/731) + +[^Google2025]: [Securing Elliptic Curve Cryptocurrencies against Quantum Vulnerabilities: Resource Estimates and Mitigations. Ryan Babbush, Adam Zalcman, Craig Gidney, Michael Broughton, Tanuj Khattar, Hartmut Neven, Thiago Bergamaschi, Justin Drake, and Dan Boneh](https://quantumai.google/static/site-assets/downloads/cryptocurrency-whitepaper.pdf) From 11aa50ba271ba6b9e2a25a5923b1929259119675 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Sun, 17 May 2026 00:21:59 +0100 Subject: [PATCH 085/115] ZIP 2005: Minor reference fixes. Signed-off-by: Daira-Emma Hopwood <daira@jacaranda.org> --- zips/zip-2005.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index ded1bcaf7..964de0dda 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -2002,9 +2002,7 @@ manipulate the note selection algorithm to some extent. [^zip-0227]: [ZIP 227: Issuance of Zcash Shielded Assets](zip-0227.rst) -[^zip-0230]: [ZIP 230: Version 6 Transaction Format](zip-0230.rst) - -[^zip-0231]: [ZIP 231: Memo Bundles](zip-0231.rst) +[^zip-0231]: [ZIP 231: Memo Bundles](zip-0231.md) [^zip-0248]: [ZIP 248: Extensible Transaction Format (PR: zcash/zips#1156)](https://github.com/zcash/zips/pull/1156) From 6a0f0abbb00a73495c03279585586062bf93c2d1 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Sun, 17 May 2026 00:52:47 +0100 Subject: [PATCH 086/115] =?UTF-8?q?ZIP=202005:=20Resolve=20TODO=20?= =?UTF-8?q?=E2=80=94=20discuss=20collapsing=20property=20for=20Recovery=20?= =?UTF-8?q?Protocol=20QROM=20lift.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cite Unruh on the collapsing property, Czajkowski et al. for sponge, ACMT2025 for the sponge strengthening, Fehr 2018 for the unified algebraic framework covering Merkle–Damgård and HAIFA (BLAKE2b's construction), and Gunsing and Mennink 2022 for tree hashes (relevant for the Recovery Protocol's note-commitment tree). Modelling H^rcm as collapsing reduces, via Fehr's theorem, to modelling BLAKE2b's compression function as collapsing — the natural post-quantum analog of the random-oracle modelling assumption underlying the classical-ROM analysis. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --- zips/zip-2005.md | 125 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 88 insertions(+), 37 deletions(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index 964de0dda..e14d457b0 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -1156,6 +1156,11 @@ $\text{where } \mathsf{pre\_rcm} = [\mathtt{0x0B}] \,||\, \mathsf{encode}(\maths ### Informal security argument for binding of note commitments +For the formal versions of these arguments and their adaptation to the +post-quantum setting, see the [key-binding](#thm-key-binding-rom) and +[Spendability](#thm-spendability-collide) theorems below, and +[§ Adaptation to the quantum setting](#adaptationtothequantumsetting). + We can view the output of $\mathsf{NoteCommit_{rcm}}$ for $\mathsf{notetuple} = (\mathsf{rseed}, \mathsf{noterepr})$ as the point addition of a randomization term @@ -1221,8 +1226,7 @@ note in the tree. As argued above, the distribution of $\mathsf{rcm}$ is indistinguishable from uniform-random on $\mathbb{F}_{r_\mathbb{P}}$. The success probability for each attempt in a classical search is therefore $2N/r_{\mathbb{P}}$ where $r_{\mathbb{P}}$ is the order of the Pallas curve, -and that is negligible because $N \leq 2^{32} \ll r_{\mathbb{P}}$. This is -also infeasible for a quantum adversary using a Grover search. +and that is negligible because $N \leq 2^{32} \ll r_{\mathbb{P}}$. We're not finished yet because we also have to prove that the nullifier is computed deterministically for a given note. @@ -1247,15 +1251,14 @@ uses (they can choose to attack either, or both simultaneously): is deterministic). <br> In particular, $\mathsf{ivk}$ is an essentially random function of $\mathsf{sk}$, and so we expect that an adversary has no better attack - than to search for values of $\mathsf{sk}$ (possibly using a Grover search) + than to search for values of $\mathsf{sk}$ 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)), 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 - $T \ll r_{\mathbb{P}}$. This is also infeasible for a quantum adversary - using a Grover search for reasonable values of $T$. + $T \ll r_{\mathbb{P}}$. * Case $\mathsf{qk} \neq \bot$: This case is almost the same except that $\mathsf{ivk}$ is now an essentially random function of @@ -1280,32 +1283,6 @@ necessary to defend against a discrete-log-breaking or quantum adversary. Therefore, the post-quantum [Recovery Statement](#proposedrecoverystatement) will need to use complete curve additions to implement Sinsemilla. -### Adaptation to the quantum setting - -In order to adapt this argument to the quantum setting, we need to consider -*collapsing* hash functions as defined in [^Unruh2015] [^Unruh2016]. - -$\mathsf{Extract}_{\mathbb{P}}$ does not interfere with the QROM lift: -it is a deterministic 2-to-1 map on non-identity Pallas points -(sending $P$ and $-P$ to the same $x$-coordinate) and does not query -$\mathsf{H^{rcm}}$ or any other random oracle, so it composes with the -underlying random oracle the same way classically and quantumly. The -factor of 2 from the 2-to-1 reduction is already absorbed into the -break-probability bound (each $\mathsf{cm}_x$ has exactly two valid -$\mathsf{cm}$ values, hence exactly two valid $\mathsf{rcm}$ values, as -stated above). - -By the argument in [^Bernstein2009], the best known *generic* quantum -attack on a hash function is simply the classical attack of [^vOW1999]. -(In particular, the Brassard–Høyer–Tapp algorithm [^BHT1997] is entirely -unimplementable for a 253-bit output size: to achieve the claimed speed-up, -it would require running Grover's algorithm with a quantum circuit that -does random accesses to a $2^{92.3}$-bit quantum memory.) Therefore, an -output size of 253 bits does not exclude a hash function from being collapsing. - -TODO: discuss [^CBHSU2017] (sponge security), [^Unruh2015] [^Unruh2016] -(collapse-binding property). - ### Security argument for key binding The security of Orchard against several attacks depends on cryptographic @@ -1782,12 +1759,82 @@ $q_{\mathsf{kb}}$ queries to the key-binding random oracles wins the Spendability-collision game with probability at most $\frac{q_{\mathsf{rcm}}(q_{\mathsf{rcm}}-1)}{r_{\mathbb{P}}} \;+\; \frac{3\, q_{\mathsf{kb}}(q_{\mathsf{kb}}-1)}{2\, r_{\mathbb{P}}}$. -TODO (QROM lift): The reduction is straight-line and does not adaptively -reprogram $\mathsf{H^{rcm}}$ on inputs the adversary may have queried in -superposition, so we expect a clean lift to the quantum random-oracle -model via standard QROM techniques [^Unruh2015] [^Unruh2016] [^CMSZ2021] -[^CDDGS2025], with at most a small loss factor. The technical conditions -have not yet been verified. +For the post-quantum lift of this bound and of the +[key-binding bound](#thm-key-binding-rom) above, see the next section. + +## Adaptation to the quantum setting + +The classical-ROM proofs above (for [key binding](#thm-key-binding-rom) +and [Spendability](#thm-spendability-collide)) rely on +$\mathsf{H^{rcm}}$ and the various $\mathsf{rivk}$-derivation hashes +being collision-resistant. The natural quantum analog is called the +*collapsing* property, introduced by Unruh [^Unruh2015] [^Unruh2016]. +It says that even a quantum adversary holding a *superposition* over +several preimages of a fixed output cannot tell —by any subsequent +measurement— which preimage it now has. This is the right property +for our reductions. Each proof above splits cases based on which oracle +query produced the colliding output; that case analysis works the same +classically and quantumly only if the underlying hash "collapses" the +adversary's superposition to a single classical preimage. + +Subsequent work has analyzed whether standard hash-function +constructions inherit collapsing from their compression function. Unruh +[^Unruh2016] proved this for Merkle–Damgård (with a padding +restriction); Czajkowski et al. [^CBHSU2017] for the *sponge* +construction (the absorb-then-squeeze paradigm used by SHA-3 / Keccak), +with [^ACMT2025] strengthening the sponge result via the related notion +of quantum indifferentiability. Fehr [^Fehr2018] gave a unified +algebraic framework that recovers these results and proves the +collapsing property of HAIFA, a Merkle–Damgård variant with a +per-iteration salt and counter. Gunsing and Mennink [^GM2022] extended +this kind of analysis to tree-hash constructions, relevant for the +Recovery Protocol's note-commitment tree. + +BLAKE2b uses HAIFA, so by Fehr's theorem modelling $\mathsf{H^{rcm}}$ +as collapsing reduces to modelling BLAKE2b's compression function as +collapsing. The "iv-preimage resistance" side condition Fehr's theorem +requires for arbitrary-length inputs is automatically satisfied if the +compression function is modelled as a random oracle — which is also +the modelling assumption underlying the classical-ROM analyses above. + +By the argument in [^Bernstein2009], the best known *generic* quantum +attack on a hash function is simply the classical attack of [^vOW1999]. +(In particular, the Brassard–Høyer–Tapp algorithm [^BHT1997] is +entirely unimplementable for a 253-bit output size: to achieve the +claimed speed-up, it would require running Grover's algorithm with a +quantum circuit that does random accesses to a $2^{92.3}$-bit quantum +memory.) Therefore, an output size of 253 bits does not exclude a hash +function from being collapsing. + +$\mathsf{Extract}_{\mathbb{P}}$ does not interfere with the QROM lift: +it is a deterministic 2-to-1 map on non-identity Pallas points (sending +$P$ and $-P$ to the same $x$-coordinate) and does not query +$\mathsf{H^{rcm}}$ or any other random oracle, so it composes with the +underlying random oracle the same way classically and quantumly. The +factor of 2 from the 2-to-1 reduction is already absorbed into the +break-probability bound (each $\mathsf{cm}_x$ has exactly two valid +$\mathsf{cm}$ values, hence exactly two valid $\mathsf{rcm}$ values, as +stated in the Spendability proof above). + +### QROM lift of the security arguments + +The classical-ROM reductions for both +[Spendability](#thm-spendability-collide) and +[key binding](#thm-key-binding-rom) satisfy the standard conditions for +a "clean" lift to the quantum random-oracle model: + +* *Straight-line.* Neither reduction rewinds the adversary or measures + intermediate state; both inspect the adversary's classical output and + bound the probability over the random oracles' randomness. + Rewinding-based QROM techniques [^CMSZ2021] [^CDDGS2025] are therefore + not needed. +* *No adaptive reprogramming.* Both reductions treat their random + oracles as fixed random functions throughout; neither reprograms + responses to adversary-queried inputs. + +Under the collapsing modelling, both classical-ROM bounds transfer to +QROM with at most a polynomial loss factor in the number of oracle +queries. ## Effects of discrete-log-breaking attacks before the switch to the Recovery Protocol @@ -2034,8 +2081,12 @@ manipulate the note selection algorithm to some extent. [^CBHSU2017]: [Post-quantum security of the sponge construction. Jan Czajkowski, Leon Groot Bruinderink, Andreas Hülsing, Christian Schaffner, and Dominique Unruh.](https://eprint.iacr.org/2017/771) +[^Fehr2018]: [Classical Proofs for the Quantum Collapsing Property of Classical Hash Functions. Serge Fehr.](https://eprint.iacr.org/2018/887) + [^CMSZ2021]: [Post-Quantum Succinct Arguments: Breaking the Quantum Rewinding Barrier. Alessandro Chiesa, Fermi Ma, Nicholas Spooner, and Mark Zhandr.](https://eprint.iacr.org/2021/334) +[^GM2022]: [Collapseability of Tree Hashes. Aldo Gunsing and Bart Mennink.](https://eprint.iacr.org/2022/248) + [^CDDGS2025]: [Quantum Rewinding for IOP-Based Succinct Arguments. Alessandro Chiesa, Marcel Dall'Agnol, Zijing Di, Ziyi Guan, and Nicholas Spooner.](https://eprint.iacr.org/2025/947) [^ACMT2025]: [The Sponge is Quantum Indifferentiable. Gorjan Alagic, Joseph Carolan, Christian Majenz, and Saliha Tokat.](https://eprint.iacr.org/2025/731) From b80fba3ba811059c7e36c90d871865018339b418 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Sun, 17 May 2026 02:16:34 +0100 Subject: [PATCH 087/115] ZIP 2005: State concrete QROM bounds via Zhandry's compressed-oracle technique. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By the standard BHT-style cubic-in-q quantum collision speed-up, the classical-ROM bounds q²/r_P transfer to QROM with at most O(q³/r_P) success probability. For Zcash-relevant parameters (q << 2^60, r_P ≈ 2^254), the cubic ceiling is ~2^{-74}; the practically achievable bound stays closer to the classical ~2^{-134} since BHT-style attacks need infeasible quantum memory (per the 2^{92.3} argument earlier in the section) and the best known generic quantum attack is the classical attack of [vOW1999]. Add [Zhandry2018] eprint 2018/276 to the references. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --- zips/zip-2005.md | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index e14d457b0..eec711ac6 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -1832,9 +1832,32 @@ a "clean" lift to the quantum random-oracle model: oracles as fixed random functions throughout; neither reprograms responses to adversary-queried inputs. -Under the collapsing modelling, both classical-ROM bounds transfer to -QROM with at most a polynomial loss factor in the number of oracle -queries. +**Concrete QROM bounds.** By Zhandry's compressed-oracle technique +[^Zhandry2018] (see also [^CFHL2021] for a classical-style derivation), +the classical $q^2 / N$ collision probability +transfers to $O(q^3 / N)$ in QROM: an adversary making at most $q$ +quantum queries to a random oracle with output space of size $N$ +finds a collision with probability $O(q^3 / N)$. Applied to our +reductions: + +* $\varepsilon^{\mathsf{QROM}}_{\mathsf{Spendability}} \leq O\!\left(q_{\mathsf{rcm}}^3 / r_{\mathbb{P}}\right) + \varepsilon^{\mathsf{QROM}}_{\mathsf{kb}}.$ +* $\varepsilon^{\mathsf{QROM}}_{\mathsf{kb}} \leq O\!\left(q_{\mathsf{kb}}^3 / r_{\mathbb{P}}\right).$ + +These are worst-case theoretical bounds. An adversary that saturates +them would need to mount a BHT-style attack, which is unimplementable +for a 253-bit output (as discussed above, the BHT algorithm would +require a quantum circuit randomly accessing a $2^{92.3}$-bit quantum +memory). In practice the achievable bound remains close to the +classical $q^2 / r_{\mathbb{P}}$, since the best *known* generic +quantum attack is the classical attack of [^vOW1999] — Bernstein +[^Bernstein2009] is careful to flag this as best-known rather than +provably best. + +For the parameters relevant to Zcash ($q_{\mathsf{rcm}}, +q_{\mathsf{kb}} \ll 2^{60}$ and $r_{\mathbb{P}} \approx 2^{254}$), +the $O(q^3 / r_{\mathbb{P}})$ worst-case bound is at most +$\sim 2^{-74}$, while the practically achievable +$O(q^2 / r_{\mathbb{P}})$ bound stays closer to $\sim 2^{-134}$. ## Effects of discrete-log-breaking attacks before the switch to the Recovery Protocol @@ -2083,6 +2106,10 @@ manipulate the note selection algorithm to some extent. [^Fehr2018]: [Classical Proofs for the Quantum Collapsing Property of Classical Hash Functions. Serge Fehr.](https://eprint.iacr.org/2018/887) +[^Zhandry2018]: [How to Record Quantum Queries, and Applications to Quantum Indifferentiability. Mark Zhandry.](https://eprint.iacr.org/2018/276) + +[^CFHL2021]: [On the Compressed-Oracle Technique, and Post-Quantum Security of Proofs of Sequential Work. Kai-Min Chung, Serge Fehr, Yu-Hsuan Huang, and Tai-Ning Liao.](https://eprint.iacr.org/2020/1305) + [^CMSZ2021]: [Post-Quantum Succinct Arguments: Breaking the Quantum Rewinding Barrier. Alessandro Chiesa, Fermi Ma, Nicholas Spooner, and Mark Zhandr.](https://eprint.iacr.org/2021/334) [^GM2022]: [Collapseability of Tree Hashes. Aldo Gunsing and Bart Mennink.](https://eprint.iacr.org/2022/248) From 603e9ad9316e14aaf052e8c436d9e34f479cd333 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Sun, 17 May 2026 02:39:47 +0100 Subject: [PATCH 088/115] ZIP 2005: Annotate bibliography entries with "Also published in ..." for conference versions. The eprint version of a paper may differ from the camera-ready published at a conference / in a journal. "Also published in ..." makes the multi-venue status explicit and signals to readers that the linked revision may differ from the named conference version. Applied to all bibliography entries that have both an eprint (or similar) URL and a known conference / journal version. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --- zips/zip-2005.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index eec711ac6..5af5fb7fd 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -2088,31 +2088,31 @@ manipulate the note selection algorithm to some extent. [^pq-zcash]: Post-Quantum Zcash ([video](https://www.youtube.com/watch?v=T2B5f297d-Y), [slides](https://docs.google.com/presentation/d/1BHBiSOEO5zt40KWBbRXVMGIIuAcT2hfPWZQ3pT_8tm8/edit?slide=id.g335164f3026_0_113#slide=id.g335164f3026_0_113)). Presentation by Daira-Emma Hopwood at ZconVI. -[^BHT1997]: [Quantum Algorithm for the Collision Problem. Gilles Brassard, Peter Høyer, and Alain Tapp.](https://arxiv.org/abs/quant-ph/9705002) +[^BHT1997]: [Quantum Algorithm for the Collision Problem. Gilles Brassard, Peter Høyer, and Alain Tapp.](https://arxiv.org/abs/quant-ph/9705002). Also published in LATIN 1998, LNCS vol. 1380, pp. 163–169. [^vOW1999]: [Parallel collision search with cryptanalytic applications. Paul C. van Oorschot and Michael Wiener.](https://link.springer.com/article/10.1007/PL00003816) -[^Bernstein2009]: [Cost analysis of hash collisions: Will quantum computers make SHARCS obsolete? Daniel J. Bernstein.](https://cr.yp.to/hash/collisioncost-20090517.pdf) +[^Bernstein2009]: [Cost analysis of hash collisions: Will quantum computers make SHARCS obsolete? Daniel J. Bernstein.](https://cr.yp.to/hash/collisioncost-20090517.pdf). Presented at SHARCS 2009. [^BLAKE3]: [BLAKE3: One Function, Fast Everywhere. Jack O'Connor, Jean-Philippe Aumasson, Samuel Neves, and Zooko Wilcox, 2020.](https://github.com/BLAKE3-team/BLAKE3-specs/blob/master/blake3.pdf) See § 2.1.2 for the `derive_key` mode. -[^Maurer2002]: [Indistinguishability of Random Systems. Ueli Maurer.](https://crypto.ethz.ch/publications/files/Maurer02.pdf) Advances in Cryptology — EUROCRYPT 2002, LNCS vol. 2332, pp. 110–132. +[^Maurer2002]: [Indistinguishability of Random Systems. Ueli Maurer.](https://crypto.ethz.ch/publications/files/Maurer02.pdf). Also published in Advances in Cryptology — EUROCRYPT 2002, LNCS vol. 2332, pp. 110–132. -[^Unruh2015]: [Computationally binding quantum commitments. Dominique Unruh.](https://eprint.iacr.org/2015/361) +[^Unruh2015]: [Computationally binding quantum commitments. Dominique Unruh.](https://eprint.iacr.org/2015/361). Also published in EUROCRYPT 2016, LNCS vol. 9666. -[^Unruh2016]: [Collapse-binding quantum commitments without random oracles. Dominique Unruh.](https://eprint.iacr.org/2016/508) +[^Unruh2016]: [Collapse-binding quantum commitments without random oracles. Dominique Unruh.](https://eprint.iacr.org/2016/508). Also published in ASIACRYPT 2016, LNCS vol. 10032. -[^CBHSU2017]: [Post-quantum security of the sponge construction. Jan Czajkowski, Leon Groot Bruinderink, Andreas Hülsing, Christian Schaffner, and Dominique Unruh.](https://eprint.iacr.org/2017/771) +[^CBHSU2017]: [Post-quantum security of the sponge construction. Jan Czajkowski, Leon Groot Bruinderink, Andreas Hülsing, Christian Schaffner, and Dominique Unruh.](https://eprint.iacr.org/2017/771). Also published in PQCrypto 2018, LNCS vol. 10786. -[^Fehr2018]: [Classical Proofs for the Quantum Collapsing Property of Classical Hash Functions. Serge Fehr.](https://eprint.iacr.org/2018/887) +[^Fehr2018]: [Classical Proofs for the Quantum Collapsing Property of Classical Hash Functions. Serge Fehr.](https://eprint.iacr.org/2018/887). Also published in TCC 2018, LNCS vol. 11240, pp. 315–338. -[^Zhandry2018]: [How to Record Quantum Queries, and Applications to Quantum Indifferentiability. Mark Zhandry.](https://eprint.iacr.org/2018/276) +[^Zhandry2018]: [How to Record Quantum Queries, and Applications to Quantum Indifferentiability. Mark Zhandry.](https://eprint.iacr.org/2018/276). Also published in CRYPTO 2019, LNCS vol. 11693. -[^CFHL2021]: [On the Compressed-Oracle Technique, and Post-Quantum Security of Proofs of Sequential Work. Kai-Min Chung, Serge Fehr, Yu-Hsuan Huang, and Tai-Ning Liao.](https://eprint.iacr.org/2020/1305) +[^CFHL2021]: [On the Compressed-Oracle Technique, and Post-Quantum Security of Proofs of Sequential Work. Kai-Min Chung, Serge Fehr, Yu-Hsuan Huang, and Tai-Ning Liao.](https://eprint.iacr.org/2020/1305). Also published in EUROCRYPT 2021, LNCS vol. 12826. -[^CMSZ2021]: [Post-Quantum Succinct Arguments: Breaking the Quantum Rewinding Barrier. Alessandro Chiesa, Fermi Ma, Nicholas Spooner, and Mark Zhandr.](https://eprint.iacr.org/2021/334) +[^CMSZ2021]: [Post-Quantum Succinct Arguments: Breaking the Quantum Rewinding Barrier. Alessandro Chiesa, Fermi Ma, Nicholas Spooner, and Mark Zhandr.](https://eprint.iacr.org/2021/334). Also published in FOCS 2021. -[^GM2022]: [Collapseability of Tree Hashes. Aldo Gunsing and Bart Mennink.](https://eprint.iacr.org/2022/248) +[^GM2022]: [Collapseability of Tree Hashes. Aldo Gunsing and Bart Mennink.](https://eprint.iacr.org/2022/248). Also published in PQCrypto 2020, LNCS vol. 12100, pp. 524–544. [^CDDGS2025]: [Quantum Rewinding for IOP-Based Succinct Arguments. Alessandro Chiesa, Marcel Dall'Agnol, Zijing Di, Ziyi Guan, and Nicholas Spooner.](https://eprint.iacr.org/2025/947) From 1ee91a57c61f637a3dfc298ae208049d551168bb Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Sun, 17 May 2026 03:07:27 +0100 Subject: [PATCH 089/115] =?UTF-8?q?ZIP=202005:=20Clarify=20leadByte=20choi?= =?UTF-8?q?ce=20for=20Orchard=20dummy=20notes=20in=20=C2=A7=204.8.3.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The leadByte choice is operationally irrelevant for dummy notes (plaintexts cannot be decrypted), but explicit guidance to use the highest allowed leadByte avoids an ambiguity flagged in review by @ebfull. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --- zips/zip-2005.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index 5af5fb7fd..791255497 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -582,11 +582,11 @@ with > $\mathsf{ZIP2005ActivationHeight}$ specifies the first block height at which > recoverable note plaintexts with lead byte $\mathtt{0x03}$ are allowed to > occur in Orchard outputs. Orchard note plaintexts sent to *wallet-internal* -> addresses SHOULD use lead byte $\mathtt{0x03}$ starting from this height. -> Orchard note plaintexts in v5 transactions sent to *external* addresses -> SHOULD use lead byte $\mathtt{0x02}$ until wallet support for receiving note -> plaintexts with lead byte $\mathtt{0x03}$ is widespread in the Zcash -> ecosystem. +> addresses, and dummy note plaintexts, SHOULD use lead byte $\mathtt{0x03}$ +> starting from this height. Orchard note plaintexts in v5 transactions sent +> to *external* addresses SHOULD use lead byte $\mathtt{0x02}$ until wallet +> support for receiving note plaintexts with lead byte $\mathtt{0x03}$ is +> widespread in the Zcash ecosystem. > > In other cases, senders SHOULD choose the highest note plaintext lead byte > allowed according to $\mathsf{allowedLeadBytes}.$ @@ -822,6 +822,10 @@ Replace the lines deriving $\mathsf{rcm}$ and $\text{ψ}$ with and use $\mathsf{g}\star_{\mathsf{d}}$, $\mathsf{pk}\star_{\mathsf{d}}$, in the inputs to $\mathsf{NoteCommit^{Orchard}}$. +Per § 3.2.1, use $\mathsf{leadByte} = \mathtt{0x03}$ starting from +$\mathsf{ZIP2005ActivationHeight}$. The choice is operationally irrelevant +for dummy notes, since their plaintexts cannot be decrypted. + #### § 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: From 537c3922aab90c9a74e5951866af22006a14b4dc Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Sun, 17 May 2026 14:49:21 +0100 Subject: [PATCH 090/115] =?UTF-8?q?ZIP=202005:=20Spell=20out=20the=20unifo?= =?UTF-8?q?rm-fibres=20condition=20for=20Extract=5F=E2=84=99's=20factor-of?= =?UTF-8?q?-2=20absorption.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Extract_ℙ composability paragraph asserted that the factor of 2 from the 2-to-1 reduction is absorbed into the break-probability bound, but didn't state the side-condition that makes this work: the fibres form a uniform partition phi for non-identity points. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --- zips/zip-2005.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index 791255497..6afdc593f 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -1820,6 +1820,14 @@ break-probability bound (each $\mathsf{cm}_x$ has exactly two valid $\mathsf{cm}$ values, hence exactly two valid $\mathsf{rcm}$ values, as stated in the Spendability proof above). +This factor-of-2 absorption relies on the +[fibres](https://en.wikipedia.org/wiki/Fiber_%28mathematics%29) $\{P, -P\}$ +of $\mathsf{Extract}_{\mathbb{P}}$ forming a *uniform* partition of the +non-identity points of $\mathbb{P}$ — the free $\mathbb{Z}/2$ negation action +gives every fibre for non-identity points exactly size 2 — which is what lets +birthday-style bounds substitute $r_{\mathbb{P}} \to r_{\mathbb{P}}/2$ cleanly. +A non-uniform mapping would not admit such a substitution. + ### QROM lift of the security arguments The classical-ROM reductions for both From 36b5204e6384fc9a928e4b4f9a4e0f7cc19d94a3 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Mon, 18 May 2026 14:46:35 +0100 Subject: [PATCH 091/115] ZIP 2005: Handle both internal and external cases in the discussion of rivk. Signed-off-by: Daira-Emma Hopwood <daira@jacaranda.org> --- zips/zip-2005.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index 6afdc593f..685693928 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -190,8 +190,9 @@ derivation of $\mathsf{rcm}$ is checked in the Recovery Protocol. Essentially the same technique also needs to be applied to the function $\mathsf{Commit^{ivk}}$ that is used to derive Orchard incoming viewing keys. The randomness $\mathsf{rivk}$ in -$\mathsf{Commit^{ivk}}$ is derived from one of two random oracles, -depending on which key material the user holds: +$\mathsf{Commit^{ivk}}$ is derived directly or indirectly from +$\mathsf{rivk\_ext}$, which is in turn derived from one of two random +oracles, depending on which key material the user holds: * For existing Orchard keys, $\mathsf{rivk\_ext}$ is derived from the secret key $\mathsf{sk}$ via $\mathsf{H^{rivk\_legacy}}(\mathsf{sk})$, @@ -206,7 +207,9 @@ depending on which key material the user holds: $\mathsf{SoK^{qsk}}$ proof of knowledge of $\mathsf{qsk}$ such that $\mathsf{H^{qk}}(\mathsf{qsk}) = \mathsf{qk}$. -Both branches are covered uniformly by the +Both branches (and both cases +$\mathsf{rivk} \in \big\{ \mathsf{rivk\_ext},\, \mathsf{H^{rivk\_int}_{rivk\_ext}}(\mathsf{ak}, \mathsf{nk}) \big\}$) +are covered uniformly by the [Security argument for key binding](#securityargumentforkeybinding): each binds the keys $(\mathsf{ak}, \mathsf{nk}, \mathsf{rivk})$ — and, when in use, $\mathsf{qk}$ — to the incoming-viewing key $\mathsf{ivk}$ From 5f05432286bf08cf20a8e8f63f84a221854acc94 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Mon, 18 May 2026 15:34:55 +0100 Subject: [PATCH 092/115] =?UTF-8?q?ZIP=202005:=20The=20randomizer=20for=20?= =?UTF-8?q?H^{=CF=88,Orchard}=20is=20rseed;=20there=20is=20no=20r=CF=88.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Daira-Emma Hopwood <daira@jacaranda.org> --- 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 685693928..a9ab9340a 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -1057,7 +1057,7 @@ $\begin{array}{l} \wedge\; \text{let } \mathsf{ivk} = \mathsf{Commit^{ivk}_{rivk}}(\mathsf{ak}, \mathsf{nk}) \vphantom{\big(}\\ \wedge\; \mathsf{ivk} \not\in \{0, \bot\} \vphantom{\Big(}\\ \wedge\; \text{let } \mathsf{pk_d} = [\mathsf{ivk}]\, \mathsf{g_d} \vphantom{\big(}\\ -\wedge\; \text{let } \text{ψ} = \mathsf{H}^{\text{ψ}}_{\mathsf{r}\text{ψ}}(\underline{\text{ρ}}) \vphantom{\Big(}\\ +\wedge\; \text{let } \text{ψ} = \mathsf{H^{\text{ψ},Orchard}_{rseed}}(\underline{\text{ρ}}) \vphantom{\Big(}\\ \wedge\; \text{let } \mathsf{noterepr} = \big(\mathsf{repr}_{\mathbb{P}}(\mathsf{g_d}), \mathsf{repr}_{\mathbb{P}}(\mathsf{pk_d}), \mathsf{v}, \underline{\text{ρ}}, \text{ψ}\big) \vphantom{\big(}\\ \wedge\; \text{let } \mathsf{rcm} = \mathsf{H^{rcm,Orchard}_{rseed}}\big(\mathtt{0x03}, \mathsf{noterepr}\big) \vphantom{\Big(}\\ \wedge\; \text{let } \mathsf{cm} = \mathsf{NoteCommit^{Orchard}_{rcm}}(\mathsf{noterepr}) \vphantom{\big(}\\ From ca3d0abba3fff5281ab64eee5017d5ac2c810faf Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Mon, 18 May 2026 20:59:24 +0100 Subject: [PATCH 093/115] ZIP 2005: The SHOULD for the lead byte of dummy note plaintexts was an overspecification. Change it to say that it doesn't matter which of the allowed lead bytes is used. Signed-off-by: Daira-Emma Hopwood <daira@jacaranda.org> --- zips/zip-2005.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index a9ab9340a..c9bcaaed8 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -585,14 +585,15 @@ with > $\mathsf{ZIP2005ActivationHeight}$ specifies the first block height at which > recoverable note plaintexts with lead byte $\mathtt{0x03}$ are allowed to > occur in Orchard outputs. Orchard note plaintexts sent to *wallet-internal* -> addresses, and dummy note plaintexts, SHOULD use lead byte $\mathtt{0x03}$ -> starting from this height. Orchard note plaintexts in v5 transactions sent -> to *external* addresses SHOULD use lead byte $\mathtt{0x02}$ until wallet -> support for receiving note plaintexts with lead byte $\mathtt{0x03}$ is -> widespread in the Zcash ecosystem. +> addresses SHOULD use lead byte $\mathtt{0x03}$ starting from this height. +> Orchard note plaintexts in v5 transactions sent to *external* addresses +> SHOULD use lead byte $\mathtt{0x02}$ until wallet support for receiving note +> plaintexts with lead byte $\mathtt{0x03}$ is widespread in the Zcash ecosystem. > -> In other cases, senders SHOULD choose the highest note plaintext lead byte -> allowed according to $\mathsf{allowedLeadBytes}.$ +> In other cases, senders of non-dummy note plaintexts SHOULD choose the +> highest note plaintext lead byte allowed according to $\mathsf{allowedLeadBytes}.$ +> For dummy note plaintexts, any of the allowed lead bytes MAY be used (it does +> not matter which). Delete the non-normative note: From 8a85e34d0a31232303612cef50e92aff96241b36 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Mon, 18 May 2026 15:46:26 +0100 Subject: [PATCH 094/115] ZIP 2005: Remove an irrelevant not-taken option. Signed-off-by: Daira-Emma Hopwood <daira@jacaranda.org> --- zips/zip-2005.md | 1 - 1 file changed, 1 deletion(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index c9bcaaed8..4c333a7ab 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -1095,7 +1095,6 @@ even if they are incomplete in the current Orchard[ZSA] statement/circuit. * 1 to compute $\mathsf{H^{rivk\_int}}$ * 1 to compute $\mathsf{H^{\text{ψ}}}$ * 2 to compute $\mathsf{H^{rcm}}$ - * we could potentially save these two by using Poseidon to implement $\mathsf{H^{rcm}}$, but it seems not worth it. * 1 BLAKE3 compression for $\mathsf{H^{qk}}$ (with the $\mathsf{derive\_key}$ context key precomputed as a constant) * 1 use of $\mathsf{Commit^{ivk}}$ ($\mathsf{SinsemillaShortCommit}$) * 1 use of $\mathsf{NoteCommit}$ ($\mathsf{SinsemillaCommit}$) From 60fd4036331816f4f4435200033cee11742a1772 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Mon, 18 May 2026 15:51:29 +0100 Subject: [PATCH 095/115] ZIP 2005: Split out the cost of SoK^qsk. Signed-off-by: Daira-Emma Hopwood <daira@jacaranda.org> --- zips/zip-2005.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index 4c333a7ab..268cfbc02 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -1089,13 +1089,13 @@ very little extra. All of the operations below need to be implemented with complete additions, even if they are incomplete in the current Orchard[ZSA] statement/circuit. +In $\mathsf{SoK^{sk}}$ and the main circuit: * 7 BLAKE2b-512 compressions: * 3 multiplexed between $\mathsf{H^{rivk\_ext}}$ when $\mathsf{use\_qsk}$ is true (1 compression), and $\mathsf{H^{ask}}$ + $\mathsf{H^{nk}}$ + $\mathsf{H^{rivk\_legacy}}$ when $\mathsf{use\_qsk}$ is false (3 compressions) * 1 to compute $\mathsf{H^{rivk\_int}}$ * 1 to compute $\mathsf{H^{\text{ψ}}}$ * 2 to compute $\mathsf{H^{rcm}}$ -* 1 BLAKE3 compression for $\mathsf{H^{qk}}$ (with the $\mathsf{derive\_key}$ context key precomputed as a constant) * 1 use of $\mathsf{Commit^{ivk}}$ ($\mathsf{SinsemillaShortCommit}$) * 1 use of $\mathsf{NoteCommit}$ ($\mathsf{SinsemillaCommit}$) * 1 full-width fixed-base Pallas scalar multiplication, $[\mathsf{ask}]\, \mathcal{G}^{\mathsf{Orchard}}$ @@ -1103,6 +1103,11 @@ even if they are incomplete in the current Orchard[ZSA] statement/circuit. * 1 Merkle tree path check * 1 additional use of $\mathsf{MerkleCRH}$ to compute $\mathsf{leaf}$. +In $\mathsf{SoK^{qsk}}$: +* 1 BLAKE3 compression for $\mathsf{H^{qk}}$ (with the $\mathsf{derive\_key}$ context key precomputed as a constant) + +plus potentially linking commitments between the circuits. + The expensive parts of this are the 7 BLAKE2b compressions. ## Security analysis From f4d8f601473958630b58d77d272d59dc1504d133 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Mon, 18 May 2026 15:57:17 +0100 Subject: [PATCH 096/115] ZIP 2005: [GM2022] is also relevant to the pq security of Merkle trees. Signed-off-by: Daira-Emma Hopwood <daira@jacaranda.org> --- zips/zip-2005.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index 268cfbc02..811993eb0 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -1132,7 +1132,8 @@ Suppose this has been done. > The post-quantum security of Merkle trees —considered as position-binding > vector commitments which is the property required by Zcash [^zcash-security]— -> is proven under reasonable assumptions in [^CMSZ2021] and [^CDDGS2025]. +> is proven under reasonable assumptions in [^CMSZ2021], [^GM2022], and +> [^CDDGS2025]. Note: when we rehash the commitment tree, we could include both $\text{ρ}$ and $\mathsf{cm}_x$ for each note (i.e. what is currently the leaf layer becomes From 7bb8c7ee5332ab5722ce0834ead27533f53cb46a Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Mon, 18 May 2026 14:23:29 +0100 Subject: [PATCH 097/115] ZIP 2005: Fix a wording nit. pre_esk is now inlined for Sapling and Orchard, and pre_rcm is inlined for Sapling. Signed-off-by: Daira-Emma Hopwood <daira@jacaranda.org> --- zips/zip-2005.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index 811993eb0..2005630e9 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -895,9 +895,9 @@ 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 -define $\mathsf{Derive\_rcm^{\{Sapling,Orchard\}}}$. +The definitions of $\mathsf{pre\_rcm}$ and $\mathsf{pre\_esk}$ are moved or inlined +into § 4.7.2 ‘Sending Notes (Sapling)’ and § 4.7.3 ‘Sending Notes (Orchard)’ which +define $\mathsf{Derive\_rcm^{\{Sapling,Orchard\}}}$ and $\mathsf{H^{esk,\{Sapling,Orchard\}}}$. For § 4.20.3, replace From 5fa8814f0aa421d598559164b3b43301427cfbdc Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Mon, 18 May 2026 14:32:45 +0100 Subject: [PATCH 098/115] ZIP 2005: Cosmetic; remove repeated '.'s in references. Signed-off-by: Daira-Emma Hopwood <daira@jacaranda.org> --- zips/zip-2005.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index 2005630e9..5fa0a6d0a 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -2109,31 +2109,31 @@ manipulate the note selection algorithm to some extent. [^pq-zcash]: Post-Quantum Zcash ([video](https://www.youtube.com/watch?v=T2B5f297d-Y), [slides](https://docs.google.com/presentation/d/1BHBiSOEO5zt40KWBbRXVMGIIuAcT2hfPWZQ3pT_8tm8/edit?slide=id.g335164f3026_0_113#slide=id.g335164f3026_0_113)). Presentation by Daira-Emma Hopwood at ZconVI. -[^BHT1997]: [Quantum Algorithm for the Collision Problem. Gilles Brassard, Peter Høyer, and Alain Tapp.](https://arxiv.org/abs/quant-ph/9705002). Also published in LATIN 1998, LNCS vol. 1380, pp. 163–169. +[^BHT1997]: [Quantum Algorithm for the Collision Problem. Gilles Brassard, Peter Høyer, and Alain Tapp.](https://arxiv.org/abs/quant-ph/9705002) Also published in LATIN 1998, LNCS vol. 1380, pp. 163–169. [^vOW1999]: [Parallel collision search with cryptanalytic applications. Paul C. van Oorschot and Michael Wiener.](https://link.springer.com/article/10.1007/PL00003816) -[^Bernstein2009]: [Cost analysis of hash collisions: Will quantum computers make SHARCS obsolete? Daniel J. Bernstein.](https://cr.yp.to/hash/collisioncost-20090517.pdf). Presented at SHARCS 2009. +[^Bernstein2009]: [Cost analysis of hash collisions: Will quantum computers make SHARCS obsolete? Daniel J. Bernstein.](https://cr.yp.to/hash/collisioncost-20090517.pdf) Presented at SHARCS 2009. [^BLAKE3]: [BLAKE3: One Function, Fast Everywhere. Jack O'Connor, Jean-Philippe Aumasson, Samuel Neves, and Zooko Wilcox, 2020.](https://github.com/BLAKE3-team/BLAKE3-specs/blob/master/blake3.pdf) See § 2.1.2 for the `derive_key` mode. -[^Maurer2002]: [Indistinguishability of Random Systems. Ueli Maurer.](https://crypto.ethz.ch/publications/files/Maurer02.pdf). Also published in Advances in Cryptology — EUROCRYPT 2002, LNCS vol. 2332, pp. 110–132. +[^Maurer2002]: [Indistinguishability of Random Systems. Ueli Maurer.](https://crypto.ethz.ch/publications/files/Maurer02.pdf) Also published in Advances in Cryptology — EUROCRYPT 2002, LNCS vol. 2332, pp. 110–132. -[^Unruh2015]: [Computationally binding quantum commitments. Dominique Unruh.](https://eprint.iacr.org/2015/361). Also published in EUROCRYPT 2016, LNCS vol. 9666. +[^Unruh2015]: [Computationally binding quantum commitments. Dominique Unruh.](https://eprint.iacr.org/2015/361) Also published in EUROCRYPT 2016, LNCS vol. 9666. -[^Unruh2016]: [Collapse-binding quantum commitments without random oracles. Dominique Unruh.](https://eprint.iacr.org/2016/508). Also published in ASIACRYPT 2016, LNCS vol. 10032. +[^Unruh2016]: [Collapse-binding quantum commitments without random oracles. Dominique Unruh.](https://eprint.iacr.org/2016/508) Also published in ASIACRYPT 2016, LNCS vol. 10032. -[^CBHSU2017]: [Post-quantum security of the sponge construction. Jan Czajkowski, Leon Groot Bruinderink, Andreas Hülsing, Christian Schaffner, and Dominique Unruh.](https://eprint.iacr.org/2017/771). Also published in PQCrypto 2018, LNCS vol. 10786. +[^CBHSU2017]: [Post-quantum security of the sponge construction. Jan Czajkowski, Leon Groot Bruinderink, Andreas Hülsing, Christian Schaffner, and Dominique Unruh.](https://eprint.iacr.org/2017/771) Also published in PQCrypto 2018, LNCS vol. 10786. -[^Fehr2018]: [Classical Proofs for the Quantum Collapsing Property of Classical Hash Functions. Serge Fehr.](https://eprint.iacr.org/2018/887). Also published in TCC 2018, LNCS vol. 11240, pp. 315–338. +[^Fehr2018]: [Classical Proofs for the Quantum Collapsing Property of Classical Hash Functions. Serge Fehr.](https://eprint.iacr.org/2018/887) Also published in TCC 2018, LNCS vol. 11240, pp. 315–338. -[^Zhandry2018]: [How to Record Quantum Queries, and Applications to Quantum Indifferentiability. Mark Zhandry.](https://eprint.iacr.org/2018/276). Also published in CRYPTO 2019, LNCS vol. 11693. +[^Zhandry2018]: [How to Record Quantum Queries, and Applications to Quantum Indifferentiability. Mark Zhandry.](https://eprint.iacr.org/2018/276) Also published in CRYPTO 2019, LNCS vol. 11693. [^CFHL2021]: [On the Compressed-Oracle Technique, and Post-Quantum Security of Proofs of Sequential Work. Kai-Min Chung, Serge Fehr, Yu-Hsuan Huang, and Tai-Ning Liao.](https://eprint.iacr.org/2020/1305). Also published in EUROCRYPT 2021, LNCS vol. 12826. -[^CMSZ2021]: [Post-Quantum Succinct Arguments: Breaking the Quantum Rewinding Barrier. Alessandro Chiesa, Fermi Ma, Nicholas Spooner, and Mark Zhandr.](https://eprint.iacr.org/2021/334). Also published in FOCS 2021. +[^CMSZ2021]: [Post-Quantum Succinct Arguments: Breaking the Quantum Rewinding Barrier. Alessandro Chiesa, Fermi Ma, Nicholas Spooner, and Mark Zhandr.](https://eprint.iacr.org/2021/334) Also published in FOCS 2021. -[^GM2022]: [Collapseability of Tree Hashes. Aldo Gunsing and Bart Mennink.](https://eprint.iacr.org/2022/248). Also published in PQCrypto 2020, LNCS vol. 12100, pp. 524–544. +[^GM2022]: [Collapseability of Tree Hashes. Aldo Gunsing and Bart Mennink.](https://eprint.iacr.org/2022/248) Also published in PQCrypto 2020, LNCS vol. 12100, pp. 524–544. [^CDDGS2025]: [Quantum Rewinding for IOP-Based Succinct Arguments. Alessandro Chiesa, Marcel Dall'Agnol, Zijing Di, Ziyi Guan, and Nicholas Spooner.](https://eprint.iacr.org/2025/947) From c139eab2aafc967ed0679985384196f6f82bc57c Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Mon, 18 May 2026 21:23:35 +0100 Subject: [PATCH 099/115] ZIP 2005: Add a cross-reference for "linking commitments" in the Cost section. Signed-off-by: Daira-Emma Hopwood <daira@jacaranda.org> --- zips/zip-2005.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/zips/zip-2005.md b/zips/zip-2005.md index 5fa0a6d0a..bdb97f7d8 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -438,6 +438,7 @@ graph BT rivk_legacy([rivk_legacy]) -->|¬use_qsk| rivk_ext ``` +<a id="linking-commitments"></a> When $\mathsf{use\_qsk}$ is used, on the other hand, it is possible for the Recovery Protocol to support spend authorization using a simpler statement that only uses $\mathsf{H^{qk}}$ and a commitment scheme. @@ -1106,7 +1107,8 @@ In $\mathsf{SoK^{sk}}$ and the main circuit: In $\mathsf{SoK^{qsk}}$: * 1 BLAKE3 compression for $\mathsf{H^{qk}}$ (with the $\mathsf{derive\_key}$ context key precomputed as a constant) -plus potentially linking commitments between the circuits. +plus, potentially, [linking commitments](#linking-commitments) between +the circuits. The expensive parts of this are the 7 BLAKE2b compressions. From bc16325a7fddea9f937596d8160f91dd13913728 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Mon, 18 May 2026 13:19:30 +0100 Subject: [PATCH 100/115] ZIP 2005: Move to Proposed. Signed-off-by: Daira-Emma Hopwood <daira@jacaranda.org> --- README.rst | 4 ++-- zips/zip-2005.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index 76a82e575..db775dc4f 100644 --- a/README.rst +++ b/README.rst @@ -144,6 +144,7 @@ Released ZIPs <tr> <td>1015</td> <td class="left"><a href="zips/zip-1015.rst">Block Subsidy Allocation for Non-Direct Development Funding</a></td> <td>Final</td> <tr> <td>1016</td> <td class="left"><a href="zips/zip-1016.md">Community and Coinholder Funding Model</a></td> <td>Proposed</td> <tr> <td>2001</td> <td class="left"><a href="zips/zip-2001.rst">Lockbox Funding Streams</a></td> <td>Final</td> + <tr> <td>2005</td> <td class="left"><a href="zips/zip-2005.md">Orchard Quantum Recoverability</a></td> <td>Proposed</td> </table></embed> Draft ZIPs @@ -213,7 +214,6 @@ written. <tr> <td>2002</td> <td class="left"><a href="zips/zip-2002.rst">Explicit Fees</a></td> <td>Draft</td> <td class="left"><a href="https://github.com/zcash/zips/issues/803">zips#803</a></td> <tr> <td>2003</td> <td class="left"><a href="zips/zip-2003.rst">Disallow version 4 transactions</a></td> <td>Draft</td> <td class="left"><a href="https://github.com/zcash/zips/issues/825">zips#825</a></td> <tr> <td>2004</td> <td class="left"><a href="zips/zip-2004.rst">Remove the dependency of consensus on note encryption</a></td> <td>Draft</td> <td class="left"><a href="https://github.com/zcash/zips/issues/917">zips#917</a></td> - <tr> <td>2005</td> <td class="left"><a href="zips/zip-2005.md">Orchard Quantum Recoverability</a></td> <td>Draft</td> <td class="left"><a href="https://github.com/zcash/zips/issues/1135">zips#1135</a></td> <tr> <td>guide-markdown</td> <td class="left"><a href="zips/zip-guide-markdown.md">{Something Short and To the Point}</a></td> <td>Draft</td> <td class="left"></td> <tr> <td>guide</td> <td class="left"><a href="zips/zip-guide.rst">{Something Short and To the Point}</a></td> <td>Draft</td> <td class="left"></td> <tr> <td>template</td> <td class="left"><a href="zips/zip-template.md">{Template for new ZIPs}</a></td> <td>Draft</td> <td class="left"></td> @@ -391,7 +391,7 @@ Index of ZIPs <tr> <td>2002</td> <td class="left"><a href="zips/zip-2002.rst">Explicit Fees</a></td> <td>Draft</td> <tr> <td>2003</td> <td class="left"><a href="zips/zip-2003.rst">Disallow version 4 transactions</a></td> <td>Draft</td> <tr> <td>2004</td> <td class="left"><a href="zips/zip-2004.rst">Remove the dependency of consensus on note encryption</a></td> <td>Draft</td> - <tr> <td>2005</td> <td class="left"><a href="zips/zip-2005.md">Orchard Quantum Recoverability</a></td> <td>Draft</td> + <tr> <td>2005</td> <td class="left"><a href="zips/zip-2005.md">Orchard Quantum Recoverability</a></td> <td>Proposed</td> <tr> <td>guide-markdown</td> <td class="left"><a href="zips/zip-guide-markdown.md">{Something Short and To the Point}</a></td> <td>Draft</td> <tr> <td>guide</td> <td class="left"><a href="zips/zip-guide.rst">{Something Short and To the Point}</a></td> <td>Draft</td> <tr> <td>template</td> <td class="left"><a href="zips/zip-template.md">{Template for new ZIPs}</a></td> <td>Draft</td> diff --git a/zips/zip-2005.md b/zips/zip-2005.md index bdb97f7d8..ce0250e76 100644 --- a/zips/zip-2005.md +++ b/zips/zip-2005.md @@ -6,7 +6,7 @@ Credits: Sean Bowe Dev Ojha Kris Nuttycombe - Status: Draft + Status: Proposed Category: Consensus Created: 2025-03-31 License: MIT From 06950efea9e03bbe5e10368f40d322cc92808fb7 Mon Sep 17 00:00:00 2001 From: Tal Derei <talderei99@gmail.com> Date: Mon, 18 May 2026 18:21:02 -0700 Subject: [PATCH 101/115] Add Tal Derei as ZIP editor --- zips/zip-0000.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/zips/zip-0000.rst b/zips/zip-0000.rst index b246f1ea6..6b5148aa7 100644 --- a/zips/zip-0000.rst +++ b/zips/zip-0000.rst @@ -9,6 +9,7 @@ Kris Nuttycombe <kris@nutty.land> Sam H. Smith <sam@shieldedlabs.net> Sean Bowe <sean@bowe.tech> + Tal Derei <tal@bowe.tech> Original-Authors: Josh Cincinnati George Tankersley Deirdre Connolly @@ -191,7 +192,7 @@ The current ZIP Editors are: capacities. * Arya, associated with the Zcash Foundation. * Mark Henderson and Sam H. Smith, associated with Shielded Labs. -* Sean Bowe, associated with Project Tachyon. +* Sean Bowe and Tal Derei, associated with Project Tachyon. All can be reached at zips@z.cash. The current design of the ZIP Process dictates that there are always at least two ZIP Editors, including at least From caaf4b3cd24e6818d04d643fea64a814d09c95d7 Mon Sep 17 00:00:00 2001 From: Daira-Emma Hopwood <daira@jacaranda.org> Date: Tue, 19 May 2026 21:52:25 +0100 Subject: [PATCH 102/115] ZIP 213: More specific reference to the Anchor selection section of ZIP 315 Co-authored-by: Daira-Emma Hopwood <daira@jacaranda.org> --- zips/zip-0213.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zips/zip-0213.rst b/zips/zip-0213.rst index e1d46159e..181427d96 100644 --- a/zips/zip-0213.rst +++ b/zips/zip-0213.rst @@ -131,7 +131,7 @@ Enforcing coinbase maturity at the consensus level for Sapling outputs would inc significant complexity in the consensus rules, because it would require special-casing coinbase note commitments in the Sapling commitment tree. The standard recommendation when spending a note is to select an anchor 3 blocks back from the current chain tip (see ZIP -315 [#zip-0315]_), which acts as a de-facto 3-block maturity on all notes, coinbase +315 [#zip-0315-anchor-selection]_), which acts as a de-facto 3-block maturity on all notes, coinbase included. This might be proposed as a consensus rule in future. There is another reason for shielded coinbase maturity being unnecessary: shielded @@ -205,4 +205,4 @@ References .. [#zip-0207] `ZIP 207: Funding Streams <zip-0207.rst>`_ .. [#zip-0250] `ZIP 250: Deployment of the Heartwood Network Upgrade <zip-0250.rst>`_ .. [#zip-0252] `ZIP 252: Deployment of the NU5 Network Upgrade <zip-0252.rst>`_ -.. [#zip-0315] `ZIP 315: Best Practices for Wallet Implementations <zip-0315.rst>`_ +.. [#zip-0315-anchor-selection] `ZIP 315: Best Practices for Wallet Implementations — Anchor selection <zip-0315.rst#anchor-selection>`_ From 1e00f3e70438aab87b7a0cf194fc192c445decf4 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe <kris@nutty.land> Date: Tue, 19 May 2026 17:44:51 -0600 Subject: [PATCH 103/115] [ZIP 416] Repurpose for documenting zcashd key generation. ZIP 416 was reserved for specifying unified address support for the zcashd wallet, but with the upcoming deprecation of `zcashd` that is no longer a useful task; instead, we need to fully document the historic schemes used for key generation by the zcashd wallet, for the purpose of future recoverability. This updates the reserved ZIP to serve that purpose. --- zips/zip-0416.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zips/zip-0416.rst b/zips/zip-0416.rst index eb15749bc..1f5a067b3 100644 --- a/zips/zip-0416.rst +++ b/zips/zip-0416.rst @@ -1,10 +1,10 @@ :: ZIP: 416 - Title: Support for Unified Addresses in zcashd + Title: Spending Key Derivation in the `zcashd` wallet Owners: Daira-Emma Hopwood <daira@jacaranda.org> Jack Grigg <thestr4d@gmail.com> Kris Nuttycombe <kris@nutty.land> Status: Reserved Category: RPC / Wallet - Discussions-To: <https://github.com/zcash/zips/issues/503> + Discussions-To: <https://github.com/zcash/zips/issues/1175> From 376fb7efacfc872c33f278e7f72ac9ea7853c42d Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe <kris@nutty.land> Date: Tue, 19 May 2026 18:07:23 -0600 Subject: [PATCH 104/115] Remove / unreserve ZIP 318 Subsumed by ZIP 231; consensus is that a symmetric key stored in memo payload data is a simpler solution to this problem. Closes #633 --- zips/zip-0318.rst | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 zips/zip-0318.rst diff --git a/zips/zip-0318.rst b/zips/zip-0318.rst deleted file mode 100644 index 1081e4d3e..000000000 --- a/zips/zip-0318.rst +++ /dev/null @@ -1,11 +0,0 @@ -:: - - ZIP: 318 - Title: Associated Payload Encryption - Owners: Kris Nuttycombe <kris@nutty.land> - Daira-Emma Hopwood <daira@jacaranda.org> - Status: Reserved - Category: Standards Track - Created: 2022-09-19 - License: MIT - Discussions-To: <https://github.com/zcash/zips/issues/633> From cfefa4503323e113e2efb06fe879ca056c270fbf Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe <kris@nutty.land> Date: Wed, 20 May 2026 11:56:15 -0600 Subject: [PATCH 105/115] ZIP 303: Withdraw (stub never developed beyond PR #119). Status changes from Reserved to Withdrawn. The ZIP was opened as a stub in PR #119 but never developed further. Closes #828. README.rst regenerated by makeindex.sh; the regeneration also removes stale entries for ZIP 318, whose source file was deleted in PR #1282 but whose README entries had not yet been regenerated. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --- README.rst | 6 ++---- zips/zip-0303.rst | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/README.rst b/README.rst index db775dc4f..7a7b373e9 100644 --- a/README.rst +++ b/README.rst @@ -187,7 +187,6 @@ written. <tr> <td><span class="reserved">260</span></td> <td class="left"><a class="reserved" href="zips/zip-0260.md">Extending Block Messages with Additional Authentication Data</a></td> <td>Reserved</td> <td class="left"><a href="https://github.com/zcash/zips/issues/522">zips#522</a></td> <tr> <td><span class="reserved">270</span></td> <td class="left"><a class="reserved" href="zips/zip-0270.md">Key Rotation for Tracked Signing Keys</a></td> <td>Reserved</td> <td class="left"><a href="https://github.com/zcash/zips/issues/1047">zips#1047</a></td> <tr> <td>302</td> <td class="left"><a href="zips/zip-0302.rst">Standardized Memo Field Format</a></td> <td>Draft</td> <td class="left"><a href="https://github.com/zcash/zips/issues/366">zips#366</a></td> - <tr> <td><span class="reserved">303</span></td> <td class="left"><a class="reserved" href="zips/zip-0303.rst">Sprout Payment Disclosure</a></td> <td>Reserved</td> <td class="left"></td> <tr> <td>304</td> <td class="left"><a href="zips/zip-0304.rst">Sapling Address Signatures</a></td> <td>Draft</td> <td class="left"><a href="https://github.com/zcash/zips/issues/345">zips#345</a></td> <tr> <td><span class="reserved">305</span></td> <td class="left"><a class="reserved" href="zips/zip-0305.rst">Best Practices for Hardware Wallets supporting Sapling</a></td> <td>Reserved</td> <td class="left"><a href="https://github.com/zcash/zips/issues/346">zips#346</a></td> <tr> <td><span class="reserved">306</span></td> <td class="left"><a class="reserved" href="zips/zip-0306.rst">Security Considerations for Anchor Selection</a></td> <td>Reserved</td> <td class="left"><a href="https://github.com/zcash/zips/issues/351">zips#351</a></td> @@ -198,7 +197,6 @@ written. <tr> <td>312</td> <td class="left"><a href="zips/zip-0312.rst">FROST for Spend Authorization Multisignatures</a></td> <td>Draft</td> <td class="left"><a href="https://github.com/zcash/zips/issues/382">zips#382</a></td> <tr> <td><span class="reserved">314</span></td> <td class="left"><a class="reserved" href="zips/zip-0314.rst">Privacy upgrades to the Zcash light client protocol</a></td> <td>Reserved</td> <td class="left"><a href="https://github.com/zcash/zips/issues/434">zips#434</a></td> <tr> <td>315</td> <td class="left"><a href="zips/zip-0315.rst">Best Practices for Wallet Implementations</a></td> <td>Draft</td> <td class="left"><a href="https://github.com/zcash/zips/issues/447">zips#447</a></td> - <tr> <td><span class="reserved">318</span></td> <td class="left"><a class="reserved" href="zips/zip-0318.rst">Associated Payload Encryption</a></td> <td>Reserved</td> <td class="left"><a href="https://github.com/zcash/zips/issues/633">zips#633</a></td> <tr> <td><span class="reserved">319</span></td> <td class="left"><a class="reserved" href="zips/zip-0319.rst">Options for Shielded Pool Retirement</a></td> <td>Reserved</td> <td class="left"><a href="https://github.com/zcash/zips/issues/635">zips#635</a></td> <tr> <td><span class="reserved">322</span></td> <td class="left"><a class="reserved" href="zips/zip-0322.rst">Generic Signed Message Format</a></td> <td>Reserved</td> <td class="left"><a href="https://github.com/zcash/zips/issues/429">zips#429</a></td> <tr> <td><span class="reserved">323</span></td> <td class="left"><a class="reserved" href="zips/zip-0323.rst">Specification of getblocktemplate for Zcash</a></td> <td>Reserved</td> <td class="left"><a href="https://github.com/zcash/zips/issues/405">zips#405</a></td> @@ -251,6 +249,7 @@ Withdrawn, Rejected, or Obsolete ZIPs <tr> <td><strike>220</strike></td> <td class="left"><strike><a href="zips/zip-0220.rst">Zcash Shielded Assets</a></strike></td> <td>Withdrawn</td> <tr> <td><strike>230</strike></td> <td class="left"><strike><a href="zips/zip-0230.rst">Withdrawn Version 6 Transaction Format</a></strike></td> <td>Withdrawn</td> <tr> <td><strike>254</strike></td> <td class="left"><strike><a href="zips/zip-0254.md">Deployment of the NU7 Network Upgrade (Withdrawn)</a></strike></td> <td>Withdrawn</td> + <tr> <td><strike>303</strike></td> <td class="left"><strike><a href="zips/zip-0303.rst">Sprout Payment Disclosure</a></strike></td> <td>Withdrawn</td> <tr> <td><strike>313</strike></td> <td class="left"><strike><a href="zips/zip-0313.rst">Reduce Conventional Transaction Fee to 1000 zatoshis</a></strike></td> <td>Obsolete</td> <tr> <td><strike>1001</strike></td> <td class="left"><strike><a href="zips/zip-1001.rst">Keep the Block Distribution as Initially Defined — 90% to Miners</a></strike></td> <td>Obsolete</td> <tr> <td><strike>1002</strike></td> <td class="left"><strike><a href="zips/zip-1002.rst">Opt-in Donation Feature</a></strike></td> <td>Obsolete</td> @@ -340,7 +339,7 @@ Index of ZIPs <tr> <td>300</td> <td class="left"><a href="zips/zip-0300.rst">Cross-chain Atomic Transactions</a></td> <td>Proposed</td> <tr> <td>301</td> <td class="left"><a href="zips/zip-0301.rst">Zcash Stratum Protocol</a></td> <td>Active</td> <tr> <td>302</td> <td class="left"><a href="zips/zip-0302.rst">Standardized Memo Field Format</a></td> <td>Draft</td> - <tr> <td><span class="reserved">303</span></td> <td class="left"><a class="reserved" href="zips/zip-0303.rst">Sprout Payment Disclosure</a></td> <td>Reserved</td> + <tr> <td><strike>303</strike></td> <td class="left"><strike><a href="zips/zip-0303.rst">Sprout Payment Disclosure</a></strike></td> <td>Withdrawn</td> <tr> <td>304</td> <td class="left"><a href="zips/zip-0304.rst">Sapling Address Signatures</a></td> <td>Draft</td> <tr> <td><span class="reserved">305</span></td> <td class="left"><a class="reserved" href="zips/zip-0305.rst">Best Practices for Hardware Wallets supporting Sapling</a></td> <td>Reserved</td> <tr> <td><span class="reserved">306</span></td> <td class="left"><a class="reserved" href="zips/zip-0306.rst">Security Considerations for Anchor Selection</a></td> <td>Reserved</td> @@ -355,7 +354,6 @@ Index of ZIPs <tr> <td>315</td> <td class="left"><a href="zips/zip-0315.rst">Best Practices for Wallet Implementations</a></td> <td>Draft</td> <tr> <td>316</td> <td class="left"><a href="zips/zip-0316.rst">Unified Addresses and Unified Viewing Keys</a></td> <td>[Revision 0] Active, [Revision 1] Withdrawn, [Revision 2] Draft</td> <tr> <td>317</td> <td class="left"><a href="zips/zip-0317.rst">Proportional Transfer Fee Mechanism</a></td> <td>Active</td> - <tr> <td><span class="reserved">318</span></td> <td class="left"><a class="reserved" href="zips/zip-0318.rst">Associated Payload Encryption</a></td> <td>Reserved</td> <tr> <td><span class="reserved">319</span></td> <td class="left"><a class="reserved" href="zips/zip-0319.rst">Options for Shielded Pool Retirement</a></td> <td>Reserved</td> <tr> <td>320</td> <td class="left"><a href="zips/zip-0320.rst">Defining an Address Type to which funds can only be sent from Transparent Addresses</a></td> <td>Active</td> <tr> <td>321</td> <td class="left"><a href="zips/zip-0321.rst">Payment Request URIs</a></td> <td>Active</td> diff --git a/zips/zip-0303.rst b/zips/zip-0303.rst index 54e439e80..85f17c416 100644 --- a/zips/zip-0303.rst +++ b/zips/zip-0303.rst @@ -4,6 +4,6 @@ Title: Sprout Payment Disclosure Owners: Deirdre Connolly <deirdre@zfnd.org> Original-Authors: Simon Liu - Status: Reserved + Status: Withdrawn Category: Standards / RPC / Wallet Pull-Request: <https://github.com/zcash/zips/pull/119> From df010cf1bd291fb7943bbc42275b6316a62f9380 Mon Sep 17 00:00:00 2001 From: Dev Ojha <dojha@berkeley.edu> Date: Fri, 15 May 2026 01:09:26 +0900 Subject: [PATCH 106/115] Updates to the blocktime reduction ZIP --- zips/zip-0218.md | 191 +++++++++++++++++++++++++---------------------- 1 file changed, 102 insertions(+), 89 deletions(-) diff --git a/zips/zip-0218.md b/zips/zip-0218.md index 9492341a4..88a2e523e 100644 --- a/zips/zip-0218.md +++ b/zips/zip-0218.md @@ -39,16 +39,16 @@ This proposal specifies a change in the block target spacing from 75 seconds to 25 seconds in NU7, and introduces per-pool action limits for the Sapling and Orchard shielded protocols. -This solves three problems. +This solves three problems. - Significantly improves the UX for actors who need 1 or 2 conf's. (Near Intents, small payments) The user-latency goes down 3x. - Increases consensus bandwidth, which amplifies the scaling impact of a future shielded pool which does not require shielded sync. -- Introduces action limits. These provide limits of the number of actions that can go into a block. There is a global limit across all pools, and per pool limits. It is configured to more than double the Orchard TPS (2.9 → 6.1 TPS), while lowering the impact a DoS attacker can impose on wallets; for example, maximum shielded sync bandwidth for light clients is reduced by 42% (270.5 → 156.83 MB/day). +- Introduces action limits. These provide limits of the number of actions that can go into a block. There is a global limit across all pools, and per pool limits. It is configured to more than double the Orchard TPS (2.9 → 6.6 TPS), while lowering the impact a DoS attacker can impose on wallets; for example, maximum shielded sync bandwidth for light clients is reduced by 37% (271 → 169 MB/day). -The action limits significantly decrease the number of Sprout and Sapling pool -outputs available per block, to lower the maximum shielded sync burden under +The action limits significantly decrease the number of Sprout and Sapling pool +outputs available per block, to lower the maximum shielded sync burden under attempted DoS. -The emission schedule of mined ZEC will be the same in terms of ZEC/day, +The emission schedule of mined ZEC will be the same in terms of ZEC/day, but this requires the emission per block to be adjusted to take account of the changed block target spacing. @@ -64,74 +64,83 @@ The motivations for decreasing the block target spacing are: confirmation to 25 seconds on average. - **Greater throughput.** With 3× as many blocks per day and the same - 2 MB block size limit, we will have allocated higher consensus bandwidth - capacity. Short term, when paired with the action limits, we will more than - double the Orchard TPS for 2-action transactions. Longer term, when we get a + 2 MB block size limit, we will have allocated higher consensus bandwidth + capacity. Short term, when paired with the action limits, we will more than + double the Orchard TPS for 2-action transactions. Longer term, when we get a shielded pool with no shielded sync burden, we will have 3x higher throughput. -- **Complementary to finality improvements.** This proposal is - complementary to, and does not compete with, finality mechanisms - such as Crosslink [^crosslink]. Faster block times improve the - responsiveness of the base layer regardless of whether an additional finality - gadget is also deployed. - The throughput goal on its own could be achieved via a block size increase. -However the goal of this proposal is to foremost improve the transaction +However the goal of this proposal is foremost to improve the transaction latency. -It is estimated that this reduction in blocktime would increase the stale rate from today's 0.4% to 1.3%. For reference, Ethereum operated at 5.4% stale rate. - -There are multiple threat models for rollback attacks. Loosely speaking, -lowering block time while keeping it significantly lower than block propagation -delay helps improve finality time. This is because more honest -miners quickly build on the block, and the block propagation constraint ensures -stale rates have not significantly increased. See [^slowfastblocks] for -analysis in various attack models. As this proposal meets the constraint of -keeping stale rates low, this should under the "X% of hashpower is byzantine" -threat model improve user confirmation times by a factor slightly under 3x. -Under the post's "Economic" threat model, where the user requires the block -rewards built on-top of their payment to exceed the value of the payment, this -significantly improves the variance in confirmation latency (but makes the -mean latency a bit higher due to stale rate). As noted there, this attack model -is not applied at sizable transactions. It is only potentially applied for small-valued -transactions, where the granularity of block times likely lowers time -until sufficient finality. We do not argue for reducing block confirmation counts in this ZIP. -However, we do expect many classes of users to be able to reduce their expected -time until funds are considered to have been received under threat modelling -consistent with block confirmation counts they choose today. - -Zcash has a second cost imposed by scaling, the shielded sync. Every -shielded transaction induces a bandwidth overhead for every wallet -and an extra trial decryption, so we must carefully understand the impact a DOS -attacker can cause. Today the worst-case DoS attack can induce 270.5 -MB of wallet sync download to clients per day, and 4.8M trial decryptions per -day. We propose introducing global action limits and per-pool action limits as follows: - -- A maximum of 306 actions per block across all pools - -- A maximum of 306 Orchard actions per block - -- A maximum of 300 Sapling inputs + outputs. (Total inputs + outputs < 300) +This proposal is complementary to, and does not compete with, finality +mechanisms such as Crosslink [^crosslink]. Faster block times improve the +responsiveness of the base layer regardless of whether an additional finality +gadget is also deployed. Rollback-risk analysis depends on the threat model. +For models that bound an attacker by a fixed fraction of total hash power, +reducing the block target spacing can reduce confirmation latency by nearly the +same factor, provided that block validation and propagation remain small +relative to the target spacing. Given that is maintained here, this proposal is +expected to improve confirmation latency by slightly less than 3x for users +applying the same rollback-risk tolerance as today. See [#slowfastblocks]_ for +analysis under several attack models. + +Economic rollback models give a different result. For recipients who wait until +the block rewards built on top of their payment exceed the payment value, then +shorter block times significantly reduce the variance of their waiting time, +while the mean stays roughly the same. Recall that proof of work block times +have high very high variance, so variance reduction is a substantial benefit. +This ZIP does not argue for clients reducing confirmation counts, but it does +expect many users to see a lower expected time until receipt under confirmation +policies comparable to those they use today. + +## Security + +Scaling and block time reductions in Zcash impose three security costs, one on +full nodes and miners' ability to verify blocks, a second on clients for +shielded sync, and a third on the whole network for the uncle rate and fork +rate. Action limits are introduced in this ZIP to limit the block processing +costs, and client shielded sync costs. The proposed parameterization lowers the +worst case for shielded sync and node processing times relative to today, while +yielding far higher Orchard TPS. We benchmark, and the uncle-rate post-proposal +on networks more distributed than mainnet at maximum load is far lower than +ETH-PoW was, leading to conclusion that it is safe. + +Today the worst-case DoS attack can induce 271 MB of wallet sync download to +clients per day, and 4.8M trial decryptions per day [^syncsimulator]. This is d +one with max utilizing Sapling transactions, with few inputs and many outputs. +The worst-cast DOS for node verification time is done with many Sapling inputs, +and a single transparent output, totalling 5680 Sapling inputs and ZKP's. This +takes 4s on our 4 physical-core benchmark machine. Meanwhile regular userflow +has far lower costs on the network, than the DOS model. + +We propose introducing global action limits and per-pool action limits as follows: + +- A maximum of 330 actions per block across all pools + +- A maximum of 330 Orchard actions per block + +- A maximum of 300 Sapling inputs + outputs. (Total inputs + outputs <= 300) - A maximum of 25 Sprout JoinSplits per block. -With these limits, the worst case becomes 156.83 MB bandwidth and 2.1M trial decrypts per day. This -is a 42% improvement in worst case wallet sync bandwidth despite 3x more blocks. -This yields a 2x in Orchard TPS, and keeps Sapling TPS at a higher level than -today's Orchard TPS. +With these limits, the worst case client load becomes 169 MB bandwidth and 2.3M +trial decrypts per day. This is a 37% improvement in worst case wallet sync +bandwidth despite 3x more blocks. This yields a 2x in Orchard TPS, and keeps +Sapling TPS at a higher level than today's Orchard TPS. We expand on these derivations in [] However, every wallet does have to download every compact block header, which is 90 bytes. This leads to an extra 200kb of wallet bandwidth per day in exchange for the improved UX. The reduced Sapling and Sprout per-block limits are justified by the -current distribution of shielded funds across pools. As of March 2026: +current distribution of shielded funds across pools. As of May 2026: | Pool | Balance | Share of shielded supply | |------|---------|--------------------------| -| Orchard | 4,511,193 ZEC | 87.5% | -| Sapling | 616,131 ZEC | 12.0% | -| Sprout | 25,480 ZEC | 0.5% | +| Orchard | 4,534,914 ZEC | 87.9% | +| Sapling | 597,910 ZEC | 11.6% | +| Sprout | 25,409 ZEC | 0.5% | The vast majority of shielded activity is already in Orchard, and this trend is expected to continue. The Sapling and Sprout limits are set @@ -140,8 +149,8 @@ their potential for DoS. ## Stale block rate -The stale rate is the percentage of blocks that get orphaned, which relates to -mining centralization risk, block propagation delay, and block verification +The stale rate is the percentage of blocks that get orphaned, which relates to +mining centralization risk, block propagation delay, and block verification times. Today the stale rate is 0.4%, but this may be lower than what pure block propagation delay may imply due to hashpower centralization in mining pools. @@ -176,13 +185,15 @@ packed Orchard block requires verifying all action proofs and spend authorization signatures for those ~617 actions. **Proposed worst case:** With the action limits, a block contains at -most 306 actions across pools. There is separately, limits per pool. We propose per-pool limits of: +most 330 actions across pools. There is separately, limits per pool. We propose per-pool limits of: -- 306 Orchard actions +- 330 Orchard actions - 300 Sapling inputs+outputs. - 25 Sprout JoinSplits. -This means the new worst case block processing time, if Orchard dominant, would be half of today's worst case, and Sapling's would be one sixth. The per-block verification work is therefore substantially reduced. +This means the new worst case block processing time, if Orchard dominant, +would be a little over half of today's worst case, and Sapling's would be +one sixth. The per-block verification work is therefore substantially reduced. **Batch verification.** Orchard transaction verification benefits from batch validation, where proof and signature verification is amortized @@ -197,7 +208,7 @@ batch-verified in a small number of batches. limited to 4 threads, availability verification for an Orchard-heavy block at the action limits completed in 529.00--554.30 ms, and availability verification for a Sapling-heavy block at the action -limits completed in 1.1017--1.1329 s. +limits completed in 1.1017--1.1329 s. {TODO: @Evan please update this, should be 210ms range. Lets also cite benchmark code} When transactions have already been pre-verified upon entering the mempool, which is the typical case for a node that has been online, block validation reduces to checking signatures and @@ -302,8 +313,8 @@ the difference will eventually be reissued. Define the following constants in § 5.3 'Constants': -$$\mathsf{GlobalShieldedBudget} := 306$$ -$$\mathsf{OrchardBlockActionLimit} := 306$$ +$$\mathsf{GlobalShieldedBudget} := 330$$ +$$\mathsf{OrchardBlockActionLimit} := 330$$ $$\mathsf{SaplingBlockIOLimit} := 300$$ $$\mathsf{SproutBlockJoinSplitLimit} := 25$$ @@ -315,7 +326,7 @@ be satisfied: - The total number of Orchard actions across all transactions in the block MUST NOT exceed $\mathsf{OrchardBlockActionLimit}$. That is, - $\sum_{\mathit{tx} \in \mathit{block}} \mathit{nActionsOrchard}(\mathit{tx}) \leq 306$. + $\sum_{\mathit{tx} \in \mathit{block}} \mathit{nActionsOrchard}(\mathit{tx}) \leq 330$. - The total number of Sapling inputs and outputs across all transactions in the block MUST NOT exceed @@ -333,7 +344,7 @@ In addition to the per-pool limits, the total shielded cost across all pools in a block MUST NOT exceed $\mathsf{GlobalShieldedBudget}$. The shielded cost of a block is defined as: -$$\sum_{\mathit{tx}} \mathit{nActionsOrchard}(\mathit{tx}) \;+\; \sum_{\mathit{tx}} (\mathit{nSpendsSapling}(\mathit{tx}) + \mathit{nOutputsSapling}(\mathit{tx})) \;+\; 2 \times \sum_{\mathit{tx}} \mathit{nJoinSplit}(\mathit{tx}) \;\leq\; 306$$ +$$\sum_{\mathit{tx}} \mathit{nActionsOrchard}(\mathit{tx}) \;+\; \sum_{\mathit{tx}} (\mathit{nSpendsSapling}(\mathit{tx}) + \mathit{nOutputsSapling}(\mathit{tx})) \;+\; 2 \times \sum_{\mathit{tx}} \mathit{nJoinSplit}(\mathit{tx}) \;\leq\; 330$$ where the factor of 2 for Sprout JoinSplits reflects that each JoinSplit produces 2 shielded outputs. @@ -375,14 +386,14 @@ consisting of: With these limits, the worst-case compact sync bandwidth per block is: -- **Orchard:** $306 \times 148 = 45{,}288$ bytes +- **Orchard:** $330 \times 148 = 48{,}840$ bytes - **Sapling:** at most $300 \times 116 = 34{,}800$ bytes (all-output pathological case) Due to the global shielded budget, these cannot stack: a block that -uses 306 Orchard actions has zero budget remaining for Sapling or +uses 330 Orchard actions has zero budget remaining for Sapling or Sprout. The worst-case compact sync bandwidth per block is therefore -always bounded by the Orchard case at 45,288 bytes. +always bounded by the Orchard case at 48,840 bytes. See the [Rationale](#rationale) section for the full daily bandwidth analysis. @@ -456,8 +467,8 @@ follows the same precedent set by the Blossom upgrade (ZIP 208 The increased likelihood of forking due to block time reduction should not be concerning here. For an issue to occur when anchor depth is 3 blocks back, you must have a 4 block re-org. In the many years of Ethereum PoW, a 4 block re-org -has never been observed [^lovejoy-reorg]. So we are not practically at risk of -inherent randomness causing a re-org. In other POW chains, re-orgs of 4+ +has never been observed [^lovejoy-reorg]. So we are not practically at risk of +inherent randomness causing a re-org. In other POW chains, re-orgs of 4+ blocks resulted from a consensus split of some form, including the recent Litecoin attack, or an attack from a surge in hashpower. Anchor height depth is not intended to protect against those two vectors. @@ -483,9 +494,9 @@ the current protocol. This section presents the analysis. | Parameter | Value | |-----------|-------| -| $\mathsf{OrchardBlockActionLimit}$ | 306 actions | +| $\mathsf{OrchardBlockActionLimit}$ | 330 actions | | Compact sync bandwidth per action | 148 bytes | -| Compact bandwidth per block | $306 \times 148 = 45{,}288$ bytes | +| Compact bandwidth per block | $330 \times 148 = 48{,}840$ bytes | **Sapling pool:** @@ -501,21 +512,21 @@ the current protocol. This section presents the analysis. | Metric | Current (75s, no pool limits) | Proposed (25s, action limits) | |--------|-------------------------------|-------------------------------| | Blocks per day | 1,152 | 3,456 | -| Max Orchard actions/block | ~617 (block-size limited) | 306 | +| Max Orchard actions/block | ~617 (block-size limited) | 330 | | Max Sapling IOs/block | ~2,140 (block-size limited) | 300 | -| Orchard compact BW/day | ~105.2 MB | 156.52 MB | +| Orchard compact BW/day | ~105.2 MB | 168.79 MB | | Sapling compact BW/day | ~270.38 MB | 120.27 MB | | Compact block headers/day | ~0.10 MB | 0.31 MB | -| **Worst-case total BW/day** | **~270.5 MB** | **156.83 MB** | -| Worst-case trial decrypts/day | ~4.8M | ~2.1M | +| **Worst-case total BW/day** | **~270.5 MB** | **169.10 MB** | +| Worst-case trial decrypts/day | ~4.8M | ~2.3M | -The worst-case compact sync bandwidth is **156.83 MB/day**, a reduction -of **42%** from today's worst case of approximately 270.5 MB/day. This +The worst-case compact sync bandwidth is **169.10 MB/day**, a reduction +of **37%** from today's worst case of approximately 270.5 MB/day. This is despite a 3× increase in block frequency and overall throughput capacity. -The binding constraint is Orchard at 306 actions per block: -$306 \times 148 \times 3{,}456 + 90 \times 3{,}456 = 156.83\text{ MB/day}$. +The binding constraint is Orchard at 330 actions per block: +$330 \times 148 \times 3{,}456 + 90 \times 3{,}456 = 169.10\text{ MB/day}$. The trial decryption count also decreases significantly, since the per-block action limits more than offset the 3× increase in block count. @@ -530,14 +541,14 @@ Orchard wallets always attempt both. ### Normal transaction throughput -For standard 2-action Orchard transactions, the action limit of 306 -allows $\lfloor 306 / 2 \rfloor = 153$ transactions per block, giving: +For standard 2-action Orchard transactions, the action limit of 330 +allows $\lfloor 330 / 2 \rfloor = 165$ transactions per block, giving: -$$\mathsf{orchard\_tps} = 153 \;/\; 25 = 6.12 \text{ TPS}$$ +$$\mathsf{orchard\_tps} = 165 \;/\; 25 = 6.6 \text{ TPS}$$ For comparison, the current protocol (75s blocks, block-size limited) supports approximately 2.9 TPS for 2-action Orchard transactions. This -is a **2.1× increase** in normal Orchard throughput. +is a **2.3× increase** in normal Orchard throughput. **Sapling throughput.** For standard Sapling transactions (2 spends + 2 outputs = 4 IOs), the limit of 300 IOs allows $\lfloor 300 / 4 \rfloor @@ -563,13 +574,13 @@ versa). The cost per unit of shielded budget consumed is identical. Furthermore, because the global shielded budget is shared, filling the Sapling budget necessarily reduces the Orchard budget by the same amount. An attacker who spends their entire budget on Sapling spam at -300 IOs leaves only 6 Orchard actions available in that block. But -this attack is no cheaper than filling 306 Orchard actions directly, +300 IOs leaves only 30 Orchard actions available in that block. But +this attack is no cheaper than filling 330 Orchard actions directly, since the per-action fee is the same. The global budget ensures that -the total shielded sync cost per block is bounded to 306 units +the total shielded sync cost per block is bounded to 330 units regardless of the attacker's pool choice. -The Orchard per-pool cap of 306 also guarantees that legitimate Orchard +The Orchard per-pool cap of 330 also guarantees that legitimate Orchard transactions always have access to the full Orchard budget when Sapling and Sprout are not used, which is the expected common case going forward. @@ -611,6 +622,8 @@ activation heights and consensus branch IDs. [^slowfastblocks]: [On Slow and Fast Block Times](https://blog.ethereum.org/2015/09/14/on-slow-and-fast-block-times/) +[^syncsimulator]: [Shielded Sync Simulator](https://nu7syncsimulator.valargroup.dev/) + [^lovejoy-reorg]: [Lovejoy, James P. (2020). *An Empirical Analysis of Chain Reorganizations and Double-Spend Attacks on Proof-of-Work Cryptocurrencies.* M.Eng. thesis, Massachusetts Institute of Technology, Department of Electrical Engineering and Computer Science.](https://static1.squarespace.com/static/6675a0d5fc9e317c60db9b37/t/66eb3560532516773c4f7ece/1726690657755/LovejoyJamesP-meng-eecs-2020+%281%29.pdf) [^forum-proposal]: [Forum: Proposal — Lower Zcash Block Target Spacing to 25s](https://forum.zcashcommunity.com/t/proposal-lower-zcash-block-target-spacing-to-25s/54577) From 1ce40d72e81bff5f25cd89236792117fed7d77d8 Mon Sep 17 00:00:00 2001 From: evan-forbes <evan.samuel.forbes@gmail.com> Date: Thu, 14 May 2026 17:34:19 -0500 Subject: [PATCH 107/115] docs: add benchmarks --- zips/zip-0218.md | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/zips/zip-0218.md b/zips/zip-0218.md index 88a2e523e..b585c7be3 100644 --- a/zips/zip-0218.md +++ b/zips/zip-0218.md @@ -102,7 +102,7 @@ shielded sync, and a third on the whole network for the uncle rate and fork rate. Action limits are introduced in this ZIP to limit the block processing costs, and client shielded sync costs. The proposed parameterization lowers the worst case for shielded sync and node processing times relative to today, while -yielding far higher Orchard TPS. We benchmark, and the uncle-rate post-proposal +yielding far higher Orchard TPS. We benchmark [block verification](#block-processing-time), and the uncle-rate post-proposal on networks more distributed than mainnet at maximum load is far lower than ETH-PoW was, leading to conclusion that it is safe. @@ -110,8 +110,8 @@ Today the worst-case DoS attack can induce 271 MB of wallet sync download to clients per day, and 4.8M trial decryptions per day [^syncsimulator]. This is d one with max utilizing Sapling transactions, with few inputs and many outputs. The worst-cast DOS for node verification time is done with many Sapling inputs, -and a single transparent output, totalling 5680 Sapling inputs and ZKP's. This -takes 4s on our 4 physical-core benchmark machine. Meanwhile regular userflow +and a single transparent output, totalling 5600 Sapling inputs and ZKP's. This +takes 3.2s on our 4 physical-core benchmark machine. Meanwhile regular userflow has far lower costs on the network, than the DOS model. We propose introducing global action limits and per-pool action limits as follows: @@ -193,7 +193,7 @@ most 330 actions across pools. There is separately, limits per pool. We propose This means the new worst case block processing time, if Orchard dominant, would be a little over half of today's worst case, and Sapling's would be -one sixth. The per-block verification work is therefore substantially reduced. +less than one tenth. The per-block verification work is therefore substantially reduced. **Batch verification.** Orchard transaction verification benefits from batch validation, where proof and signature verification is amortized @@ -204,11 +204,23 @@ verification during live network syncing since version 3.0.0. With the action limits, a worst-case block's Orchard bundle can be fully batch-verified in a small number of batches. -**Estimated timing.** In local benchmarks on a modern AMD laptop CPU -limited to 4 threads, availability verification for an Orchard-heavy -block at the action limits completed in 529.00--554.30 ms, and -availability verification for a Sapling-heavy block at the action -limits completed in 1.1017--1.1329 s. {TODO: @Evan please update this, should be 210ms range. Lets also cite benchmark code} +**Measured timing.** We benchmarked worst-case block verification with +Zebra, limited to 4 physical cores.[^verification-benchmark] The figures +report wall-clock time for verifying the zero-knowledge proofs and +signatures in a single block, without any mempool pre-verification. + +| Case | Block composition | Mean ± stddev | +|------|-------------------|---------------| +| Full Orchard limit (proposed) | 330 Orchard actions | 432.11 ± 11.03 ms | +| Full Sapling limit (proposed) | 300 Sapling spends, 0 outputs | 271.51 ± 5.03 ms | +| Today's Orchard worst case | ~616 actions in dense multi-action txs in a 2 MB block | 769.85 ± 16.18 ms | +| Today's Sapling worst case | ~5,600 spends in dense multi-spend txs in a 2 MB block | 3,174.90 ± 144.04 ms | + +- **Full Orchard limit (proposed)** — binding post-NU7 verification worst case. +- **Full Sapling limit (proposed)** — verification worst case is all-spends; the bandwidth worst case (all-outputs) is in [Rationale](#rationale). +- **Today's Orchard worst case** — dense multi-action (single-action would understate the byte bound). +- **Today's Sapling worst case** — analogous, dense multi-spend. + When transactions have already been pre-verified upon entering the mempool, which is the typical case for a node that has been online, block validation reduces to checking signatures and @@ -629,3 +641,5 @@ activation heights and consensus branch IDs. [^forum-proposal]: [Forum: Proposal — Lower Zcash Block Target Spacing to 25s](https://forum.zcashcommunity.com/t/proposal-lower-zcash-block-target-spacing-to-25s/54577) [^devnet-blocktime-test]: [Forum: Zcash Block Time Reduction Appears Safe for NU7 w/ Zebra-only Devnet](https://forum.zcashcommunity.com/t/zcash-block-time-reduction-appears-safe-for-nu7-w-zebra-only-devnet/55586) + +[^verification-benchmark]: [Zebra worst-case block verification benchmark (`worst_case_tx_verification.rs`)](https://github.com/valargroup/zebra/blob/evan/benchmark-worst-case-block-verification/zebra-consensus/benches/worst_case_tx_verification.rs) From 939a1557aebf8627f240e030bcd9714604fb5589 Mon Sep 17 00:00:00 2001 From: evan-forbes <evan.samuel.forbes@gmail.com> Date: Thu, 14 May 2026 18:15:25 -0500 Subject: [PATCH 108/115] docs: describe benchmark hardware consistently Replace ambiguous '4 physical-core benchmark machine' wording with 'modern AMD laptop CPU with 4 pinned threads' in both the Security and Measured timing sections. --- zips/zip-0218.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/zips/zip-0218.md b/zips/zip-0218.md index b585c7be3..b8b9da0fb 100644 --- a/zips/zip-0218.md +++ b/zips/zip-0218.md @@ -111,7 +111,7 @@ clients per day, and 4.8M trial decryptions per day [^syncsimulator]. This is d one with max utilizing Sapling transactions, with few inputs and many outputs. The worst-cast DOS for node verification time is done with many Sapling inputs, and a single transparent output, totalling 5600 Sapling inputs and ZKP's. This -takes 3.2s on our 4 physical-core benchmark machine. Meanwhile regular userflow +takes 3.2s on a modern AMD laptop CPU with 4 pinned threads. Meanwhile regular userflow has far lower costs on the network, than the DOS model. We propose introducing global action limits and per-pool action limits as follows: @@ -205,9 +205,9 @@ action limits, a worst-case block's Orchard bundle can be fully batch-verified in a small number of batches. **Measured timing.** We benchmarked worst-case block verification with -Zebra, limited to 4 physical cores.[^verification-benchmark] The figures -report wall-clock time for verifying the zero-knowledge proofs and -signatures in a single block, without any mempool pre-verification. +Zebra on a modern AMD laptop CPU with 4 pinned threads.[^verification-benchmark] +The figures report wall-clock time for verifying the zero-knowledge proofs +and signatures in a single block, without any mempool pre-verification. | Case | Block composition | Mean ± stddev | |------|-------------------|---------------| From 3862b93ab5c399dbe9f6bfed250a5307e3b1ea87 Mon Sep 17 00:00:00 2001 From: evan-forbes <evan.samuel.forbes@gmail.com> Date: Thu, 14 May 2026 18:17:33 -0500 Subject: [PATCH 109/115] docs: update dense Orchard worst-case from re-run benchmark MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Today's Orchard worst case is ~436 actions / 556.53 ± 9.81 ms (was ~616 / 769.85 ± 16.18). Updates the derived ratio in the proposed worst-case prose accordingly (a little over half -> about three quarters). --- zips/zip-0218.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zips/zip-0218.md b/zips/zip-0218.md index b8b9da0fb..797690857 100644 --- a/zips/zip-0218.md +++ b/zips/zip-0218.md @@ -192,7 +192,7 @@ most 330 actions across pools. There is separately, limits per pool. We propose - 25 Sprout JoinSplits. This means the new worst case block processing time, if Orchard dominant, -would be a little over half of today's worst case, and Sapling's would be +would be about three quarters of today's worst case, and Sapling's would be less than one tenth. The per-block verification work is therefore substantially reduced. **Batch verification.** Orchard transaction verification benefits from @@ -213,7 +213,7 @@ and signatures in a single block, without any mempool pre-verification. |------|-------------------|---------------| | Full Orchard limit (proposed) | 330 Orchard actions | 432.11 ± 11.03 ms | | Full Sapling limit (proposed) | 300 Sapling spends, 0 outputs | 271.51 ± 5.03 ms | -| Today's Orchard worst case | ~616 actions in dense multi-action txs in a 2 MB block | 769.85 ± 16.18 ms | +| Today's Orchard worst case | ~436 actions in dense multi-action txs in a 2 MB block | 556.53 ± 9.81 ms | | Today's Sapling worst case | ~5,600 spends in dense multi-spend txs in a 2 MB block | 3,174.90 ± 144.04 ms | - **Full Orchard limit (proposed)** — binding post-NU7 verification worst case. From 15c2bd02f1a4acc543cea52f5eccd951393da6d3 Mon Sep 17 00:00:00 2001 From: evan-forbes <evan.samuel.forbes@gmail.com> Date: Thu, 14 May 2026 23:57:21 -0500 Subject: [PATCH 110/115] docs: raise PoWAveragingWindow to 51 at NU7 activation Specify PostNU7PoWAveragingWindow := 51 and redefine PoWAveragingWindow as a height-dependent function (17 pre-NU7, 51 post-NU7), preserving the 1,275-second wall-clock smoothing window across the target-spacing reduction. Add a Difficulty averaging window rationale section covering motivation, simulator recovery, Blossom as a real-world reference point, and devnet variance measurements. Trim the duplicated rationale from the Effect on difficulty adjustment section. Also restore the dense-Orchard worst-case row to the earlier ~616-action / 769.85 ms figure pending verification of the re-run benchmark. --- zips/zip-0218.md | 95 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 88 insertions(+), 7 deletions(-) diff --git a/zips/zip-0218.md b/zips/zip-0218.md index 797690857..c8073332e 100644 --- a/zips/zip-0218.md +++ b/zips/zip-0218.md @@ -192,7 +192,7 @@ most 330 actions across pools. There is separately, limits per pool. We propose - 25 Sprout JoinSplits. This means the new worst case block processing time, if Orchard dominant, -would be about three quarters of today's worst case, and Sapling's would be +would be a little over half of today's worst case, and Sapling's would be less than one tenth. The per-block verification work is therefore substantially reduced. **Batch verification.** Orchard transaction verification benefits from @@ -213,7 +213,7 @@ and signatures in a single block, without any mempool pre-verification. |------|-------------------|---------------| | Full Orchard limit (proposed) | 330 Orchard actions | 432.11 ± 11.03 ms | | Full Sapling limit (proposed) | 300 Sapling spends, 0 outputs | 271.51 ± 5.03 ms | -| Today's Orchard worst case | ~436 actions in dense multi-action txs in a 2 MB block | 556.53 ± 9.81 ms | +| Today's Orchard worst case | ~617 actions in dense multi-action txs in a 2 MB block | 769.85 ± 16.18 ms | | Today's Sapling worst case | ~5,600 spends in dense multi-spend txs in a 2 MB block | 3,174.90 ± 144.04 ms | - **Full Orchard limit (proposed)** — binding post-NU7 verification worst case. @@ -271,6 +271,34 @@ $$ \end{cases} $$ +### Averaging window [averaging-window] + +In § 2 'Notation', add $\mathsf{PostNU7PoWAveragingWindow}$ to the +list of integer constants. + +In § 5.3 'Constants', define: + +$$\mathsf{PostNU7PoWAveragingWindow} := 51$$ + +In § 7.7.3 'Difficulty adjustment', redefine +$\mathsf{PoWAveragingWindow}$ as a height-dependent function: + +$$ +\mathsf{PoWAveragingWindow}(\mathsf{height}) := + \begin{cases} + 17, &\text{if not } \mathsf{IsNU7Activated}(\mathsf{height}) \\\\ + \mathsf{PostNU7PoWAveragingWindow} &\text{otherwise} + \end{cases} +$$ + +All other references to $\mathsf{PoWAveragingWindow}$ in +§ 7.7.3 'Difficulty adjustment' that previously took the constant +value 17 are reinterpreted as +$\mathsf{PoWAveragingWindow}(\mathsf{height})$ for the height of the +block under consideration. This includes the size of the averaging +window used to compute the average target threshold and the average +block timespan. + ### Halving interval and block subsidy Define: @@ -413,11 +441,12 @@ analysis. ## Effect on difficulty adjustment As with the Blossom activation [^zip-0208], the difficulty adjustment -parameters $\mathsf{PoWAveragingWindow}$ and -$\mathsf{PoWMedianBlockSpan}$ refer to numbers of blocks and do *not* -change at activation. The change in the effective value of -$\mathsf{PoWTargetSpacing}$ will cause the block spacing to adjust to -the new target at the normal rate for a difficulty adjustment. +parameter $\mathsf{PoWMedianBlockSpan}$ refers to a number of blocks +and does not change at activation. The change in the effective value +of $\mathsf{PoWTargetSpacing}$ will cause the block spacing to adjust +to the new target at the normal rate for a difficulty adjustment. See +[Difficulty averaging window](#difficulty-averaging-window) in the +Rationale for analysis of the $\mathsf{PoWAveragingWindow}$ change. It is likely that the difficulty adjustment for the first few blocks after activation will be limited by $\mathsf{PoWMaxAdjustDown}$. This @@ -598,6 +627,54 @@ and Sprout are not used, which is the expected common case going forward. +## Difficulty averaging window [difficulty-averaging-window] + +This proposal increases $\mathsf{PoWAveragingWindow}$ from 17 to 51 at +NU7 activation (specified in +[Averaging window](#averaging-window) under Consensus changes), so the +wall-clock smoothing window stays at +$51 \times 25 = 17 \times 75 = 1{,}275$ seconds rather than +contracting threefold. + +The motivations are: + +1. To preserve the wall-clock duration over which difficulty is + smoothed, so that NU7 does not amplify difficulty-manipulation + attacks like the one recently observed on Litecoin + [^litecoin-difficulty-attack]. +2. As an additional improvement over keeping + $\mathsf{PoWAveragingWindow} = 17$, to reduce the standard + deviation of block-spacing averages over short rolling windows. + +Under a Zebra difficulty-adjustment simulator +[^daa-recovery-benchmark] with a stable hash rate and with +$\mathsf{PoWAveragingWindow} = 17$ unchanged across the transition, +the expected block spacing recovers to within 5% of the new 25 s +target within 62 blocks of NU7 activation: + +| Expected spacing | Blocks after activation | Wall-clock | +|-----------------------|-------------------------|------------| +| 75 s (pre-NU7 target) | — | — | +| 56.8 s (activation) | 0 | — | +| $\leq 30$ s | 30 | \~21 min | +| $\leq 26.25$ s | 62 | \~36 min | + +Setting $\mathsf{PoWAveragingWindow} = 51$ is expected to require +roughly 3× as many blocks to cross each threshold, which is the same +wall-clock duration as today. + +For a real-world reference point, the Blossom upgrade [^zip-0208] +made a 2× target-spacing reduction (150 s → 75 s) with +$\mathsf{PoWAveragingWindow}$ unchanged; mainnet block spacing +(20-block rolling average) reached approximately 74 s at height +653,664 — 64 blocks after activation. + +Two geographically-distributed devnets of 99 Zebra nodes across 14 +regions (1 vCPU per node), one at $\mathsf{PoWAveragingWindow} = 17$ +and one at 51, confirmed a \~1-second reduction in the standard +deviation of 5- and 10-block rolling-average block spacings. + + # Deployment This proposal is intended to be deployed as part of NU7, should tokenholder polling and developer consensus agree on it. A separate ZIP will specify the deployment details including @@ -643,3 +720,7 @@ activation heights and consensus branch IDs. [^devnet-blocktime-test]: [Forum: Zcash Block Time Reduction Appears Safe for NU7 w/ Zebra-only Devnet](https://forum.zcashcommunity.com/t/zcash-block-time-reduction-appears-safe-for-nu7-w-zebra-only-devnet/55586) [^verification-benchmark]: [Zebra worst-case block verification benchmark (`worst_case_tx_verification.rs`)](https://github.com/valargroup/zebra/blob/evan/benchmark-worst-case-block-verification/zebra-consensus/benches/worst_case_tx_verification.rs) + +[^daa-recovery-benchmark]: [Zebra difficulty-adjustment recovery simulator: `benchmark_hash_rate_shock_daa_configurations` in `zebra-state/src/service/check/difficulty.rs`](https://github.com/valargroup/zebra/blob/evan/benchmark-worst-case-block-verification/zebra-state/src/service/check/difficulty.rs#L555). The 3× target-spacing transition is exercised by [`simulate_three_x_target_spacing_reduction`](https://github.com/valargroup/zebra/blob/evan/benchmark-worst-case-block-verification/zebra-state/src/service/check/difficulty.rs#L397) in the same file. + +[^litecoin-difficulty-attack]: [Litecoin MWEB Security Incident Postmortem](https://litecoin.com/news/litecoin-mweb-security-incident-postmortem) From c851d98de1db35ac36526d68210e7cea792e0cb3 Mon Sep 17 00:00:00 2001 From: evan-forbes <evan.samuel.forbes@gmail.com> Date: Thu, 14 May 2026 23:57:30 -0500 Subject: [PATCH 111/115] docs: restate proposed-vs-today Orchard ratio against overall worst case MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The reference is today's global worst case = Sapling at 3,174.90 ms. - New Orchard worst case: 432.11 / 3,174.90 ≈ 14% - New Sapling worst case: 271.51 / 3,174.90 ≈ 8.6% ("less than one tenth") This also makes the sentence internally consistent. The previous wording compared new-Orchard to today's-Orchard (432/770 ≈ 56%, "a little over half") but compared new-Sapling to today's-Sapling (272/3175 ≈ 8.6%, "less than one tenth") — two different denominators. With "14%", both halves now reference the same denominator (today's overall worst case). --- zips/zip-0218.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zips/zip-0218.md b/zips/zip-0218.md index c8073332e..22caf61ac 100644 --- a/zips/zip-0218.md +++ b/zips/zip-0218.md @@ -192,7 +192,7 @@ most 330 actions across pools. There is separately, limits per pool. We propose - 25 Sprout JoinSplits. This means the new worst case block processing time, if Orchard dominant, -would be a little over half of today's worst case, and Sapling's would be +would be 14% of today's worst case, and Sapling's would be less than one tenth. The per-block verification work is therefore substantially reduced. **Batch verification.** Orchard transaction verification benefits from From 57aaa582c413d2bb347ee104f78588c985956fc6 Mon Sep 17 00:00:00 2001 From: evan-forbes <evan.samuel.forbes@gmail.com> Date: Fri, 15 May 2026 18:18:47 -0500 Subject: [PATCH 112/115] docs: scale COINBASE_MATURITY and MAX_REORG_LENGTH by 3 at NU7 Raises COINBASE_MATURITY from 100 to 300 and MAX_REORG_LENGTH from 99 to 299 at activation so the wall-clock coverage is preserved at ~125 min. At unchanged 25-second spacing, the existing 100-block window would shrink to ~42 minutes, less than recent multi-hour consensus splits in deployed PoW chains (e.g. Litecoin's April 2026 MWEB incident). --- zips/zip-0218.md | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/zips/zip-0218.md b/zips/zip-0218.md index 22caf61ac..4ceace05d 100644 --- a/zips/zip-0218.md +++ b/zips/zip-0218.md @@ -484,14 +484,22 @@ measured in blocks (marked "No change"): | Constant | Current | Post-activation | Notes | |---------------------------------------------|---------|-----------------|-------| -| `COINBASE_MATURITY` | 100 | 100 | No change; security measured in blocks | -| `MAX_REORG_LENGTH` | 99 | 99 | No change; follows `COINBASE_MATURITY` | +| `COINBASE_MATURITY` | 100 | 300 | Scale by 3 | +| `MAX_REORG_LENGTH` | 99 | 299 | Scale by 3; follows `COINBASE_MATURITY` | | `TX_EXPIRING_SOON_THRESHOLD` | 3 | 3 | No change; | | `MAX_BLOCKS_IN_TRANSIT_PER_PEER` | 16 | 48 | Scale by 3 | | `BLOCK_DOWNLOAD_WINDOW` | 1024 | 3072 | Scale by 3 | | `MIN_BLOCKS_TO_KEEP` | 288 | 864 | Scale by 3; keep 6 hours worth of blocks | | `NETWORK_UPGRADE_PEER_PREFERENCE_BLOCK_PERIOD` | 1728 | 1728 | No change; | +`COINBASE_MATURITY` and `MAX_REORG_LENGTH` are scaled with the +target-spacing change so their wall-clock coverage (~125 min) is +preserved. Holding them at 100 blocks would shrink that window to +~42 minutes, far less than recent multi-hour consensus splits +observed on deployed PoW chains, for example Litecoin's ~3-hour +fork following the April 2026 MWEB exploit +[^litecoin-mweb-incident]. + ### Anchor selection depth ZIP 315 [^zip-0315], recommends selecting an anchor 3 blocks back from @@ -641,7 +649,7 @@ The motivations are: 1. To preserve the wall-clock duration over which difficulty is smoothed, so that NU7 does not amplify difficulty-manipulation attacks like the one recently observed on Litecoin - [^litecoin-difficulty-attack]. + [^litecoin-mweb-incident]. 2. As an additional improvement over keeping $\mathsf{PoWAveragingWindow} = 17$, to reduce the standard deviation of block-spacing averages over short rolling windows. @@ -723,4 +731,4 @@ activation heights and consensus branch IDs. [^daa-recovery-benchmark]: [Zebra difficulty-adjustment recovery simulator: `benchmark_hash_rate_shock_daa_configurations` in `zebra-state/src/service/check/difficulty.rs`](https://github.com/valargroup/zebra/blob/evan/benchmark-worst-case-block-verification/zebra-state/src/service/check/difficulty.rs#L555). The 3× target-spacing transition is exercised by [`simulate_three_x_target_spacing_reduction`](https://github.com/valargroup/zebra/blob/evan/benchmark-worst-case-block-verification/zebra-state/src/service/check/difficulty.rs#L397) in the same file. -[^litecoin-difficulty-attack]: [Litecoin MWEB Security Incident Postmortem](https://litecoin.com/news/litecoin-mweb-security-incident-postmortem) +[^litecoin-mweb-incident]: [Litecoin MWEB Security Incident Postmortem](https://litecoin.com/news/litecoin-mweb-security-incident-postmortem) From 15acdf377a941d5e45af77e49ef23f964e695859 Mon Sep 17 00:00:00 2001 From: evan-forbes <evan.samuel.forbes@gmail.com> Date: Fri, 15 May 2026 22:03:20 -0500 Subject: [PATCH 113/115] docs: raise MAX_REORG_LENGTH to 300 at NU7 Decouples MAX_REORG_LENGTH from COINBASE_MATURITY. Reverts COINBASE_MATURITY to 100 and sets MAX_REORG_LENGTH to 300, preserving the current ~125 minute window at 25-second spacing. The Bitcoin-inherited MAX_REORG_LENGTH < COINBASE_MATURITY convention is not the security boundary for coinbase spendability. This change is the minimum needed to avoid regressing on the wall-clock margin. The right long-term value is out of scope here. --- zips/zip-0218.md | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/zips/zip-0218.md b/zips/zip-0218.md index 4ceace05d..96453810c 100644 --- a/zips/zip-0218.md +++ b/zips/zip-0218.md @@ -484,21 +484,38 @@ measured in blocks (marked "No change"): | Constant | Current | Post-activation | Notes | |---------------------------------------------|---------|-----------------|-------| -| `COINBASE_MATURITY` | 100 | 300 | Scale by 3 | -| `MAX_REORG_LENGTH` | 99 | 299 | Scale by 3; follows `COINBASE_MATURITY` | +| `COINBASE_MATURITY` | 100 | 100 | No change; | +| `MAX_REORG_LENGTH` | 99 | 300 | Scale by 3; decoupled from `COINBASE_MATURITY` | | `TX_EXPIRING_SOON_THRESHOLD` | 3 | 3 | No change; | | `MAX_BLOCKS_IN_TRANSIT_PER_PEER` | 16 | 48 | Scale by 3 | | `BLOCK_DOWNLOAD_WINDOW` | 1024 | 3072 | Scale by 3 | | `MIN_BLOCKS_TO_KEEP` | 288 | 864 | Scale by 3; keep 6 hours worth of blocks | | `NETWORK_UPGRADE_PEER_PREFERENCE_BLOCK_PERIOD` | 1728 | 1728 | No change; | -`COINBASE_MATURITY` and `MAX_REORG_LENGTH` are scaled with the -target-spacing change so their wall-clock coverage (~125 min) is -preserved. Holding them at 100 blocks would shrink that window to -~42 minutes, far less than recent multi-hour consensus splits -observed on deployed PoW chains, for example Litecoin's ~3-hour -fork following the April 2026 MWEB exploit -[^litecoin-mweb-incident]. +Zebra's `MAX_REORG_LENGTH` is currently 100, set just below +`COINBASE_MATURITY` by Bitcoin-inherited convention. At Bitcoin's +10-minute spacing 100 blocks covers about 16.7 hours, at Zcash's +current 75-second spacing about 125 minutes, and at NU7's proposed +25-second spacing only about 42 minutes. Recent incidents show +consensus splits can persist beyond tens of minutes. For example, +Litecoin's April 2026 MWEB incident produced a 13-block invalid +chain that was later reorged out, with a ~3-hour recovery window +per the postmortem [^litecoin-mweb-incident]. + +This proposal is fundamentally about decreasing the target +spacing, which makes the wall-clock margin shorter for any given +`MAX_REORG_LENGTH`. The optimal long-term value for that parameter +likely needs to change further in the future, but that is out of +scope here. The change in this proposal is the minimum needed to +avoid making the problem worse. Raising `MAX_REORG_LENGTH` to 300 +blocks preserves the current ~125 minute window at 25-second +spacing, while `COINBASE_MATURITY` remains 100. + +This deliberately means that a supported reorg may invalidate a +mature coinbase output. That case is already a valid consequence +of deep PoW reorgs in the abstract protocol model. Zebra will now +handle such reorgs rather than reject them at the old 100-block +bound. ### Anchor selection depth From 6455e794d4bd0131c25e768c22765ee2e8daa661 Mon Sep 17 00:00:00 2001 From: evan-forbes <evan.samuel.forbes@gmail.com> Date: Tue, 19 May 2026 15:52:38 -0500 Subject: [PATCH 114/115] docs: scale wall-clock parameters to launch 150 s spacing at NU7 Raise PostNU7PoWAveragingWindow from 17 to 102 and MAX_REORG_LENGTH from 99 to 600 at NU7 activation, so that at the proposed 25 s target spacing each parameter's wall-clock window matches the duration it provided at Zcash's launch 150 s spacing: 17 * 150 = 102 * 25 = 2,550 s, and 100 * 150 = 600 * 25 = 15,000 s (~4.2 hours). The previously-merged values of 51 and 300 only preserved today's post-Blossom 75 s wall-clock windows; restoring the launch-mainnet durations is more conservative and matches the wall-clock these parameters were originally chosen against. Update the Difficulty averaging window and MAX_REORG_LENGTH rationales accordingly (including the recovery-multiplier reference, 3x -> 6x). Also correct the current MAX_REORG_LENGTH value in prose from 100 to 99: Zebra defines MAX_BLOCK_REORG_HEIGHT as MIN_TRANSPARENT_COINBASE_MATURITY - 1. COINBASE_MATURITY itself remains decoupled and unchanged at 100. --- zips/zip-0218.md | 69 ++++++++++++++++++++++++++---------------------- 1 file changed, 38 insertions(+), 31 deletions(-) diff --git a/zips/zip-0218.md b/zips/zip-0218.md index 96453810c..7bb50f1de 100644 --- a/zips/zip-0218.md +++ b/zips/zip-0218.md @@ -278,7 +278,7 @@ list of integer constants. In § 5.3 'Constants', define: -$$\mathsf{PostNU7PoWAveragingWindow} := 51$$ +$$\mathsf{PostNU7PoWAveragingWindow} := 102$$ In § 7.7.3 'Difficulty adjustment', redefine $\mathsf{PoWAveragingWindow}$ as a height-dependent function: @@ -485,37 +485,38 @@ measured in blocks (marked "No change"): | Constant | Current | Post-activation | Notes | |---------------------------------------------|---------|-----------------|-------| | `COINBASE_MATURITY` | 100 | 100 | No change; | -| `MAX_REORG_LENGTH` | 99 | 300 | Scale by 3; decoupled from `COINBASE_MATURITY` | +| `MAX_REORG_LENGTH` | 99 | 600 | Scale by 6; decoupled from `COINBASE_MATURITY` | | `TX_EXPIRING_SOON_THRESHOLD` | 3 | 3 | No change; | | `MAX_BLOCKS_IN_TRANSIT_PER_PEER` | 16 | 48 | Scale by 3 | | `BLOCK_DOWNLOAD_WINDOW` | 1024 | 3072 | Scale by 3 | | `MIN_BLOCKS_TO_KEEP` | 288 | 864 | Scale by 3; keep 6 hours worth of blocks | | `NETWORK_UPGRADE_PEER_PREFERENCE_BLOCK_PERIOD` | 1728 | 1728 | No change; | -Zebra's `MAX_REORG_LENGTH` is currently 100, set just below -`COINBASE_MATURITY` by Bitcoin-inherited convention. At Bitcoin's -10-minute spacing 100 blocks covers about 16.7 hours, at Zcash's -current 75-second spacing about 125 minutes, and at NU7's proposed -25-second spacing only about 42 minutes. Recent incidents show -consensus splits can persist beyond tens of minutes. For example, -Litecoin's April 2026 MWEB incident produced a 13-block invalid -chain that was later reorged out, with a ~3-hour recovery window -per the postmortem [^litecoin-mweb-incident]. - This proposal is fundamentally about decreasing the target spacing, which makes the wall-clock margin shorter for any given -`MAX_REORG_LENGTH`. The optimal long-term value for that parameter -likely needs to change further in the future, but that is out of -scope here. The change in this proposal is the minimum needed to -avoid making the problem worse. Raising `MAX_REORG_LENGTH` to 300 -blocks preserves the current ~125 minute window at 25-second -spacing, while `COINBASE_MATURITY` remains 100. +`MAX_REORG_LENGTH`. Zebra's `MAX_REORG_LENGTH` is currently 99, set +just below `COINBASE_MATURITY` (= 100) by Bitcoin-inherited +convention. At Zcash's launch 150-second spacing it covered about +4.2 hours, at the current 75-second spacing about 125 minutes, and +at NU7's proposed 25-second spacing only about 42 minutes. + +Recent incidents show consensus splits can persist beyond tens of minutes: +for example, Litecoin's April 2026 MWEB incident produced a +13-block invalid chain that was later reorged out, with a ~3-hour +recovery window per the postmortem [^litecoin-mweb-incident]. The +optimal long-term value for `MAX_REORG_LENGTH` likely needs to +change further in the future, but that is out of scope here. +Raising it to 600 blocks restores the ~4.2-hour wall-clock window +it provided at Zcash's launch 150-second target spacing, while +`COINBASE_MATURITY` remains 100. This is more conservative than the +~125-minute window at today's 75-second spacing. Given the incident +above and that the launch 150-second-spacing value predates this +line of evidence, restoring the launch wall-clock margin is the +safer choice. This deliberately means that a supported reorg may invalidate a mature coinbase output. That case is already a valid consequence -of deep PoW reorgs in the abstract protocol model. Zebra will now -handle such reorgs rather than reject them at the old 100-block -bound. +of deep PoW reorgs in the abstract protocol model. ### Anchor selection depth @@ -654,12 +655,15 @@ forward. ## Difficulty averaging window [difficulty-averaging-window] -This proposal increases $\mathsf{PoWAveragingWindow}$ from 17 to 51 at -NU7 activation (specified in -[Averaging window](#averaging-window) under Consensus changes), so the -wall-clock smoothing window stays at -$51 \times 25 = 17 \times 75 = 1{,}275$ seconds rather than -contracting threefold. +This proposal increases $\mathsf{PoWAveragingWindow}$ from 17 to 102 +at NU7 activation (specified in +[Averaging window](#averaging-window) under Consensus changes), so +that the wall-clock smoothing window is +$102 \times 25 = 17 \times 150 = 2{,}550$ seconds — the same +wall-clock window the value $\mathsf{PoWAveragingWindow} = 17$ was +originally chosen to provide at Zcash's launch target spacing of +150 s. At today's 75 s spacing the same value covers only 1,275 s, +and at NU7's proposed 25 s spacing it would cover only 425 s. The motivations are: @@ -684,9 +688,10 @@ target within 62 blocks of NU7 activation: | $\leq 30$ s | 30 | \~21 min | | $\leq 26.25$ s | 62 | \~36 min | -Setting $\mathsf{PoWAveragingWindow} = 51$ is expected to require -roughly 3× as many blocks to cross each threshold, which is the same -wall-clock duration as today. +Setting $\mathsf{PoWAveragingWindow} = 102$ is expected to require +roughly 6× as many blocks to cross each threshold, which is the +same wall-clock duration as recovery would have taken at Zcash's +launch 150 s spacing with $\mathsf{PoWAveragingWindow} = 17$. For a real-world reference point, the Blossom upgrade [^zip-0208] made a 2× target-spacing reduction (150 s → 75 s) with @@ -697,7 +702,9 @@ $\mathsf{PoWAveragingWindow}$ unchanged; mainnet block spacing Two geographically-distributed devnets of 99 Zebra nodes across 14 regions (1 vCPU per node), one at $\mathsf{PoWAveragingWindow} = 17$ and one at 51, confirmed a \~1-second reduction in the standard -deviation of 5- and 10-block rolling-average block spacings. +deviation of 5- and 10-block rolling-average block spacings. The +variance reduction is expected to be somewhat larger at +$\mathsf{PoWAveragingWindow} = 102$. # Deployment From 7eb15ccf0d27b67d0d1ff0f7d9d02a6eb4f04e80 Mon Sep 17 00:00:00 2001 From: nobody <nobody@nowhere.net> Date: Sun, 14 Jun 2026 19:55:01 -0700 Subject: [PATCH 115/115] First attempt at `nix build` completing the upstream render. --- flake.nix | 89 ++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 58 insertions(+), 31 deletions(-) diff --git a/flake.nix b/flake.nix index 14035b348..146a1f09c 100644 --- a/flake.nix +++ b/flake.nix @@ -63,40 +63,67 @@ # Tests require additional fixtures not included in the PyPI tarball doCheck = false; }; + + buildInputs = [ + # Core dependencies for render.sh + rst2html5 # rst2html5 2.0.1 (PyPI) + pkgs.python3Packages.pygments # syntax highlighting for code blocks + pkgs.pandoc # pandoc markdown renderer + mmd # multimarkdown renderer (zcash fork) + pkgs.perl # perl for text processing + + # Build system dependencies + pkgs.gnumake # make command for building + pkgs.git # required by Makefile for safe.directory + + # LaTeX dependencies for protocol PDF generation + (pkgs.texlive.combine { inherit (pkgs.texlive) scheme-full; }) + + # Python dependencies for links_and_dests.py + pkgs.python3 + pkgs.python3Packages.beautifulsoup4 + pkgs.python3Packages.html5lib + pkgs.python3Packages.certifi + + # Standard utilities (usually available, but ensuring they're present) + pkgs.coreutils + pkgs.bash + pkgs.gnused + pkgs.gnugrep + pkgs.diffutils + pkgs.findutils + ]; + + all = pkgs.stdenv.mkDerivation { + pname = "zcash-zips-rendered-all"; + version = "0.0.1"; + src = ./.; + + inherit buildInputs; + + buildPhase = '' + # Subprocess for bash set flags scope, especially -x so that we + # don't see very verbose nix cleanup traces on errors: + ( + set -efuxo pipefail + # Ewww... looks like `kpathsea` mutates the user's home. + # Create a fake home dir inside the buildir: + fake_home='./messy-fake-home' + mkdir "$fake_home" + HOME="$fake_home" make all + ) + ''; + }; in { + packages = { + inherit all; + + default = all; + }; + devShells.default = pkgs.mkShell { - buildInputs = [ - # Core dependencies for render.sh - rst2html5 # rst2html5 2.0.1 (PyPI) - pkgs.python3Packages.pygments # syntax highlighting for code blocks - pkgs.pandoc # pandoc markdown renderer - mmd # multimarkdown renderer (zcash fork) - pkgs.perl # perl for text processing - - # Build system dependencies - pkgs.gnumake # make command for building - pkgs.git # required by Makefile for safe.directory - - # LaTeX dependencies for protocol PDF generation - (pkgs.texlive.combine { - inherit (pkgs.texlive) scheme-full; - }) - - # Python dependencies for links_and_dests.py - pkgs.python3 - pkgs.python3Packages.beautifulsoup4 - pkgs.python3Packages.html5lib - pkgs.python3Packages.certifi - - # Standard utilities (usually available, but ensuring they're present) - pkgs.coreutils - pkgs.bash - pkgs.gnused - pkgs.gnugrep - pkgs.diffutils - pkgs.findutils - ]; + inherit buildInputs; shellHook = '' echo "ZIP documentation rendering environment"