Skip to content

[ZIP 2007] Quantum recoverability of a subset of the transparent protocol #1302

Description

@daira

Motivation

ZIP 2005 makes new Orchard-protocol (Ironwood) notes quantum-recoverable: if the discrete-log assumption on the curves Zcash uses is broken, funds committed in the recoverable format can be moved into a future post-quantum protocol by proving —in zero knowledge— that you know the secret a recovery is entitled to, without revealing anything a discrete-log break would let an attacker exploit.

This issue asks a similar question for the transparent protocol: which transparent UTXOs could be recovered the same way? The point is to scope what a transparent recovery statement would have to cover, and to identify what is recoverable in principle versus what is fundamentally exposed.

Scope

Restrict attention to UTXOs that are:

  • sent to a representable t-address (i.e. a t1... P2PKH address or a t3... P2SH address — these are the only transparent address forms Zcash defines); and
  • spendable by zcashd or librustzcash; and
  • have not had their ECDSA public keys revealed to a potential adversary.

Note that as long as we can still only spend these UTXOs via the existing transparent protocol, the form of quantum recoverability obtained is weaker than for Ironwood: once the public key(s) are exposed, any funds subsequently sent to that address are vulnerable. For Ironwood, spending using the existing protocol does not expose keys to attack.

Note that this analysis also does not consider attacks against $\mathsf{Hash160}$ via Grover's algorithm, although there is reason to believe these are not likely to be practical on the same timescale as attacks using Shor's algorithm.

Script-type numbering below refers to the standard types in qa/rpc-tests/decodescript.py.

Standard output (scriptPubKey) types

1. P2PK and 3. bare multisig — out of scope: neither has a t-address, and neither is spendable at the top level in a way reachable via an address. zcashd's IsMine will spend a top-level P2PK output if it holds the key, but there is no way to send to one via an address. Bare multisig is explicitly never spendable at the top level — IsMineInner breaks when sigversion == TOP.

5. OP_RETURN (TX_NULL_DATA) — out of scope: provably unspendable, no funds at risk.

2. P2PKHOP_DUP OP_HASH160 $\langle\mathsf{PubKeyHash}\rangle$ OP_EQUALVERIFY OP_CHECKSIG. Recoverable. Prove

$$\mathsf{ZKPoK} { (\mathsf{privkey}) : \mathsf{PubKeyHash} = \mathsf{Hash160}(\mathsf{PubKeyOf}(\mathsf{privkey})) }$$

i.e. knowledge of a private key whose public key hashes to the committed $\mathsf{PubKeyHash}$. Note that $\mathsf{Hash160}(\bullet) = \mathsf{RIPEMD160}(\mathsf{SHA256}(\bullet))$ commits to a specific public-key encoding (compressed vs. uncompressed), so the recovery statement must account for that encoding.

4. P2SHOP_HASH160 $\langle\mathsf{Hash160}(\mathsf{redeemScript})\rangle$ OP_EQUAL. The on-chain output commits only to $\mathsf{Hash160}(\mathsf{redeemScript})$; the $\mathsf{redeemScript}$ itself is revealed only when spending. The $\mathsf{redeemScript}$ forms that zcashd or librustzcash will spend (one level deep; nested P2SH is not standard) are:

  • P2SH-wrapped P2PKH ($\mathsf{redeemScript}$ = a P2PKH script): recoverable, for the same reason as (2).
  • P2SH-wrapped P2PK ($\mathsf{redeemScript} = \langle\mathsf{pubkey}\rangle$ OP_CHECKSIG): recoverable. Unlike a top-level P2PK (case 1), the P2SH wrapper keeps the public key hidden until spend, so it is recoverable in the same way as P2SH-multisig below. The circuit must compute the $\mathsf{redeemScript}$ hash so that the public key is never exposed, plus a ZKPoK of the private key for that public key.
  • P2SH-wrapped threshold multisig ($\mathsf{redeemScript} = \langle m\rangle \langle\mathsf{pubkey}_1\rangle \ldots \langle\mathsf{pubkey}_n\rangle \langle n\rangle$ OP_CHECKMULTISIG): recoverable in principle. Because the $\mathsf{redeemScript}$ carries the public keys in the clear, recovery cannot reveal it; the $\mathsf{Hash160}$ of the $\mathsf{redeemScript}$ must be computed in zero knowledge to protect the keys.

This makes the statement sensitive to the $\mathsf{redeemScript}$ being exactly this form (the circuit reconstructs the precise script bytes and hashes them). It is feasible but needs either recursive proofs or a large circuit (SHA-256 + RIPEMD-160 over the script, plus $m$ secp256k1 scalar multiplications).

Recoverable vs. exposed — summary

Output type t-address Spendable by Recoverable?
P2PK (top-level) zcashd (no send path) n/a (out of scope)
bare multisig (top-level) never (top level) n/a (out of scope)
OP_RETURN unspendable n/a (no funds)
P2PKH t1... zcashd, librustzcash yes — ZKPoK of privkey for the committed hash
P2SH -> P2PKH t3... zcashd yes — as P2PKH
P2SH -> P2PK t3... zcashd yes — in-circuit redeemScript hashing + ZKPoK
P2SH -> multisig t3... zcashd, librustzcash yes, in principle — in-circuit redeemScript hashing + ZKPoK of $m$ of $n$

Implementation notes

  • zcashd vs. librustzcash divergence for P2SH. The librustzcash transaction builder currently constructs only P2SH-multisig spends (p2sh_input_serialized_len: "currently only P2MS-in-P2SH is supported"). P2SH-wrapped P2PKH and P2PK are spendable via zcashd's wallet, not the librustzcash builder — so they are in scope under "spendable by zcashd or librustzcash", but only zcashd actually builds those spends today. (The librustzcash PCZT signer does recognize PubKey, PubKeyHash, and MultiSig redeemScript kinds via zcash_script's solver::ScriptKind.)

Open questions

  • For P2SH-multisig, is the cost (recursive proofs or a large circuit to take into account the in-circuit $\mathsf{Hash160}(\mathsf{redeemScript})$ and $m$ secp256k1 scalar multiplications) justified, given how transparent multisig funds are actually used? It could also be reasonable to just classify these funds as not recoverable, and require transparent multisig holders to spend them into P2PKH or a FROST-based multisig in the Ironwood (or Tachyon) pool.
  • Are P2SH-wrapped P2PKH or P2SH-wrapped P2PK actually used at all?

Next steps

  • Survey the chain to see what proportion of funds are currently recoverable and in each category. This includes Ironwood funds if Ironwood has already activated. Note that funds held in P2SH addresses can't be definitively classified as recoverable based on public information. (They can be classified as non-recoverable if the corresponding script has been seen.)
  • Estimate the cost of the circuit to spend P2PKH and P2SH-wrapped-P2PKH funds.
  • Deploy that circuit.

Drafted with the assistance of Claude Opus 4.8 (1M context).

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions