Zero-knowledge · BIP32 · runs in your browser

Prove two keys share a wallet.
Reveal nothing else.

Show that any two child keys — m/0/1 and m/1/3, or any depth you like — descend from one xpub, without revealing the xpub, its chain code, or the derivation paths.

  1. 1Wallet & paths
  2. 2Prove
  3. 3Verify
1

Wallet & derivation paths

A real BIP32 signet wallet (kept in this browser). Both children are derived from the xpub side (public key + chain code only), exactly like a watch-only wallet. Pick any two non-hardened paths.

Restore a wallet from its seed
2

Prover runs privately

Witness: parent pubkey, chain code and both paths. The prover walks each path — one HMAC-SHA512 and one point addition per level — and proves it did so correctly, revealing only the two resulting keys. The same statement is implemented twice: a Noir circuit (in-browser) and an SP1 zkVM program (server). See SPEC.md.

SIMULATEDinstant

Runs the real relation check and emits a Fiat-Shamir-shaped envelope. For exploring the flow; not a proof.

Self-hosting? Run the xproof-host server to also get SP1 STARK and Groth16 provers (see README).

3

Verifier

Sees only the proof and the chain. Re-verifies the proof, the on-chain anchor, context freshness, and scans the proof bytes for leaked witness material. Hit Forge to watch tampering get caught.

proof loaded: none

Why this is the right shape

BIP32 normal derivation is additive in the discrete log, one level at a time: Kchild = K + HMAC-SHA512(c, serP(K) ‖ i)[0..32]·G, with the new chain code taken from the other half of the HMAC. A path like m/1/3 just applies this twice. The chain code is a master linking secret: revealing it (even for one child) links every descendant — so selective disclosure must hide the HMACs inside a zero-knowledge proof.

What a proof revealsThe two child pubkeys and that one hidden xpub links them. The xpub, chain code and both paths are witnesses.
Any shape of relationshipm/0/1 vs m/0/2 (siblings), m/0/1 vs m/1/3 (cousins), or m/0 vs m/0/5/2 (ancestor/descendant). Up to depth 3 in the browser, 16 on the server.
Hardened vs normalOnly normal steps are provable from an xpub witness — matching real wallets, where an account xpub derives receive/change children normally.
SemanticsProves “the prover knows the linking xpub”. An auditor holding the xpub can too; add a parent-privkey check for spend-level ownership.

Which proof to use: both ZK · in your browser (UltraHonk) and ZK · Groth16 hide the witness and are constant-size, so they don't hint at path depth; the in-browser circuit even does the same work for every path shape. SP1's raw STARK is sound but not zero-knowledge on its own — use it for debugging only.