140 lines
5.9 KiB
Markdown
140 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.
|