Skip to content

BIP draft: Binary Output Descriptors #1548

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 7 commits into
base: master
Choose a base branch
from
139 changes: 139 additions & 0 deletions bip-bod-descriptors.mediawiki
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
<pre>
BIP: ?
Layer: Applications
Title: Binary Output Descriptors
Author: SeedHammer <[email protected]>
License: BSD-2-Clause
</pre>

==Introduction==

===Abstract===

This document proposes an efficient encoding format for output descriptors as
defined by [[bip-0380.mediawiki|BIP 380]] and its extensions. The format is
based on key-value maps as defined by [[bip-0174.mediawiki|BIP 174]] with a
distinct header to avoid confusing PSBT decoders.

===Copyright===

This BIP is licensed under the BSD 2-clause license.

===Motivation===

A BIP 380 output descriptor is a textual representation of a set of output
scripts, such that Bitcoin wallets may agree on the scripts and addresses
to provide the user. However, a descriptor string by itself is not ideal for
transferring between wallets: it lacks a machine recognizable header and cannot
represent metadata such as name and birth block.

BIP 174 gives us a self-describing file format, metadata as well as a compact,
binary representation of keys. Assuming most wallets already implements the PSBT
format, the implementation overhead of this BIP is expected to be low.

==Specification==

The Binary Output Descriptor (BOD) format consists of a fixed header, a
key-value map describing the output descriptor and its metadata followed by a
map for each key referenced by the descriptor.

<bod> := <magic> <global-map> <key-map>*
<magic> := 0x62 0x6F 0x64 0xFF
<global-map> := <keypair>* 0x00
<key-map> := <keypair>* 0x00

