WizardConnect/docs/xpub-sharing.md
2026-03-17 14:47:04 +01:00

139 lines
5.9 KiB
Markdown

# xpub sharing: why it's safe and why we do it
When people hear "xpub sharing" they think of handing over the account-level
xpub — the master key that can derive every address in a wallet. That's not
what WizardConnect does. This page explains what we actually share, why it's
safe, and why the alternatives are worse.
## What we share
A BIP44 HD wallet has this tree structure:
```
m / 44' / 145' / 0' ← account xpub (we do NOT share this)
/ 0 ← receive chain xpub (we share this)
/ 0 ← address 0
/ 1 ← address 1
/ 2 ← address 2
/ ...
/ 1 ← change chain xpub (we share this)
/ 0
/ 1
/ ...
```
WizardConnect shares xpubs **one level below the account** — at the chain
level. The dapp gets the receive chain xpub and can derive receive addresses.
It cannot derive change addresses, and it cannot derive the account xpub.
This is the same level of key material that watch-only wallets, block
explorers, and payment processors have always worked with. Electron Cash's
"watching-only wallet" import works at exactly this level.
## What about privacy?
Sharing a chain xpub gives the dapp the ability to derive all addresses on
that chain. This means a dapp you connect to can see your receive addresses
and monitor incoming payments.
This is by design — the dapp needs addresses to construct transactions. The
question is how you deliver them.
### The three options
| Approach | Round trips | Privacy | UX |
|----------|-------------|---------|-----|
| Individual pubkeys | One per address | Best — dapp sees only what it asks for | Terrible on mobile — constant app switching |
| Chain xpub (WizardConnect) | Zero after handshake | Good — dapp sees one chain, not the whole wallet | Seamless — scan once, done |
| Account xpub | Zero after handshake | Poor — dapp sees everything | Seamless |
We started with individual pubkeys. On desktop it was tolerable. On mobile it
was unusable — every new address required switching to the wallet app,
approving, switching back. For a transaction with two inputs and a change
output, that's three round trips with three app switches. Users gave up.
Chain xpubs eliminate all round trips while limiting exposure to a single
purpose. A dapp connected for receive addresses cannot see your change
addresses or any other internal wallet activity.
### Per-session xpubs (advanced)
A wallet that wants maximum privacy can derive xpubs from non-standard paths
and rotate them each session:
```
Session 1: receive xpub from m/44'/145'/0'/1000/0
Session 2: receive xpub from m/44'/145'/0'/1001/0
```
The protocol carries only the xpub and a name ("receive") — the dapp never
learns the derivation path. Each session gets a fresh, isolated set of
addresses. The trade-off is that standard wallet recovery (which scans only
the BIP44 paths) won't find funds at these paths without extra metadata.
## Is this the same as sharing your full xpub?
No. The account xpub (`m/44'/145'/0'`) can derive keys for *all* chains —
receive, change, and any application-specific paths. Sharing it gives a dapp
complete visibility into your wallet's transaction graph, including internal
change outputs.
A chain xpub can only derive addresses on its own chain. It's one branch of
the tree, not the trunk.
```
Account xpub → can derive receive + change + defi + everything else
(this is what people worry about)
Receive chain xpub → can derive receive addresses only
(this is what we share)
```
## The security question: "can someone steal my funds?"
An xpub contains only public keys. Public keys cannot sign transactions.
Sharing an xpub — at any level — does not give anyone the ability to move
funds.
The theoretical concern with BIP32 unhardened derivation is: if an attacker
gets a child *private* key **and** the parent xpub, they can compute the
parent private key. But in WizardConnect, private keys never leave the wallet.
Signing happens on the wallet device and only the signed transaction is
returned. The attack requires compromising the wallet itself, at which point
the attacker already has the keys.
This is the same security model as every BIP44 wallet in existence. Electron
Cash, Bitcoin Core (with descriptors), and every hardware wallet that supports
watch-only mode all rely on the same property: xpub sharing is safe as long
as private keys stay private.
## Comparison with other protocols
**Electrum protocol**: shares individual pubkeys on demand. Maximum privacy,
but requires the wallet to be online for every new address. Poor mobile UX.
**WalletConnect v2 (Ethereum)**: shares account addresses, not xpubs. Works
for Ethereum's account model where one address is reused. Does not apply to
UTXO chains like BCH where each transaction should use a fresh address.
**BIP47 payment codes**: enables reusable payment addresses between two
parties using a shared secret derived from both parties' xpubs. Solves a
different problem (sender-receiver privacy for recurring payments) and
requires an on-chain notification transaction.
**WizardConnect**: shares chain-level xpubs by name. Zero round trips, chain
isolation, optional per-session rotation. Designed specifically for the UTXO
model where dapps need to derive many addresses.
## Summary
- We share chain xpubs, not account xpubs. A dapp sees one branch, not the
whole tree.
- Chain xpubs contain only public keys. They cannot sign transactions or move
funds.
- The security model is identical to watch-only wallets, which have been
standard practice in Bitcoin for over a decade.
- The alternative (individual pubkeys) was tried and produced an unusable
mobile experience.
- Wallets that want stronger privacy can rotate xpubs per session — the
protocol supports this without changes.