1
0
mirror of https://github.com/bitcoin/bips.git synced 2026-10-19 19:29:18 +00:00

Merge pull request #2300 from Sjors/2026/09/bip138-recipients

bip138: clarify key selection and apply exclusions across expressions
This commit is contained in:
Murch
2026-09-24 20:19:29 -07:00
committed by GitHub
3 changed files with 168 additions and 64 deletions

View File

@@ -10,8 +10,8 @@
Discussion: https://delvingbitcoin.org/t/a-simple-backup-scheme-for-wallet-accounts/1607 Discussion: https://delvingbitcoin.org/t/a-simple-backup-scheme-for-wallet-accounts/1607
https://groups.google.com/g/bitcoindev/c/5NgJbpVDgEc/m/TtGK9sF9BgAJ https://groups.google.com/g/bitcoindev/c/5NgJbpVDgEc/m/TtGK9sF9BgAJ
https://github.com/bitcoin/bips/pull/1951 https://github.com/bitcoin/bips/pull/1951
Version: 0.1.2 Version: 0.1.3
Requires: 32, 340, 380, 388, 389 Requires: 32, 340, 380, 388, 389, 390
``` ```
## Introduction ## Introduction
@@ -98,7 +98,8 @@ Note: in the following sections, the operator ⊕ refers to the bitwise XOR oper
### Secret generation ### Secret generation
- Let $p_1, p_2, \dots, p_n$, be the public keys in the descriptor/wallet policy, in - Let $p_1, p_2, \dots, p_n$, be the distinct public keys across all descriptor
and policy sets and all content items in the payload, in
increasing lexicographical order. The scheme is defined for any $n \geq 1$, increasing lexicographical order. The scheme is defined for any $n \geq 1$,
in particular it supports single-signature descriptors ($n = 1$). Each $p_i$ in particular it supports single-signature descriptors ($n = 1$). Each $p_i$
is the x-only-normalized root public key of one *allowed* key expression is the x-only-normalized root public key of one *allowed* key expression
@@ -113,8 +114,8 @@ hash construction from [BIP340](bip-0340.mediawiki#design).
Because $s$ and $s_i$ use distinct domain-separation tags, $s \neq s_i$ and Because $s$ and $s_i$ use distinct domain-separation tags, $s \neq s_i$ and
therefore $c_i$ is never the all-zero string. therefore $c_i$ is never the all-zero string.
Keys published on chain are already kept out of $\{p_1, \dots, p_n\}$ by the The [Descriptor key requirements](#descriptor-key-requirements) exclude
[Descriptor key requirements](#descriptor-key-requirements). keys exposed by literal or bare-xpub expressions in the backed-up scripts.
Implementations MUST exclude the key with x coordinate Implementations MUST exclude the key with x coordinate
`50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0` (the BIP341 NUMS `50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0` (the BIP341 NUMS
point). Applications MAY exclude any further key they know to be public. point). Applications MAY exclude any further key they know to be public.
@@ -138,8 +139,8 @@ accounts whose xpub was never sent to such a server, such as BIP48 or BIP87 acco
### Descriptor key requirements ### Descriptor key requirements
Only key expressions of the extended-public-key type with a trailing Outside `musig()`, only key expressions of the extended-public-key type with a
derivation step or wildcard contribute to $\{p_1, \dots, p_n\}$. Without trailing derivation step or wildcard contribute to $\{p_1, \dots, p_n\}$. Without
that derivation, the xpub's root pubkey, used to seed $s$, would also be that derivation, the xpub's root pubkey, used to seed $s$, would also be
the on-chain pubkey of every spend, so observing one spend would let the on-chain pubkey of every spend, so observing one spend would let
anyone recompute $s$ and decrypt the backup.[^trailing-derivation] The anyone recompute $s$ and decrypt the backup.[^trailing-derivation] The
@@ -150,9 +151,9 @@ rule generalizes to any network prefix (`xpub`/`tpub`/`Vpub`/...).
a wildcard, breaks the identity between the xpub root pubkey and the a wildcard, breaks the identity between the xpub root pubkey and the
on-chain pubkey. Fixed-derivation expressions like `xpub.../0/5` are on-chain pubkey. Fixed-derivation expressions like `xpub.../0/5` are
allowed because the on-chain key (`xpub/0/5`) already differs from the allowed because the on-chain key (`xpub/0/5`) already differs from the
encryption seed (the xpub root). Literal pubkeys and bare xpubs are encryption seed (the xpub root). Outside `musig()`, literal pubkeys and
disallowed for the same reason: the literal value is exactly what goes bare xpubs are disallowed for the same reason: the literal value is exactly
on-chain, so $s$ would become recoverable from a single observed spend. what goes on-chain, so $s$ would become recoverable from a single observed spend.
Allowed forms (origin information `[...]` is optional and orthogonal): Allowed forms (origin information `[...]` is optional and orthogonal):
@@ -163,15 +164,27 @@ Allowed forms (origin information `[...]` is optional and orthogonal):
| `<xpub>/<path>/*` (fixed derivation followed by a wildcard) | `xpub.../0/*` | | `<xpub>/<path>/*` (fixed derivation followed by a wildcard) | `xpub.../0/*` |
| `<xpub>/<a;b;...>` (multipath, no wildcard) | `xpub.../<0;1>` | | `<xpub>/<a;b;...>` (multipath, no wildcard) | `xpub.../<0;1>` |
| `<xpub>/<a;b;...>/*` (multipath followed by a wildcard) | `xpub.../<0;1>/*` | | `<xpub>/<a;b;...>/*` (multipath followed by a wildcard) | `xpub.../<0;1>/*` |
| `<xpub>` (only as a `musig()` participant) | `xpub...` |
Within a [BIP390](bip-0390.mediawiki) `musig()` expression, participant xpubs
are allowed with or without trailing derivation: the aggregate on-chain key
does not reveal the individual participant keys. For encryption, use each
participant's xpub root rather than the aggregate key. Literal public-key
participants remain excluded.
A candidate root MUST be excluded if its x-coordinate matches a literal key
or a bare xpub root used outside `musig()` in any descriptor or resolved
policy in the payload. For example,
`wsh(or_i(pk(X/0/*),pk(X)))` exposes the root of xpub `X` on spending, so that
root must be excluded even though `X/0/*` is otherwise eligible.
Implementations: Implementations:
- MUST exclude every other form (literal pubkeys, bare xpubs, ...) from - MUST exclude every other form (literal pubkeys, bare xpubs outside `musig()`,
$\{p_1, \dots, p_n\}$. ...) from $\{p_1, \dots, p_n\}$.
- MUST refuse to encode a backup if the resulting set is empty. - MUST refuse to encode a backup if the resulting set is empty.
- MUST make the user aware of each excluded expression, since the - MUST make the user aware of each excluded expression and candidate root,
cosigner holding that key will be unable to decrypt the backup with since its holder may be unable to decrypt the backup with that key.
their key.
### Key Normalization ### Key Normalization
@@ -590,8 +603,11 @@ The version field enables possible future enhancements:
### Test Vectors ### Test Vectors
[key_types.json](./bip-0138/test_vectors/keys_types.json) contains test [recipient_keys.json](./bip-0138/test_vectors/recipient_keys.json) contains
vectors for key serialisations. test vectors for recipient selection. `descriptors` lists the payload's descriptor
strings; `expected_keys` lists the sorted, deduplicated x-only recipient roots
before application-specific exclusions. `null` requires refusing to encode.
[content_type.json](./bip-0138/test_vectors/content_type.json) contains test [content_type.json](./bip-0138/test_vectors/content_type.json) contains test
vectors for content types serialisations. vectors for content types serialisations.
[payload.json](./bip-0138/test_vectors/payload.json) contains test vectors for payload parsing. [payload.json](./bip-0138/test_vectors/payload.json) contains test vectors for payload parsing.
@@ -633,6 +649,10 @@ their reviews and suggestions.
## Changelog ## Changelog
* __0.1.3__ (2026-09-24):
* Rename, generalize and expand the key-selection test vectors.
* Clarify MuSig participant eligibility and recipient selection across the payload.
* Exclude roots exposed by another key expression.
* __0.1.2__ (2026-09-24): * __0.1.2__ (2026-09-24):
* Specify empty AEAD associated data. * Specify empty AEAD associated data.
* Clarify that `0x00` ends payload parsing and add test vectors. * Clarify that `0x00` ends payload parsing and add test vectors.

View File

@@ -1,47 +0,0 @@
[
{
"description": "Xpub with origin and multipath wildcard",
"key": "[58b7f8dc/48'/1'/0'/2']tpubDEPBvXvhta3pjVaKokqC3eeMQnszj9ehFaA2zD5nSdkaccwGAizu8jVB2NeSpvmP2P52MBoZvNCixqXRJnTyXx51FQzARR63tjxQSyP3Btw/<0;1>/*",
"expected": "ebd252ca0877aae09b9d058219682775aa3cbcd049c12f07832f2cf6a3b51708"
},
{
"description": "Xpub with single-path wildcard",
"key": "[58b7f8dc/48'/1'/0'/2']tpubDEPBvXvhta3pjVaKokqC3eeMQnszj9ehFaA2zD5nSdkaccwGAizu8jVB2NeSpvmP2P52MBoZvNCixqXRJnTyXx51FQzARR63tjxQSyP3Btw/0/*",
"expected": "ebd252ca0877aae09b9d058219682775aa3cbcd049c12f07832f2cf6a3b51708"
},
{
"description": "Xpub with bare wildcard (no preceding path)",
"key": "[58b7f8dc/48'/1'/0'/2']tpubDEPBvXvhta3pjVaKokqC3eeMQnszj9ehFaA2zD5nSdkaccwGAizu8jVB2NeSpvmP2P52MBoZvNCixqXRJnTyXx51FQzARR63tjxQSyP3Btw/*",
"expected": "ebd252ca0877aae09b9d058219682775aa3cbcd049c12f07832f2cf6a3b51708"
},
{
"description": "Xpub with fixed deep derivation, no wildcard",
"key": "[58b7f8dc/48'/1'/0'/2']tpubDEPBvXvhta3pjVaKokqC3eeMQnszj9ehFaA2zD5nSdkaccwGAizu8jVB2NeSpvmP2P52MBoZvNCixqXRJnTyXx51FQzARR63tjxQSyP3Btw/0/5",
"expected": "ebd252ca0877aae09b9d058219682775aa3cbcd049c12f07832f2cf6a3b51708"
},
{
"description": "Xpub with multipath, no wildcard",
"key": "[58b7f8dc/48'/1'/0'/2']tpubDEPBvXvhta3pjVaKokqC3eeMQnszj9ehFaA2zD5nSdkaccwGAizu8jVB2NeSpvmP2P52MBoZvNCixqXRJnTyXx51FQzARR63tjxQSyP3Btw/<0;1>",
"expected": "ebd252ca0877aae09b9d058219682775aa3cbcd049c12f07832f2cf6a3b51708"
},
{
"description": "Bare xpub (no derivation, no wildcard); DISALLOWED",
"key": "[d4ab66f1/48'/1'/1'/2']tpubDFTxBKyUCgkwp5enwZh3t2FJ5AMJqmCWoh1NRT13qNYQb1iKTUrAG6u5gpsDYhG8cZGXouYWuQtzcuSVjPStTc4dwU6JqPMFtgaLGvSQXhi",
"expected": null
},
{
"description": "Compressed literal pubkey; DISALLOWED",
"key": "02ebd252ca0877aae09b9d058219682775aa3cbcd049c12f07832f2cf6a3b51708",
"expected": null
},
{
"description": "X-only literal pubkey; DISALLOWED",
"key": "ebd252ca0877aae09b9d058219682775aa3cbcd049c12f07832f2cf6a3b51708",
"expected": null
},
{
"description": "Uncompressed literal pubkey; DISALLOWED",
"key": "04ebd252ca0877aae09b9d058219682775aa3cbcd049c12f07832f2cf6a3b517089e956909c4c07e8529f45f3ff8904d28df5a181619e21bdf748a896322530039",
"expected": null
}
]

View File

@@ -0,0 +1,131 @@
[
{
"description": "Xpub with origin and multipath wildcard",
"descriptors": [
"tr([58b7f8dc/48'/1'/0'/2']tpubDEPBvXvhta3pjVaKokqC3eeMQnszj9ehFaA2zD5nSdkaccwGAizu8jVB2NeSpvmP2P52MBoZvNCixqXRJnTyXx51FQzARR63tjxQSyP3Btw/<0;1>/*)"
],
"expected_keys": [
"ebd252ca0877aae09b9d058219682775aa3cbcd049c12f07832f2cf6a3b51708"
]
},
{
"description": "Xpub with single-path wildcard",
"descriptors": [
"tr([58b7f8dc/48'/1'/0'/2']tpubDEPBvXvhta3pjVaKokqC3eeMQnszj9ehFaA2zD5nSdkaccwGAizu8jVB2NeSpvmP2P52MBoZvNCixqXRJnTyXx51FQzARR63tjxQSyP3Btw/0/*)"
],
"expected_keys": [
"ebd252ca0877aae09b9d058219682775aa3cbcd049c12f07832f2cf6a3b51708"
]
},
{
"description": "Xpub with bare wildcard (no preceding path)",
"descriptors": [
"tr([58b7f8dc/48'/1'/0'/2']tpubDEPBvXvhta3pjVaKokqC3eeMQnszj9ehFaA2zD5nSdkaccwGAizu8jVB2NeSpvmP2P52MBoZvNCixqXRJnTyXx51FQzARR63tjxQSyP3Btw/*)"
],
"expected_keys": [
"ebd252ca0877aae09b9d058219682775aa3cbcd049c12f07832f2cf6a3b51708"
]
},
{
"description": "Xpub with fixed deep derivation, no wildcard",
"descriptors": [
"tr([58b7f8dc/48'/1'/0'/2']tpubDEPBvXvhta3pjVaKokqC3eeMQnszj9ehFaA2zD5nSdkaccwGAizu8jVB2NeSpvmP2P52MBoZvNCixqXRJnTyXx51FQzARR63tjxQSyP3Btw/0/5)"
],
"expected_keys": [
"ebd252ca0877aae09b9d058219682775aa3cbcd049c12f07832f2cf6a3b51708"
]
},
{
"description": "Xpub with multipath, no wildcard",
"descriptors": [
"tr([58b7f8dc/48'/1'/0'/2']tpubDEPBvXvhta3pjVaKokqC3eeMQnszj9ehFaA2zD5nSdkaccwGAizu8jVB2NeSpvmP2P52MBoZvNCixqXRJnTyXx51FQzARR63tjxQSyP3Btw/<0;1>)"
],
"expected_keys": [
"ebd252ca0877aae09b9d058219682775aa3cbcd049c12f07832f2cf6a3b51708"
]
},
{
"description": "Bare xpub (no derivation, no wildcard); DISALLOWED",
"descriptors": [
"tr([d4ab66f1/48'/1'/1'/2']tpubDFTxBKyUCgkwp5enwZh3t2FJ5AMJqmCWoh1NRT13qNYQb1iKTUrAG6u5gpsDYhG8cZGXouYWuQtzcuSVjPStTc4dwU6JqPMFtgaLGvSQXhi)"
],
"expected_keys": null
},
{
"description": "Compressed literal pubkey; DISALLOWED",
"descriptors": [
"tr(02ebd252ca0877aae09b9d058219682775aa3cbcd049c12f07832f2cf6a3b51708)"
],
"expected_keys": null
},
{
"description": "X-only literal pubkey; DISALLOWED",
"descriptors": [
"tr(ebd252ca0877aae09b9d058219682775aa3cbcd049c12f07832f2cf6a3b51708)"
],
"expected_keys": null
},
{
"description": "Uncompressed literal pubkey; DISALLOWED",
"descriptors": [
"pk(04ebd252ca0877aae09b9d058219682775aa3cbcd049c12f07832f2cf6a3b517089e956909c4c07e8529f45f3ff8904d28df5a181619e21bdf748a896322530039)"
],
"expected_keys": null
},
{
"description": "Bare MuSig participant xpubs",
"descriptors": [
"tr(musig(tpubDEPBvXvhta3pjVaKokqC3eeMQnszj9ehFaA2zD5nSdkaccwGAizu8jVB2NeSpvmP2P52MBoZvNCixqXRJnTyXx51FQzARR63tjxQSyP3Btw,tpubDC5FSnBiZDMmhiuCmWAYsLwgLYrrT9rAqvTySfuCCrgsWz8wxMXUS9Tb9iVMvcRbvFcAHGkMD5Kx8koh4GquNGNTfohfk7pgjhaPCdXpoba))"
],
"expected_keys": [
"8b42cd4776376c82791b494155151f56c2d7b471e0c7a526a7ce60dd872e3867",
"ebd252ca0877aae09b9d058219682775aa3cbcd049c12f07832f2cf6a3b51708"
]
},
{
"description": "Derivation after MuSig aggregation",
"descriptors": [
"tr(musig(tpubDEPBvXvhta3pjVaKokqC3eeMQnszj9ehFaA2zD5nSdkaccwGAizu8jVB2NeSpvmP2P52MBoZvNCixqXRJnTyXx51FQzARR63tjxQSyP3Btw,tpubDC5FSnBiZDMmhiuCmWAYsLwgLYrrT9rAqvTySfuCCrgsWz8wxMXUS9Tb9iVMvcRbvFcAHGkMD5Kx8koh4GquNGNTfohfk7pgjhaPCdXpoba)/<0;1>/*)"
],
"expected_keys": [
"8b42cd4776376c82791b494155151f56c2d7b471e0c7a526a7ce60dd872e3867",
"ebd252ca0877aae09b9d058219682775aa3cbcd049c12f07832f2cf6a3b51708"
]
},
{
"description": "Same root in several descriptor sets contributes once",
"descriptors": [
"tr(tpubDEPBvXvhta3pjVaKokqC3eeMQnszj9ehFaA2zD5nSdkaccwGAizu8jVB2NeSpvmP2P52MBoZvNCixqXRJnTyXx51FQzARR63tjxQSyP3Btw/0/*)",
"tr(tpubDEPBvXvhta3pjVaKokqC3eeMQnszj9ehFaA2zD5nSdkaccwGAizu8jVB2NeSpvmP2P52MBoZvNCixqXRJnTyXx51FQzARR63tjxQSyP3Btw/1/*)",
"tr(tpubDC5FSnBiZDMmhiuCmWAYsLwgLYrrT9rAqvTySfuCCrgsWz8wxMXUS9Tb9iVMvcRbvFcAHGkMD5Kx8koh4GquNGNTfohfk7pgjhaPCdXpoba/*)"
],
"expected_keys": [
"8b42cd4776376c82791b494155151f56c2d7b471e0c7a526a7ce60dd872e3867",
"ebd252ca0877aae09b9d058219682775aa3cbcd049c12f07832f2cf6a3b51708"
]
},
{
"description": "Root used both bare and derived is excluded",
"descriptors": [
"wsh(or_i(pk(tpubDEPBvXvhta3pjVaKokqC3eeMQnszj9ehFaA2zD5nSdkaccwGAizu8jVB2NeSpvmP2P52MBoZvNCixqXRJnTyXx51FQzARR63tjxQSyP3Btw/0/*),pk(tpubDEPBvXvhta3pjVaKokqC3eeMQnszj9ehFaA2zD5nSdkaccwGAizu8jVB2NeSpvmP2P52MBoZvNCixqXRJnTyXx51FQzARR63tjxQSyP3Btw)))"
],
"expected_keys": null
},
{
"description": "Xpub root (03ebd252ca0877aae09b9d058219682775aa3cbcd049c12f07832f2cf6a3b51708) excluded by an opposite-parity literal in another descriptor set",
"descriptors": [
"tr(tpubDEPBvXvhta3pjVaKokqC3eeMQnszj9ehFaA2zD5nSdkaccwGAizu8jVB2NeSpvmP2P52MBoZvNCixqXRJnTyXx51FQzARR63tjxQSyP3Btw/*)",
"wpkh(02ebd252ca0877aae09b9d058219682775aa3cbcd049c12f07832f2cf6a3b51708)"
],
"expected_keys": null
},
{
"description": "MuSig participant exposed in a script leaf",
"descriptors": [
"tr(musig(tpubDC5FSnBiZDMmhiuCmWAYsLwgLYrrT9rAqvTySfuCCrgsWz8wxMXUS9Tb9iVMvcRbvFcAHGkMD5Kx8koh4GquNGNTfohfk7pgjhaPCdXpoba,tpubDEPBvXvhta3pjVaKokqC3eeMQnszj9ehFaA2zD5nSdkaccwGAizu8jVB2NeSpvmP2P52MBoZvNCixqXRJnTyXx51FQzARR63tjxQSyP3Btw)/0/*,pk(tpubDC5FSnBiZDMmhiuCmWAYsLwgLYrrT9rAqvTySfuCCrgsWz8wxMXUS9Tb9iVMvcRbvFcAHGkMD5Kx8koh4GquNGNTfohfk7pgjhaPCdXpoba))"
],
"expected_keys": [
"ebd252ca0877aae09b9d058219682775aa3cbcd049c12f07832f2cf6a3b51708"
]
}
]