The definition for <tt><keypair></tt> follows [[bip-0174.mediawiki#specification|BIP 174]].

The defined global types are as follows:

{|
! Name
! <tt><keytype></tt>
! <tt><keydata></tt>
! <tt><keydata></tt> Description
! <tt><valuedata></tt>
! <tt><valuedata></tt> Description
|-
| Output Descriptor
| <tt>BOD_GLOBAL_OUTPUT_DESCRIPTOR = 0x00</tt>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be beneficial if we could specify a list of output descriptors, not just one, for two reasons:

  • it should be possible to securely sign a transaction where inputs/changes belong to different descriptors
  • a signer may want to inform a user which account/wallet (registered descriptor) they are sending funds to if they send funds to a different account/wallet, even if the inputs all belong to a different descriptor. For this, the signer needs access to the full descriptor

To achieve this, the global field could contain a list of all descriptors, and each input and output can reference one of them, e.g. by index.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your comment seem to assume that this proposal expands signing PSBT with extra information.

As per #1548 (comment), the high-level issue blocking this proposal is whether to expand the PSBT format, or to create a new format (that happens to have similar structure). I don't think we can move forward without a decision either way.

FWIW, I lean towards separating the formats., given @achow101 et al insisting on PSBT being kept for signing use cases only (for good reasons).

Copy link

@benma benma Mar 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed that was my assumption, apologies. I should have read the full BIP again before commenting.

I lean strongly towards extending the PSBT format instead of creating a new format.

  1. Descriptors are essential for secure signing as @bigspider explained here, so including them in the PSBT format is appropriate.
  2. @achow101 commented that one could infer the descriptor. It is not quite clear to me if descriptors can really be inferred from other existing PSBT fields in all cases, but even if, it would add significant complexity, performance problems and code bloat - especially for hardware signers that don't have many resources
  3. There is a lot of software that interacts with PSBTs. Getting all of them to support a parallel format would take a long time and adds needless friction. Wallets handling PSBTs already simply ignore fields unknown to them, so having the descriptors in the PSBT is automatically compatible with all existing software.
  4. UX for users who directly use PSBTs (importing/exporting) would become tricky: how would a user export and transfer both formats between wallets? Doing it twice (once per format) is cumbersome and error prone.

| <tt><compact size uint birth block><bytes></tt>
| The earliest block height that may contain transactions for the descriptor, optionally followed by the UTF-8 encoded name of the descriptor.
| <tt><bytes descriptor></tt>
| The output descriptor in BIP 380 format without inline keys.
|}

It is an error to omit the BOD_GLOBAL_OUTPUT_DESCRIPTOR entry.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An error in which stage? It seems like this should still be optional. For example, for regular single-sig transactions (and even multisig if the global xpub field is populated), one can infer the descriptor.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The descriptor field is mandatory if we assume the format is separate from PSBT (albeit similar structure). See previous comment.


All key expressions in the BOD_GLOBAL_OUTPUT_DESCRIPTOR descriptor string must be
specified as references on the form <tt>@<index></tt> where <tt>index</tt> is
the 0-based index into the ordered list of <tt><key-map></tt> entries. An index
out of range is invalid.

A BOD_GLOBAL_OUTPUT_DESCRIPTOR with inline keys is invalid<ref>'''Why not allow inline
keys?'''
Allowing inline keys risks incompatible implementations that omit parsing of referenced
keys.</ref><ref>'''What about named <tt>pk(NAME)</tt> references?'''
Named references would allow Miniscript descriptors as-is in BOD_GLOBAL_OUTPUT_DESCRIPTOR.
They are left out because they complicate decoders and can trivially be replaced by indexed
references.</ref>.

Key references may be followed by derivation paths as specified in [[bip-0389.mediawiki#specification|BIP 389]].

The defined key types are as follows:

{|
! Name
! <tt><keytype></tt>
! <tt><keydata></tt>
! <tt><keydata></tt> Description
! <tt><valuedata></tt>
! <tt><valuedata></tt> Description
|-
| Extended Public Key
| <tt>BOD_KEY_XPUB = 0x00</tt>
| <tt><bytes xpub></tt>
| The 78 byte serialized extended public key as defined by BIP 32.
| <tt><4 byte fingerprint> <32-bit little endian uint path element>*</tt>
| The master key fingerprint as defined by BIP 32 concatenated with the derivation path of the public key. The derivation path is represented as 32-bit little endian unsigned integer indexes concatenated with each other. The number of 32 bit unsigned integer indexes must match the depth provided in the extended public key.
|}

==Test Vectors==

===Invalid Cases===

A descriptor with a key reference out of bounds.
Descriptor: wpkh(@0/*)
Hex encoded BOD: 70736274ff0207000a77706b682840302f2a29000000

A descriptor with an invalid UTF-8 name.
Hex encoded BOD: 70736274ff05070061c57a0a77706b682840302f2a2953010488b21e041c0ae906800000025afed56d755c088320ec9bc6acd84d33737b580083759e0a0ff8f26e429e0b77028342f5f7773f6fab374e1c2d3ccdba26bc0933fc4f63828b662b4357e4cc3791bec0fbd814c5d8729748000080000000800000008002000080000000

A descriptor with an inline key.
Hex encoded BOD: 70736274ff0207008e77706b68285b64633536373237362f3438682f30682f30682f32685d7870756236446959726652774e6e6a655834764873574d616a4a56464b726245456e753867415739764475517a675457457345484531367347576558585556314c42575145317943546d657072534e63715a3357373468715664674462745948557633654d3457325445556870616e2f2a29000000

===Valid Cases===

A 2-of-3 multisig descriptor
Descriptor: wsh(sortedmulti(2,@0/<0;1>/*,@1/<0;1>/*,@2/<0;1>/*))
Name: Satoshi's Stash
Birth block: 123456789012345
Key 0: [dc567276/48h/0h/0h/2h]xpub6DiYrfRwNnjeX4vHsWMajJVFKrbEEnu8gAW9vDuQzgTWEsEHE16sGWeXXUV1LBWQE1yCTmeprSNcqZ3W74hqVdgDbtYHUv3eM4W2TEUhpan
Key 1: [f245ae38/48h/0h/0h/2h]xpub6DnT4E1fT8VxuAZW29avMjr5i99aYTHBp9d7fiLnpL5t4JEprQqPMbTw7k7rh5tZZ2F5g8PJpssqrZoebzBChaiJrmEvWwUTEMAbHsY39Ge
Key 2: [c5d87297/48h/0h/0h/2h]xpub6DjrnfAyuonMaboEb3ZQZzhQ2ZEgaKV2r64BFmqymZqJqviLTe1JzMr2X2RfQF892RH7MyYUbcy77R7pPu1P71xoj8cDUMNhAMGYzKR4noZ
Hex encoded BOD: 70736274ff1907ff79df0d86487000005361746f73686927732053746173683477736828736f727465646d756c746928322c40302f3c303b313e2f2a2c40312f3c303b313e2f2a2c40322f3c303b313e2f2a292953010488b21e0418f8c2e7800000026b3a4cfb6a45f6305efe6e0e976b5d26ba27f7c344d7fc7abef7be2d06d52dfd021c0b479ecf6e67713ddf0c43b634592f51c037b6f951fb1dc6361a98b1e5735e0f8b515314dc5672764800008000000080000000800200008053010488b21e04221eb5a080000002c887c72d9d8ac29cddd5b2b060e8b0239039a149c784abe6079e24445db4aa8a0397fcf2274abd243d42d42d3c248608c6d1935efca46138afef43af08e971289657009d2b14f245ae384800008000000080000000800200008053010488b21e041c0ae906800000025afed56d755c088320ec9bc6acd84d33737b580083759e0a0ff8f26e429e0b77028342f5f7773f6fab374e1c2d3ccdba26bc0933fc4f63828b662b4357e4cc3791bec0fbd814c5d8729748000080000000800000008002000080000000

==Rationale==

<references/>

== Reference Implementation==

There is a [https://github.com/seedhammer/bip-bod-descriptors Go implementation]
for development and testing purposes. Don't use it in production, because it only
validates the BOD format, not the descriptor itself.

==Acknowledgments==

This specification builds upon the draft BIP 388 by specifying
a serialization format for compact descriptors. It also uses the indexed key
references from that BIP, as well as examples and test vectors.
Loading