Merge branch 'doc-xpub' into 'master'
doc: An article on xpub sharing See merge request riftenlabs/lib/wizardconnect!8
This commit is contained in:
commit
cc63e39dc7
2 changed files with 140 additions and 0 deletions
|
|
@ -82,3 +82,4 @@ future if needed. You will be prompted to sign the CLA when you open your first
|
|||
| Dapp integration guide | [dapp.md](dapp.md) |
|
||||
| React components and hooks | [react.md](react.md) |
|
||||
| xpub delivery and pubkey derivation | [pubkey-derivation.md](pubkey-derivation.md) |
|
||||
| xpub sharing: why it's safe | [xpub-sharing.md](xpub-sharing.md) |
|
||||
|
|
|
|||
139
docs/xpub-sharing.md
Normal file
139
docs/xpub-sharing.md
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
# 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.
|
||||
Loading…
Add table
Reference in a new issue