{"number":138,"title":"Compact Encryption Scheme for Non-seed Wallet Data","authors":["Pyth"],"status":"Draft","type":"Specification","layer":"Applications","created":"2026-05-11","license":"BSD-2-Clause","version":"0.1.3","requires":[32,340,380,388,389,390],"replaces":[],"replacedBy":[],"discussion":["https://delvingbitcoin.org/t/a-simple-backup-scheme-for-wallet-accounts/1607","https://groups.google.com/g/bitcoindev/c/5NgJbpVDgEc/m/TtGK9sF9BgAJ","https://github.com/bitcoin/bips/pull/1951"],"abstract":"This BIP defines a compact encryption scheme for output script descriptors (BIP-0380), wallet policies (BIP-0388), and other wallet metadata. The payload must not contain any private key material. Users can store encrypted backups on untrusted media or cloud services without leaking addresses, script structures, or cosigner counts. The encryption key derives from the lexicographically-sorted public keys in the descriptor, allowing any keyholder to decrypt without additional secrets. Though designed for descriptors and policies, the scheme works equally well for labels and backup metadata.","eli5":"Specifies a compact way to encrypt wallet backup details, such as descriptors (a recipe describing which addresses a wallet uses), without including any private keys. Anyone holding one of the wallet's keys can decrypt it, so users can store backups on cloud services without revealing their addresses or multisig setup.","categories":["signatures"],"filename":"bip-0138.md","githubUrl":"https://github.com/bitcoin/bips/blob/master/bip-0138.md","format":"markdown","readingMinutes":18,"inbound":0,"revisions":44,"impact":65,"core":false,"references":[],"lastModified":"2026-09-23","html":"<h2 id=\"introduction\">Introduction</h2>\n<h3 id=\"abstract\">Abstract</h3>\n<p>This BIP defines a compact encryption scheme for <strong>output script descriptors</strong> (BIP-0380),\n<strong>wallet policies</strong> (BIP-0388), and other wallet metadata.\nThe payload must not contain any private key material.</p>\n<p>Users can store encrypted backups on untrusted media or cloud services without leaking\naddresses, script structures, or cosigner counts. The encryption key derives from the\nlexicographically-sorted public keys in the descriptor, allowing any keyholder to decrypt\nwithout additional secrets.</p>\n<p>Though designed for descriptors and policies, the scheme works equally well for labels\nand backup metadata.</p>\n<h3 id=\"copyright\">Copyright</h3>\n<p>This BIP is licensed under the BSD 2-Clause License.<br>Redistribution and use in source and binary forms, with or without modification, are\npermitted provided that the above copyright notice and this permission notice appear\nin all copies.</p>\n<h3 id=\"motivation\">Motivation</h3>\n<p>Losing the <strong>wallet descriptor</strong> (or <strong>wallet policy</strong>) is almost as catastrophic as\nlosing the seed itself. The seed lets you sign, but the descriptor maps you to your coins.\nFor multisig or miniscript wallets, keys alone are insufficient: without the descriptor, you\ncan&#39;t reconstruct the script.</p>\n<p>Multisig setups can be designed to retain access to coins even if one of the\nseeds is lost, for example a 3-of-3 MuSig2 keypath with a script path that lets\n2-of-3 recover. But when one seed is lost, its public key may also be lost,\nrendering the coins inaccessible. This risk is not intuitive.</p>\n<p>Offline storage of descriptors has two practical obstacles:</p>\n<ol>\n<li><p><strong>Descriptors are hard to store offline.</strong><br>Descriptors can be much longer than a 12/24-word seed. Paper and steel backups\nbecome impractical or error-prone, while USB sticks and other offline digital\nstorage solutions degrade over time and are unlikely to survive flood or fire.</p>\n</li>\n<li><p><strong>Online redundancy carries privacy risk.</strong><br>Phones and cloud storage solve the length problem but expose your wallet\nstructure. Plaintext descriptors leak your pubkeys and script details.\nCloud storage is often unencrypted, and even cloud encryption could be compromised,\ndepending on (often opaque) implementation details. Its security also reduces to\nthat of the weakest device with cloud access. Each copy increases the attack surface.</p>\n</li>\n</ol>\n<p>This BIP therefore proposes an <strong>encrypted</strong>, compact backup format that:</p>\n<ul>\n<li>can be <strong>safely stored in multiple places</strong>, including untrusted online services,  </li>\n<li>can be <strong>decrypted only by intended holders</strong> of specified <em>public</em> keys,</li>\n</ul>\n<p>See the original <a href=\"https://delvingbitcoin.org/t/a-simple-backup-scheme-for-wallet-accounts/1607/31\">Delving post</a>\nfor more background.</p>\n<h3 id=\"expected-properties\">Expected properties</h3>\n<ul>\n<li><strong>Encrypted</strong>: safe to store with untrusted cloud providers or backup services  </li>\n<li><strong>Access controlled</strong>:<ul>\n<li>only designated cosigners can decrypt, using their xpub</li>\n<li>can&#39;t be decrypted using public keys revealed on chain</li>\n</ul>\n</li>\n<li><strong>Easy to implement</strong>:<ul>\n<li>it should not require any sophisticated tools/libraries</li>\n<li>it should not require access to private key material, which secure signing systems may not yield</li>\n</ul>\n</li>\n<li><strong>Vendor-neutral</strong>: works with any hardware signer</li>\n</ul>\n<h3 id=\"scope\">Scope</h3>\n<p>This proposal targets output script descriptors (BIP-0380) and policies (BIP-0388), but the\nscheme also works for labels (BIP-0329) and other wallet metadata like\nwallet backup metadata (BIP-0139).</p>\n<p>Private key material MUST be removed before encrypting any payload.\nThis is because the use of <em>public key</em> material for decryption makes the\nscheme unsuitable for storing private key material.</p>\n<h2 id=\"specification\">Specification</h2>\n<p>Note: in the following sections, the operator ⊕ refers to the bitwise XOR operation.</p>\n<h3 id=\"secret-generation\">Secret generation</h3>\n<ul>\n<li>Let $p_1, p_2, \\dots, p_n$, be the distinct public keys across all descriptor\nand policy sets and all content items in the payload, in\nincreasing lexicographical order. The scheme is defined for any $n \\geq 1$,\nin particular it supports single-signature descriptors ($n = 1$). Each $p_i$\nis the x-only-normalized root public key of one <em>allowed</em> key expression\n(see <a href=\"#descriptor-key-requirements\">Descriptor key requirements</a>).</li>\n<li>Let $s$ = tagged_hash(&quot;BIP138_DECRYPTION_SECRET&quot;, $p_1$ | $p_2$ | ... | $p_n$)</li>\n<li>Let $s_i$ = tagged_hash(&quot;BIP138_INDIVIDUAL_SECRET&quot;, $p_i$)</li>\n<li>Let $c_i$ = $s$ ⊕ $s_i$</li>\n</ul>\n<p>where tagged_hash(tag, m) = sha256(sha256(tag) | sha256(tag) | m) is the tagged\nhash construction from <a href=\"/bip/340#design\">BIP340</a>.</p>\n<p>Because $s$ and $s_i$ use distinct domain-separation tags, $s \\neq s_i$ and\ntherefore $c_i$ is never the all-zero string.</p>\n<p>The <a href=\"#descriptor-key-requirements\">Descriptor key requirements</a> exclude\nkeys exposed by literal or bare-xpub expressions in the backed-up scripts.\nImplementations MUST exclude the key with x coordinate\n<code>50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0</code> (the BIP341 NUMS\npoint). Applications MAY exclude any further key they know to be public.</p>\n<p>Applications that exclude keys beyond the NUMS point SHOULD document which keys they\nexclude, so that users know which keys cannot open the backup. A cosigner holding an\nexcluded key will simply fail to decrypt, while the cosigners holding the keys that\nremain in ${p_1, \\dots, p_n}$ can still decrypt the backup.</p>\n<p><strong>Note:</strong> A key is <em>publicly known</em> when a third party can learn it without the wallet\nowner disclosing it. There is no registry of such keys. In practice they come from two\nsources: the blockchain, and well-known constants.</p>\n<p><strong>Warning:</strong> An xpub can be known to a third party without ever appearing on chain.\nSome single-signature wallets, such as the Ledger and Trezor desktop apps, send the\nBIP44/49/84/86 account xpub to a server, the server then derive every key from\nthat xpub. For a single-signature descriptor this leaks little the server does not\nalready know, but reusing such an xpub as a key of a multisig descriptor lets that\nserver decrypt every backup of the multisig. Users SHOULD build a multisig from\naccounts whose xpub was never sent to such a server, such as BIP48 or BIP87 accounts.</p>\n<h3 id=\"descriptor-key-requirements\">Descriptor key requirements</h3>\n<p>Outside <code>musig()</code>, only key expressions of the extended-public-key type with a\ntrailing derivation step or wildcard contribute to ${p_1, \\dots, p_n}$. Without\nthat derivation, the xpub&#39;s root pubkey, used to seed $s$, would also be\nthe on-chain pubkey of every spend, so observing one spend would let\nanyone recompute $s$ and decrypt the backup.[^trailing-derivation] The\nrule generalizes to any network prefix (<code>xpub</code>/<code>tpub</code>/<code>Vpub</code>/...).</p>\n<p>[^trailing-derivation]: <strong>Why require trailing derivation?</strong>\n    Any trailing derivation step, or the implicit child derivation forced by\n    a wildcard, breaks the identity between the xpub root pubkey and the\n    on-chain pubkey. Fixed-derivation expressions like <code>xpub.../0/5</code> are\n    allowed because the on-chain key (<code>xpub/0/5</code>) already differs from the\n    encryption seed (the xpub root). Outside <code>musig()</code>, literal pubkeys and\n    bare xpubs are disallowed for the same reason: the literal value is exactly\n    what goes on-chain, so $s$ would become recoverable from a single observed spend.</p>\n<p>Allowed forms (origin information <code>[...]</code> is optional and orthogonal):</p>\n<table>\n<thead>\n<tr>\n<th>Form</th>\n<th>Example</th>\n</tr>\n</thead>\n<tbody><tr>\n<td><code>&lt;xpub&gt;/&lt;path&gt;</code> (fixed derivation, no wildcard)</td>\n<td><code>xpub.../0/5</code></td>\n</tr>\n<tr>\n<td><code>&lt;xpub&gt;/*</code> (wildcard only)</td>\n<td><code>xpub.../*</code></td>\n</tr>\n<tr>\n<td><code>&lt;xpub&gt;/&lt;path&gt;/*</code> (fixed derivation followed by a wildcard)</td>\n<td><code>xpub.../0/*</code></td>\n</tr>\n<tr>\n<td><code>&lt;xpub&gt;/&lt;a;b;...&gt;</code> (multipath, no wildcard)</td>\n<td><code>xpub.../&lt;0;1&gt;</code></td>\n</tr>\n<tr>\n<td><code>&lt;xpub&gt;/&lt;a;b;...&gt;/*</code> (multipath followed by a wildcard)</td>\n<td><code>xpub.../&lt;0;1&gt;/*</code></td>\n</tr>\n<tr>\n<td><code>&lt;xpub&gt;</code> (only as a <code>musig()</code> participant)</td>\n<td><code>xpub...</code></td>\n</tr>\n</tbody></table>\n<p>Within a <a href=\"/bip/390\">BIP390</a> <code>musig()</code> expression, participant xpubs\nare allowed with or without trailing derivation: the aggregate on-chain key\ndoes not reveal the individual participant keys. For encryption, use each\nparticipant&#39;s xpub root rather than the aggregate key. Literal public-key\nparticipants remain excluded.</p>\n<p>A candidate root MUST be excluded if its x-coordinate matches a literal key\nor a bare xpub root used outside <code>musig()</code> in any descriptor or resolved\npolicy in the payload. For example,\n<code>wsh(or_i(pk(X/0/*),pk(X)))</code> exposes the root of xpub <code>X</code> on spending, so that\nroot must be excluded even though <code>X/0/*</code> is otherwise eligible.</p>\n<p>Implementations:</p>\n<ul>\n<li>MUST exclude every other form (literal pubkeys, bare xpubs outside <code>musig()</code>,\n...) from ${p_1, \\dots, p_n}$.</li>\n<li>MUST refuse to encode a backup if the resulting set is empty.</li>\n<li>MUST make the user aware of each excluded expression and candidate root,\nsince its holder may be unable to decrypt the backup with that key.</li>\n</ul>\n<h3 id=\"key-normalization\">Key Normalization</h3>\n<p>For each allowed expression, take the root extended public key (ignoring\norigin information, the trailing derivation path, the wildcard, and any\nmultipath specifiers) and extract its x-coordinate. The result is the\n32-byte <strong>x-only public key</strong> $p_i$.[^x-only]</p>\n<p>[^x-only]: <strong>Why x-only keys?</strong>\n    X-only public keys are 32 bytes, a natural size for cryptographic operations.\n    This format is also used in BIP340 (Schnorr signatures) and BIP341 (Taproot).</p>\n<h3 id=\"encryption\">Encryption</h3>\n<p>The format uses CHACHA20_POLY1305 (RFC 8439) as the encryption algorithm,\nwith a 96-bit random nonce and a 128-bit authentication tag to provide confidentiality\nand integrity.[^chacha-default]</p>\n<p>[^chacha-default]: <strong>Why CHACHA20-POLY1305 ?</strong>\n    ChaCha20-Poly1305 is already used in Bitcoin Core (e.g., BIP324) and is widely\n    available in cryptographic libraries. It performs well in software without\n    hardware acceleration, making it suitable for hardware wallets and embedded devices.</p>\n<ul>\n<li>let $nonce$ = random(96 bits)</li>\n<li>let $ciphertext$ = encrypt($payload$, $secret$, $nonce$, $aad$)</li>\n</ul>\n<p>The additional authenticated data ($aad$) is empty.</p>\n<p>The $nonce$ MUST NOT be all zero. If the random source yields an all-zero nonce,\nthe encoder MUST generate a new one.</p>\n<h3 id=\"decryption\">Decryption</h3>\n<p>In order to decrypt the payload of a backup, the owner of a certain public key p\ncomputes:</p>\n<ul>\n<li>let $s_i$ = tagged_hash(&quot;BIP138_INDIVIDUAL_SECRET&quot;, $p$)</li>\n<li>for each <code>individual_secret_i</code> generate <code>reconstructed_secret_i</code> =\n<code>individual_secret_i</code> ⊕ <code>si</code></li>\n<li>for each <code>reconstructed_secret_i</code> process $payload$ =\ndecrypt($ciphertext$, $secret$, $nonce$, $aad$)</li>\n</ul>\n<p>Decryption will succeed if and only if <strong>p</strong> was one of the keys in the\ndescriptor/wallet policy.</p>\n<h3 id=\"encoding\">Encoding</h3>\n<p>The encrypted backup must be encoded as follows:</p>\n<p><code>MAGIC</code> <code>VERSION</code> <code>DERIVATION_PATHS</code> <code>INDIVIDUAL_SECRETS</code> <code>ENCRYPTION</code>\n<code>ENCRYPTED_PAYLOAD</code></p>\n<h4 id=\"magic\">Magic</h4>\n<p><code>MAGIC</code>: 6 bytes which are ASCII/UTF-8 representation of <strong>BIP138</strong>.</p>\n<h4 id=\"version\">Version</h4>\n<p><code>VERSION</code>: 1 byte unsigned integer representing the format version. The current\nspecification defines version <code>0x01</code>.</p>\n<h4 id=\"derivation-paths\">Derivation Paths</h4>\n<p>Derivation paths are optional; they can be useful to simplify the recovery process\nif one has used a non-common derivation path to derive his key.[^derivation-optional]</p>\n<p>All implementations that can fetch xpubs from a signing device SHOULD try the following\ncommon paths automatically:</p>\n<ul>\n<li><code>m/44h/&lt;coin&gt;h/{0..9}h</code></li>\n<li><code>m/49h/&lt;coin&gt;h/{0..9}h</code></li>\n<li><code>m/84h/&lt;coin&gt;h/{0..9}h</code></li>\n<li><code>m/86h/&lt;coin&gt;h/{0..9}h</code></li>\n<li><code>m/87h/&lt;coin&gt;h/{0..9}h</code></li>\n<li><code>m/48h/&lt;coin&gt;h/{0..9}h/1h</code></li>\n<li><code>m/48h/&lt;coin&gt;h/{0..9}h/2h</code></li>\n</ul>\n<p><code>&lt;coin&gt;</code> is the BIP44 coin type of the network being recovered: <code>0</code> for mainnet\nand <code>1</code> for test networks. <code>{0..9}h</code> covers accounts 0 through 9.</p>\n<p>Some signing devices can fail or require confirmation when fetching xpubs for\nsome of these paths. This list is not exhaustive: an implementation MAY treat a\npath as allowed to fail for any device it supports, in particular\n<code>m/87h/&lt;coin&gt;h/{0..9}h</code>, which is widely under-supported. Implementations SHOULD\nat least classify these:[^common-derivation-paths]</p>\n<ul>\n<li>BitBox02: <code>m/44h/&lt;coin&gt;h/{0..9}h</code>, <code>m/87h/&lt;coin&gt;h/{0..9}h</code></li>\n<li>Ledger: <code>m/87h/&lt;coin&gt;h/{0..9}h</code></li>\n</ul>\n<p>If fetching an xpub for one of these common paths fails or times out and\ndecryption fails, implementations SHOULD warn the user.</p>\n<p>[^derivation-optional]: <strong>Why are derivation paths optional?</strong>\n    When standard derivation paths are used, they are easily discoverable, making\n    them straightforward to brute-force. Omitting them enhances privacy by reducing\n    the information shared publicly about the descriptor scheme.</p>\n<p>[^common-derivation-paths]: <strong>Why this restricted list?</strong>\n    The list covers common account paths for the network being recovered, accounts 0\n    through 9. Some signing devices reject or display some of these paths before\n    exporting an xpub, so implementations should treat the listed paths for that\n    device as optional rather than aborting recovery.</p>\n<p><code>DERIVATION_PATH</code> follows this format:</p>\n<p><code>COUNT</code><br><code>CHILD_COUNT</code> <code>CHILD</code> <code>...</code> <code>CHILD</code><br><code>...</code><br><code>CHILD_COUNT</code> <code>CHILD</code> <code>...</code> <code>CHILD</code></p>\n<p><code>COUNT</code>: 1-byte unsigned integer (0–255) indicating how many derivation paths are\nincluded.<br><code>CHILD_COUNT</code>: 1-byte unsigned integer (1–255) indicating how many children are in\nthe current path.<br><code>CHILD</code>: 4-byte big-endian unsigned integer representing a child index per BIP-32.</p>\n<p>The derivation-path vector SHOULD be encoded in lexicographic order. This avoids\nleaking information through implementation-specific ordering. The vector SHOULD NOT\ncontain duplicates. Implementations SHOULD deduplicate paths during encoding or\nparsing.</p>\n<h4 id=\"individual-secrets\">Individual Secrets</h4>\n<p>At least one individual secret must be supplied.[^no-fingerprints]</p>\n<p>[^no-fingerprints]: <strong>Why no fingerprints in plaintext encoding?</strong>\n    Including fingerprints would leak direct information about the descriptor\n    participants, which compromises privacy.</p>\n<p>The <code>INDIVIDUAL_SECRETS</code> section follows this format:</p>\n<p><code>COUNT</code><br><code>INDIVIDUAL_SECRET</code><br><code>INDIVIDUAL_SECRET</code></p>\n<p><code>COUNT</code>: 1-byte unsigned integer (1–255) indicating how many secrets are included.<br><code>INDIVIDUAL_SECRET</code>: 32-byte serialization of the derived individual secret.</p>\n<p>The individual secrets vector SHOULD be encoded in lexicographic order. This avoids\nleaking information through implementation-specific ordering. The vector SHOULD NOT\ncontain duplicates. Implementations SHOULD deduplicate secrets during encoding or\nparsing.</p>\n<p>Encoders SHOULD append random decoy <code>INDIVIDUAL_SECRET</code> entries to hide the exact\nnumber of real decryption keys. The total count SHOULD be rounded up to the\nsmallest bucket greater than or equal to the real count, starting at 5 and doubling\nfor each following bucket: 5, 10, 20, and so on. The bucket sequence saturates at\nthe 255 <code>COUNT</code> limit: when the smallest fitting bucket would exceed 255, encoders\nSHOULD pad to 255 instead. Decoders do not distinguish real\nentries from decoys; they try each entry until one decrypts the payload.</p>\n<h4 id=\"encryption-1\">Encryption</h4>\n<p><code>ENCRYPTION</code>: 1-byte unsigned integer identifying the encryption algorithm.</p>\n<table>\n<thead>\n<tr>\n<th align=\"left\">Value</th>\n<th align=\"left\">Definition</th>\n</tr>\n</thead>\n<tbody><tr>\n<td align=\"left\">0x00</td>\n<td align=\"left\">Reserved</td>\n</tr>\n<tr>\n<td align=\"left\">0x01</td>\n<td align=\"left\">CHACHA20_POLY1305</td>\n</tr>\n</tbody></table>\n<h4 id=\"payload-size-limits\">Payload Size Limits</h4>\n<p>CHACHA20_POLY1305 (per RFC 8439) supports plaintext up to 2^38 - 64 bytes.\nImplementations MAY impose stricter limits based on platform constraints\n(e.g., limiting to 2^32 - 1 bytes on 32-bit architectures).</p>\n<p>Implementations MUST reject empty payloads (i.e. zero content items).</p>\n<h4 id=\"ciphertext\">Ciphertext</h4>\n<p><code>CIPHERTEXT</code> is the encrypted data resulting from encryption of <code>PAYLOAD</code> with algorithm\ndefined in <code>ENCRYPTION</code> where <code>PAYLOAD</code> is encoded following this format:</p>\n<p><code>CONTENT_TYPE</code> <code>CONTENT_LENGTH</code> <code>CONTENT</code> (<code>CONTENT_TYPE</code> <code>CONTENT_LENGTH</code> <code>CONTENT</code> ...) (<code>PADDING</code>)</p>\n<p><code>CONTENT_LENGTH</code>: variable-length integer representing the length of <code>CONTENT</code> in bytes.\nIt MUST be present.</p>\n<p><code>CONTENT</code>: the <code>CONTENT_LENGTH</code> bytes of payload data.</p>\n<p><code>PADDING</code>: OPTIONAL bytes after the final <code>CONTENT</code>, up to the end of the decrypted\n<code>PAYLOAD</code>. Parsers MUST consume exactly <code>CONTENT_LENGTH</code> bytes of each <code>CONTENT</code>. The padding\nbytes are reserved for size padding (see Padding) and/or vendor-specific data, the same\nway trailing bytes after <code>CIPHERTEXT</code> are reserved and ignored.</p>\n<h4 id=\"padding\">Padding</h4>\n<p>Backups that are updated over time can leak information through their size even when the\ncontents are encrypted. A wallet that uploads a new backup after every received transaction\ncan reveal activity to the storage provider through changing payload sizes. This is relevant\nfor mutable payloads such as BIP-329 or BIP-0139.[^padding-privacy]</p>\n<p>Padding is OPTIONAL and is an encoder concern only: decoders ignore the <code>PADDING</code> bytes and\nMUST NOT validate any bucket. Because the padding sits inside <code>CIPHERTEXT</code>, the\n<code>ENCRYPTED_PAYLOAD</code> <code>LENGTH</code> reveals only the padded size, not the real <code>PAYLOAD</code> size.</p>\n<p>Encoders that pad SHOULD zero-fill <code>PAYLOAD</code> up to the smallest bucket <code>S_n</code> that fits it,\nwith <code>S_0 = 10240</code> (10 KiB) and <code>S_n = floor(S_0 * (5 / 4)^n)</code>. Payloads of 10 KiB or less\nare padded to 10 KiB. This keeps padding overhead under 25% above the smallest fitting bucket\nwhile coarsening the observable size. Padding is RECOMMENDED for mutable payloads and\nunnecessary for static ones such as BIP-380 descriptors and BIP-388 wallet policies.</p>\n<p>[^padding-privacy]: <strong>Why pad inside the ciphertext?</strong>\n    Padding the encrypted payload, rather than appending bytes after the backup, hides the\n    real payload size from anyone who parses the backup, not just from someone who measures\n    the file size. The size field a parser sees is the padded <code>ENCRYPTED_PAYLOAD</code> <code>LENGTH</code>.</p>\n<h4 id=\"integer-encodings\">Integer Encodings</h4>\n<p>All variable-length integers are encoded as\n<a href=\"https://en.bitcoin.it/wiki/Protocol_documentation#Variable_length_integer\">compact size</a>.</p>\n<h4 id=\"content-type\">Content Type</h4>\n<p><code>CONTENT_TYPE</code> is a variable length field defining the type of the <code>CONTENT</code> that follows\nit. It follows this format:</p>\n<p><code>TYPE</code> (<code>TYPE_LENGTH</code>) <code>TYPE_PARAMS</code></p>\n<p>A <code>PAYLOAD</code> carries one or more <code>CONTENT_TYPE CONTENT_LENGTH CONTENT</code> items, each <code>CONTENT_TYPE</code>\ndescribing the <code>CONTENT</code> immediately following it. The sequence ends at the first\n<code>TYPE</code> byte equal to <code>0x00</code>, or at the end of the <code>PAYLOAD</code>, whichever comes first; all\nremaining bytes are <code>PADDING</code>. A <code>PAYLOAD</code> MUST contain at least one item (see\n<a href=\"#payload-size-limits\">Payload Size Limits</a>).</p>\n<p><code>TYPE</code>: 1-byte unsigned integer identifying how to interpret <code>TYPE_PARAMS</code>.</p>\n<table>\n<thead>\n<tr>\n<th align=\"left\">Value</th>\n<th align=\"left\">Definition</th>\n</tr>\n</thead>\n<tbody><tr>\n<td align=\"left\">0x00</td>\n<td align=\"left\">End of content items; padding follows</td>\n</tr>\n<tr>\n<td align=\"left\">0x01</td>\n<td align=\"left\">BIP Number (big-endian uint16)</td>\n</tr>\n<tr>\n<td align=\"left\">0x02</td>\n<td align=\"left\">Vendor-Specific Opaque Tag</td>\n</tr>\n<tr>\n<td align=\"left\">0x03</td>\n<td align=\"left\">String</td>\n</tr>\n</tbody></table>\n<p><code>TYPE_LENGTH</code>: variable-length integer representing the length of <code>TYPE_PARAMS</code> in bytes.</p>\n<p>For all <code>TYPE</code> values except <code>0x00</code> and <code>0x01</code>, <code>TYPE_LENGTH</code> MUST be present.[^length-required]</p>\n<p>[^length-required]: <strong>Why is <code>TYPE_LENGTH</code> mandatory?</strong>\n    <code>TYPE_LENGTH</code> is what lets a parser skip a content type it does not implement and still\n    read the items that follow; without it, the parser cannot know where <code>TYPE_PARAMS</code> ends.\n    A string note placed before a descriptor, for example, must not stop an\n    implementation that only handles descriptors from recovering that descriptor. A\n    type whose <code>TYPE_PARAMS</code> is always empty still carries a zero <code>TYPE_LENGTH</code> for this reason.\n    <code>0x01</code> is exempt because every implementation handles it, so it is never skipped\n    blindly. <code>0x00</code> is a terminator rather than a content item.</p>\n<p><code>TYPE_PARAMS</code>: variable-length field whose encoding depends on <code>TYPE</code>.</p>\n<p>For <code>TYPE</code> values defined above:</p>\n<ul>\n<li>0x00: parsers MUST stop immediately and treat the remaining bytes as padding.</li>\n<li>0x01: <code>TYPE_LENGTH</code> MUST be omitted and <code>TYPE_PARAMS</code> is a 2-byte big-endian unsigned integer\nrepresenting the BIP number that defines it.</li>\n<li>0x02: <code>TYPE_PARAMS</code> MUST be <code>TYPE_LENGTH</code> bytes of opaque, vendor-specific data.</li>\n<li>0x03: <code>TYPE_PARAMS</code> MUST be empty, and the following <code>CONTENT</code> is the string itself,\nwhich MUST be valid UTF-8.</li>\n</ul>\n<p>For all <code>TYPE</code> values except <code>0x00</code> and <code>0x01</code>, parsers MUST reject <code>CONTENT_TYPE</code> if <code>TYPE_LENGTH</code> exceeds\nthe remaining payload bytes.</p>\n<p>For an unknown <code>TYPE</code> less than <code>0x80</code>, parsers MUST consume its <code>TYPE_LENGTH</code> bytes of\n<code>TYPE_PARAMS</code>, treat the content type as unknown, consume the following payload\n<code>CONTENT_LENGTH</code> and <code>CONTENT</code>, and continue with the next item.</p>\n<p>For an unknown <code>TYPE</code> greater than or equal to <code>0x80</code>, parsers MUST reject the\npayload.[^type-upgrade]</p>\n<p>[^type-upgrade]: <strong>Why the 0x80 threshold?</strong>\n    The <code>TYPE &gt;= 0x80</code> rule keeps the encoding upgradeable. A future version can\n    define a new content type at or above <code>0x80</code> that older parsers reject rather\n    than misread, while types below <code>0x80</code> stay backward compatible.</p>\n<h4 id=\"bip380-descriptor-backup-content\">BIP380 Descriptor Backup Content</h4>\n<p>When <code>CONTENT_TYPE</code> is <code>TYPE = 0x01</code> with <code>TYPE_PARAMS = 0x017c</code> (BIP380), <code>CONTENT</code> is a\nUTF-8 BIP380 descriptor backup. It is either a single bare descriptor string, or\na JSON descriptor backup document (for several descriptors) when the first\ncharacter is <code>{</code>.</p>\n<p>Test vectors are in\n<a href=\"https://github.com/bitcoin/bips/blob/master/bip-0138/test_vectors/bip380_descriptor_backup.json\"><code>bip380_descriptor_backup.json</code></a>.</p>\n<p>Descriptor strings MUST NOT contain private key material and SHOULD include a\nchecksum.</p>\n<h5>JSON Descriptor Backup Documents</h5>\n<p>The descriptor backup document is a JSON object with the following fields:</p>\n<ul>\n<li><code>version</code>: integer. This specification defines version <code>1</code>.</li>\n<li><code>descriptor_sets</code>: array of descriptor set objects.</li>\n</ul>\n<p>Each descriptor set describes BIP380 output script descriptors belonging to one\nlogical account or script family.</p>\n<h5>Descriptor Set Fields</h5>\n<p><code>descriptor</code> is a required string containing a BIP380 output script descriptor.</p>\n<p>For BIP389 multipath descriptors, <code>/&lt;0;1&gt;</code> means receive and change,\nrespectively. The <code>change_descriptor</code> field MUST NOT be used.</p>\n<p>For descriptors without BIP389 multipath key expressions, <code>descriptor</code> is the\nreceive descriptor. The optional <code>change_descriptor</code> string can be omitted for a\nreceive-only set.</p>\n<p>If optional boolean <code>archived</code> is <code>true</code>, importing wallets SHOULD NOT use the\ndescriptor set for new address generation.</p>\n<p><code>range</code> is an optional two-element array <code>[start, end]</code>, inclusive, describing\nthe <a href=\"/bip/32\">BIP32</a> non-hardened child indexes covered by the\ndescriptor set, with <code>start &lt;= end</code>.</p>\n<p><code>birth_time</code> is an optional integer Unix timestamp in seconds, indicating a\nlower bound for when the descriptor set may have received funds. Importing\nwallets MAY use this value as a scanning hint.\nIf <code>0</code> or omitted, no lower bound is known. Importers SHOULD scan from the wallet\nbirthday if known, otherwise from genesis.</p>\n<h4 id=\"bip388-wallet-policy-backup-content\">BIP388 Wallet Policy Backup Content</h4>\n<p>When <code>CONTENT_TYPE</code> is <code>TYPE = 0x01</code> with <code>TYPE_PARAMS = 0x0184</code> (BIP388), <code>CONTENT</code> is a\nUTF-8 JSON wallet policy backup document. A BIP388 wallet policy is a descriptor\ntemplate plus a vector of key information items, as defined in BIP388.</p>\n<p>Test vectors are in\n<a href=\"https://github.com/bitcoin/bips/blob/master/bip-0138/test_vectors/bip388.json\"><code>bip388.json</code></a>.</p>\n<p>The document is one of two forms:</p>\n<ul>\n<li>A single policy, a JSON object <code>{ &quot;keys&quot;: [...], &quot;policy&quot;: &quot;&lt;template&gt;&quot; }</code>.</li>\n<li>Multiple policies, a JSON object <code>{ &quot;version&quot;: 1, &quot;policy_sets&quot;: [...] }</code>.</li>\n</ul>\n<p>Parsers select the form by structure: an object with a <code>policy_sets</code> field is the\nmultiple form, an object with a <code>policy</code> field is the single form.</p>\n<h5>Policy Fields</h5>\n<p><code>keys</code> is a required array of BIP388 key information items, each a serialized\nextended public key with optional key origin (<code>[fingerprint/path]xpub</code>). It MUST\ncontain at least one key. Keys MUST NOT contain private key material.</p>\n<p><code>policy</code> is a required non-empty string containing a BIP388 wallet descriptor\ntemplate, with <code>@i</code> key placeholders referring to <code>keys</code>.</p>\n<h5>Policy Set Fields</h5>\n<p>A policy set has the same <code>keys</code> and <code>policy</code> fields as the single form, plus the\noptional metadata fields:</p>\n<p>If optional boolean <code>archived</code> is <code>true</code>, importing wallets SHOULD NOT use the\npolicy for new address generation.</p>\n<p><code>range</code> is an optional two-element array <code>[start, end]</code>, inclusive, describing\nthe <a href=\"/bip/32\">BIP32</a> non-hardened child indexes covered by the\npolicy, with <code>start &lt;= end</code>.</p>\n<p><code>birth_time</code> is an optional integer Unix timestamp in seconds, indicating a lower\nbound for when the policy may have received funds. Importing wallets MAY use this\nvalue as a scanning hint.\nIf <code>0</code> or omitted, no lower bound is known. Importers SHOULD scan from the wallet\nbirthday if known, otherwise from genesis.</p>\n<h5>Multiple Policies Document</h5>\n<p>The multiple form is a JSON object with the following fields:</p>\n<ul>\n<li><code>version</code>: integer. This specification defines version <code>1</code>.</li>\n<li><code>policy_sets</code>: array of policy set objects.</li>\n</ul>\n<h4 id=\"encrypted-payload\">Encrypted Payload</h4>\n<p><code>ENCRYPTED_PAYLOAD</code> follows this format:</p>\n<p><code>NONCE</code> <code>LENGTH</code> <code>CIPHERTEXT</code></p>\n<p><code>NONCE</code>: 12-byte (96-bit) nonce. Parsers MUST reject a backup whose <code>NONCE</code> is all zero.\n<code>LENGTH</code>: variable-length integer representing ciphertext length.\n<code>CIPHERTEXT</code>: variable-length ciphertext.</p>\n<p>Note: <code>CIPHERTEXT</code> is followed by the end of the <code>ENCRYPTED_PAYLOAD</code> section.<br>Compliant parsers MUST stop reading after consuming <code>LENGTH</code> bytes of ciphertext;\nadditional trailing bytes are reserved for vendor-specific extensions and MUST\nbe ignored.</p>\n<h3 id=\"text-representation\">Text Representation</h3>\n<p>Implementations SHOULD encode and decode the backup using Base64 (RFC 4648).[^psbt-base64]</p>\n<p>[^psbt-base64]: <strong>Why Base64?</strong>\n    PSBT (BIP174) is commonly exchanged as a Base64 string, so wallet software\n    likely already supports this representation.</p>\n<h3 id=\"file-extension\">File Extension</h3>\n<p>Backups saved to a file SHOULD use the <code>.bip138</code> file extension for the raw binary\nencoding and the <code>.txt</code> extension for the Base64 text representation, so that the\nextension tells implementations which encoding to expect.</p>\n<h2 id=\"rationale\">Rationale</h2>\n<p>See footnotes throughout the specification for design rationale.</p>\n<h3 id=\"future-extensions\">Future Extensions</h3>\n<p>The version field enables possible future enhancements:</p>\n<ul>\n<li>Additional encryption algorithms</li>\n<li>Support for threshold-based decryption</li>\n<li>Hiding number of participants</li>\n<li>bech32m export</li>\n</ul>\n<h3 id=\"implementation\">Implementation</h3>\n<ul>\n<li>Rust <a href=\"https://github.com/pythcoiner/bip138\">implementation</a></li>\n</ul>\n<h3 id=\"test-vectors\">Test Vectors</h3>\n<p><a href=\"https://github.com/bitcoin/bips/blob/master/bip-0138/test_vectors/recipient_keys.json\">recipient_keys.json</a> contains\ntest vectors for recipient selection. <code>descriptors</code> lists the payload&#39;s descriptor\nstrings; <code>expected_keys</code> lists the sorted, deduplicated x-only recipient roots\nbefore application-specific exclusions. <code>null</code> requires refusing to encode.</p>\n<p><a href=\"https://github.com/bitcoin/bips/blob/master/bip-0138/test_vectors/content_type.json\">content_type.json</a> contains test\nvectors for content types serialisations.<br><a href=\"https://github.com/bitcoin/bips/blob/master/bip-0138/test_vectors/payload.json\">payload.json</a> contains test vectors for payload parsing.\n<code>payload</code> and each item&#39;s <code>content</code> are hexadecimal bytes; <code>type</code> is the numeric\ntype byte, and <code>items</code> lists the content items before the terminator.</p>\n<p><a href=\"https://github.com/bitcoin/bips/blob/master/bip-0138/test_vectors/derivation_path.json\">derivation_path.json</a> contains\ntest vectors for derivation paths serialisations.<br><a href=\"https://github.com/bitcoin/bips/blob/master/bip-0138/test_vectors/individual_secrets.json\">individual_secrets.json</a>\ncontains test vectors for individual secrets serialization.<br><a href=\"https://github.com/bitcoin/bips/blob/master/bip-0138/test_vectors/encryption_secret.json\">encryption_secret.json</a>\ncontains test vectors for generation of encryption secret.<br><a href=\"https://github.com/bitcoin/bips/blob/master/bip-0138/test_vectors/chacha20poly1305_encryption.json\">chacha20poly1305_encryption.json</a>\ncontains test vectors for ciphertexts generated using CHACHA20-POLY1305.\n<a href=\"https://github.com/bitcoin/bips/blob/master/bip-0138/test_vectors/encrypted_backup.json\">encrypted_backup.json</a>\ncontains test vectors for generation of complete encrypted backups, including\nBIP380 and BIP388 content, a multi-content payload, and an all-zero-nonce backup\nthat parsers MUST reject.<br><a href=\"https://github.com/bitcoin/bips/blob/master/bip-0138/test_vectors/bip380_descriptor_backup.json\">bip380_descriptor_backup.json</a>\ncontains test vectors for BIP380 descriptor backup documents.<br><a href=\"https://github.com/bitcoin/bips/blob/master/bip-0138/test_vectors/bip388.json\">bip388.json</a>\ncontains test vectors for BIP388 wallet policy backup documents.  </p>\n<h2 id=\"backward-compatibility\">Backward Compatibility</h2>\n<p>This BIP defines a new format and changes no existing one. Liana wallet uses an early\nversion of this BIP, which is not compatible: its magic is <code>BEB</code> rather than <code>BIP138</code>.</p>\n<h2 id=\"acknowledgements\">Acknowledgements</h2>\n<p>This BIP builds on the backup scheme proposed by @bigspider on\n<a href=\"https://delvingbitcoin.org/t/a-simple-backup-scheme-for-wallet-accounts/1607\">Delving Bitcoin</a>,\nwho also suggested the payload padding design.</p>\n<p>Thanks to @Sjors for extensive reviews, many design contributions to the payload\nencoding, and a proof-of-concept implementation on top of Bitcoin Core. Thanks\nalso to @murchandamus, @jonatack, @craigraw, @jp1ac4, and @torkelrogstad for\ntheir reviews and suggestions.</p>\n<h2 id=\"changelog\">Changelog</h2>\n<ul>\n<li><strong>0.1.3</strong> (2026-09-24):<ul>\n<li>Rename, generalize and expand the key-selection test vectors.</li>\n<li>Clarify MuSig participant eligibility and recipient selection across the payload.</li>\n<li>Exclude roots exposed by another key expression.</li>\n</ul>\n</li>\n<li><strong>0.1.2</strong> (2026-09-24):<ul>\n<li>Specify empty AEAD associated data.</li>\n<li>Clarify that <code>0x00</code> ends payload parsing and add test vectors.</li>\n</ul>\n</li>\n<li><strong>0.1.1</strong> (2026-09-23):<ul>\n<li>Clarify derivation range bounds and zero or omitted birth-time semantics for descriptors and policies.</li>\n<li>Clarify receive-only descriptor sets and add a corresponding test vector.</li>\n</ul>\n</li>\n<li><strong>0.1.0</strong> (2026-09-21):<ul>\n<li>Initial publication.</li>\n</ul>\n</li>\n</ul>\n","toc":[{"id":"introduction","title":"Introduction","level":2},{"id":"abstract","title":"Abstract","level":3},{"id":"copyright","title":"Copyright","level":3},{"id":"motivation","title":"Motivation","level":3},{"id":"expected-properties","title":"Expected properties","level":3},{"id":"scope","title":"Scope","level":3},{"id":"specification","title":"Specification","level":2},{"id":"secret-generation","title":"Secret generation","level":3},{"id":"descriptor-key-requirements","title":"Descriptor key requirements","level":3},{"id":"key-normalization","title":"Key Normalization","level":3},{"id":"encryption","title":"Encryption","level":3},{"id":"decryption","title":"Decryption","level":3},{"id":"encoding","title":"Encoding","level":3},{"id":"magic","title":"Magic","level":4},{"id":"version","title":"Version","level":4},{"id":"derivation-paths","title":"Derivation Paths","level":4},{"id":"individual-secrets","title":"Individual Secrets","level":4},{"id":"encryption-1","title":"Encryption","level":4},{"id":"payload-size-limits","title":"Payload Size Limits","level":4},{"id":"ciphertext","title":"Ciphertext","level":4},{"id":"padding","title":"Padding","level":4},{"id":"integer-encodings","title":"Integer Encodings","level":4},{"id":"content-type","title":"Content Type","level":4},{"id":"bip380-descriptor-backup-content","title":"BIP380 Descriptor Backup Content","level":4},{"id":"bip388-wallet-policy-backup-content","title":"BIP388 Wallet Policy Backup Content","level":4},{"id":"encrypted-payload","title":"Encrypted Payload","level":4},{"id":"text-representation","title":"Text Representation","level":3},{"id":"file-extension","title":"File Extension","level":3},{"id":"rationale","title":"Rationale","level":2},{"id":"future-extensions","title":"Future Extensions","level":3},{"id":"implementation","title":"Implementation","level":3},{"id":"test-vectors","title":"Test Vectors","level":3},{"id":"backward-compatibility","title":"Backward Compatibility","level":2},{"id":"acknowledgements","title":"Acknowledgements","level":2},{"id":"changelog","title":"Changelog","level":2}],"history":{"totalCommits":44,"firstCommit":"2026-05-11T12:26:05-07:00","lastUpdated":"2026-09-23T13:10:00+02:00","events":[{"sha":"346008db8943cb90c1e091eaac8277066d4dbee7","date":"2026-09-23T13:10:00+02:00","author":"Sjors Provoost","message":"bip138: record recipients clarifications in changelog","url":"https://github.com/bitcoin/bips/commit/346008db8943cb90c1e091eaac8277066d4dbee7","kind":"edit"},{"sha":"299442b7ded6c58c64fce45f6972795a2d9f3109","date":"2026-09-22T14:52:10+02:00","author":"Sjors Provoost","message":"bip138: exclude roots exposed by another expression","url":"https://github.com/bitcoin/bips/commit/299442b7ded6c58c64fce45f6972795a2d9f3109","kind":"edit"},{"sha":"bde776ecb8afc18e0f320d53c6f516105a18d6e8","date":"2026-09-22T14:52:10+02:00","author":"Sjors Provoost","message":"bip138: collect and deduplicate recipient keys across the backup","url":"https://github.com/bitcoin/bips/commit/bde776ecb8afc18e0f320d53c6f516105a18d6e8","kind":"edit"},{"sha":"11a3be74588576bbf20953afed3a2265da3873cd","date":"2026-09-22T14:52:10+02:00","author":"Sjors Provoost","message":"bip138: clarify MuSig participant eligibility","url":"https://github.com/bitcoin/bips/commit/11a3be74588576bbf20953afed3a2265da3873cd","kind":"edit"},{"sha":"5fc05e2b17ce8272360b8b6774ac12c907c3e231","date":"2026-09-23T15:21:20+02:00","author":"Sjors Provoost","message":"bip138: generalize key-selection test vectors","url":"https://github.com/bitcoin/bips/commit/5fc05e2b17ce8272360b8b6774ac12c907c3e231","kind":"edit"},{"sha":"62dc1c4e8f4c907a2932318cbd578896cf872590","date":"2026-09-23T13:10:31+02:00","author":"Sjors Provoost","message":"bip138: record encoding clarifications in changelog","url":"https://github.com/bitcoin/bips/commit/62dc1c4e8f4c907a2932318cbd578896cf872590","kind":"edit"},{"sha":"bf64a12098691b7ba32444584300addfeec9f445","date":"2026-09-23T14:31:54+02:00","author":"Sjors Provoost","message":"bip138: clarify rejection of empty payloads","url":"https://github.com/bitcoin/bips/commit/bf64a12098691b7ba32444584300addfeec9f445","kind":"edit"},{"sha":"aa098559bf39633a2b424ce60a4b962d6fbe5c93","date":"2026-09-23T14:31:54+02:00","author":"Sjors Provoost","message":"bip138: clarify that 0x00 ends payload parsing","url":"https://github.com/bitcoin/bips/commit/aa098559bf39633a2b424ce60a4b962d6fbe5c93","kind":"edit"},{"sha":"0f8c26b7c20bab5a58f098ac81f1bb86974c5934","date":"2026-09-22T14:52:10+02:00","author":"Sjors Provoost","message":"bip138: specify empty associated data","url":"https://github.com/bitcoin/bips/commit/0f8c26b7c20bab5a58f098ac81f1bb86974c5934","kind":"edit"},{"sha":"8c1314949ec8b3d3bad718488f99f2c9fd9d0b33","date":"2026-09-23T13:10:38+02:00","author":"Sjors Provoost","message":"bip138: record metadata clarifications in changelog","url":"https://github.com/bitcoin/bips/commit/8c1314949ec8b3d3bad718488f99f2c9fd9d0b33","kind":"edit"},{"sha":"ffa6bf4944c4c883970b8a9b6e7386459d5efd0d","date":"2026-09-23T13:32:01+02:00","author":"Sjors Provoost","message":"bip138: clarify zero and omitted birth times","url":"https://github.com/bitcoin/bips/commit/ffa6bf4944c4c883970b8a9b6e7386459d5efd0d","kind":"edit"},{"sha":"399ea2a09155130e9519c58f85f3cf9fa5215f84","date":"2026-09-23T13:32:00+02:00","author":"Sjors Provoost","message":"bip138: clarify derivation ranges using BIP32","url":"https://github.com/bitcoin/bips/commit/399ea2a09155130e9519c58f85f3cf9fa5215f84","kind":"edit"},{"sha":"51995cc228a6c65f9a74dd24962fe9562a472d83","date":"2026-09-23T13:32:00+02:00","author":"Sjors Provoost","message":"bip138: clarify receive-only descriptor sets","url":"https://github.com/bitcoin/bips/commit/51995cc228a6c65f9a74dd24962fe9562a472d83","kind":"edit"},{"sha":"bf63783c10649a3ae33d4c63d3e54fa1e04d1951","date":"2026-09-23T13:09:10+02:00","author":"Sjors Provoost","message":"bip138: introduce changelog at version 0.1.0","url":"https://github.com/bitcoin/bips/commit/bf63783c10649a3ae33d4c63d3e54fa1e04d1951","kind":"edit"},{"sha":"5af62cba9958a519218bcad8a0aae9e2090bb5bd","date":"2026-08-18T15:15:05+00:00","author":"pythcoiner","message":"bip138: address review","url":"https://github.com/bitcoin/bips/commit/5af62cba9958a519218bcad8a0aae9e2090bb5bd","kind":"edit"},{"sha":"1ad6f11811b2e852be7099cbc956cde3cdb1965c","date":"2026-08-18T11:38:06+00:00","author":"pythcoiner","message":"bip138: address review","url":"https://github.com/bitcoin/bips/commit/1ad6f11811b2e852be7099cbc956cde3cdb1965c","kind":"edit"},{"sha":"c21f642b832ea30fd25d236fa50145a4f391643e","date":"2026-08-18T08:38:49+00:00","author":"pythcoiner","message":"bip138: address review","url":"https://github.com/bitcoin/bips/commit/c21f642b832ea30fd25d236fa50145a4f391643e","kind":"edit"},{"sha":"0fbc187b99eaee624b6b7b34df629d1dac5e0be9","date":"2026-08-07T09:32:01-04:00","author":"pythcoiner","message":"bip138: address review","url":"https://github.com/bitcoin/bips/commit/0fbc187b99eaee624b6b7b34df629d1dac5e0be9","kind":"edit"},{"sha":"65b4c38a0237e1cfeb2c80f845ca4547d09c5403","date":"2026-07-16T08:32:47-04:00","author":"pythcoiner","message":"bip138: address review","url":"https://github.com/bitcoin/bips/commit/65b4c38a0237e1cfeb2c80f845ca4547d09c5403","kind":"edit"},{"sha":"1b1513ebafe1005700a7937787eff136b74582e3","date":"2026-07-16T08:30:15-04:00","author":"pythcoiner","message":"bip138: add acknowledgements","url":"https://github.com/bitcoin/bips/commit/1b1513ebafe1005700a7937787eff136b74582e3","kind":"edit"},{"sha":"e1b35253bc5c54fc29fe04f8fe69cf1f05959f04","date":"2026-07-16T08:30:00-04:00","author":"pythcoiner","message":"bip138: add Requires header","url":"https://github.com/bitcoin/bips/commit/e1b35253bc5c54fc29fe04f8fe69cf1f05959f04","kind":"edit"},{"sha":"5d441163be8a62212de11697866adb7d961a48f4","date":"2026-07-16T08:06:52-04:00","author":"pythcoiner","message":"bip138: address review","url":"https://github.com/bitcoin/bips/commit/5d441163be8a62212de11697866adb7d961a48f4","kind":"edit"},{"sha":"d041c01f2fc41997342e855d070050e88355e1f4","date":"2026-07-16T02:31:20-04:00","author":"pythcoiner","message":"bip138: add a backward compatibility section","url":"https://github.com/bitcoin/bips/commit/d041c01f2fc41997342e855d070050e88355e1f4","kind":"edit"},{"sha":"f79d0862b89ee3bc5d16aa624772487362212ae2","date":"2026-07-16T02:19:27-04:00","author":"pythcoiner","message":"bip138: address review","url":"https://github.com/bitcoin/bips/commit/f79d0862b89ee3bc5d16aa624772487362212ae2","kind":"edit"},{"sha":"1a157a641837c90343fc8d191cb249430eaee222","date":"2026-07-15T02:32:55-04:00","author":"pythcoiner","message":"bip-138 saturate the decoy bucket at the count limit","url":"https://github.com/bitcoin/bips/commit/1a157a641837c90343fc8d191cb249430eaee222","kind":"edit"},{"sha":"86e10c907eb0e7c470cf8d0a6e9cfb2908757185","date":"2026-07-15T01:16:08-04:00","author":"pythcoiner","message":"bip-138 recommend sorting and deduplicating derivation paths","url":"https://github.com/bitcoin/bips/commit/86e10c907eb0e7c470cf8d0a6e9cfb2908757185","kind":"edit"},{"sha":"c1170d463475c3c8d952ed310bffb5488f949196","date":"2026-07-15T00:28:36-04:00","author":"pythcoiner","message":"bip-138 require warning about excluded key expressions","url":"https://github.com/bitcoin/bips/commit/c1170d463475c3c8d952ed310bffb5488f949196","kind":"edit"},{"sha":"317b8fdb2fb493bd571283521ee8f4e2efb8896b","date":"2026-07-15T00:03:38-04:00","author":"pythcoiner","message":"bip-138 reference the CHACHA20-POLY1305 rationale footnote","url":"https://github.com/bitcoin/bips/commit/317b8fdb2fb493bd571283521ee8f4e2efb8896b","kind":"edit"},{"sha":"1de39be4e389e6dfc55517f12daa156cfeab2f0f","date":"2026-07-14T23:24:16-04:00","author":"pythcoiner","message":"bip-138 document why content LENGTH is mandatory","url":"https://github.com/bitcoin/bips/commit/1de39be4e389e6dfc55517f12daa156cfeab2f0f","kind":"edit"},{"sha":"9f1be26e2f8f5ddd40f80e0b41cc1896e8ba098e","date":"2026-07-08T00:55:16-04:00","author":"pythcoiner","message":"bip-138 recommend sorting and deduplicating individual secrets","url":"https://github.com/bitcoin/bips/commit/9f1be26e2f8f5ddd40f80e0b41cc1896e8ba098e","kind":"edit"},{"sha":"1e776e7a7219a6507724bf008a3fc8037a47390d","date":"2026-07-14T22:49:33-04:00","author":"pythcoiner","message":"bip-138 pad individual secrets with decoys","url":"https://github.com/bitcoin/bips/commit/1e776e7a7219a6507724bf008a3fc8037a47390d","kind":"edit"},{"sha":"fb52eaab03ea1f5341d1f52e63478fc7e49a8a24","date":"2026-07-14T22:49:24-04:00","author":"pythcoiner","message":"bip-138 document common derivation paths to try automatically","url":"https://github.com/bitcoin/bips/commit/fb52eaab03ea1f5341d1f52e63478fc7e49a8a24","kind":"edit"},{"sha":"1358003bc8f71881cc2b6ba15e5a61680b4ecbfd","date":"2026-07-14T22:48:57-04:00","author":"pythcoiner","message":"bip-138 add string content type","url":"https://github.com/bitcoin/bips/commit/1358003bc8f71881cc2b6ba15e5a61680b4ecbfd","kind":"edit"},{"sha":"86f5c28f7c6784eb6a4b0a67a4e44b5114734687","date":"2026-07-14T23:50:57-04:00","author":"pythcoiner","message":"bip-138 treat content type 0x00 as the end of content items","url":"https://github.com/bitcoin/bips/commit/86f5c28f7c6784eb6a4b0a67a4e44b5114734687","kind":"edit"},{"sha":"56deb75d626ab0548dd1dad4877a6cff01011b7e","date":"2026-06-30T10:56:17-04:00","author":"pythcoiner","message":"bip-138: allow multiple content items per payload","url":"https://github.com/bitcoin/bips/commit/56deb75d626ab0548dd1dad4877a6cff01011b7e","kind":"edit"},{"sha":"99217c680f31792e576838d6879365303e7f7cbf","date":"2026-06-18T10:43:37-04:00","author":"pythcoiner","message":"bip-138: reference BIP-0139 for wallet backup metadata","url":"https://github.com/bitcoin/bips/commit/99217c680f31792e576838d6879365303e7f7cbf","kind":"edit"},{"sha":"c6b04e23dfb959be3675cefbf06d97f06e235f08","date":"2026-06-18T07:07:45-04:00","author":"pythcoiner","message":"bip-138: BIP380 content is a bare descriptor or a JSON document","url":"https://github.com/bitcoin/bips/commit/c6b04e23dfb959be3675cefbf06d97f06e235f08","kind":"edit"},{"sha":"d115620881878d8431e466562e44f84578f9e82e","date":"2026-06-18T06:36:38-04:00","author":"pythcoiner","message":"bip-138: make BIP380 backup content JSON-only","url":"https://github.com/bitcoin/bips/commit/d115620881878d8431e466562e44f84578f9e82e","kind":"edit"},{"sha":"810b4df73ef161e91b5ef10819e589e21e90b9ab","date":"2026-06-18T04:38:58-04:00","author":"pythcoiner","message":"bip-138: specify BIP388 wallet policy backup content","url":"https://github.com/bitcoin/bips/commit/810b4df73ef161e91b5ef10819e589e21e90b9ab","kind":"edit"},{"sha":"9e2a585a9ad2bc01d1114725f822953e1ae1ed81","date":"2026-06-18T03:44:25-04:00","author":"pythcoiner","message":"bip-138: specify BIP380 descriptor backup content","url":"https://github.com/bitcoin/bips/commit/9e2a585a9ad2bc01d1114725f822953e1ae1ed81","kind":"edit"},{"sha":"b7ba2840a980ffde6831bc270fe804e041b1e638","date":"2026-06-18T03:02:17-04:00","author":"pythcoiner","message":"bip-138: clarify CONTENT is a single TLV and forbid all-zero nonce","url":"https://github.com/bitcoin/bips/commit/b7ba2840a980ffde6831bc270fe804e041b1e638","kind":"edit"},{"sha":"72d8a9533f209d0f8e5e51223a2f7a17b635a01e","date":"2026-06-18T00:11:49-04:00","author":"pythcoiner","message":"bip-0138: use assigned BIP number 138 for magic and domain separation tags","url":"https://github.com/bitcoin/bips/commit/72d8a9533f209d0f8e5e51223a2f7a17b635a01e","kind":"edit"},{"sha":"7707cf2935d9b2d033fa3eaea597d76c9b912a93","date":"2026-06-17T22:45:43-04:00","author":"pythcoiner","message":"bip-0138: make PLAINTEXT LENGTH mandatory and add optional payload padding","url":"https://github.com/bitcoin/bips/commit/7707cf2935d9b2d033fa3eaea597d76c9b912a93","kind":"edit"},{"sha":"e9858e8bbee3fbf12510f7af9816772a10a82392","date":"2026-05-11T12:26:05-07:00","author":"Murch","message":"Assign BIP138","url":"https://github.com/bitcoin/bips/commit/e9858e8bbee3fbf12510f7af9816772a10a82392","kind":"edit"}]}}