# ZIP 374: Partially Created Zcash Transaction Format

Status: Draft

Owners: Jack Grigg

Snapshot: a34cfc091434275120ff017c92c3b50d3cef623a

Source date: 2026-10-16T02:56:04+01:00

[Source revision](https://github.com/zcash/zips/commit/a34cfc091434275120ff017c92c3b50d3cef623a)

[Official source](https://zips.z.cash/zip-0374) · [Source file](https://github.com/zcash/zips/blob/a34cfc091434275120ff017c92c3b50d3cef623a/zips/zip-0374.md) · [Discussion](https://github.com/zcash/zips/issues/693)

## Document parts

[Part 1](https://zips.tools/zip/374) · [Part 2](https://zips.tools/zip/374?part=2)

Reading part 2 of 2. Follow all parts for the complete proposal.

- `nullifier: [u8; 32]`
  
  
  
  
  This is filled in by the Constructor when adding a spend.

- `rk: [u8; 32]`
  
  
  
  
  This is filled in by the Constructor when adding a spend.

- `spend_auth_sig: Option<[u8; 64]>`
  
  
  
  
  The spend authorization signature.
  
  
  
  
  This is set by the Signer.

- `recipient: Option<[u8; 43]>`
  
  
  
  
  The raw encoding <a id="user-content-fnref-protocol-orchardpaymentaddrencoding"></a>
  [22](#user-content-fn-protocol-orchardpaymentaddrencoding) of the Orchard payment
  address that received the note being spent.
  
  
  
  
  
  - This is set by the Constructor.
  
  - This is required by the Prover.

- `value: Option<u64>`
  
  
  
  
  The value of the input being spent.
  
  
  
  
  
  - This is required by the Prover.
  
  - This may be used by Signers to verify that the value matches `cv`, and to
    confirm the values and change involved in the transaction.
  
  
  
  
  
  This exposes the input value to all participants. For Signers who don't need
  this information, or after signatures have been applied, this can be redacted.

- `rho: Option<[u8; 32]>`
  
  
  
  
  The rho value for the note being spent.
  
  
  
  
  
  - This is set by the Constructor.
  
  - This is required by the Prover.

- `rseed: Option<[u8; 32]>`
  
  
  
  
  The seed randomness for the note being spent.
  
  
  
  
  
  - This is set by the Constructor.
  
  - This is required by the Prover.

- `fvk: Option<[u8; 96]>`
  
  
  
  
  The full viewing key that received the note being spent.
  
  
  
  
  
  - This is set by the Updater.
  
  - This is required by the Prover.

- `witness: Option<(u32, [[u8; 32]; 32])>`
  
  
  
  
  A witness from the note to the bundle's anchor.
  
  
  
  
  
  - This is set by the Updater.
  
  - This is required by the Prover.
  
  - If `tx_version` is 6, this MAY be absent when the spend is signed, and
    added later by an Updater — including for a spend of a note that has not
    yet been added to the note commitment tree (see "Anchors and
    pre-authorization"). Signatures do not commit to it.

- `alpha: Option<[u8; 32]>`
  
  
  
  
  The spend authorization randomizer.
  
  
  
  
  
  - This is chosen by the Constructor.
  
  - This is required by the Signer for creating `spend_auth_sig`, and may be
    used to validate `rk`.
  
  - After `zkproof` / `spend_auth_sig` has been set, this can be redacted.

- `zip32_derivation: Option<Zip32Derivation>`
  
  
  
  
  The ZIP 32 derivation path at which the spending key can be found for the note
  being spent.

- `dummy_sk: Option<[u8; 32]>`
  
  
  
  
  The spending key for this spent note, if it is a dummy note.
  
  
  
  
  
  - This is chosen by the Constructor.
  
  - This is required by the IO Finalizer, and is cleared by it once used.
  
  - Signers MUST reject PCZTs that contain `dummy_sk` values.

- `proprietary: Map<UTF8String, List<u8>>`
  
  
  
  
  Proprietary fields related to the note being spent. See "Proprietary Use
  fields" below.

###### `OrchardOutput`

The  `OrchardOutput` struct has the following fields:

- `cmx: [u8; 32]`
  
  
  
  
  This is filled in by the Constructor when adding an output.

- `ephemeral_key: [u8; 32]`
  
  
  
  
  This is filled in by the Constructor when adding an output.

- `enc_ciphertext: List<u8>`
  
  
  
  
  The encrypted note plaintext for the output.
  
  
  
  
  This is filled in by the Constructor when adding an output.
  
  
  
  
  Encoded as a `List<u8>` because its length depends on the transaction version.
  
  
  
  
  Once we have memo bundles <a id="user-content-fnref-zip-0231-2"></a>
  [20](#user-content-fn-zip-0231), we will be able to set memos
  independently of Outputs. For now, the Constructor sets both at the same time.

- `out_ciphertext: List<u8>`
  
  
  
  
  The encrypted note plaintext for the output.
  
  
  
  
  This is filled in by the Constructor when adding an output.
  
  
  
  
  Encoded as a `List<u8>` because its length depends on the transaction version.

- `recipient: Option<[u8; 43]>`
  
  
  
  
  The raw encoding <a id="user-content-fnref-protocol-orchardpaymentaddrencoding-2"></a>
  [22](#user-content-fn-protocol-orchardpaymentaddrencoding) of the Orchard payment
  address that will receive the output.
  
  
  
  
  
  - This is set by the Constructor.
  
  - This is required by the Prover.

- `value: Option<u64>`
  
  
  
  
  The value of the output.
  
  
  
  
  This may be used by Signers to verify that the value matches `cv`, and to
  confirm the values and change involved in the transaction.
  
  
  
  
  This exposes the value to all participants. For Signers who don't need this
  information, we can drop the values and compress the rcvs into the bsk global.

- `rseed: Option<[u8; 32]>`
  
  
  
  
  The seed randomness for the output.
  
  
  
  
  
  - This is set by the Constructor.
  
  - This is required by the Prover, instead of disclosing `shared_secret` to them.

- `ock: Option<[u8; 32]>`
  
  
  
  
  The `ock` value used to encrypt `out_ciphertext`.
  
  
  
  
  This enables Signers to verify that `out_ciphertext` is correctly encrypted.
  
  
  
  
  This may be `None` if the Constructor added the output using an OVK policy of
  "None", to make the output unrecoverable from the chain by the sender.

- `zip32_derivation: Option<Zip32Derivation>`
  
  
  
  
  The ZIP 32 derivation path at which the spending key can be found for the
  output.

- `user_address: Option<UTF8String>`
  
  
  
  
  The user-facing address to which this output is being sent, if any.
  
  
  
  
  
  - This is set by an Updater.
  
  - Signers MUST parse this address (if present) and confirm that it contains
    `recipient` (either directly, or e.g. as a receiver within a Unified
    Address).

- `proprietary: Map<UTF8String, List<u8>>`
  
  
  
  
  Proprietary fields related to the note being created. See "Proprietary Use
  fields" below.

#### `IronwoodBundle` (PCZT v2)

The `IronwoodBundle` struct carries the *Ironwood-pool* component of a v6
transaction <a id="user-content-fnref-zip-0229-10"></a>
[4](#user-content-fn-zip-0229). The *Ironwood pool* is a second value pool of the
Orchard protocol, so the `IronwoodBundle` has exactly the same structure,
field semantics, and role interactions as the `OrchardBundle`, with the
following differences:

- `flags`: the `enableCrossAddress` flag (bit 2) is meaningful and is normally
  1 for an `IronwoodBundle` (cross-address transfers are the usual case in the
  *Ironwood pool*, and are consensus-disabled in the *Orchard pool* from NU6.3
  onward) <a id="user-content-fnref-zip-0229-11"></a>
  [4](#user-content-fn-zip-0229) <a id="user-content-fnref-zip-0258-2"></a>
  [21](#user-content-fn-zip-0258).

- `anchor` refers to a root of the **Ironwood** note commitment tree, which is
  distinct from the Orchard note commitment tree.

- `note_version` MUST be `V3`: every *Ironwood-pool* output note uses the
  ZIP 2005 <a id="user-content-fnref-zip-2005-3"></a>
  [10](#user-content-fn-zip-2005) quantum-recoverable note plaintext format.

An `IronwoodBundle` that is not the canonical empty bundle MUST NOT be present
in a PCZT whose `tx_version` is 5; roles MUST reject such a PCZT.

#### Other Internal Structures

##### `Zip32Derivation`

The  `Zip32Derivation` struct has the following fields:

- `seed_fingerprint: [u8; 32]`
  
  
  
  
  The ZIP 32 seed fingerprint <a id="user-content-fnref-zip-0032-seedfp"></a>
  [23](#user-content-fn-zip-0032-seedfp).

- `derivation_path: List<u32>`
  
  
  
  
  The sequence of indices corresponding to the shielded HD path.
  
  
  
  
  Indices can be hardened or non-hardened (i.e. the hardened flag bit may be
  set). When used with a Sapling or Orchard spend, the derivation path will
  generally be entirely hardened; when used with a transparent input, the
  derivation path will generally include a non-hardened section matching either
  the BIP 44 <a id="user-content-fnref-bip-0044-2"></a>
  [16](#user-content-fn-bip-0044) path, or the path at which ephemeral addresses are
  derived for ZIP 320 <a id="user-content-fnref-zip-0320"></a>
  [24](#user-content-fn-zip-0320) transactions.

<a id="interpretation"></a>

### Interpretation

#### Determining Lock Time

The `nLockTime` field of a transaction is determined by inspecting the
`Global.fallback_lock_time` and each `TransparentInput.required_time_locktime`
and `TransparentInput.required_height_locktime` field. If none of the
transparent inputs have a `TransparentInput.required_time_locktime` and
`TransparentInput.required_height_locktime`, then `Global.fallback_lock_time`
must be used. If `Global.fallback_lock_time` is not provided, then it is assumed
to be 0.

If one or more inputs have a `TransparentInput.required_time_locktime` or
`TransparentInput.required_height_locktime`, then the field chosen is the one
which is supported by all of the inputs. This can be determined by looking at
all of the inputs which specify a locktime in either of those fields, and
choosing the field which is present in all of those inputs. Inputs not
specifying a lock time field can take both types of lock times, as can those
that specify both. The lock time chosen is then the maximum value of the chosen
type of lock time.

If a PCZT has both types of locktimes possible because one or more inputs
specify both `TransparentInput.required_time_locktime` and
`TransparentInput.required_height_locktime`, then a locktime determined by
looking at the `TransparentInput.required_height_locktime` fields of the inputs
must be chosen.

#### Anchors and pre-authorization

In the v5 transaction format, the Sapling and Orchard anchors are transaction
effecting data: the signature hash commits to them <a id="user-content-fnref-zip-0244-2"></a>
[8](#user-content-fn-zip-0244). In the v6
transaction format, the anchors of all shielded bundles are authorizing data:
the transaction identifier and signature hash omit them, and they are instead
committed to by the authorizing data commitment <a id="user-content-fnref-zip-0229-12"></a>
[4](#user-content-fn-zip-0229). Merkle witnesses
never appear in the transaction in either format; they are consumed only by
the proofs, which are themselves authorizing data.

For a PCZT whose `tx_version` is 5:

- Every shielded bundle anchor MUST be set at the time the bundle's first
  spend is added, and MUST NOT change thereafter.

For a PCZT whose `tx_version` is 6 (which requires PCZT v2):

- A shielded bundle anchor MAY be absent until proving. An Updater MAY set an
  absent anchor, and MAY replace a previously set anchor, at any time before
  the Prover runs for that bundle.

- Setting or replacing a bundle's anchor MUST clear any proof fields already
  set in that bundle (`SaplingSpend.zkproof` for the Sapling bundle;
  `OrchardBundle.zkproof` or `IronwoodBundle.zkproof` for the Orchard-protocol
  bundles): proofs commit to the anchor as a circuit public input.

- Signatures (spend authorization signatures and binding signatures) do not
  commit to the anchors or witnesses, so setting or replacing them does not
  invalidate signatures, and Signers MAY sign while they are absent.

- A `SaplingSpend.witness` or `OrchardSpend.witness` MAY likewise be absent
  until proving, and set by an Updater once known.

- When setting an anchor for a bundle in which witnesses are already present,
  or a witness for a bundle whose anchor is already present, the Updater MUST
  verify that each witness's Merkle path roots to the bundle's anchor, and the
  Prover MUST perform the same check before creating a proof.

This enables two workflows that are impossible for v5 transactions:

- **Re-anchoring**: a fully signed transaction can be updated to use a more
  recent anchor at broadcast time (for example, an anchor shared by many
  wallets <a id="user-content-fnref-draft-schell-ironwood-migration-2"></a>
  [5](#user-content-fn-draft-schell-ironwood-migration)), requiring only re-proving. The
  transaction identifier is unchanged by re-anchoring.

- **Spending unmined notes**: every field of a v6 signature hash is computable
  for a transaction that spends an Orchard-protocol note created by a parent
  transaction that has not yet been mined, because Orchard-protocol nullifiers
  depend only on note data (ρ is fixed by the action that created the note),
  not on the note's position in the note commitment tree. Such a transaction
  can be constructed and fully signed before the parent transaction is even
  broadcast, with its witnesses, anchor, and proofs supplied after the parent
  is mined.

Note that the second workflow is not available for Sapling spends even under
the v6 format: a Sapling nullifier depends on the spent note's position in the
note commitment tree, which is unknown until the note is mined. For Sapling,
deferred anchors enable only the re-anchoring workflow.

Fields that remain effecting data — notably `Global.expiry_height`,
`Global.fallback_lock_time`, per-input lock time requirements, and all values —
are committed to by signatures in both formats and can never change after
signing.

#### Fabricated same-address outputs (NU6.3)

From NU6.3 activation, every *Orchard-pool* action is required by consensus to
be created with cross-address transfers disabled: the action's output must be
addressed to the same protocol-level address as its spend
<a id="user-content-fnref-draft-dairaemma-nu6.3-wallets"></a>
[25](#user-content-fn-draft-dairaemma-nu6.3-wallets). To spend in the *Orchard pool* under this
restriction, a wallet pairs each real spend with a fabricated, zero-valued
output addressed to the spent note's own receiver, and fills that output's
`enc_ciphertext` with random bytes rather than a real encryption (see
<a id="user-content-fnref-draft-dairaemma-nu6.3-wallets-2"></a>
[25](#user-content-fn-draft-dairaemma-nu6.3-wallets) for the privacy rationale).

In a PCZT, such a fabricated output still carries its explicit `recipient`,
`value`, and `rseed` fields, but no `user_address`. A Signer encountering an
output whose `value` is zero and whose ciphertext does not decrypt MUST NOT
reject the PCZT on that basis alone; it SHOULD classify the output as a
tolerable dummy output (verifying, if it wishes, that `cmx` is consistent with
the explicit `recipient`, `value`, and `rseed`).

Conversely, an action whose output is real but whose spend carries no
spendable value (for example, in a note-splitting transaction) uses a
fabricated zero-valued spend note addressed to the wallet's own receiver.
Such a spend is a real spend from the Signer's perspective: it has no
`dummy_sk`, and its `spend_auth_sig` MUST be produced through the normal
Signer flow using the spend authorizing key for that receiver's address.
Only fully-dummy actions (fabricated spend *and* fabricated output, at a
common freshly random address) carry `dummy_sk` and are signed by the IO
Finalizer.

#### Proprietary Use fields

The following fields of type `Map` are reserved for proprietary use:

- `Global.proprietary`

- `TransparentInput.proprietary`

- `TransparentOutput.proprietary`

- `SaplingSpend.proprietary`

- `SaplingOutput.proprietary`

- `OrchardSpend.proprietary`

- `OrchardOutput.proprietary`

The map keys can be any variable-length string that software can use to identify
whether the particular data in the proprietary maps can be used by it.

The proprietary use maps are for private use by individuals and organizations who
wish to use PCZT in their processes. It is useful when there are additional data
that they need attached to a PCZT but such data are not useful or available for
the general public. The proprietary use maps are not to be used by any public
specification, and there is no expectation that any publicly available software
be able to understand any specific meanings of any keys. These fields MUST be
used for internal processes only.

<a id="roles"></a>

### Roles

#### Creator

> Single entity

The Creator creates the base PCZT with no information about spends or outputs.

The Creator chooses the transaction version and consensus branch ID, and
initializes the global fields and the (empty) bundles. For a v5 transaction,
the Creator sets the shielded bundle anchors; for a v6 transaction, the
Creator MAY leave the anchors unset, to be provided later by an Updater (see
"Anchors and pre-authorization").

#### Constructor

The Constructor adds spends and outputs to the PCZT.

Before any input or output may be added, the Constructor MUST check the
`Global.tx_modifiable` field. Transparent inputs may only be added if the
Transparent Inputs Modifiable flag is True. Transparent outputs may only be
added if the Transparent Outputs Modifiable flag is True. Shielded spends or
outputs may only be added if the Shielded Modifiable flag is True.

When adding a shielded spend whose bundle anchor is set, the Constructor MUST
either provide a `witness` whose Merkle path roots to that anchor, or (for
zero-valued notes, whose Merkle paths are not checked by the circuits) any
placeholder witness. When `tx_version` is 6, the Constructor MAY instead add a
spend with no `witness` — including a spend of a note that does not yet exist
in the note commitment tree — leaving the witness to be provided by an Updater
(see "Anchors and pre-authorization"). When `tx_version` is 5, every non-dummy
spend added MUST be of a note that exists in the note commitment tree with a
witness to the bundle's anchor, since the anchor can no longer change.

If a transparent input being added specifies a required time lock, then the
Constructor must iterate through all of the existing transparent inputs and
ensure that the time lock types are compatible. Additionally, if during this
iteration, it finds that any transparent inputs have signatures, it must ensure
that the newly added transparent input does not change the transaction's
locktime. If the newly added transparent input has an incompatible time lock,
then it must not be added. If it changes the transaction's locktime when there
are existing signatures, it must not be added.

If the Has `SIGHASH_SINGLE` Flag is True, then the Constructor must iterate
through the transparent inputs and find those which have signatures that use
`SIGHASH_SINGLE`. The same number of transparent inputs and outputs must be
added before those transparent inputs and their corresponding outputs.

A single entity is likely to be both a Creator and Constructor.

#### IO Finalizer

> Anyone can execute

The IO Finalizer declares that no further inputs and outputs can be added to the
transaction by setting the appropriate bits in `Global.tx_modifiable` to 0.

The IO Finalizer also updates:

- `SaplingBundle.bsk` using `SaplingSpend.rcv` and `SaplingOutput.rcv`.

- `OrchardBundle.bsk` (and, in PCZT v2, `IronwoodBundle.bsk`) using
  `OrchardAction.rcv`.

While doing so, it MUST check that each bundle's `value_sum` is consistent
with the value commitments and `rcv` values it is aggregating, and fail
otherwise.

The IO Finalizer then computes the transaction's shielded signature hash, and
uses each `SaplingSpend.dummy_ask` and `OrchardSpend.dummy_sk` to produce the
`spend_auth_sig` for the corresponding dummy spends, clearing the dummy key
fields once used. This ensures that no Signer needs to parse spending key
material from a PCZT.

For a bundle whose `flags` have `enableCrossAddress` set to 0, the IO
Finalizer MUST verify that each action's output `recipient` equals its spend
`recipient` (see "Fabricated same-address outputs"), and fail otherwise.

A single entity is likely to be both a Constructor and an IO Finalizer.

#### Updater

> Anyone can contribute

The Updater adds information to the PCZT that it has access to, and that is
necessary for subsequent entities to proceed, such as key paths for signing
spends, full viewing keys and Merkle witnesses for proving, and (for v6
transactions) the shielded bundle anchors.

When setting or replacing a bundle anchor, or setting a witness, the Updater
MUST follow the rules in "Anchors and pre-authorization": anchors of v5
transactions never change; replacing a v6 bundle's anchor clears its proofs;
witnesses of non-zero-valued spends must root to the bundle's anchor whenever
both are present.

A single entity is likely to be both a Constructor and Updater.

#### Redactor

> Anyone can execute

The Redactor removes information that is unnecessary for subsequent
entities to proceed.

This can be useful, for example, when creating a transaction that has inputs
from multiple independent Signers; each can receive a PCZT with just the
information they need to sign, but (e.g.) not the `alpha` values for other
Signers.

#### Verifier

> Anyone can execute

The Verifier is not a step in the transaction lifecycle, but a way of
inspecting a PCZT and checking the internal consistency of its fields — for
example, that a spend's `nullifier` is consistent with its explicit note data
and `fvk`, that an output's `cmx` is consistent with its explicit `recipient`,
`value`, and `rseed`, or that a bundle satisfies the cross-address restriction.
Signers typically perform a subset of these checks before signing; a separate
Verifier can perform them on behalf of an entity (such as a hardware signer)
that lacks the capacity to do so itself and trusts the Verifier's judgement.

#### Prover

> Capability holders can contribute

The Prover needs all private information for a single spend or output.

For Sapling, the Prover requires, per spend: the explicit note data
(`recipient`, `value`, and `rcm` or `rseed`), `rcv`, `proof_generation_key`,
and `witness`; and per output: `recipient`, `value`, `rseed`, and `rcv`. For
the Orchard-protocol bundles, the Prover requires, per action: the spend's
explicit note data (`recipient`, `value`, `rho`, `rseed`), `fvk`, `witness`,
and `alpha`; the output's `recipient`, `value`, and `rseed`; and the action's
`rcv`. In all cases the bundle's `anchor` MUST be set before proving.

Before creating a proof, the Prover MUST verify that the Merkle path in each
non-zero-valued spend's `witness` roots to the bundle's `anchor`, and fail
otherwise. (A proof created from an inconsistent witness/anchor pair would
simply be invalid; checking first surfaces the error at the responsible role.)

In practice, the Updater that adds a given spend or output will either act as
the Prover themselves, or add the necessary data, offload to the Prover, and
then receive back the PCZT with private data stripped and proof added.

Proofs are authorizing data: creating them does not require spending key
material, and (from the v6 transaction format onward, where anchors are also
authorizing data) proving is fully independent of signing and may occur before
it, after it, or in parallel with it.

#### Signer

> Capability holders can contribute

The Signer:

- Needs the spend authorization randomizers to create signatures.

- Needs sufficient information to verify that the proof is over the correct
  data, without needing to verify the proof itself.

Signers do not need to sign for all possible input types. For example, a Signer
may choose to only sign Orchard inputs.

Before signing, a Signer:

- MUST reject a PCZT that contains `dummy_ask` or `dummy_sk` values (the IO
  Finalizer signs dummy spends and clears these fields; their presence means
  the Signer is being asked to parse spending key material).

- MUST, for each output carrying a `user_address`, parse that address and
  confirm that it contains the output's `recipient` (either directly, or e.g.
  as a receiver within a Unified Address).

- SHOULD verify that the explicit values and note data it relies upon for user
  confirmation are consistent with the effecting data being signed (for
  example, that values match value commitments via `rcv`, and that ciphertexts
  of non-fabricated outputs decrypt to the explicit note data — see
  "Fabricated same-address outputs" for the exception).

Having produced a signature, the Signer MUST update `Global.tx_modifiable` as
specified in that field's description. (A shielded signature pins all
effecting data; a transparent signature pins whatever its sighash type commits
to.)

For a v6 transaction, a Signer MAY sign a PCZT whose shielded bundle anchors,
witnesses, or proofs are absent: signatures commit to none of these. A Signer
asked to do so SHOULD be aware (and, where applicable, make its user aware)
that a spend whose witness is absent may be of a note that does not yet exist
on chain — the signature authorizes the spend regardless of whether the note
is ever created. For a v5 transaction, the bundle anchors are part of the
signature hash, and MUST be present before signing.

A single entity is likely to be both an Updater and a Signer as it can update a
PCZT with necessary information prior to signing it.

#### Combiner

> Anyone can execute

The Combiner can accept 1 or many PCZTs. The Combiner MUST merge them into one
PCZT (if possible), or fail. The resulting PCZT MUST contain all of the fields
from each of the PCZTs.

The merge rules are as follows:

- **Global fields.** The transaction effecting data in `Global` (`tx_version`,
  `version_group_id`, `consensus_branch_id`, `fallback_lock_time`,
  `expiry_height`) and `coin_type` MUST be equal in all inputs.
  `Global.tx_modifiable` is merged bit by bit as specified in that field's
  description (the modifiable flags merge towards `false`; the Has
  `SIGHASH_SINGLE` flag merges towards `true`; bits 3-6 MUST be 0 in all
  inputs).

- **Lists of inputs, outputs, spends, and actions.** If the IO Finalizer has
  run on either input for a shielded bundle (indicated by its `bsk` being
  set), then the bundles MUST have equal numbers of entries and equal
  `value_sum` fields. Otherwise, if one input's list is a strict prefix
  extension of the other's (it contains additional entries beyond those held
  in common), the additional entries are appended — but only if the
  shorter input's `Global.tx_modifiable` permits modification of the
  corresponding kind (transparent inputs, transparent outputs, or shielded
  spends and outputs); otherwise the merge MUST fail. Entries held in common
  are merged pairwise by position.

- **Required (always-present) fields** of entries merged pairwise — the
  transaction effecting data such as `prevout_txid`, `cv`, `nullifier`, `rk`,
  `cmx`, `ephemeral_key`, `enc_ciphertext`, `out_ciphertext`, and the bundle
  `flags` and `note_version` — MUST be equal, or the merge MUST fail.

- **Optional fields** merge as follows: if one side is absent, the result is
  the other side; if both sides are present, they MUST be equal, or the merge
  MUST fail. Note that this differs from BIP 174, which in some cases keeps
  one of two conflicting values; see the Rationale.
  
  
  
  
  In PCZT v2, this rule applies to the shielded bundle anchors: an absent
  anchor merges with a set one. Two inputs whose anchors are both set MUST
  have equal anchors.

- **Map fields** (`partial_signatures`, `bip32_derivation`, the preimage maps,
  and the `proprietary` maps) merge by key union; if a key is present on both
  sides, the values MUST be equal, or the merge MUST fail.

A Combiner MUST NOT combine two different PCZTs — that is, two PCZTs that do
not represent the same transaction. Two PCZTs represent the same transaction
if and only if they were derived from a common ancestor PCZT by sequences of
the roles defined in this ZIP, which the merge rules above verify structurally:
all transaction effecting data held in common must be identical. Once a PCZT's
input/output set has been finalized, its effecting data uniquely determines
the transaction identifier of the transaction that will be extracted from it,
and PCZTs can be considered to be uniquely identified by that transaction
identifier. (For a v6 transaction the identifier is independent of the
anchors, so re-anchored copies of a PCZT still represent the same
transaction.)

For every field that a Combiner understands, it MAY refuse to combine PCZTs if
it detects that there will be inconsistencies or conflicts for that field in the
combined PCZT.

The Combiner does not need to know how to interpret transparent scripts in order
to combine PCZTs. It can do so without understanding scripts or the network
serialization format.

In general, the result of a Combiner combining two PCZTs from independent
participants A and B should be functionally equivalent to a result obtained from
processing the original PCZT by A and then B in a sequence. Or, for participants
performing `fA(pczt)` and `fB(pczt)`:
`Combine(fA(pczt), fB(pczt)) == fA(fB(pczt)) == fB(fA(pczt))`

#### Spend Finalizer

> Anyone can execute

For each transparent input, the Spend Finalizer determines if there is enough
data to pass validation. If there is, it must construct and set
`TransparentInput.script_sig`. All other optional data in `TransparentInput`
(except for `TransparentInput.proprietary`) SHOULD be cleared from the PCZT.

#### Transaction Extractor

> Anyone can execute

The Transaction Extractor checks whether the PCZT is complete and internally
consistent:

- `Global.tx_version`, `Global.version_group_id`, and
  `Global.consensus_branch_id` MUST identify a supported transaction format
  (see the `Global` field descriptions), and the transparent inputs' lock time
  requirements MUST be satisfiable (see "Determining Lock Time").

- If `Global.tx_version` is 5, the `IronwoodBundle` MUST be the canonical
  empty bundle.

- Every `TransparentInput.script_sig` MUST be set.

- Every `SaplingSpend` MUST have `zkproof` and `spend_auth_sig` set, and every
  `SaplingOutput` MUST have `zkproof` set.

- Every `OrchardBundle` or `IronwoodBundle` containing actions MUST have its
  bundle `zkproof` set, of the canonical length for its number of actions, and
  every action MUST have `spend_auth_sig` set.

- Every non-empty shielded bundle MUST have its `anchor` and `bsk` set.

- No action's `rk` may be the identity point (this would be rejected by
  consensus <a id="user-content-fnref-zip-0256"></a>
  [26](#user-content-fn-zip-0256)).

If all of the above checks pass, the Transaction Extractor computes the
shielded signature hash, uses each bundle's `bsk` to create the Sapling,
Orchard, and (for v6) Ironwood binding signatures over it, and extracts the
final transaction. If a binding signature verification key derived from the
bundle's value commitments and value balance does not match its `bsk`, the
extraction MUST fail. The Transaction Extractor SHOULD then verify the proofs
and signatures of the final transaction, so that an invalid transaction is
detected before it is broadcast.

The Transaction Extractor does not need to know how to interpret transparent
scripts in order to extract the network serialized transaction. However it may
be able to in order to validate the network serialized transaction at the same
time.

A single entity is likely to be both a Spend Finalizer and Transaction Extractor.

<a id="extensibility"></a>

### Extensibility

The PCZT format is extended by revising this ZIP, in one of two ways:

- **New fields within an existing PCZT version.** This is not possible: the
  Postcard encoding is positional, so a parser cannot skip a field it does not
  know about. Unlike PSBTs, PCZTs deliberately have no non-proprietary
  arbitrary key-value maps; every field of a given PCZT version is known
  up-front, which guarantees that a Signer's view of a PCZT is complete. The
  `proprietary` maps are the only extension point within a version, and are
  reserved for private use (see "Proprietary Use fields").

- **New PCZT versions.** A revision of this ZIP may define a new version of
  the version-specific encoding, which may change anything about the format:
  adding or removing fields, changing field types (as v2 does for the bundle
  anchors), adding bundles for new payment protocols (as v2 does for the
  *Ironwood pool*), or changing the encoding scheme entirely. The 4-byte
  version field in the encoding header namespaces the versions; a parser
  encountering an unknown version MUST NOT attempt to parse the remainder.

Implementations SHOULD be able to parse every specified PCZT version, and to
emit the oldest version capable of representing a given PCZT's state, when
interoperating with entities (such as hardware signers with infrequent
firmware updates) that may not support the newest version. Conversion between
versions is lossless exactly when the target version can represent the PCZT's
state; the v1 Encoding section enumerates the states that v1 cannot represent.

Forks of Zcash that modify the transaction format should not reuse the PCZT
magic bytes (see the Rationale for `Global.coin_type`).

<a id="rationale"></a>

## Rationale

<a id="including-a-global-coin-type-field"></a>

### Including a `Global.coin_type` field

This makes the PCZT format useful to forks of Zcash that have common transaction
versions. It was motivated by the PSBT format's lack of a "network" field which
led to proprietary fields being used to track that information between specific
vendors. It is also encoded into a PCZT in `Zip32Derivation.derivation_path` at
later stages (and implicitly encoded elsewhere); having the Creator encode it
up-front enables later Roles to check their data against it for correctness.

Note however that the field is not as useful to Zcash forks as a "network" field
would be in PSBTs, because the PCZT format does not contain non-proprietary
arbitrary maps; every field must be known up-front. If a fork makes additions to
its transaction format, those additions cannot be represented in a way that is
compatible with existing PCZT parsers, and constructing transactions that make
use of those additions would require forking the PCZT format (which should then
use different magic bytes for its encoding).

<a id="transparent-protocol-choices"></a>

### Transparent protocol choices

The contents of `TransparentBundle`, and the actions that Roles take regarding
transparent inputs and outputs, is taken directly from BIP 174 <a id="user-content-fnref-bip-0174-2"></a>
[6](#user-content-fn-bip-0174) and
BIP 370 <a id="user-content-fnref-bip-0370-2"></a>
[7](#user-content-fn-bip-0370), and intended to follow the behaviour of PSBT version 2 when
used solely with non-SegWit inputs and outputs. The rationale is that this makes
integration of PCZTs simpler for codebases that already support PSBTs.

<a id="separate-shielded-modifiable-flag-from-transparent-modifiable-flags"></a>

### Separate Shielded Modifiable Flag from Transparent Modifiable Flags

The PSBT format allows Constructor and Signer roles to be interleaved when
inputs are not using `SIGHASH_ALL`. Due to how Zcash sighash digests are
specified, signing any input causes all non-transparent effecting data to be
pinned. The Shielded and Transparent Modifiable Flags were split apart to reduce
the semantic delta between PSBTs and purely-transparent PCZTs.

<a id="adding-an-io-finalizer-role"></a>

### Adding an IO Finalizer role

The effective `SaplingBundle.bsk` and `OrchardBundle.bsk` for a PCZT change when
a Constructor adds a shielded spend or output. They are required by the
Transaction Extractor, however leaving their computation to that role would
require preserving all `*.rcv` values until then, which reveals the
opening of all `*.cv` values to all participants. However, we cannot require the
Constructor to update `*.bsk` due to an interaction with the Combiner role:

- If Constructors add shielded spends or outputs in series, they should always
  update `*.bsk` when doing so, even if `*.rcv` is present.

- If Constructors add shielded spends or outputs in parallel and then a Combiner
  merges the results, `*.bsk` must *never* be updated.

We can't control which of these two situations happens, ergo we need an IO
Finalizer role that is responsible for updating `*.bsk`.

The IO Finalizer role also produces signatures for all dummy spends, and can
clear their spending keys. This ensures that there is never a need for a Signer
to parse spending key material from a PCZT, which we want to discourage for
security reasons.

<a id="combiner-rejecting-non-identical-duplicates"></a>

### Combiner rejecting non-identical duplicates

This behaviour intentionally differs from BIP 174 <a id="user-content-fnref-bip-0174-3"></a>
[6](#user-content-fn-bip-0174), which specifies
that when two PSBTs have conflicting values for the same key, "the Combiner
must choose the value from the PSBT it considers to be correct" (in practice,
often last-wins). That rule silently discards data: a conflicting contribution
from a buggy or malicious participant can overwrite, for example, a derivation
path or preimage that a later Signer relies upon, without any participant
being alerted. Because every PCZT field is typed and known up-front, there is
no analogue of PSBT's unknown key-value pairs for which "keep one of them" is
the only available policy; requiring equality is always possible, and turns
every conflict into a loud failure at the Combiner rather than a silent
divergence discovered later (or not at all).

- Once every spend and output has its zkproof field set, PCZT equality MUST include
  the SpendDescription and OutputDescription contents being identical.
  
  
  
  - In practice enforced by creating a TransactionData / CMutableTransaction from
    the PCZT, with spendAuthSigs and bindingSig empty, and then enforcing equality.
  
  - This is equivalent to BIP 174's equality definition (the partial transactions
    must be identical).

<a id="optional-anchors-in-pczt-v2"></a>

### Optional anchors in PCZT v2

The v6 transaction format moves the shielded bundle anchors from effecting
data to authorizing data, expressly so that a transaction can be
pre-authorized using spending key material with the anchor and proofs updated
later <a id="user-content-fnref-zip-0229-13"></a>
[4](#user-content-fn-zip-0229). A PCZT is precisely the artifact that holds a transaction
during such a deferral, so the v2 format makes the anchor's absence
representable rather than requiring a sentinel value. The all-zeroes byte
string was rejected as a sentinel because it is a valid Pallas base field
element and therefore a syntactically valid anchor; an explicit `Option`
cannot be confused with data.

The deferral rules are gated on `tx_version`, not on the PCZT version: a v5
transaction carried in a v2 PCZT still commits to its anchors in its signature
hash, so its anchors must be fixed before signing exactly as in PCZT v1.

Making the *witness* deferrable requires no format change (it was already
optional, being consumed only by the Prover); v2 merely permits states — a
signed spend with no witness — that v1 role implementations were not required
to support. The combination enables the pre-signed transaction chains
described in the Motivation: for Orchard-protocol notes, nullifiers depend
only on note data, so every field that a v6 signature commits to is knowable
before the note being spent is mined.

<a id="omitting-empty-bundles-in-pczt-v2"></a>

### Omitting empty bundles in PCZT v2

A PCZT logically always contains every bundle substructure (see "Structure"),
but most transactions leave at least one shielded protocol unused, and PCZTs
are routinely transferred over constrained transports (QR codes, NFC, serial
links to hardware signers). Omitting bundles that exactly equal their
canonical empty values reduces the encoded size at no informational cost. The
omission rule is defined byte-exactly (equality with a canonical empty value)
so that serialization is deterministic: two copies of the same PCZT serialize
identically regardless of the software that produced them, and re-encoding
cannot flip a bundle between present and absent representations of the same
state.

<a id="carrying-the-ironwood-component-as-a-second-orchard-shaped-bundle"></a>

### Carrying the Ironwood component as a second Orchard-shaped bundle

ZIP 229 defines the *Ironwood pool* as a second value pool of the Orchard
protocol, reusing the Action structure, proof system, and encodings, with the
pools distinguished by their note commitment trees, nullifier sets, value
balances, and component position <a id="user-content-fnref-zip-0229-14"></a>
[4](#user-content-fn-zip-0229). The PCZT v2 format mirrors this
exactly: the `IronwoodBundle` reuses the `OrchardBundle` structure, and the
`note_version` field (rather than a structural difference) captures the one
note-level distinction between the pools. This keeps implementation surface
shared, exactly as it is in the transaction format itself.

<a id="reference-implementation"></a>

## Reference implementation

The `pczt` Rust crate and the protocol crates listed below are the reference
implementation of this ZIP; the ZIP itself is the canonical definition of the
format. The v1 encoding corresponds to release `pczt 0.7.0`. <a id="user-content-fnref-pczt-0.7.0-2"></a>
[13](#user-content-fn-pczt-0.7.0)

- Core PCZT format and roles:
  
  
  
  - [https://github.com/zcash/librustzcash/tree/main/pczt](https://github.com/zcash/librustzcash/tree/main/pczt)

- Transparent-specific logic:
  
  
  
  - [https://github.com/zcash/librustzcash/blob/main/zcash_transparent/src/pczt.rs](https://github.com/zcash/librustzcash/blob/main/zcash_transparent/src/pczt.rs)
  
  - [https://github.com/zcash/librustzcash/tree/main/zcash_transparent/src/pczt](https://github.com/zcash/librustzcash/tree/main/zcash_transparent/src/pczt)

- Sapling-specific logic:
  
  
  
  - [https://github.com/zcash/sapling-crypto/blob/main/src/pczt.rs](https://github.com/zcash/sapling-crypto/blob/main/src/pczt.rs)
  
  - [https://github.com/zcash/sapling-crypto/tree/main/src/pczt](https://github.com/zcash/sapling-crypto/tree/main/src/pczt)

- Orchard-specific logic:
  
  
  
  - [https://github.com/zcash/orchard/blob/main/src/pczt.rs](https://github.com/zcash/orchard/blob/main/src/pczt.rs)
  
  - [https://github.com/zcash/orchard/tree/main/src/pczt](https://github.com/zcash/orchard/tree/main/src/pczt)

<a id="references"></a>

## References

<a id="footnote-label"></a>

### Footnotes

1. [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) [↩](/zip/374#user-content-fnref-bcp14)

2. [RFC 9591: The Flexible Round-Optimized Schnorr Threshold (FROST) Protocol for Two-Round Schnorr Signatures](https://datatracker.ietf.org/doc/rfc9591/) [↩](/zip/374#user-content-fnref-frost)

3. [ZIP 48: Transparent Multisig Wallets](/zip/48) [↩](/zip/374#user-content-fnref-zip-0048)

4. [ZIP 229: Version 6 Transaction Format](/zip/229) [↩](/zip/374#user-content-fnref-zip-0229) [↩2](/zip/374#user-content-fnref-zip-0229-2) [↩3](/zip/374#user-content-fnref-zip-0229-3) [↩4](/zip/374#user-content-fnref-zip-0229-4) [↩5](/zip/374#user-content-fnref-zip-0229-5) [↩6](/zip/374#user-content-fnref-zip-0229-6) [↩7](/zip/374#user-content-fnref-zip-0229-7) [↩8](/zip/374#user-content-fnref-zip-0229-8) [↩9](/zip/374#user-content-fnref-zip-0229-9) [↩10](#user-content-fnref-zip-0229-10) [↩11](#user-content-fnref-zip-0229-11) [↩12](#user-content-fnref-zip-0229-12) [↩13](#user-content-fnref-zip-0229-13) [↩14](#user-content-fnref-zip-0229-14)

5. [Orchard to Ironwood Migration (draft)](/draft/draft-schell-ironwood-migration) [↩](/zip/374#user-content-fnref-draft-schell-ironwood-migration) [↩2](#user-content-fnref-draft-schell-ironwood-migration-2)

6. [BIP 174: Partially Signed Bitcoin Transaction Format](https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki) [↩](/zip/374#user-content-fnref-bip-0174) [↩2](#user-content-fnref-bip-0174-2) [↩3](#user-content-fnref-bip-0174-3)

7. [BIP 370: PSBT Version 2](https://github.com/bitcoin/bips/blob/master/bip-0370.mediawiki) [↩](/zip/374#user-content-fnref-bip-0370) [↩2](#user-content-fnref-bip-0370-2)

8. [ZIP 244: Transaction Identifier Non-Malleability](/zip/244) [↩](/zip/374#user-content-fnref-zip-0244) [↩2](#user-content-fnref-zip-0244-2)

9. [ZIP 225: Version 5 Transaction Format](/zip/225) [↩](/zip/374#user-content-fnref-zip-0225) [↩2](/zip/374#user-content-fnref-zip-0225-2) [↩3](/zip/374#user-content-fnref-zip-0225-3)

10. [ZIP 2005: Ironwood Quantum Recoverability](/zip/2005) [↩](/zip/374#user-content-fnref-zip-2005) [↩2](/zip/374#user-content-fnref-zip-2005-2) [↩3](#user-content-fnref-zip-2005-3)

11. [The Postcard Wire Specification](https://postcard.jamesmunns.com/) [↩](/zip/374#user-content-fnref-postcard)

12. [Source code for the `pczt` Rust crate](https://github.com/zcash/librustzcash/tree/main/pczt) [↩](/zip/374#user-content-fnref-pczt-rust)

13. [Release `pczt 0.7.0` of the `pczt` Rust crate](https://github.com/zcash/librustzcash/releases/tag/pczt-0.7.0) [↩](/zip/374#user-content-fnref-pczt-0.7.0) [↩2](#user-content-fnref-pczt-0.7.0-2)

14. [ZIP 203: Transaction Expiry](/zip/203) [↩](/zip/374#user-content-fnref-zip-0203)

15. [SLIP-0044 : Registered coin types for BIP-0044](https://github.com/satoshilabs/slips/blob/master/slip-0044.md) [↩](/zip/374#user-content-fnref-slip-0044)

16. [BIP 44: Multi-Account Hierarchy for Deterministic Wallets](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki) [↩](/zip/374#user-content-fnref-bip-0044) [↩2](#user-content-fnref-bip-0044-2)

17. [ZIP 32: Shielded Hierarchical Deterministic Wallets](/zip/32) [↩](/zip/374#user-content-fnref-zip-0032)

18. [Zcash Protocol Specification, Version 2024.5.1 [NU6]. Section 5.6.3.1: Sapling Payment Addresses](protocol/protocol.pdf#saplingpaymentaddrencoding) [↩](/zip/374#user-content-fnref-protocol-saplingpaymentaddrencoding) [↩2](/zip/374#user-content-fnref-protocol-saplingpaymentaddrencoding-2)

19. [ZIP 212: Allow Recipient to Derive Ephemeral Secret from Note Plaintext](/zip/212) [↩](/zip/374#user-content-fnref-zip-0212) [↩2](/zip/374#user-content-fnref-zip-0212-2) [↩3](/zip/374#user-content-fnref-zip-0212-3)

20. [ZIP 231: Memo Bundles](/zip/231) [↩](/zip/374#user-content-fnref-zip-0231) [↩2](#user-content-fnref-zip-0231-2)

21. [ZIP 258: Deployment of the NU6.3 Network Upgrade](/zip/258) [↩](/zip/374#user-content-fnref-zip-0258) [↩2](#user-content-fnref-zip-0258-2)

22. [Zcash Protocol Specification, Version 2024.5.1 [NU6]. Section 5.6.4.2: Orchard Raw Payment Addresses](protocol/protocol.pdf#orchardpaymentaddrencoding) [↩](#user-content-fnref-protocol-orchardpaymentaddrencoding) [↩2](#user-content-fnref-protocol-orchardpaymentaddrencoding-2)

23. [ZIP 32: Shielded Hierarchical Deterministic Wallets. Section "Seed Fingerprints"](/zip/32#seed-fingerprints) [↩](#user-content-fnref-zip-0032-seedfp)

24. [ZIP 320: Defining an Address Type to which funds can only be sent from Transparent Addresses](/zip/320) [↩](#user-content-fnref-zip-0320)

25. [NU6.3 Consequences for Wallets (draft)](draft-dairaemma-nu6.3-consequences-for-wallets.md) [↩](#user-content-fnref-draft-dairaemma-nu6.3-wallets) [↩2](#user-content-fnref-draft-dairaemma-nu6.3-wallets-2)

26. [ZIP 256: Deployment of Consensus Bug Fixes Between NU6.1 and NU6.2](/zip/256) [↩](#user-content-fnref-zip-0256)

## Citation relationships

Cites: [ZIP 32](https://zips.tools/zip/32), [ZIP 48](https://zips.tools/zip/48), [ZIP 203](https://zips.tools/zip/203), [ZIP 212](https://zips.tools/zip/212), [ZIP 225](https://zips.tools/zip/225), [ZIP 229](https://zips.tools/zip/229), [ZIP 231](https://zips.tools/zip/231), [ZIP 244](https://zips.tools/zip/244), [ZIP 256](https://zips.tools/zip/256), [ZIP 258](https://zips.tools/zip/258), [ZIP 320](https://zips.tools/zip/320), [ZIP 2005](https://zips.tools/zip/2005)

Cited by: None