Explainer

A Bitcoin wallet needs more than its keys

An output descriptor records which scripts a wallet watches, how its keys are derived and which addresses belong to the same policy. It can make a wallet portable, but it is not automatically a safe backup and it may contain private keys.

5 min readWallets
A Bitcoin wallet needs more than its keys

The short answer

A Bitcoin output descriptor is a compact recipe for the scripts a wallet should recognise. It says how keys are derived, what kind of address those keys create, and sometimes which branches are for receiving and change.

That fills a gap a seed phrase cannot fill by itself. The same keys can be wrapped in different spending conditions, so restoring only the keys does not always tell new wallet software what to look for.

How it actually works

Bitcoin does not pay a named account. Each output carries a script that states the condition for spending it. A wallet finds its money by generating the scripts it expects and matching them against outputs on the chain. If the wallet generates the wrong kind of script, the keys may be correct while the balance appears to be zero.

BIP 380 defines the general descriptor language. Its motivation is blunt: private-key backups became insufficient once wallets could use several output types and several key-derivation paths. A descriptor writes those choices down instead of asking the restoring wallet to guess.

This shortened example describes a family of native SegWit outputs:

wpkh([d34db33f/84h/0h/0h]xpub.../0/*)#checksum

Read it from the outside inward:

  • wpkh(...) says to build pay-to-witness-public-key-hash outputs, the form commonly shown as a bc1q address.
  • [d34db33f/84h/0h/0h] records a key fingerprint and the hardened path from that key's origin. It is provenance for the key, not a secret.
  • xpub.../0/* identifies an extended public key, the receiving branch and a wildcard for every child index on that branch.
  • #checksum detects copying errors in the descriptor string. BIP 380 specifies an eight-character checksum and guarantees detection of every one-symbol error.

The descriptor is a recipe for a collection, not one address. Replacing the wildcard with 0, 1 or 2 produces different child keys and therefore different scripts. Bitcoin Core's descriptor documentation also supports multipath forms that put receiving and change branches in one expression. That distinction matters because change should not be presented as a new payment from someone else.

The outer functions carry the policy. wpkh(KEY) describes a single-key native SegWit output. tr(KEY) describes a Taproot output. wsh(sortedmulti(2,KEY,KEY,KEY)) can describe a two-of-three multisignature policy whose public keys are sorted before the script is built. The keys alone cannot tell a restoring wallet which of those policies was intended.

Bitcoin Core exposes the same model through its wallet and utility commands. getdescriptorinfo returns a canonical public form, a checksum, and flags showing whether the expression is ranged, solvable or contains private keys. That last flag is the line between a description that can only watch and one that may be able to spend.

Why it matters

The first benefit is a better watch-only wallet. A descriptor containing extended public keys can generate the same scripts as the signing wallet without carrying the private keys. A node can then find incoming payments and build unsigned transactions while an offline device keeps the power to sign. This is useful, but the descriptor is still sensitive: an extended public key can reveal the transaction history and future addresses for its branch.

The second benefit is a more exact handoff between programs. Saying "these are my keys" leaves the output type and derivation path unstated. Saying "this is the descriptor" gives the receiving program the script template, key origins and derivation pattern together. That makes a multisignature setup or an unusual path less dependent on one vendor's hidden defaults.

The third benefit is auditability. The policy is visible as a line that can be inspected. Two-of-three is written as two-of-three. Taproot is written as Taproot. A checksum can catch a damaged copy before it produces a different wallet view. Bitcoin Core can canonicalise the expression before it is stored or compared.

There is still operational work. Bitcoin Core's importdescriptors requires a timestamp that tells the node how far back to scan. An early timestamp can make the scan take more than an hour, while "now" skips old history and is suitable only when the scripts have never been used. The command also warns that importing requires a new wallet backup. The descriptor explains what to watch; it does not preserve every later change to the wallet database.

What people get wrong

"A descriptor is just a public key." It can contain a public key, but the script type, origin path, child path and checksum are separate information. That surrounding information is the point.

"A descriptor is always watch-only." It is not. BIP 380 permits private keys and extended private keys inside key expressions. Copying such a descriptor into a note, chat or cloud document can be equivalent to copying signing material. Check it before treating it as public.

"A descriptor replaces the seed phrase." A public descriptor cannot sign. A private descriptor may be able to sign, but it is still a poor excuse for an untested recovery plan. Labels, contacts, transaction notes and the last-used index may live elsewhere. Multisignature recovery also needs every required signer or its own backup, not merely the public policy.

"The checksum proves the descriptor is trustworthy." It proves that likely copying errors were detected. It does not prove who created the descriptor, that its keys belong to the intended devices, or that two-of-three was the policy everyone agreed to. A perfectly checksummed wrong descriptor is still wrong.

"Importing it will immediately find everything." The scan starts from the timestamp provided at import. Give a date that is too late and old payments can remain invisible. Give the beginning of the chain and the result is more complete but slower. A missing balance after an import can therefore be a scan-boundary problem rather than lost bitcoin.

Where to go next

Start with unspent outputs if the difference between a wallet balance and the scripts it watches is unfamiliar. Then read the examples in Bitcoin Core's descriptor document beside BIP 380, rather than copying a descriptor from a tutorial.

For an actual recovery plan, record what each copy can do: watch, construct, or sign. Keep private descriptors under the same controls as seed material. Test recovery with a wallet that holds no meaningful funds, including its receiving and change branches. The useful property of a descriptor is precision. It only helps when the backup process preserves that precision all the way to restoration.

Newsletter

Bitcoin, without the noise

What happened in Bitcoin, what it actually changes, and the sources so you can check us. One issue at a time, straight to your inbox.

  • One email per issue, never a drip campaign
  • No tracking pixels and no shared addresses
  • Unsubscribe from any issue in one click

Get the next issue

One email per issue, no tracking pixels, and unsubscribe from any of them. We do not share your address. Privacy policy