* [bitcoindev] Exposure-aware transaction construction for wallets
@ 2026-10-19 17:29 Zeeshan Ali Khan
0 siblings, 0 replies; only message in thread
From: Zeeshan Ali Khan @ 2026-10-19 17:29 UTC (permalink / raw)
To: bitcoindev; +Cc: duncan0k
I would like to discuss an opt-in wallet transaction-construction
policy for preserving resistance to BIP 360 long exposure attacks [1].
This is a companion to bitcoin/bips PR #2294 [2], which classifies
exposure and informatively recommends SWEEP_WHEN_SPENDING for outputs
sharing a script.
Bitcoin Core's -avoidpartialspends [3] and BitGo's quantum-risk
controls [4] already group UTXOs by address, but both are best-effort.
The proposal here is a stronger wallet-local rule based on everything
the wallet knows it is about to disclose.
PR #2294 discussion: Delving Bitcoin [5]; bitcoin-dev [6].
## Motivation
If several P2WPKH outputs pay the same script, spending one reveals
the public key needed to spend the others. A wallet preserving long
exposure resistance should cover those newly affected outputs in the
same spend workflow and send change to a fresh, non-exposed condition.
The boundary can cross scripts when key material is reused. Avoiding
unnecessary disclosure may also preserve eligibility for future rescue
mechanisms that depend on still-hidden one-way-function commitments,
such as DropKick [7].
## Trust boundary
A wallet can reason only about disclosures it knows. Its trust
boundary is the set of components and parties assumed not to disclose
wallet material to the adversary. This mode is intentionally opt-in
because restrictions on public-key sharing can be operationally
burdensome [8].
Disclosure includes public keys, xpubs/descriptors, relevant PSBT
derivation data, reuse in another protocol, and ECDSA signatures over
known messages, from which public-key candidates can be recovered. BIP
340 Schnorr signatures do not have that public-key-recovery property
[9]. If an account xpub has left the trust boundary, this protection
cannot be claimed for that subtree.
## Exposure set
Call material hidden when it is hash-committed and a complete spend
recipe has not been published. An output becomes long-exposure
vulnerable only when disclosed material is enough to reconstruct some
complete spend recipe: required key material plus any script, Merkle
path, preimage, or other path data.
Let D_prior be material already disclosed before this spend, derived
from on-chain history (for example PR #2294's classification) plus the
wallet's local disclosure metadata. Let S contain the intended inputs.
When an output is added, choose one spending path and keep that choice
fixed while computing the set:
```text
S = intended inputs
repeat:
previous = S
D = D_prior | material disclosed by the chosen paths for S
V = wallet outputs whose complete spend recipe is reconstructible
from D but not from D_prior alone
S = S | V
until S == previous
R = S
```
Here | is set union. R is the exposure set, and "affected" below means
an output in R. Outputs that were already vulnerable before this spend
are handled by the remediation workflow and may be added to a
protected spend at the user's option; they do not enter V merely
because they were already exposed.
Example: if D_prior already contains key a and the intended spend
reveals b, a standard sortedmulti 2-of-2 {a,b} script may become newly
vulnerable once its script is reconstructible. A hash-committed 2-of-3
{a,b,d} script does not: without d the attacker cannot reconstruct the
witnessScript. For ordinary P2SH/P2WSH this normally converges in one
step; iteration mainly matters when prior disclosure and spending-path
choice interact.
## Transaction construction
Before new material for R leaves the trust boundary, prepare spends
covering every confirmed affected output the current signing workflow
can spend now, without waiting for a timelock or additional
cooperation. If an affected output cannot be covered, the wallet
should not claim protection unless the user explicitly overrides it.
If several transactions are required, prepare them before disclosure
and hand them to the network in the same batch. Replacements should
jointly keep covering R; if coverage is lost through eviction,
invalidation or replacement, rebroadcast or reconstruct/fee-bump the
affected spends.
### Intended property
When new material is deliberately disclosed, every confirmed affected
output in `R` that can be spent now has been handed to the network in
the same batch.
## Unconfirmed and local state
Wallet-authored unconfirmed parents are controllable by the wallet;
third-party payments may be replaced by their sender. The default
should therefore be to wait for relevant third-party outputs to
confirm. After a documented or user-configurable wait bound, ask
whether to keep waiting or explicitly relax the guarantee. This
creates an unavoidable griefing/DoS tradeoff.
Wallet-local disclosure state is deliberately broader than PR #2294's
chain-derived classification: once material leaves the trust boundary,
keep treating it as disclosed even if the transaction never confirms.
A seed/descriptor restore cannot reconstruct every prior off-chain
disclosure, so missing disclosure metadata should be reported as
unknown rather than safe.
## Change and reused destinations
Change must use a condition whose required secp256k1 material is still
hidden. Fresh P2WPKH can do this only if its derivation data stays
inside the trust boundary, including through PSBT handling [10]. P2TR
cannot, because its output key Q is public at rest and consensus
accepts a key-path signature for Q however Q was constructed. P2MR is
the intended direction once available [1].
Funds later received to an already disclosed destination are
vulnerable immediately. Bitcoin Core's avoid_reuse is useful precedent
[11]: mark them as reused/exposed, exclude them from the protection
claim, warn the user, and offer remediation instead of automatically
sweeping every receipt.
## Privacy and scope
Cross-script grouping can add input linkage. CoinJoin, Payjoin,
explicit coin control, timelocks or unavailable cosigners may prevent
full coverage. In those cases the wallet should decline to claim the
property or require an explicit override. This is a wallet
security/privacy/usability policy, not a consensus rule.
## Open questions
1. Is a separate companion proposal, cross-linked from PR #2294, the
right place for this rule?
2. Is complete-spend-recipe exposure the right abstraction for
Taproot, Miniscript and future scripts?
3. Should economically insignificant outputs ever be excluded
automatically, or only by explicit override?
4. What wait policy should apply to relevant third-party unconfirmed outputs?
5. Could BIP 329 label records [12] carry disclosure metadata across
backup/sync, or is separate metadata needed?
6. Are there implementations that go beyond the address grouping of
Bitcoin Core APS and BitGo by reasoning across complete spending
conditions?
The intended guarantee is narrow: wallet behavior should not
unnecessarily turn hidden-key outputs into long-exposure-vulnerable
outputs while leaving value behind under the newly disclosed spend
recipe.
## References
[1] BIP 360: https://github.com/bitcoin/bips/blob/master/bip-0360.mediawiki
[2] bitcoin/bips PR #2294: https://github.com/bitcoin/bips/pull/2294
[3] Bitcoin Core -avoidpartialspends source:
https://github.com/bitcoin/bitcoin/blob/master/src/wallet/init.cpp
[4] BitGo quantum-risk controls:
https://www.bitgo.com/resources/blog/bitgo-adds-new-quantum-risk-management-capabilities-for-bitcoin-wallets/
[5] PR #2294 Delving discussion:
https://delvingbitcoin.org/t/standardizing-an-exposure-classification-for-existing-outputs-pre-bip/2866
[6] PR #2294 bitcoin-dev discussion:
https://groups.google.com/g/bitcoindev/c/A3MFJt8mOM4
[7] DropKick: https://gnusha.org/pi/bitcoindev/CAHPaHkr5r4+hodZv6F2S1yCq_UcHSr2iCrkYLgZ_vryNgwbRPA@mail.gmail.com/
[8] P2XX thread: https://groups.google.com/g/bitcoindev/c/aWYtPLVPZ3U
[9] BIP 340: https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki
[10] BIP 174 (PSBT):
https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki
[11] Bitcoin Core avoid_reuse release notes:
https://github.com/bitcoin/bitcoin/blob/master/doc/release-notes/release-notes-0.19.0.1.md
[12] BIP 329: https://github.com/bitcoin/bips/blob/master/bip-0329.mediawiki
--
Regards,
Zeeshan Ali Khan
--
You received this message because you are subscribed to the Google Groups "Bitcoin Development Mailing List" group.
To unsubscribe from this group and stop receiving emails from it, send an email to bitcoindev+unsubscribe@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/bitcoindev/CAAa3hFNACEoE4KXi06SaqGM0qsOTrgT3HB6X2oiocp--r6-rmg%40mail.gmail.com.
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2026-10-19 17:36 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-19 17:29 [bitcoindev] Exposure-aware transaction construction for wallets Zeeshan Ali Khan
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox