Home › Learn › Output descriptors explained (BIP 380 to 386)

Output descriptors explained (BIP 380 to 386)

An output descriptor is a short line of text that tells a wallet exactly which output scripts belong to it: the script type, the keys, where those keys come from and which derivation path to follow. For example, wpkh([73c5da0a/84h/0h/0h]xpub.../0/*) means "native SegWit addresses from this account's receive chain". Descriptors are specified in BIPs 380 to 386 by Pieter Wuille and Ava Chow, and they fix what a seed phrase alone can't record.

Updated · 8 min read

What is an output descriptor?

BIP 380 defines Output Script Descriptors as "a simple language which can be used to describe collections of output scripts". A descriptor is written like a function call: the outer function names the script type, and the arguments are keys or other scripts. A wallet reads it and can then generate every address it describes, recognize incoming payments and sign for them.

Descriptors were first built into Bitcoin Core and then written up as a set of BIPs in 2021, all by Pieter Wuille and Ava Chow:

BIP What it specifies
380 General syntax, key expressions and the checksum
381 Non-SegWit scripts: pk(), pkh(), sh()
382 SegWit scripts: wpkh(), wsh()
383 Multisig: multi(), sortedmulti()
384 combo()
385 raw() and addr()
386 Taproot: tr()

Later BIPs extend the language, as covered below.

What problem do descriptors solve?

For years, a wallet backup meant a seed phrase and nothing else. That worked while every address was the same type. After SegWit added new output types, the same keys could produce legacy, nested SegWit or native SegWit addresses, and later Taproot ones. BIP 380 puts it plainly: "Given just the private keys, it is not possible for restored wallets to know which kinds of output scripts and addresses to produce."

Standard derivation paths (BIPs 44, 49 and 84) helped, but not every wallet used them, and special key prefixes like ypub and zpub only covered a few cases. BIP 380 calls those prefixes "a layer violation". Descriptors replace the guessing with an explicit statement: this script type, these keys, this path.

Anatomy of a descriptor

Here is a complete descriptor for the receive addresses of a native SegWit account. It belongs to the public test seed used in the BIPs ("abandon" eleven times, then "about"), so never send real funds to it:

wpkh([73c5da0a/84h/0h/0h]xpub6CatWdiZiodmUeTDp8LT5or8nmbKNcuyvz7WyksVFkKB4RHwCD3XyuvPEbvqAQY3rAPshWcMLoP2fMFMKHPJ4ZeZXYVUhLv1VMrjPC7PW6V/0/*)#afwvtk2s
Part Meaning
wpkh(...) Script expression: produce P2WPKH (native SegWit) outputs
[73c5da0a/84h/0h/0h] Key origin: the master key's fingerprint, and the path from it to the key that follows
xpub6Cat...PW6V The account's extended public key
/0/* Derive child 0 (the receive chain), then every child index below it
#afwvtk2s Checksum over everything before the #

Its first address, at index 0, is bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu, the same address BIP 84 lists for path m/84'/0'/0'/0/0. The descriptor contains no private keys: it can watch the wallet but not spend from it.

Script expressions: pkh, wpkh, sh, wsh, tr and more

Each script expression produces one kind of output script:

Expression BIP Produces
pk(KEY) 381 Pay to public key (P2PK), usable inside other expressions
pkh(KEY) 381 P2PKH, legacy addresses starting with 1
sh(SCRIPT) 381 P2SH wrapping another script, addresses starting with 3
wpkh(KEY) 382 P2WPKH, addresses starting with bc1q
wsh(SCRIPT) 382 P2WSH wrapping another script, long bc1q addresses
multi(k,KEY,...) and sortedmulti(k,KEY,...) 383 k-of-n OP_CHECKMULTISIG, on its own or inside sh() or wsh()
combo(KEY) 384 P2PK and P2PKH, plus P2WPKH and P2SH-P2WPKH for compressed keys
raw(HEX) and addr(ADDR) 385 Exactly the given script, or the script behind an address
tr(KEY) and tr(KEY,TREE) 386 P2TR (Taproot), addresses starting with bc1p
multi_a(k,KEY,...) and sortedmulti_a(k,KEY,...) 387 Tapscript k-of-n multisig, only inside tr()

Expressions nest. Nested SegWit is sh(wpkh(KEY)); native SegWit multisig is wsh(sortedmulti(2,KEY1,KEY2,KEY3)). Some placements are not allowed: sh() and tr() must be at the top level, and wpkh() and wsh() only accept compressed public keys.

sortedmulti() sorts the keys before building the script, as BIP 67 does for P2SH multisig, so every cosigner gets the same address regardless of the order keys were entered. BIP 383 also records the key limits: at most 3 keys for bare multi(), 15 compressed keys inside sh() (because of the 520-byte script limit), and 20 otherwise. multi_a() allows up to 999.

Key expressions and key origin

A key expression can be a hex public key, a WIF private key, or an extended key (xpub or xprv) followed by derivation steps:

  • Key origin in square brackets: exactly 8 hex characters of fingerprint, then the path from that master key, such as [73c5da0a/84h/0h/0h]. Hardware signers use it to recognize their own keys.
  • Hardened steps can be written with h or ': 84h and 84' mean the same.
  • /* at the end means "every unhardened child", and /*h every hardened child.
  • Normalization: when a descriptor is exported without private keys, the exporter derives the xpub at the last hardened step and moves those steps into the key origin. That's why descriptors show an account-level xpub followed only by unhardened steps.
  • Inside tr(), keys are 32-byte x-only public keys, as used by Taproot.

Receive and change in one descriptor: <0;1>

A wallet usually needs two nearly identical descriptors: one ending /0/* for receive addresses and one ending /1/* for change. BIP 389, by Ava Chow, lets you write both at once with a multipath step:

wpkh([73c5da0a/84h/0h/0h]xpub6CatWdiZiodmUeTDp8LT5or8nmbKNcuyvz7WyksVFkKB4RHwCD3XyuvPEbvqAQY3rAPshWcMLoP2fMFMKHPJ4ZeZXYVUhLv1VMrjPC7PW6V/<0;1>/*)#qf45pmyh

The first value in <0;1> gives the receive descriptor and the second the change descriptor. Each key expression may contain only one <...> step, and when several keys have one, the tuples must be the same length so they derive in lockstep.

The descriptor checksum

The 8 characters after the # are an error-detecting checksum, similar in design to Bech32 and written in the same 32-character alphabet (qpzry9x8gf2tvdw0s3jn54khce6mua7l). According to BIP 380 it:

  • always detects any single-character mistake, and any case error;
  • always detects 2 or 3 errors in descriptors up to 49,154 characters, 4 errors up to 507 characters and 5 errors up to 77 characters;
  • lets random errors through with a chance of only 1 in 2^40.

The checksum is optional when parsing, but software may refuse descriptors without one. BIP 380's simplest test vector is raw(deadbeef)#89f8spxm: change a single character and the checksum fails. Because it is computed over the exact text, even switching h to ' changes it.

Common descriptor examples

With keys shortened for readability (fp is a master fingerprint, xpub... an account xpub):

  • Legacy, BIP 44: pkh([fp/44h/0h/0h]xpub.../<0;1>/*)
  • Nested SegWit, BIP 49: sh(wpkh([fp/49h/0h/0h]xpub.../<0;1>/*))
  • Native SegWit, BIP 84: wpkh([fp/84h/0h/0h]xpub.../<0;1>/*)
  • Taproot, BIP 86: tr([fp/86h/0h/0h]xpub.../<0;1>/*)
  • 2-of-3 native SegWit multisig, BIP 48: wsh(sortedmulti(2,[fpA/48h/0h/0h/2h]xpubA.../<0;1>/*,[fpB/48h/0h/0h/2h]xpubB.../<0;1>/*,[fpC/48h/0h/0h/2h]xpubC.../<0;1>/*))
  • Taproot with a script tree: tr(KEY_A,{pk(KEY_B),multi_a(2,KEY_C,KEY_D,KEY_E)}), which can be spent by key A alone or by revealing one of the two scripts.
  • MuSig2 key path: tr(musig(xpubA...,xpubB...,xpubC...)/0/*), using the musig() key expression from BIP 390, which aggregates the keys with MuSig2 and derives children from the aggregate as BIP 328 describes.

Miniscript: descriptors for any spending policy

Miniscript (BIP 379), by Pieter Wuille, Andrew Poelstra, Sanket Kanjalkar, Antoine Poinsot and Ava Chow, is a structured way to write Bitcoin Script so that software can analyze it: what conditions allow spending, what a spend will cost, and whether the witness could be tampered with. Its fragments include pk(), older() and after() for timelocks, sha256() for hash locks, and_v(), or_d() and thresh().

BIP 379 says that "from a user's perspective, Miniscript is not a separate language, but rather a significant expansion of the descriptor language". It is used inside wsh() and tr(). For example:

wsh(and_v(v:pk(KEY_USER),or_d(pk(KEY_SERVICE),older(12960))))

This requires the user's signature plus either a co-signing service's signature or a wait of 12,960 blocks (about 90 days) since the coins were received. Because any wallet that understands Miniscript can work out how to sign for it, complex policies such as timelocked recovery paths don't each need custom signing software.

Wallet policies for hardware signers (BIP 388)

Full descriptors can be long, and hardware signing devices have little memory and small screens. BIP 388, by Salvatore Ingala, defines wallet policies: a descriptor template with numbered placeholders, plus a separate list of keys. The 2-of-3 example above becomes:

wsh(sortedmulti(2,@0/**,@1/**,@2/**))

where /** is shorthand for /<0;1>/*. The user registers the policy on the device once, checks it on the device's own screen, and from then on the device can verify that change goes back to the same policy.

Newer descriptor BIPs

The descriptor language keeps growing. Proposals extending it include:

  • BIP 387: multi_a() and sortedmulti_a() for Tapscript multisig, built on OP_CHECKSIGADD.
  • BIP 390: the musig() key expression for MuSig2 aggregate keys.
  • BIP 392: sp() descriptors for silent payments, with new spscan and spspend key encodings.
  • BIP 393: annotations, recovery hints appended after a ?, such as bh (the block height to start scanning from), gl (the gap limit) and ml (the highest silent payment label used). They don't change which scripts the descriptor produces, and the checksum covers them.

Check each BIP's page for its current status before relying on it.

How to back up a descriptor

A descriptor without private keys can't spend coins, but it does reveal every address in the wallet, and so your whole transaction history and balance. Treat it as private, but it is not as critical as your seed.

  1. Single-signature wallets: your seed phrase plus the descriptor is a complete backup. The seed alone usually works if the wallet followed a standard path, but the descriptor removes any doubt about script type, path and account.
  2. Multisig wallets: the descriptor is essential. Without every cosigner's xpub and the exact policy, a quorum of seeds still can't find or spend the coins. Keep a copy of the descriptor with each seed backup; see the multisig guide.
  3. Keep the checksum. It lets the restoring wallet catch transcription errors.
  4. Write down the first address too. After restoring, check that the wallet shows the same one.
  5. Check what you export. Some software can export descriptors that include private keys (xprv). Those must be protected like a seed phrase.

Descriptors also travel well between programs: PSBTs carry the same key origin information, so a signer can confirm which of its keys a transaction uses.

Frequently asked questions

What is a descriptor wallet?

A descriptor wallet stores output descriptors instead of a loose collection of keys. Each descriptor states exactly which scripts the wallet watches, for example wpkh() for native SegWit or tr() for Taproot, along with the keys and derivation paths. This makes backups, watch-only exports and multisig setups unambiguous across different wallet software.

What does the checksum at the end of a descriptor mean?

The eight characters after the # are a checksum defined in BIP 380. They let software detect typos: any single-character error is always caught, and random errors slip through only about once in 2^40 cases. The checksum is optional when parsing, but keeping it in backups is strongly recommended.

What does <0;1> mean in a descriptor?

It is a multipath step from BIP 389. It packs two descriptors into one: the first uses 0 at that position (receive addresses) and the second uses 1 (change addresses). So xpub/<0;1>/* stands for both xpub/0/* and xpub/1/*, which saves storing two almost identical lines.

Is it safe to share an output descriptor?

A descriptor with only public keys cannot be used to spend your coins, but it reveals all of your addresses, balances and transaction history. Share it only with software or people you'd trust with that information, such as your own watch-only wallet or your multisig cosigners. Descriptors containing xprv keys must be kept secret.

What is the difference between a descriptor and a derivation path?

A derivation path only says where a key sits in an HD wallet's tree, such as m/84'/0'/0'. A descriptor includes the path but also the script type, the extended public key, the master fingerprint and, for multisig, every cosigner's key and the threshold. It is a complete description of which addresses a wallet owns.

BIPs in this article

  • BIP 380: Output Script Descriptors General Operation: Deployed. Output script descriptors are a compact text language for describing exactly which addresses a wallet owns and how they are spent. This document defines their general syntax and checksum, giving…
  • BIP 381: Non-Segwit Output Script Descriptors: Deployed. Defines the descriptor functions for Bitcoin's older address types: pay-to-public-key, pay-to-public-key-hash (classic addresses starting with '1'), and pay-to-script-hash (addresses starting with…
  • BIP 382: Segwit Output Script Descriptors: Deployed. Defines the descriptor functions for native SegWit outputs, covering both single-key addresses and script-based ones. With these, wallets can precisely describe and back up SegWit wallets, including…
  • BIP 383: Multisig Output Script Descriptors: Deployed. Defines descriptor functions for multisignature setups, where a certain number of keys out of a group must sign. One version keeps keys in the given order and another sorts them automatically, which…
  • BIP 384: combo() Output Script Descriptors: Deployed. Defines a 'combo' descriptor that, from a single key, describes all the common address types that key could be used with. This is handy for wallets that need to find coins sent to any of those…
  • BIP 385: raw() and addr() Output Script Descriptors: Deployed. Defines two simple descriptor functions: one that wraps an arbitrary raw script and one that wraps a plain address. They let wallets track coins in formats not otherwise covered, or watch an address…
  • BIP 386 (Taproot descriptors): tr() Output Script Descriptors: Deployed. Defines the descriptor function for Taproot outputs, combining a main key with an optional tree of alternative spending conditions. This gives wallets a standard way to describe, back up and recover…
  • BIP 387: Tapscript Multisig Output Script Descriptors: Deployed. Defines descriptor functions for multisignature setups inside Taproot scripts, which require a different construction than older multisig. One form keeps keys in the given order and the other sorts…
  • BIP 389: Multipath Descriptor Key Expressions: Draft. Extends descriptors so one key expression can represent several related derivation paths at once, such as a wallet's receiving and change addresses. This shortens wallet backups and avoids having to…
  • BIP 390 (MuSig2 descriptors): musig() Descriptor Key Expression: Draft. Adds a 'musig()' expression to descriptors, which combines several people's public keys into a single shared key using the MuSig2 method. The resulting coins look like an ordinary single-key payment…
  • BIP 379: Miniscript: Draft. Miniscript is a structured way of writing Bitcoin scripts, the small programs that define how coins can be spent. It lets software analyze spending conditions, combine them safely, and sign for them…
  • BIP 388: Wallet Policies for Descriptor Wallets: Complete. Wallet policies are a compact, human-reviewable way of describing an 'account' in a wallet, built on top of output descriptors. They are designed especially for hardware wallets with small screens,…
  • BIP 392: Silent Payment Output Script Descriptors: Draft. Defines an 'sp()' descriptor for Silent Payment wallets, describing the keys needed to detect and spend payments sent to a reusable Silent Payment address. This lets such wallets be backed up and…
  • BIP 393: Output Script Descriptor Annotations: Draft. Introduces optional tags that can be attached to a descriptor, such as the block height to start scanning from or how many unused addresses to check. These hints speed up and simplify wallet…

Learn more

Guides

Free tools

Glossary