Skip to content

Make output-metadata redaction opt-in and split into two composable functions #77

Description

@evanlinjin

Finalizer::finalize currently strips bip32_derivation, tap_key_origins, and tap_internal_key from every output when the PSBT is fully finalized (finalizer.rs:139-146). Two issues:

  1. Not spec-compliant by default. BIP-174's finalizer role is defined over inputs only; output PSBT_OUT_* fields are normally retained until extraction. Bitcoin Core never touches outputs on finalize. Doing it silently diverges from both, and destroys metadata a downstream consumer may legitimately need (verifying change ownership, re-deriving addresses, registering change on a watch-only).

  2. Incomplete for policy privacy. The current set removes wallet-linkage (key origins) but leaves redeem_script / witness_script / tap_tree, which expose an output's spending policy (multisig structure, full taproot tree). tap_internal_key sits between the two categories — it's a raw key, not a KeySource — so the split below assigns it to the key-origin function deliberately rather than leaving it ambiguous.

Proposal

  • Make finalize pure BIP-174 (inputs only; outputs untouched). Redaction becomes explicit opt-in.
  • Add two standalone, composable functions (no Finalizer/plan dependency):
    • redact_output_key_origins → clears bip32_derivation, tap_key_origins, tap_internal_key (unlink output from wallet/xpub)
    • redact_output_scripts → clears redeem_script, witness_script, tap_tree (hide spending policy)
  • Leave proprietary / unknown untouched (opaque, often load-bearing; mirrors input handling at finalizer.rs:107-109).

Reasoning

  • Two threat models, two field sets — callers pick what they need; calling both gives the full strip.
  • Separate functions over a finalize parameter: redaction doesn't depend on the finalizer's plans, so coupling it to finalize is artificial. Distinct names make each function's leak-surface obvious.
  • Opt-in default keeps us spec-compliant and Core-aligned; privacy is an explicit, deliberate step.

Acceptance criteria

  • finalize no longer modifies outputs.
  • redact_output_key_origins and redact_output_scripts added.
  • Doc comment at finalizer.rs:20-22 updated; the "cleared after finalize" test (finalizer.rs:300-304) moved to exercise the new functions; preserve-by-default tests retained.

Metadata

Metadata

Assignees

No one assigned

    Labels

    apiChanges the public API

    Fields

    No fields configured for Feature.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions