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

Merge pull request #1951 from pythcoiner/encrypted_descriptor

BIP138: Compact Encryption Scheme for Non-seed Wallet Data
This commit is contained in:
Murch
2026-09-21 13:18:48 -07:00
committed by GitHub
11 changed files with 1931 additions and 0 deletions

View File

@@ -827,6 +827,13 @@ users (see also: [https://en.bitcoin.it/wiki/Economic_majority economic majority
| Christopher Gilliard
| Specification
| Deployed
|-
| [[bip-0138.md|138]]
| Applications
| Compact Encryption Scheme for Non-seed Wallet Data
| Pyth
| Specification
| Draft
|- style="background-color: #ffcfcf"
| [[bip-0140.mediawiki|140]]
| Consensus (soft fork)

619
bip-0138.md Normal file
View File

@@ -0,0 +1,619 @@
```
BIP: 138
Layer: Applications
Title: Compact Encryption Scheme for Non-seed Wallet Data
Authors: Pyth <pythcoiner@wizardsardine.com>
Status: Draft
Type: Specification
Assigned: 2026-05-11
License: BSD-2-Clause
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
Requires: 32, 340, 380, 388, 389
```
## Introduction
### 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.
### Copyright
This BIP is licensed under the BSD 2-Clause License.
Redistribution and use in source and binary forms, with or without modification, are
permitted provided that the above copyright notice and this permission notice appear
in all copies.
### Motivation
Losing the **wallet descriptor** (or **wallet policy**) is almost as catastrophic as
losing the seed itself. The seed lets you sign, but the descriptor maps you to your coins.
For multisig or miniscript wallets, keys alone are insufficient: without the descriptor, you
can't reconstruct the script.
Multisig setups can be designed to retain access to coins even if one of the
seeds is lost, for example a 3-of-3 MuSig2 keypath with a script path that lets
2-of-3 recover. But when one seed is lost, its public key may also be lost,
rendering the coins inaccessible. This risk is not intuitive.
Offline storage of descriptors has two practical obstacles:
1. **Descriptors are hard to store offline.**
Descriptors can be much longer than a 12/24-word seed. Paper and steel backups
become impractical or error-prone, while USB sticks and other offline digital
storage solutions degrade over time and are unlikely to survive flood or fire.
2. **Online redundancy carries privacy risk.**
Phones and cloud storage solve the length problem but expose your wallet
structure. Plaintext descriptors leak your pubkeys and script details.
Cloud storage is often unencrypted, and even cloud encryption could be compromised,
depending on (often opaque) implementation details. Its security also reduces to
that of the weakest device with cloud access. Each copy increases the attack surface.
This BIP therefore proposes an **encrypted**, compact backup format that:
* can be **safely stored in multiple places**, including untrusted online services,
* can be **decrypted only by intended holders** of specified _public_ keys,
See the original [Delving post](https://delvingbitcoin.org/t/a-simple-backup-scheme-for-wallet-accounts/1607/31)
for more background.
### Expected properties
* **Encrypted**: safe to store with untrusted cloud providers or backup services
* **Access controlled**:
* only designated cosigners can decrypt, using their xpub
* can't be decrypted using public keys revealed on chain
* **Easy to implement**:
* it should not require any sophisticated tools/libraries
* it should not require access to private key material, which secure signing systems may not yield
* **Vendor-neutral**: works with any hardware signer
### Scope
This proposal targets output script descriptors (BIP-0380) and policies (BIP-0388), but the
scheme also works for labels (BIP-0329) and other wallet metadata like
wallet backup metadata (BIP-0139).
Private key material MUST be removed before encrypting any payload.
This is because the use of _public key_ material for decryption makes the
scheme unsuitable for storing private key material.
## Specification
Note: in the following sections, the operator ⊕ refers to the bitwise XOR operation.
### Secret generation
- Let $p_1, p_2, \dots, p_n$, be the public keys in the descriptor/wallet policy, in
increasing lexicographical order. The scheme is defined for any $n \geq 1$,
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
(see [Descriptor key requirements](#descriptor-key-requirements)).
- Let $s$ = tagged_hash("BIP138_DECRYPTION_SECRET", $p_1$ | $p_2$ | ... | $p_n$)
- Let $s_i$ = tagged_hash("BIP138_INDIVIDUAL_SECRET", $p_i$)
- Let $c_i$ = $s$ ⊕ $s_i$
where tagged_hash(tag, m) = sha256(sha256(tag) | sha256(tag) | m) is the tagged
hash construction from [BIP340](bip-0340.mediawiki#design).
Because $s$ and $s_i$ use distinct domain-separation tags, $s \neq s_i$ and
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
[Descriptor key requirements](#descriptor-key-requirements).
Implementations MUST exclude the key with x coordinate
`50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0` (the BIP341 NUMS
point). Applications MAY exclude any further key they know to be public.
Applications that exclude keys beyond the NUMS point SHOULD document which keys they
exclude, so that users know which keys cannot open the backup. A cosigner holding an
excluded key will simply fail to decrypt, while the cosigners holding the keys that
remain in $\{p_1, \dots, p_n\}$ can still decrypt the backup.
**Note:** A key is *publicly known* when a third party can learn it without the wallet
owner disclosing it. There is no registry of such keys. In practice they come from two
sources: the blockchain, and well-known constants.
**Warning:** An xpub can be known to a third party without ever appearing on chain.
Some single-signature wallets, such as the Ledger and Trezor desktop apps, send the
BIP44/49/84/86 account xpub to a server, the server then derive every key from
that xpub. For a single-signature descriptor this leaks little the server does not
already know, but reusing such an xpub as a key of a multisig descriptor lets that
server decrypt every backup of the multisig. Users SHOULD build a multisig from
accounts whose xpub was never sent to such a server, such as BIP48 or BIP87 accounts.
### Descriptor key requirements
Only key expressions of the extended-public-key type with a 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
the on-chain pubkey of every spend, so observing one spend would let
anyone recompute $s$ and decrypt the backup.[^trailing-derivation] The
rule generalizes to any network prefix (`xpub`/`tpub`/`Vpub`/...).
[^trailing-derivation]: **Why require trailing derivation?**
Any trailing derivation step, or the implicit child derivation forced by
a wildcard, breaks the identity between the xpub root pubkey and the
on-chain pubkey. Fixed-derivation expressions like `xpub.../0/5` are
allowed because the on-chain key (`xpub/0/5`) already differs from the
encryption seed (the xpub root). Literal pubkeys and bare xpubs are
disallowed for the same reason: the literal value is exactly what goes
on-chain, so $s$ would become recoverable from a single observed spend.
Allowed forms (origin information `[...]` is optional and orthogonal):
| Form | Example |
|-------------------------------------------------------------|-------------------|
| `<xpub>/<path>` (fixed derivation, no wildcard) | `xpub.../0/5` |
| `<xpub>/*` (wildcard only) | `xpub.../*` |
| `<xpub>/<path>/*` (fixed derivation followed by a wildcard) | `xpub.../0/*` |
| `<xpub>/<a;b;...>` (multipath, no wildcard) | `xpub.../<0;1>` |
| `<xpub>/<a;b;...>/*` (multipath followed by a wildcard) | `xpub.../<0;1>/*` |
Implementations:
- MUST exclude every other form (literal pubkeys, bare xpubs, ...) from
$\{p_1, \dots, p_n\}$.
- MUST refuse to encode a backup if the resulting set is empty.
- MUST make the user aware of each excluded expression, since the
cosigner holding that key will be unable to decrypt the backup with
their key.
### Key Normalization
For each allowed expression, take the root extended public key (ignoring
origin information, the trailing derivation path, the wildcard, and any
multipath specifiers) and extract its x-coordinate. The result is the
32-byte **x-only public key** $p_i$.[^x-only]
[^x-only]: **Why x-only keys?**
X-only public keys are 32 bytes, a natural size for cryptographic operations.
This format is also used in BIP340 (Schnorr signatures) and BIP341 (Taproot).
### Encryption
The format uses CHACHA20_POLY1305 (RFC 8439) as the encryption algorithm,
with a 96-bit random nonce and a 128-bit authentication tag to provide confidentiality
and integrity.[^chacha-default]
[^chacha-default]: **Why CHACHA20-POLY1305 ?**
ChaCha20-Poly1305 is already used in Bitcoin Core (e.g., BIP324) and is widely
available in cryptographic libraries. It performs well in software without
hardware acceleration, making it suitable for hardware wallets and embedded devices.
* let $nonce$ = random(96 bits)
* let $ciphertext$ = encrypt($payload$, $secret$, $nonce$)
The $nonce$ MUST NOT be all zero. If the random source yields an all-zero nonce,
the encoder MUST generate a new one.
### Decryption
In order to decrypt the payload of a backup, the owner of a certain public key p
computes:
* let $s_i$ = tagged_hash("BIP138_INDIVIDUAL_SECRET", $p$)
* for each `individual_secret_i` generate `reconstructed_secret_i` =
`individual_secret_i` ⊕ `si`
* for each `reconstructed_secret_i` process $payload$ =
decrypt($ciphertext$, $secret$, $nonce$)
Decryption will succeed if and only if **p** was one of the keys in the
descriptor/wallet policy.
### Encoding
The encrypted backup must be encoded as follows:
`MAGIC` `VERSION` `DERIVATION_PATHS` `INDIVIDUAL_SECRETS` `ENCRYPTION`
`ENCRYPTED_PAYLOAD`
#### Magic
`MAGIC`: 6 bytes which are ASCII/UTF-8 representation of **BIP138**.
#### Version
`VERSION`: 1 byte unsigned integer representing the format version. The current
specification defines version `0x01`.
#### Derivation Paths
Derivation paths are optional; they can be useful to simplify the recovery process
if one has used a non-common derivation path to derive his key.[^derivation-optional]
All implementations that can fetch xpubs from a signing device SHOULD try the following
common paths automatically:
- `m/44h/<coin>h/{0..9}h`
- `m/49h/<coin>h/{0..9}h`
- `m/84h/<coin>h/{0..9}h`
- `m/86h/<coin>h/{0..9}h`
- `m/87h/<coin>h/{0..9}h`
- `m/48h/<coin>h/{0..9}h/1h`
- `m/48h/<coin>h/{0..9}h/2h`
`<coin>` is the BIP44 coin type of the network being recovered: `0` for mainnet
and `1` for test networks. `{0..9}h` covers accounts 0 through 9.
Some signing devices can fail or require confirmation when fetching xpubs for
some of these paths. This list is not exhaustive: an implementation MAY treat a
path as allowed to fail for any device it supports, in particular
`m/87h/<coin>h/{0..9}h`, which is widely under-supported. Implementations SHOULD
at least classify these:[^common-derivation-paths]
- BitBox02: `m/44h/<coin>h/{0..9}h`, `m/87h/<coin>h/{0..9}h`
- Ledger: `m/87h/<coin>h/{0..9}h`
If fetching an xpub for one of these common paths fails or times out and
decryption fails, implementations SHOULD warn the user.
[^derivation-optional]: **Why are derivation paths optional?**
When standard derivation paths are used, they are easily discoverable, making
them straightforward to brute-force. Omitting them enhances privacy by reducing
the information shared publicly about the descriptor scheme.
[^common-derivation-paths]: **Why this restricted list?**
The list covers common account paths for the network being recovered, accounts 0
through 9. Some signing devices reject or display some of these paths before
exporting an xpub, so implementations should treat the listed paths for that
device as optional rather than aborting recovery.
`DERIVATION_PATH` follows this format:
`COUNT`
`CHILD_COUNT` `CHILD` `...` `CHILD`
`...`
`CHILD_COUNT` `CHILD` `...` `CHILD`
`COUNT`: 1-byte unsigned integer (0–255) indicating how many derivation paths are
included.
`CHILD_COUNT`: 1-byte unsigned integer (1–255) indicating how many children are in
the current path.
`CHILD`: 4-byte big-endian unsigned integer representing a child index per BIP-32.
The derivation-path vector SHOULD be encoded in lexicographic order. This avoids
leaking information through implementation-specific ordering. The vector SHOULD NOT
contain duplicates. Implementations SHOULD deduplicate paths during encoding or
parsing.
#### Individual Secrets
At least one individual secret must be supplied.[^no-fingerprints]
[^no-fingerprints]: **Why no fingerprints in plaintext encoding?**
Including fingerprints would leak direct information about the descriptor
participants, which compromises privacy.
The `INDIVIDUAL_SECRETS` section follows this format:
`COUNT`
`INDIVIDUAL_SECRET`
`INDIVIDUAL_SECRET`
`COUNT`: 1-byte unsigned integer (1–255) indicating how many secrets are included.
`INDIVIDUAL_SECRET`: 32-byte serialization of the derived individual secret.
The individual secrets vector SHOULD be encoded in lexicographic order. This avoids
leaking information through implementation-specific ordering. The vector SHOULD NOT
contain duplicates. Implementations SHOULD deduplicate secrets during encoding or
parsing.
Encoders SHOULD append random decoy `INDIVIDUAL_SECRET` entries to hide the exact
number of real decryption keys. The total count SHOULD be rounded up to the
smallest bucket greater than or equal to the real count, starting at 5 and doubling
for each following bucket: 5, 10, 20, and so on. The bucket sequence saturates at
the 255 `COUNT` limit: when the smallest fitting bucket would exceed 255, encoders
SHOULD pad to 255 instead. Decoders do not distinguish real
entries from decoys; they try each entry until one decrypts the payload.
#### Encryption
`ENCRYPTION`: 1-byte unsigned integer identifying the encryption algorithm.
| Value | Definition |
|:-------|:---------------------------------------|
| 0x00 | Reserved |
| 0x01 | CHACHA20_POLY1305 |
#### Payload Size Limits
CHACHA20_POLY1305 (per RFC 8439) supports plaintext up to 2^38 - 64 bytes.
Implementations MAY impose stricter limits based on platform constraints
(e.g., limiting to 2^32 - 1 bytes on 32-bit architectures).
Implementations MUST reject empty payloads.
#### Ciphertext
`CIPHERTEXT` is the encrypted data resulting from encryption of `PAYLOAD` with algorithm
defined in `ENCRYPTION` where `PAYLOAD` is encoded following this format:
`CONTENT_TYPE` `CONTENT_LENGTH` `CONTENT` (`CONTENT_TYPE` `CONTENT_LENGTH` `CONTENT` ...) (`PADDING`)
`CONTENT_LENGTH`: variable-length integer representing the length of `CONTENT` in bytes.
It MUST be present.
`CONTENT`: the `CONTENT_LENGTH` bytes of payload data.
`PADDING`: OPTIONAL bytes after the final `CONTENT`, up to the end of the decrypted
`PAYLOAD`. Parsers MUST consume exactly `CONTENT_LENGTH` bytes of each `CONTENT`. The padding
bytes are reserved for size padding (see Padding) and/or vendor-specific data, the same
way trailing bytes after `CIPHERTEXT` are reserved and ignored.
#### Padding
Backups that are updated over time can leak information through their size even when the
contents are encrypted. A wallet that uploads a new backup after every received transaction
can reveal activity to the storage provider through changing payload sizes. This is relevant
for mutable payloads such as BIP-329 or BIP-0139.[^padding-privacy]
Padding is OPTIONAL and is an encoder concern only: decoders ignore the `PADDING` bytes and
MUST NOT validate any bucket. Because the padding sits inside `CIPHERTEXT`, the
`ENCRYPTED_PAYLOAD` `LENGTH` reveals only the padded size, not the real `PAYLOAD` size.
Encoders that pad SHOULD zero-fill `PAYLOAD` up to the smallest bucket `S_n` that fits it,
with `S_0 = 10240` (10 KiB) and `S_n = floor(S_0 * (5 / 4)^n)`. Payloads of 10 KiB or less
are padded to 10 KiB. This keeps padding overhead under 25% above the smallest fitting bucket
while coarsening the observable size. Padding is RECOMMENDED for mutable payloads and
unnecessary for static ones such as BIP-380 descriptors and BIP-388 wallet policies.
[^padding-privacy]: **Why pad inside the ciphertext?**
Padding the encrypted payload, rather than appending bytes after the backup, hides the
real payload size from anyone who parses the backup, not just from someone who measures
the file size. The size field a parser sees is the padded `ENCRYPTED_PAYLOAD` `LENGTH`.
#### Integer Encodings
All variable-length integers are encoded as
[compact size](https://en.bitcoin.it/wiki/Protocol_documentation#Variable_length_integer).
#### Content Type
`CONTENT_TYPE` is a variable length field defining the type of the `CONTENT` that follows
it. It follows this format:
`TYPE` (`TYPE_LENGTH`) `TYPE_PARAMS`
A `PAYLOAD` carries one or more `CONTENT_TYPE CONTENT_LENGTH CONTENT` items, each `CONTENT_TYPE`
describing the `CONTENT` immediately following it. The sequence ends at the first
`TYPE` byte equal to `0x00`, or at the end of the `PAYLOAD`, whichever comes first; all
remaining bytes are `PADDING`. A `PAYLOAD` MUST contain at least one item (see
[Payload Size Limits](#payload-size-limits)).
`TYPE`: 1-byte unsigned integer identifying how to interpret `TYPE_PARAMS`.
| Value | Definition |
|:-------|:---------------------------------------|
| 0x00 | End of content items; padding follows |
| 0x01 | BIP Number (big-endian uint16) |
| 0x02 | Vendor-Specific Opaque Tag |
| 0x03 | String |
`TYPE_LENGTH`: variable-length integer representing the length of `TYPE_PARAMS` in bytes.
For all `TYPE` values except `0x01`, `TYPE_LENGTH` MUST be present.[^length-required]
[^length-required]: **Why is `TYPE_LENGTH` mandatory?**
`TYPE_LENGTH` is what lets a parser skip a content type it does not implement and still
read the items that follow; without it, the parser cannot know where `TYPE_PARAMS` ends.
A string note placed before a descriptor, for example, must not stop an
implementation that only handles descriptors from recovering that descriptor. A
type whose `TYPE_PARAMS` is always empty still carries a zero `TYPE_LENGTH` for this reason.
`0x01` is exempt because every implementation handles it, so it is never skipped
blindly.
`TYPE_PARAMS`: variable-length field whose encoding depends on `TYPE`.
For `TYPE` values defined above:
- 0x00: parsers MUST stop reading content items and treat the remaining bytes as
padding.
- 0x01: `TYPE_LENGTH` MUST be omitted and `TYPE_PARAMS` is a 2-byte big-endian unsigned integer
representing the BIP number that defines it.
- 0x02: `TYPE_PARAMS` MUST be `TYPE_LENGTH` bytes of opaque, vendor-specific data.
- 0x03: `TYPE_PARAMS` MUST be empty, and the following `CONTENT` is the string itself,
which MUST be valid UTF-8.
For all `TYPE` values except `0x01`, parsers MUST reject `CONTENT_TYPE` if `TYPE_LENGTH` exceeds
the remaining payload bytes.
For an unknown `TYPE` less than `0x80`, parsers MUST consume its `TYPE_LENGTH` bytes of
`TYPE_PARAMS`, treat the content type as unknown, consume the following payload
`CONTENT_LENGTH` and `CONTENT`, and continue with the next item.
For an unknown `TYPE` greater than or equal to `0x80`, parsers MUST reject the
payload.[^type-upgrade]
[^type-upgrade]: **Why the 0x80 threshold?**
The `TYPE >= 0x80` rule keeps the encoding upgradeable. A future version can
define a new content type at or above `0x80` that older parsers reject rather
than misread, while types below `0x80` stay backward compatible.
#### BIP380 Descriptor Backup Content
When `CONTENT_TYPE` is `TYPE = 0x01` with `TYPE_PARAMS = 0x017c` (BIP380), `CONTENT` is a
UTF-8 BIP380 descriptor backup. It is either a single bare descriptor string, or
a JSON descriptor backup document (for several descriptors) when the first
character is `{`.
Test vectors are in
[`bip380_descriptor_backup.json`](./bip-0138/test_vectors/bip380_descriptor_backup.json).
Descriptor strings MUST NOT contain private key material and SHOULD include a
checksum.
##### JSON Descriptor Backup Documents
The descriptor backup document is a JSON object with the following fields:
- `version`: integer. This specification defines version `1`.
- `descriptor_sets`: array of descriptor set objects.
Each descriptor set describes BIP380 output script descriptors belonging to one
logical account or script family.
##### Descriptor Set Fields
`descriptor` is a required string containing a BIP380 output script descriptor.
For BIP389 multipath descriptors, `/<0;1>` means receive and change,
respectively. The `change_descriptor` field MUST NOT be used.
For descriptors without BIP389 multipath key expressions, `descriptor` is the
receive descriptor and `change_descriptor` is the change descriptor.
If optional boolean `archived` is `true`, importing wallets SHOULD NOT use the
descriptor set for new address generation.
`range` is an optional two-element array `[start, end]`, inclusive, describing
the ranged derivation indexes covered by the descriptor set.
`birth_time` is an optional integer Unix timestamp in seconds, indicating a
lower bound for when the descriptor set may have received funds. Importing
wallets MAY use this value as a scanning hint.
#### BIP388 Wallet Policy Backup Content
When `CONTENT_TYPE` is `TYPE = 0x01` with `TYPE_PARAMS = 0x0184` (BIP388), `CONTENT` is a
UTF-8 JSON wallet policy backup document. A BIP388 wallet policy is a descriptor
template plus a vector of key information items, as defined in BIP388.
Test vectors are in
[`bip388.json`](./bip-0138/test_vectors/bip388.json).
The document is one of two forms:
- A single policy, a JSON object `{ "keys": [...], "policy": "<template>" }`.
- Multiple policies, a JSON object `{ "version": 1, "policy_sets": [...] }`.
Parsers select the form by structure: an object with a `policy_sets` field is the
multiple form, an object with a `policy` field is the single form.
##### Policy Fields
`keys` is a required array of BIP388 key information items, each a serialized
extended public key with optional key origin (`[fingerprint/path]xpub`). It MUST
contain at least one key. Keys MUST NOT contain private key material.
`policy` is a required non-empty string containing a BIP388 wallet descriptor
template, with `@i` key placeholders referring to `keys`.
##### Policy Set Fields
A policy set has the same `keys` and `policy` fields as the single form, plus the
optional metadata fields:
If optional boolean `archived` is `true`, importing wallets SHOULD NOT use the
policy for new address generation.
`range` is an optional two-element array `[start, end]`, inclusive, describing the
ranged derivation indexes covered by the policy.
`birth_time` is an optional integer Unix timestamp in seconds, indicating a lower
bound for when the policy may have received funds. Importing wallets MAY use this
value as a scanning hint.
##### Multiple Policies Document
The multiple form is a JSON object with the following fields:
- `version`: integer. This specification defines version `1`.
- `policy_sets`: array of policy set objects.
#### Encrypted Payload
`ENCRYPTED_PAYLOAD` follows this format:
`NONCE` `LENGTH` `CIPHERTEXT`
`NONCE`: 12-byte (96-bit) nonce. Parsers MUST reject a backup whose `NONCE` is all zero.
`LENGTH`: variable-length integer representing ciphertext length.
`CIPHERTEXT`: variable-length ciphertext.
Note: `CIPHERTEXT` is followed by the end of the `ENCRYPTED_PAYLOAD` section.
Compliant parsers MUST stop reading after consuming `LENGTH` bytes of ciphertext;
additional trailing bytes are reserved for vendor-specific extensions and MUST
be ignored.
### Text Representation
Implementations SHOULD encode and decode the backup using Base64 (RFC 4648).[^psbt-base64]
[^psbt-base64]: **Why Base64?**
PSBT (BIP174) is commonly exchanged as a Base64 string, so wallet software
likely already supports this representation.
### File Extension
Backups saved to a file SHOULD use the `.bip138` file extension for the raw binary
encoding and the `.txt` extension for the Base64 text representation, so that the
extension tells implementations which encoding to expect.
## Rationale
See footnotes throughout the specification for design rationale.
### Future Extensions
The version field enables possible future enhancements:
- Additional encryption algorithms
- Support for threshold-based decryption
- Hiding number of participants
- bech32m export
### Implementation
- Rust [implementation](https://github.com/pythcoiner/bip138)
### Test Vectors
[key_types.json](./bip-0138/test_vectors/keys_types.json) contains test
vectors for key serialisations.
[content_type.json](./bip-0138/test_vectors/content_type.json) contains test
vectors for content types serialisations.
[derivation_path.json](./bip-0138/test_vectors/derivation_path.json) contains
test vectors for derivation paths serialisations.
[individual_secrets.json](./bip-0138/test_vectors/individual_secrets.json)
contains test vectors for individual secrets serialization.
[encryption_secret.json](./bip-0138/test_vectors/encryption_secret.json)
contains test vectors for generation of encryption secret.
[chacha20poly1305_encryption.json](./bip-0138/test_vectors/chacha20poly1305_encryption.json)
contains test vectors for ciphertexts generated using CHACHA20-POLY1305.
[encrypted_backup.json](./bip-0138/test_vectors/encrypted_backup.json)
contains test vectors for generation of complete encrypted backups, including
BIP380 and BIP388 content, a multi-content payload, and an all-zero-nonce backup
that parsers MUST reject.
[bip380_descriptor_backup.json](./bip-0138/test_vectors/bip380_descriptor_backup.json)
contains test vectors for BIP380 descriptor backup documents.
[bip388.json](./bip-0138/test_vectors/bip388.json)
contains test vectors for BIP388 wallet policy backup documents.
## Backward Compatibility
This BIP defines a new format and changes no existing one. Liana wallet uses an early
version of this BIP, which is not compatible: its magic is `BEB` rather than `BIP138`.
## Acknowledgements
This BIP builds on the backup scheme proposed by @bigspider on
[Delving Bitcoin](https://delvingbitcoin.org/t/a-simple-backup-scheme-for-wallet-accounts/1607),
who also suggested the payload padding design.
Thanks to @Sjors for extensive reviews, many design contributions to the payload
encoding, and a proof-of-concept implementation on top of Bitcoin Core. Thanks
also to @murchandamus, @jonatack, @craigraw, @jp1ac4, and @torkelrogstad for
their reviews and suggestions.

View File

@@ -0,0 +1,33 @@
[
{
"description": "Descriptor with change descriptor",
"valid": true,
"document": {
"version": 1,
"descriptor_sets": [
{
"archived": false,
"birth_time": 1710000000,
"range": [0, 999],
"descriptor": "wpkh([d34db33f/84h/1h/0h]tpubDC5FSnBiZDMmhiuCmWAYsLwgLYrrT9rAqvTySfuCCrgsWz8wxMXUS9Tb9iVMvcRbvFcAHGkMD5Kx8koh4GquNGNTfohfk7pgjhaPCdXpoba/0/*)",
"change_descriptor": "wpkh([d34db33f/84h/1h/0h]tpubDC5FSnBiZDMmhiuCmWAYsLwgLYrrT9rAqvTySfuCCrgsWz8wxMXUS9Tb9iVMvcRbvFcAHGkMD5Kx8koh4GquNGNTfohfk7pgjhaPCdXpoba/1/*)"
}
]
}
},
{
"description": "BIP389 multipath descriptor",
"valid": true,
"document": {
"version": 1,
"descriptor_sets": [
{
"archived": false,
"birth_time": 1710000000,
"range": [0, 999],
"descriptor": "wpkh([d34db33f/84h/1h/0h]tpubDC5FSnBiZDMmhiuCmWAYsLwgLYrrT9rAqvTySfuCCrgsWz8wxMXUS9Tb9iVMvcRbvFcAHGkMD5Kx8koh4GquNGNTfohfk7pgjhaPCdXpoba/<0;1>/*)"
}
]
}
}
]

View File

@@ -0,0 +1,92 @@
[
{
"description": "single pkh policy",
"valid": true,
"document": {
"keys": [
"[d34db33f/44'/0'/0']xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL"
],
"policy": "pkh(@0/**)"
}
},
{
"description": "multiple policy sets with metadata",
"valid": true,
"document": {
"version": 1,
"policy_sets": [
{
"keys": [
"[6738736c/48'/0'/0'/2']xpub6FC1fXFP1GXLX5TKtcjHGT4q89SDRehkQLtbKJ2PzWcvbBHtyDsJPLtpLtkGqYNYZdVVAjRQ5kug9CsapegmmeRutpP7PW4u4wVF9JfkDhw",
"[b2b1f0cf/48'/0'/0'/2']xpub6EWhjpPa6FqrcaPBuGBZRJVjzGJ1ZsMygRF26RwN932Vfkn1gyCiTbECVitBjRCkexEvetLdiqzTcYimmzYxyR1BZ79KNevgt61PDcukmC7"
],
"policy": "wsh(sortedmulti(2,@0/**,@1/**))",
"archived": true,
"range": [
0,
999
],
"birth_time": 1710000000
},
{
"keys": [
"[d34db33f/44'/0'/0']xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL"
],
"policy": "pkh(@0/**)"
}
]
}
},
{
"description": "version not one",
"valid": false,
"document": {
"version": 2,
"policy_sets": [
{
"keys": [
"[d34db33f/44'/0'/0']xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL"
],
"policy": "pkh(@0/**)"
}
]
}
},
{
"description": "missing policy",
"valid": false,
"document": {
"keys": [
"[d34db33f/44'/0'/0']xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL"
]
}
},
{
"description": "empty policy",
"valid": false,
"document": {
"keys": [
"[d34db33f/44'/0'/0']xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL"
],
"policy": ""
}
},
{
"description": "empty keys",
"valid": false,
"document": {
"keys": [],
"policy": "pkh(@0/**)"
}
},
{
"description": "single literal pubkey in keys",
"valid": false,
"document": {
"keys": [
"0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"
],
"policy": "pkh(@0/**)"
}
}
]

View File

@@ -0,0 +1,37 @@
[
{
"description": "Basic encryption with short plaintext",
"nonce": "000102030405060708090a0b",
"plaintext": "48656c6c6f",
"secret": "0000000000000000000000000000000000000000000000000000000000000000",
"ciphertext": "7df9cb9a0ac5851cc054b14d05f781127b2b0d31fa"
},
{
"description": "Empty plaintext should fail",
"nonce": "000102030405060708090a0b",
"plaintext": "",
"secret": "0000000000000000000000000000000000000000000000000000000000000000",
"ciphertext": null
},
{
"description": "Encryption with zeroed nonce should fail",
"nonce": "000000000000000000000000",
"plaintext": "00000000000000000000000000000000",
"secret": "0000000000000000000000000000000000000000000000000000000000000000",
"ciphertext": null
},
{
"description": "Encryption with all FFs",
"nonce": "ffffffffffffffffffffffff",
"plaintext": "ffffffffffffffffffffffffffffffff",
"secret": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"ciphertext": "22d8bfc313e141bd692c82cec7785b29a0e5d5014c0d3b2d3a8b00548cd8d221"
},
{
"description": "Longer plaintext",
"nonce": "0f1e2d3c4b5a69788796a5b4",
"plaintext": "546869732069732061206c6f6e67657220706c61696e746578742074686174207368756c6420626520656e637279707465642070726f7065726c792e",
"secret": "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef",
"ciphertext": "2af094190e2b43a02b8dd6bfc25a8833f84f81bc6f690d75f0214e466ef392616c4644bee65118c444a926e1e365b3a7ba0509a5636524eb4e5722f5926938f32e4df79237acb6dd4a6ccbc4"
}
]

View File

@@ -0,0 +1,82 @@
[
{
"description": "Bip 138",
"valid": true,
"content": "01008a"
},
{
"description": "Bip 380",
"valid": true,
"content": "01017c"
},
{
"description": "Bip 388",
"valid": true,
"content": "010184"
},
{
"description": "Bip 329",
"valid": true,
"content": "010149"
},
{
"description": "Bip 999",
"valid": true,
"content": "0103e7"
},
{
"description": "Bip max",
"valid": true,
"content": "01ffff"
},
{
"description": "Bip min",
"valid": true,
"content": "010000"
},
{
"description": "Propietary 00010203",
"valid": true,
"content": "020400010203"
},
{
"description": "String",
"valid": true,
"content": "0300"
},
{
"description": "TYPE 0x00 ends the content items",
"valid": false,
"content": "00"
},
{
"description": "Invalid BIP (insufficient bytes)",
"valid": false,
"content": "0100"
},
{
"description": "Invalid proprietary (missing data)",
"valid": false,
"content": "0201"
},
{
"description": "Invalid proprietary (TYPE_LENGTH exceeds payload)",
"valid": false,
"content": "020500"
},
{
"description": "Invalid string (metadata must be empty)",
"valid": false,
"content": "030161"
},
{
"description": "TYPE >= 0x80 stops parsing",
"valid": false,
"content": "ff"
},
{
"description": "TYPE >= 0x80 stops parsing",
"valid": false,
"content": "ff000000"
}
]

View File

@@ -0,0 +1,186 @@
[
{
"description": "Empty derivation paths",
"paths": [],
"expected": "00"
},
{
"description": "Single path with one child: m/0",
"paths": ["m/0"],
"expected": "010100000000"
},
{
"description": "Single path with hardened child: m/44'",
"paths": ["m/44'"],
"expected": "01018000002c"
},
{
"description": "Standard BIP-84 path: m/84'/0'/0'",
"paths": ["m/84'/0'/0'"],
"expected": "0103800000548000000080000000"
},
{
"description": "Mixed hardened and normal: m/0/1'/2/3'",
"paths": ["m/0/1'/2/3'"],
"expected": "010400000000800000010000000280000003"
},
{
"description": "Multiple paths: m/0/1'/2/3' and m/84'/0'/0'/2'",
"paths": ["m/0/1'/2/3'", "m/84'/0'/0'/2'"],
"expected": "0204000000008000000100000002800000030480000054800000008000000080000002"
},
{
"description": "Path with large indices: m/2147483647'/2147483646",
"paths": ["m/2147483647'/2147483646"],
"expected": "0102ffffffff7ffffffe"
},
{
"description": "Single child path: m/1",
"paths": ["m/1"],
"expected": "010100000001"
},
{
"description": "Path with max normal index: m/2147483647",
"paths": ["m/2147483647"],
"expected": "01017fffffff"
},
{
"description": "Path with multiple normal indices: m/0/1/2/3/4",
"paths": ["m/0/1/2/3/4"],
"expected": "01050000000000000001000000020000000300000004"
},
{
"description": "Path with all hardened: m/0'/1'/2'",
"paths": ["m/0'/1'/2'"],
"expected": "0103800000008000000180000002"
},
{
"description": "Two different single-child paths: m/0 and m/1",
"paths": ["m/0", "m/1"],
"expected": "0201000000000100000001"
},
{
"description": "Unsorted paths are sorted when encoded",
"paths": ["m/84'/0'/0'/2'", "m/0/1'/2/3'"],
"expected": "0204000000008000000100000002800000030480000054800000008000000080000002"
},
{
"description": "Duplicate paths are deduplicated",
"paths": ["m/1", "m/0", "m/1"],
"expected": "0201000000000100000001"
},
{
"description": "BIP-44 account 0: m/44'/0'/0'",
"paths": ["m/44'/0'/0'"],
"expected": "01038000002c8000000080000000"
},
{
"description": "BIP-49 account 0: m/49'/0'/0'",
"paths": ["m/49'/0'/0'"],
"expected": "0103800000318000000080000000"
},
{
"description": "Common fallback path: m/49'/0'/9'",
"paths": ["m/49'/0'/9'"],
"expected": "0103800000318000000080000009"
},
{
"description": "Common fallback path: m/84'/1'/9'",
"paths": ["m/84'/1'/9'"],
"expected": "0103800000548000000180000009"
},
{
"description": "Common fallback path: m/86'/1'/9'",
"paths": ["m/86'/1'/9'"],
"expected": "0103800000568000000180000009"
},
{
"description": "Fallible fallback path: m/87'/1'/9'",
"paths": ["m/87'/1'/9'"],
"expected": "0103800000578000000180000009"
},
{
"description": "Common fallback path: m/48'/0'/9'/1'",
"paths": ["m/48'/0'/9'/1'"],
"expected": "010480000030800000008000000980000001"
},
{
"description": "Common fallback path: m/48'/1'/9'/2'",
"paths": ["m/48'/1'/9'/2'"],
"expected": "010480000030800000018000000980000002"
},
{
"description": "Single path with 255 children (maximum depth, success)",
"paths": ["m/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0"],
"expected": "01ff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
},
{
"description": "256 paths should fail (exceeds u8::MAX)",
"paths": [
"m/0", "m/1", "m/2", "m/3", "m/4", "m/5", "m/6", "m/7", "m/8", "m/9",
"m/10", "m/11", "m/12", "m/13", "m/14", "m/15", "m/16", "m/17", "m/18", "m/19",
"m/20", "m/21", "m/22", "m/23", "m/24", "m/25", "m/26", "m/27", "m/28", "m/29",
"m/30", "m/31", "m/32", "m/33", "m/34", "m/35", "m/36", "m/37", "m/38", "m/39",
"m/40", "m/41", "m/42", "m/43", "m/44", "m/45", "m/46", "m/47", "m/48", "m/49",
"m/50", "m/51", "m/52", "m/53", "m/54", "m/55", "m/56", "m/57", "m/58", "m/59",
"m/60", "m/61", "m/62", "m/63", "m/64", "m/65", "m/66", "m/67", "m/68", "m/69",
"m/70", "m/71", "m/72", "m/73", "m/74", "m/75", "m/76", "m/77", "m/78", "m/79",
"m/80", "m/81", "m/82", "m/83", "m/84", "m/85", "m/86", "m/87", "m/88", "m/89",
"m/90", "m/91", "m/92", "m/93", "m/94", "m/95", "m/96", "m/97", "m/98", "m/99",
"m/100", "m/101", "m/102", "m/103", "m/104", "m/105", "m/106", "m/107", "m/108", "m/109",
"m/110", "m/111", "m/112", "m/113", "m/114", "m/115", "m/116", "m/117", "m/118", "m/119",
"m/120", "m/121", "m/122", "m/123", "m/124", "m/125", "m/126", "m/127", "m/128", "m/129",
"m/130", "m/131", "m/132", "m/133", "m/134", "m/135", "m/136", "m/137", "m/138", "m/139",
"m/140", "m/141", "m/142", "m/143", "m/144", "m/145", "m/146", "m/147", "m/148", "m/149",
"m/150", "m/151", "m/152", "m/153", "m/154", "m/155", "m/156", "m/157", "m/158", "m/159",
"m/160", "m/161", "m/162", "m/163", "m/164", "m/165", "m/166", "m/167", "m/168", "m/169",
"m/170", "m/171", "m/172", "m/173", "m/174", "m/175", "m/176", "m/177", "m/178", "m/179",
"m/180", "m/181", "m/182", "m/183", "m/184", "m/185", "m/186", "m/187", "m/188", "m/189",
"m/190", "m/191", "m/192", "m/193", "m/194", "m/195", "m/196", "m/197", "m/198", "m/199",
"m/200", "m/201", "m/202", "m/203", "m/204", "m/205", "m/206", "m/207", "m/208", "m/209",
"m/210", "m/211", "m/212", "m/213", "m/214", "m/215", "m/216", "m/217", "m/218", "m/219",
"m/220", "m/221", "m/222", "m/223", "m/224", "m/225", "m/226", "m/227", "m/228", "m/229",
"m/230", "m/231", "m/232", "m/233", "m/234", "m/235", "m/236", "m/237", "m/238", "m/239",
"m/240", "m/241", "m/242", "m/243", "m/244", "m/245", "m/246", "m/247", "m/248", "m/249",
"m/250", "m/251", "m/252", "m/253", "m/254", "m/255"
],
"expected": null
},
{
"description": "Path with 256 children should fail (exceeds u8::MAX)",
"paths": ["m/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0"],
"expected": null
},
{
"description": "255 paths should succeed (maximum allowed)",
"paths": [
"m/0", "m/1", "m/2", "m/3", "m/4", "m/5", "m/6", "m/7", "m/8", "m/9",
"m/10", "m/11", "m/12", "m/13", "m/14", "m/15", "m/16", "m/17", "m/18", "m/19",
"m/20", "m/21", "m/22", "m/23", "m/24", "m/25", "m/26", "m/27", "m/28", "m/29",
"m/30", "m/31", "m/32", "m/33", "m/34", "m/35", "m/36", "m/37", "m/38", "m/39",
"m/40", "m/41", "m/42", "m/43", "m/44", "m/45", "m/46", "m/47", "m/48", "m/49",
"m/50", "m/51", "m/52", "m/53", "m/54", "m/55", "m/56", "m/57", "m/58", "m/59",
"m/60", "m/61", "m/62", "m/63", "m/64", "m/65", "m/66", "m/67", "m/68", "m/69",
"m/70", "m/71", "m/72", "m/73", "m/74", "m/75", "m/76", "m/77", "m/78", "m/79",
"m/80", "m/81", "m/82", "m/83", "m/84", "m/85", "m/86", "m/87", "m/88", "m/89",
"m/90", "m/91", "m/92", "m/93", "m/94", "m/95", "m/96", "m/97", "m/98", "m/99",
"m/100", "m/101", "m/102", "m/103", "m/104", "m/105", "m/106", "m/107", "m/108", "m/109",
"m/110", "m/111", "m/112", "m/113", "m/114", "m/115", "m/116", "m/117", "m/118", "m/119",
"m/120", "m/121", "m/122", "m/123", "m/124", "m/125", "m/126", "m/127", "m/128", "m/129",
"m/130", "m/131", "m/132", "m/133", "m/134", "m/135", "m/136", "m/137", "m/138", "m/139",
"m/140", "m/141", "m/142", "m/143", "m/144", "m/145", "m/146", "m/147", "m/148", "m/149",
"m/150", "m/151", "m/152", "m/153", "m/154", "m/155", "m/156", "m/157", "m/158", "m/159",
"m/160", "m/161", "m/162", "m/163", "m/164", "m/165", "m/166", "m/167", "m/168", "m/169",
"m/170", "m/171", "m/172", "m/173", "m/174", "m/175", "m/176", "m/177", "m/178", "m/179",
"m/180", "m/181", "m/182", "m/183", "m/184", "m/185", "m/186", "m/187", "m/188", "m/189",
"m/190", "m/191", "m/192", "m/193", "m/194", "m/195", "m/196", "m/197", "m/198", "m/199",
"m/200", "m/201", "m/202", "m/203", "m/204", "m/205", "m/206", "m/207", "m/208", "m/209",
"m/210", "m/211", "m/212", "m/213", "m/214", "m/215", "m/216", "m/217", "m/218", "m/219",
"m/220", "m/221", "m/222", "m/223", "m/224", "m/225", "m/226", "m/227", "m/228", "m/229",
"m/230", "m/231", "m/232", "m/233", "m/234", "m/235", "m/236", "m/237", "m/238", "m/239",
"m/240", "m/241", "m/242", "m/243", "m/244", "m/245", "m/246", "m/247", "m/248", "m/249",
"m/250", "m/251", "m/252", "m/253", "m/254"
],
"expected": "ff0100000000010000000101000000020100000003010000000401000000050100000006010000000701000000080100000009010000000a010000000b010000000c010000000d010000000e010000000f0100000010010000001101000000120100000013010000001401000000150100000016010000001701000000180100000019010000001a010000001b010000001c010000001d010000001e010000001f0100000020010000002101000000220100000023010000002401000000250100000026010000002701000000280100000029010000002a010000002b010000002c010000002d010000002e010000002f0100000030010000003101000000320100000033010000003401000000350100000036010000003701000000380100000039010000003a010000003b010000003c010000003d010000003e010000003f0100000040010000004101000000420100000043010000004401000000450100000046010000004701000000480100000049010000004a010000004b010000004c010000004d010000004e010000004f0100000050010000005101000000520100000053010000005401000000550100000056010000005701000000580100000059010000005a010000005b010000005c010000005d010000005e010000005f0100000060010000006101000000620100000063010000006401000000650100000066010000006701000000680100000069010000006a010000006b010000006c010000006d010000006e010000006f0100000070010000007101000000720100000073010000007401000000750100000076010000007701000000780100000079010000007a010000007b010000007c010000007d010000007e010000007f0100000080010000008101000000820100000083010000008401000000850100000086010000008701000000880100000089010000008a010000008b010000008c010000008d010000008e010000008f0100000090010000009101000000920100000093010000009401000000950100000096010000009701000000980100000099010000009a010000009b010000009c010000009d010000009e010000009f01000000a001000000a101000000a201000000a301000000a401000000a501000000a601000000a701000000a801000000a901000000aa01000000ab01000000ac01000000ad01000000ae01000000af01000000b001000000b101000000b201000000b301000000b401000000b501000000b601000000b701000000b801000000b901000000ba01000000bb01000000bc01000000bd01000000be01000000bf01000000c001000000c101000000c201000000c301000000c401000000c501000000c601000000c701000000c801000000c901000000ca01000000cb01000000cc01000000cd01000000ce01000000cf01000000d001000000d101000000d201000000d301000000d401000000d501000000d601000000d701000000d801000000d901000000da01000000db01000000dc01000000dd01000000de01000000df01000000e001000000e101000000e201000000e301000000e401000000e501000000e601000000e701000000e801000000e901000000ea01000000eb01000000ec01000000ed01000000ee01000000ef01000000f001000000f101000000f201000000f301000000f401000000f501000000f601000000f701000000f801000000f901000000fa01000000fb01000000fc01000000fd01000000fe"
}
]

View File

@@ -0,0 +1,157 @@
[
{
"description": "Single key, no derivation paths, BIP380 content",
"version": 1,
"encryption": 1,
"content": "01017c",
"keys": [
"02e6642fd69bd211f93f7f1f36ca51a26a5290eb2dd1b0d8279a87bb0d480c8443"
],
"decoy_individual_secrets": [
"0000000000000000000000000000000000000000000000000000000000000001",
"c000000000000000000000000000000000000000000000000000000000000000",
"c200000000000000000000000000000000000000000000000000000000000000",
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
],
"derivation_paths": [],
"plaintext": "00",
"nonce": "a1b2c3d4e5f607080910a1b2",
"expected": "4249503133380100050000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000000c14d5bfeb7f9709e996c6696959107d4c57d367d2aee207d5361f116e3c4708bc200000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01a1b2c3d4e5f607080910a1b216a42cdae8b34bb573f5cd678ef6a25c29a214abbf52de",
"trailing": "deadbeef00ff",
"expected_base64": "QklQMTM4AQAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMFNW/63+XCemWxmlpWRB9TFfTZ9Ku4gfVNh8RbjxHCLwgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////////////////////////////////////wGhssPU5fYHCAkQobIWpCza6LNLtXP1zWeO9qJcKaIUq79S3g=="
},
{
"description": "Two keys, 1 derivation paths, BIP380 content",
"version": 1,
"encryption": 1,
"content": "01017c",
"keys": [
"02e6642fd69bd211f93f7f1f36ca51a26a5290eb2dd1b0d8279a87bb0d480c8443",
"0384526253c27c7aef56c7b71a5cd25bebb66dddda437826defc5b2568bde81f07"
],
"decoy_individual_secrets": [
"0000000000000000000000000000000000000000000000000000000000000001",
"c000000000000000000000000000000000000000000000000000000000000000",
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
],
"derivation_paths": [
"m/48'/1'/0'/2'"
],
"plaintext": "wsh(or_d(pk([9d69155f/48'/1'/0'/2']tpubDDxT9mkZzWwkKwpGT5fY6iiM9muYTPkTx6Eig8dpHR7TChuGGCWYAHVmpW1ciido5RiFWwjzYsF1GZHkEHg2nrYp3zNtx3QQRkznyLhQ77x/<0;1>/*),and_v(v:pkh([9d69155f/48'/1'/0'/2']tpubDDxT9mkZzWwkKwpGT5fY6iiM9muYTPkTx6Eig8dpHR7TChuGGCWYAHVmpW1ciido5RiFWwjzYsF1GZHkEHg2nrYp3zNtx3QQRkznyLhQ77x/<2;3>/*),older(52596))))#gx5f42wh",
"nonce": "0102030405060708090a0b0c",
"expected": "4249503133380100050000000000000000000000000000000000000000000000000000000000000001b8c6ce74f81b0ffe7d7511824e75f95114f9b140e57bb570e5c5d807f0a5e96fb8e749fceb0dd84d20a75af4dbd6d585d89c54053f6313ac6592cbfe8c1bdd4fc000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff010102030405060708090a0b0cfd6601829ae3ce2f35059533a55d10fead962d645b08a53a6fad9da13e2aa270d4561f36602d92ba9af12ef4bb495fb8296a7f7ec1ddabef1d1b25cd7e93b8dc9d437dfcd282d24ab22aaa29292ceb463cb7560321cdcae6e537fafcbedbf59e75ccb15f3a930e132037b54d8bb9b675f5f979ed8c1e084b8d9e0216519bd8ab22825ab40868133ff0ec76b623d9341c51f96cbc97e61c753e4c12e5841b640fba3fc09864ac1b67f690447c6db5e960f2ca507cad5bfae71b2fef38cc0b68c34d7f956ca0cc59d54c2d53ff5a678b4e09ce5408f6ca723040ab42e889e77c6be3771fb38a0df881128466deaa8a84e3b7cbd0ddf4a000b03d63a8e2cf5f73310e1066d3b392dc45ad30bd664490641a6bd78d4008d44193b9ea3d9285029eaa309e80afff383dda3cff1df4df4b75a254eaaf8e0f0af86e90f40b78c9d98bd354eb6eb512b6b95d05d5f95c0ca56042cea52f76252d7f2e8a95ddc4e8bffe631b399a9d69ef80d56c",
"expected_base64": "QklQMTM4AQAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG4xs50+BsP/n11EYJOdflRFPmxQOV7tXDlxdgH8KXpb7jnSfzrDdhNIKda9NvW1YXYnFQFP2MTrGWSy/6MG91PwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////////////////////////////////////wEBAgMEBQYHCAkKCwz9ZgGCmuPOLzUFlTOlXRD+rZYtZFsIpTpvrZ2hPiqicNRWHzZgLZK6mvEu9LtJX7gpan9+wd2r7x0bJc1+k7jcnUN9/NKC0kqyKqopKSzrRjy3VgMhzcrm5Tf6/L7b9Z51zLFfOpMOEyA3tU2LubZ19fl57YweCEuNngIWUZvYqyKCWrQIaBM/8Ox2tiPZNBxR+Wy8l+YcdT5MEuWEG2QPuj/AmGSsG2f2kER8bbXpYPLKUHytW/rnGy/vOMwLaMNNf5VsoMxZ1UwtU/9aZ4tOCc5UCPbKcjBAq0Loied8a+N3H7OKDfiBEoRm3qqKhOO3y9Dd9KAAsD1jqOLPX3MxDhBm07OS3EWtML1mRJBkGmvXjUAI1EGTueo9koUCnqownoCv/zg92jz/HfTfS3WiVOqvjg8K+G6Q9At4ydmL01TrbrUStrldBdX5XAylYELOpS92JS1/LoqV3cTov/5jGzmanWnvgNVs"
},
{
"description": "Three keys, multiple derivation paths, BIP329 content",
"version": 1,
"encryption": 1,
"content": "010149",
"keys": [
"02e6642fd69bd211f93f7f1f36ca51a26a5290eb2dd1b0d8279a87bb0d480c8443",
"0384526253c27c7aef56c7b71a5cd25bebb66dddda437826defc5b2568bde81f07",
"03c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5"
],
"decoy_individual_secrets": [
"7000000000000000000000000000000000000000000000000000000000000000",
"8000000000000000000000000000000000000000000000000000000000000000"
],
"derivation_paths": [
"m/84'/0'/0'",
"m/0/1'/2/3'"
],
"plaintext": "{\"type\":\"tx\",\"ref\":\"f91d0a8a78462bc59398f2c5d7a84fcff491c26ba54c4833478b202796c8aafd\",\"label\":\"Transaction\",\"origin\":\"wpkh([d34db33f/84'/0'/0'])\"}\n{\"type\":\"addr\",\"ref\":\"bc1q34aq5drpuwy3wgl9lhup9892qp6svr8ldzyy7c\",\"label\":\"Address\"}\n{\"type\":\"pubkey\",\"ref\":\"0283409659355b6d1cc3c32decd5d561abaac86c37a353b52895a5e6c196d6f448\",\"label\":\"Public Key\"}\n{\"type\":\"input\",\"ref\":\"f91d0a8a78462bc59398f2c5d7a84fcff491c26ba54c4833478b202796c8aafd:0\",\"label\":\"Input\"}\n{\"type\":\"output\",\"ref\":\"f91d0a8a78462bc59398f2c5d7a84fcff491c26ba54c4833478b202796c8aafd:1\",\"label\":\"Output\",\"spendable\":false}\n{\"type\":\"xpub\",\"ref\":\"xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8\",\"label\":\"Extended Public Key\"}\n{\"type\":\"tx\",\"ref\":\"f546156d9044844e02b181026a1a407abfca62e7ea1159f87bbeaa77b4286c74\",\"label\":\"Account #1 Transaction\",\"origin\":\"wpkh([d34db33f/84'/0'/1'])\"}",
"nonce": "deadbeefcafebabe12345678",
"expected": "4249503133380101040000000080000001000000028000000305281aff33e4b8186ac4176427b59ec3c72af96bf6ecd1ad7ed1d746103d078a17283b78bbf7aecfd999c52f51203def13e69c8eb336c90ba2518055e941b9be3770000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000f6353d50c714c43f7b86794ee21e3490af33468ef30217dd93003413e23b4c1701deadbeefcafebabe12345678fd9f032b5e117a385bfc3c88c2eae4e2e4aeeaaff5c5ced44579c77cb67fbb6c12bdc113c1e2c9bb1029ec47f589311030efe4aa3924958aa53b737d5fdf0fc2272037ba9260303a07010ceaf38e40aec5d28318968e833511bdc6d4ab99cb1e51153f0571fd6c0e08b58a8b75bdb91c7fb94b16872ac5800c981f06d3c28fdf71a9382c08c74d2d0ffe9e20774e6c8bec95cd6713ec60ff2fa54d50a507e84448d91ba5fcaa8dd17ad19dbb962e4514a127d795d8cf82ced19d242a9777a9bd6f714c3deec247530f74c055410e6b42ae98de71259103cf14f0d5719ae2900675841c010c1e6c076a9be2ddf271e3281184dc8759063a4c1be8f2e3a57e6557b76228bf13e5d1cf6fc8726d6429cad74c84fbb15046abb12fe7f6f6e3856016dae37fff0a161cb9da34e814976ccc9b03a587900eb36cbd56049cdc9680816fe9c4a14838fa2a999bf4ad7fe5efa7d31c7164886d6eafa18fe40185bcc982768d0a3ca05e3450979e4140cacd834f8e6399048b59e6ab025964c2afcf6119b614c56755e5e37b6425ea3926dd9b9fe4cd6e127d6006abdb38b393437cb26cd8ccbda13825c90b857deab2dbaf759b14ffb0692e448ecbba9a3cdbac7b7661be2a8cec5a0b9df3bbe1a67014653e159c41c3b36974563b8392731f3dec68c16e4a644bad4236208876aba0d00bdd3cefac04c31b1e1673b91d0010f8ebe7070c07f8b00effa79b8e94fb1b9285904114e37d4e2987d9246a300958a9fbf1c2af1016edcec7b9e0fca80935652c3426e837a9ce018615d1f1127da307daca4dc8bc201f44b09c0adb52859f49cc625a5ecd31bbe513ea5c97dfb8f192cffd60864acc4c1a0a4f630190cbf1e1fe8201d8b7b2b4da7e8813f56e1d885f57700289ee4661928540607be79221137c1a79b8b4ab6150f1c9c4c6ca2367a673d5f7faa2cbcdbc1fd68c45acb33e7344e55a431c03ad03fb4442bd01b8b51cce71c7779fa2f63120bed1ed30ff35969cc2cb049b598a473b670012bd155e6efcad815a83cd76ea06eef14867cef22998bf39debadd78fface8cb6cb9ee3f02636683d69458f6ace058f232ef1d1d547c0073a82ba507a006df40f69d2a247b485ee6010cfbb58bbc6f0423287f475df21c2e23533a1653c48aac55b7a64e489850477482a08924c984700d5be68834455c17b8cae220f898679515735273d4d8e8a0c62735e859d7a7158db7f8e8d1d94e94dd9750c1bd8b5a89a8f67a1ba146201a3999b00350ae1467de39d984b56d4d62ec04bdf0cf05a241468b6a0b70e8ccbbe476ee",
"expected_base64": "QklQMTM4AQEEAAAAAIAAAAEAAAACgAAAAwUoGv8z5LgYasQXZCe1nsPHKvlr9uzRrX7R10YQPQeKFyg7eLv3rs/ZmcUvUSA97xPmnI6zNskLolGAVelBub43cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPY1PVDHFMQ/e4Z5TuIeNJCvM0aO8wIX3ZMANBPiO0wXAd6tvu/K/rq+EjRWeP2fAyteEXo4W/w8iMLq5OLkruqv9cXO1EV5x3y2f7tsEr3BE8HiybsQKexH9YkxEDDv5Ko5JJWKpTtzfV/fD8InIDe6kmAwOgcBDOrzjkCuxdKDGJaOgzURvcbUq5nLHlEVPwVx/WwOCLWKi3W9uRx/uUsWhyrFgAyYHwbTwo/fcak4LAjHTS0P/p4gd05si+yVzWcT7GD/L6VNUKUH6ERI2Rul/KqN0XrRnbuWLkUUoSfXldjPgs7RnSQql3epvW9xTD3uwkdTD3TAVUEOa0KumN5xJZEDzxTw1XGa4pAGdYQcAQwebAdqm+Ld8nHjKBGE3IdZBjpMG+jy46V+ZVe3Yii/E+XRz2/Icm1kKcrXTIT7sVBGq7Ev5/b244VgFtrjf/8KFhy52jToFJdszJsDpYeQDrNsvVYEnNyWgIFv6cShSDj6Kpmb9K1/5e+n0xxxZIhtbq+hj+QBhbzJgnaNCjygXjRQl55BQMrNg0+OY5kEi1nmqwJZZMKvz2EZthTFZ1Xl43tkJeo5Jt2bn+TNbhJ9YAar2zizk0N8smzYzL2hOCXJC4V96rLbr3WbFP+waS5Ejsu6mjzbrHt2Yb4qjOxaC53zu+GmcBRlPhWcQcOzaXRWO4OScx897GjBbkpkS61CNiCIdqug0AvdPO+sBMMbHhZzuR0AEPjr5wcMB/iwDv+nm46U+xuShZBBFON9TimH2SRqMAlYqfvxwq8QFu3Ox7ng/KgJNWUsNCboN6nOAYYV0fESfaMH2spNyLwgH0SwnArbUoWfScxiWl7NMbvlE+pcl9+48ZLP/WCGSsxMGgpPYwGQy/Hh/oIB2LeytNp+iBP1bh2IX1dwAonuRmGShUBge+eSIRN8Gnm4tKthUPHJxMbKI2emc9X3+qLLzbwf1oxFrLM+c0TlWkMcA60D+0RCvQG4tRzOccd3n6L2MSC+0e0w/zWWnMLLBJtZikc7ZwASvRVebvytgVqDzXbqBu7xSGfO8imYvzneut14/6zoy2y57j8CY2aD1pRY9qzgWPIy7x0dVHwAc6grpQegBt9A9p0qJHtIXuYBDPu1i7xvBCMof0dd8hwuI1M6FlPEiqxVt6ZOSJhQR3SCoIkkyYRwDVvmiDRFXBe4yuIg+JhnlRVzUnPU2Oigxic16FnXpxWNt/jo0dlOlN2XUMG9i1qJqPZ6G6FGIBo5mbADUK4UZ9452YS1bU1i7AS98M8FokFGi2oLcOjMu+R27g=="
},
{
"description": "Single key, proprietary content (3 bytes)",
"version": 1,
"encryption": 1,
"content": "0204deadbeef",
"keys": [
"02e6642fd69bd211f93f7f1f36ca51a26a5290eb2dd1b0d8279a87bb0d480c8443"
],
"decoy_individual_secrets": [
"0000000000000000000000000000000000000000000000000000000000000001",
"c000000000000000000000000000000000000000000000000000000000000000",
"c200000000000000000000000000000000000000000000000000000000000000",
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
],
"derivation_paths": [],
"plaintext": "706c61696e74657874",
"nonce": "000102030405060708090a0b",
"expected": "4249503133380100050000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000000c14d5bfeb7f9709e996c6696959107d4c57d367d2aee207d5361f116e3c4708bc200000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01000102030405060708090a0b2988e0747028c10af011cba311ebabb3a094366a96ad747cd8e3edfc1474b356c2393e13ee9c5cd0aae5",
"expected_base64": "QklQMTM4AQAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMFNW/63+XCemWxmlpWRB9TFfTZ9Ku4gfVNh8RbjxHCLwgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////////////////////////////////////wEAAQIDBAUGBwgJCgspiOB0cCjBCvARy6MR66uzoJQ2apatdHzY4+38FHSzVsI5PhPunFzQquU="
},
{
"description": "Two keys, BIP388 wallet policy content (multisig)",
"version": 1,
"encryption": 1,
"content": "010184",
"keys": [
"02ee3887104834ec2970bb793abc7fd37661e2c44c49fb48c10745ef7d7c85b17c",
"036f155ae2153b09bb4e1383756723c0879e80d0f32767c7e4875d5de2fb9a400d"
],
"decoy_individual_secrets": [
"0000000000000000000000000000000000000000000000000000000000000001",
"8000000000000000000000000000000000000000000000000000000000000000",
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
],
"derivation_paths": [
"m/48'/0'/0'/2'"
],
"plaintext": "{\"keys\":[\"[6738736c/48'/0'/0'/2']xpub6FC1fXFP1GXLX5TKtcjHGT4q89SDRehkQLtbKJ2PzWcvbBHtyDsJPLtpLtkGqYNYZdVVAjRQ5kug9CsapegmmeRutpP7PW4u4wVF9JfkDhw\",\"[b2b1f0cf/48'/0'/0'/2']xpub6EWhjpPa6FqrcaPBuGBZRJVjzGJ1ZsMygRF26RwN932Vfkn1gyCiTbECVitBjRCkexEvetLdiqzTcYimmzYxyR1BZ79KNevgt61PDcukmC7\"],\"policy\":\"wsh(sortedmulti(2,@0/**,@1/**))\"}",
"nonce": "000000000000000000000388",
"expected": "424950313338010005000000000000000000000000000000000000000000000000000000000000000163f5769bbb36d77fc5d3251700590c087013ca44284850e88f379f2519190f978000000000000000000000000000000000000000000000000000000000000000e5b4cabf8bdb9a04a92fc3e104dd2d8a2cb8e5ea886e143236dd4b04619e796dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01000000000000000000000388fd5d011def7dae872431f1fa0df78989f7e5087cd0cb112a69bc211d3346b1031c5d1e8702197712ac46597e05d80421fda7e60d09f3ba2178bd770c904bf840d3d779565fbd0668a989934483820c4c828f32ffe5fc1ce55bbfe287a6d4eb4461e4da1b6a6f22cc0932773c84f07d879b1ed8035831e2a358101be023ea2efb7c70411f757c42715f4e5f7eff416a456a5dadf1b980480e22a7b66726ebc84afe04acdfbf47c6b41c2bb39c5a069a93dba0de4ea9bc192f938f968c9fa2afc26025dd577461b73bad0870e97d7519945ced9d73500c7ece85696d98f223350cd6a337cb74feeeea8d5144ee94553dc54a46e43f67fa48f11c7746e006aac4478fa0c484f041be451548152a1f11f632a9d966de62e3cd80ed9885117e5901042974c80d3f95a13c1cfe2157f2bfb80bea7b3bc0a71127d8daa6a75d3cc517ef934dd9af4b504600c5ce223ba9538c9bc0472aa3832571b1486e2f51b40a5351",
"expected_base64": "QklQMTM4AQAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFj9XabuzbXf8XTJRcAWQwIcBPKRChIUOiPN58lGRkPl4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5bTKv4vbmgSpL8PhBN0tiiy45eqIbhQyNt1LBGGeeW3//////////////////////////////////////////wEAAAAAAAAAAAAAA4j9XQEd732uhyQx8foN94mJ9+UIfNDLESppvCEdM0axAxxdHocCGXcSrEZZfgXYBCH9p+YNCfO6IXi9dwyQS/hA09d5Vl+9BmipiZNEg4IMTIKPMv/l/BzlW7/ih6bU60Rh5Nobam8izAkydzyE8H2Hmx7YA1gx4qNYEBvgI+ou+3xwQR91fEJxX05ffv9BakVqXa3xuYBIDiKntmcm68hK/gSs379HxrQcK7OcWgaak9ug3k6pvBkvk4+WjJ+ir8JgJd1XdGG3O60IcOl9dRmUXO2dc1AMfs6FaW2Y8iM1DNajN8t0/u7qjVFE7pRVPcVKRuQ/Z/pI8Rx3RuAGqsRHj6DEhPBBvkUVSBUqHxH2MqnZZt5i482A7ZiFEX5ZAQQpdMgNP5WhPBz+IVfyv7gL6ns7wKcRJ9japqddPMUX75NN2a9LUEYAxc4iO6lTjJvARyqjgyVxsUhuL1G0ClNR"
},
{
"description": "Two content items in one payload (BIP380 descriptor + BIP329 labels)",
"version": 1,
"encryption": 1,
"content": "01017c",
"keys": [
"02e6642fd69bd211f93f7f1f36ca51a26a5290eb2dd1b0d8279a87bb0d480c8443",
"0384526253c27c7aef56c7b71a5cd25bebb66dddda437826defc5b2568bde81f07"
],
"decoy_individual_secrets": [
"0000000000000000000000000000000000000000000000000000000000000001",
"c000000000000000000000000000000000000000000000000000000000000000",
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
],
"derivation_paths": [],
"plaintext": "wsh(or_d(pk([9d69155f/48'/1'/0'/2']tpubDDxT9mkZzWwkKwpGT5fY6iiM9muYTPkTx6Eig8dpHR7TChuGGCWYAHVmpW1ciido5RiFWwjzYsF1GZHkEHg2nrYp3zNtx3QQRkznyLhQ77x/<0;1>/*),and_v(v:pkh([9d69155f/48'/1'/0'/2']tpubDDxT9mkZzWwkKwpGT5fY6iiM9muYTPkTx6Eig8dpHR7TChuGGCWYAHVmpW1ciido5RiFWwjzYsF1GZHkEHg2nrYp3zNtx3QQRkznyLhQ77x/<2;3>/*),older(52596))))#gx5f42wh",
"nonce": "0c0d0e0f101112131415161a",
"expected": "4249503133380100050000000000000000000000000000000000000000000000000000000000000001b8c6ce74f81b0ffe7d7511824e75f95114f9b140e57bb570e5c5d807f0a5e96fb8e749fceb0dd84d20a75af4dbd6d585d89c54053f6313ac6592cbfe8c1bdd4fc000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff010c0d0e0f101112131415161afde201d35ed73109113688c5cc808c44e3e4a6837adf0ee8c9339947e176418c41f16e92c36b395a07e036117df93fda41bf3b1bacae6cb0fe1cf2c07f519fff3a96b95540de161c48cd8ee6485a1b5477c18d038257af7bacedc36ef0cea2f0661c2267b0d72cf8273f32d734046eb8fbfe75a47619a7d5c12b95e9ec6a49b0a031ccdbfaa6bd201ddf94cb3979ceae1390af41baaedeba38dfcf078c97c33404f0833d36a750e1ebac14d2139719c35aacfa025cde5a19f776d8e1d1367764700f8e8bc3ae99d08fbffaa322abe1e69f2839f8840cdffbcfed9544e4fde1dac882bee1e0d34367f63fc5eec38540f0b3683cd79dbe67eab0ddd52765edf6de7f24adb3e9df8e7b9bf793863f60dfa6fd39aed67eac5d4f774069af6ff436bd85affb199846c55e7d2063d950182b60886f8d65c890d0a4ff6253a8ed0963a052c46ed858dcdefe3e929d970e97d7b65b9843caf94a5649bd8547f5a976cc40b7356dfb6cf3df6b87267ca83d15a2d11cd8e918f2a2b17bb717b33f55a78fd5a6a01cd11d39b54af2734066be57977fb140db2944bf612ce63fa2dc7ae841f47f930637eaaacc96bf5a9cf82483f0aba57dafb79319631a3b954c0a05731607c29290b5c9487def5371585671f4ae6ab0e8cdb51423faf15de6ca34430d21581de9cfe36e",
"extra": [
{
"content": "010149",
"plaintext": "{\"type\": \"tx\", \"ref\": \"f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16\", \"label\": \"multi content demo\"}"
}
],
"expected_base64": "QklQMTM4AQAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG4xs50+BsP/n11EYJOdflRFPmxQOV7tXDlxdgH8KXpb7jnSfzrDdhNIKda9NvW1YXYnFQFP2MTrGWSy/6MG91PwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////////////////////////////////////wEMDQ4PEBESExQVFhr94gHTXtcxCRE2iMXMgIxE4+Smg3rfDujJM5lH4XZBjEHxbpLDazlaB+A2EX35P9pBvzsbrK5ssP4c8sB/UZ//Opa5VUDeFhxIzY7mSFobVHfBjQOCV697rO3DbvDOovBmHCJnsNcs+Cc/Mtc0BG64+/51pHYZp9XBK5Xp7GpJsKAxzNv6pr0gHd+Uyzl5zq4TkK9Buq7eujjfzweMl8M0BPCDPTanUOHrrBTSE5cZw1qs+gJc3loZ93bY4dE2d2RwD46Lw66Z0I+/+qMiq+Hmnyg5+IQM3/vP7ZVE5P3h2siCvuHg00Nn9j/F7sOFQPCzaDzXnb5n6rDd1Sdl7fbefySts+nfjnub95OGP2Dfpv05rtZ+rF1Pd0Bpr2/0Nr2Fr/sZmEbFXn0gY9lQGCtgiG+NZciQ0KT/YlOo7QljoFLEbthY3N7+PpKdlw6X17ZbmEPK+UpWSb2FR/WpdsxAtzVt+2zz32uHJnyoPRWi0RzY6RjyorF7txezP1Wnj9WmoBzRHTm1SvJzQGa+V5d/sUDbKUS/YSzmP6LceuhB9H+TBjfqqsyWv1qc+CSD8Kulfa+3kxljGjuVTAoFcxYHwpKQtclIfe9TcVhWcfSuarDozbUUI/rxXebKNEMNIVgd6c/jbg=="
},
{
"description": "All-zero nonce MUST be rejected",
"version": 1,
"encryption": 1,
"content": "01017c",
"keys": [
"02e6642fd69bd211f93f7f1f36ca51a26a5290eb2dd1b0d8279a87bb0d480c8443",
"0384526253c27c7aef56c7b71a5cd25bebb66dddda437826defc5b2568bde81f07"
],
"decoy_individual_secrets": [
"0000000000000000000000000000000000000000000000000000000000000001",
"c000000000000000000000000000000000000000000000000000000000000000",
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
],
"derivation_paths": [],
"plaintext": "wsh(or_d(pk([9d69155f/48'/1'/0'/2']tpubDDxT9mkZzWwkKwpGT5fY6iiM9muYTPkTx6Eig8dpHR7TChuGGCWYAHVmpW1ciido5RiFWwjzYsF1GZHkEHg2nrYp3zNtx3QQRkznyLhQ77x/<0;1>/*),and_v(v:pkh([9d69155f/48'/1'/0'/2']tpubDDxT9mkZzWwkKwpGT5fY6iiM9muYTPkTx6Eig8dpHR7TChuGGCWYAHVmpW1ciido5RiFWwjzYsF1GZHkEHg2nrYp3zNtx3QQRkznyLhQ77x/<2;3>/*),older(52596))))#gx5f42wh",
"nonce": "000000000000000000000000",
"expected": "4249503133380100050000000000000000000000000000000000000000000000000000000000000001b8c6ce74f81b0ffe7d7511824e75f95114f9b140e57bb570e5c5d807f0a5e96fb8e749fceb0dd84d20a75af4dbd6d585d89c54053f6313ac6592cbfe8c1bdd4fc000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01000000000000000000000000fd66010d8538e52c03d7069660ca0fc3e961eb7d2ae284498ba1358b7476c09d44bfa60e1963f0271eaf66e816348f001fa4ee1d0fd11e24e93ed12ee288371ce6ca8629b70692e36a43d7647cb340f8f22c6ef4aeb8968f16920ddd2f11f450f7d2420f210f55204d4c40eb8306c02ec8e30c2fd13a15ba0999ad4831a9be7754eab3ddf4f5e71301b89a881a279cf262556708697b8e3da7236872270d3f8d62b6d56e4065835df66277f30177566c233764417eb7d2de6cf5f293321d80c6328c261d0f2d06c9fbd6fd29cd059e0db61d6e1b60951605f40f93c239b643da049186fcc5811bd116808d8bdd8beaefc0d4124088dcd00261c396eb3f27ed254ff91c4457a1c817c53004ea0e764309149044d4e8f92d2ee688619fc44a67a096bdd6c978411d6c103b634896e080cb3dba6f66f0fe580cdb9f944457c65312f449d82c2b1bc86ac972df641ae93ff2d1ea2d9ae64abdce2dd452bf2fc37a5f493dd1704f91a2c765",
"valid": false,
"expected_base64": "QklQMTM4AQAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG4xs50+BsP/n11EYJOdflRFPmxQOV7tXDlxdgH8KXpb7jnSfzrDdhNIKda9NvW1YXYnFQFP2MTrGWSy/6MG91PwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//////////////////////////////////////////wEAAAAAAAAAAAAAAAD9ZgENhTjlLAPXBpZgyg/D6WHrfSrihEmLoTWLdHbAnUS/pg4ZY/AnHq9m6BY0jwAfpO4dD9EeJOk+0S7iiDcc5sqGKbcGkuNqQ9dkfLNA+PIsbvSuuJaPFpIN3S8R9FD30kIPIQ9VIE1MQOuDBsAuyOMML9E6FboJma1IMam+d1Tqs9309ecTAbiaiBonnPJiVWcIaXuOPacjaHInDT+NYrbVbkBlg132YnfzAXdWbCM3ZEF+t9LebPXykzIdgMYyjCYdDy0GyfvW/SnNBZ4Nth1uG2CVFgX0D5PCObZD2gSRhvzFgRvRFoCNi92L6u/A1BJAiNzQAmHDlus/J+0lT/kcRFehyBfFMATqDnZDCRSQRNTo+S0u5ohhn8RKZ6CWvdbJeEEdbBA7Y0iW4IDLPbpvZvD+WAzbn5REV8ZTEvRJ2CwrG8hqyXLfZBrpP/LR6i2a5kq9zi3UUr8vw3pfST3RcE+Rosdl"
}
]

View File

@@ -0,0 +1,100 @@
[
{
"description": "Single public key",
"keys": [
"02e6642fd69bd211f93f7f1f36ca51a26a5290eb2dd1b0d8279a87bb0d480c8443"
],
"decryption_secret": "9628546fe8fbf82fb10ff692d82953fa2db546275be9ce1b00134aff1a8bacdd",
"individual_secrets": [
"c14d5bfeb7f9709e996c6696959107d4c57d367d2aee207d5361f116e3c4708b"
]
},
{
"description": "Two public keys",
"keys": [
"02e6642fd69bd211f93f7f1f36ca51a26a5290eb2dd1b0d8279a87bb0d480c8443",
"0384526253c27c7aef56c7b71a5cd25bebb66dddda437826defc5b2568bde81f07"
],
"decryption_secret": "efa3c1e5a719874f5516818603cdad7ffc31c11a947c5b16b6b763ee09ea3539",
"individual_secrets": [
"b8e749fceb0dd84d20a75af4dbd6d585d89c54053f6313ac6592cbfe8c1bdd4f",
"b8c6ce74f81b0ffe7d7511824e75f95114f9b140e57bb570e5c5d807f0a5e96f"
]
},
{
"description": "Three public keys",
"keys": [
"02e6642fd69bd211f93f7f1f36ca51a26a5290eb2dd1b0d8279a87bb0d480c8443",
"0384526253c27c7aef56c7b71a5cd25bebb66dddda437826defc5b2568bde81f07",
"03c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5"
],
"decryption_secret": "7f7ff0a2bbba90dbec74f423f82697e9c2311bac9dd6431882a5fdf9c4485641",
"individual_secrets": [
"283b78bbf7aecfd999c52f51203def13e69c8eb336c90ba2518055e941b9be37",
"f6353d50c714c43f7b86794ee21e3490af33468ef30217dd93003413e23b4c17",
"281aff33e4b8186ac4176427b59ec3c72af96bf6ecd1ad7ed1d746103d078a17"
]
},
{
"description": "Three public keys bis (different sorting)",
"keys": [
"03c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5",
"02e6642fd69bd211f93f7f1f36ca51a26a5290eb2dd1b0d8279a87bb0d480c8443",
"0384526253c27c7aef56c7b71a5cd25bebb66dddda437826defc5b2568bde81f07"
],
"decryption_secret": "7f7ff0a2bbba90dbec74f423f82697e9c2311bac9dd6431882a5fdf9c4485641",
"individual_secrets": [
"283b78bbf7aecfd999c52f51203def13e69c8eb336c90ba2518055e941b9be37",
"f6353d50c714c43f7b86794ee21e3490af33468ef30217dd93003413e23b4c17",
"281aff33e4b8186ac4176427b59ec3c72af96bf6ecd1ad7ed1d746103d078a17"
]
},
{
"description": "Three public keys ter (different sorting)",
"keys": [
"0384526253c27c7aef56c7b71a5cd25bebb66dddda437826defc5b2568bde81f07",
"03c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5",
"02e6642fd69bd211f93f7f1f36ca51a26a5290eb2dd1b0d8279a87bb0d480c8443"
],
"decryption_secret": "7f7ff0a2bbba90dbec74f423f82697e9c2311bac9dd6431882a5fdf9c4485641",
"individual_secrets": [
"283b78bbf7aecfd999c52f51203def13e69c8eb336c90ba2518055e941b9be37",
"f6353d50c714c43f7b86794ee21e3490af33468ef30217dd93003413e23b4c17",
"281aff33e4b8186ac4176427b59ec3c72af96bf6ecd1ad7ed1d746103d078a17"
]
},
{
"description": "Keys processed in sorted order",
"keys": [
"0384526253c27c7aef56c7b71a5cd25bebb66dddda437826defc5b2568bde81f07",
"02e6642fd69bd211f93f7f1f36ca51a26a5290eb2dd1b0d8279a87bb0d480c8443"
],
"decryption_secret": "efa3c1e5a719874f5516818603cdad7ffc31c11a947c5b16b6b763ee09ea3539",
"individual_secrets": [
"b8e749fceb0dd84d20a75af4dbd6d585d89c54053f6313ac6592cbfe8c1bdd4f",
"b8c6ce74f81b0ffe7d7511824e75f95114f9b140e57bb570e5c5d807f0a5e96f"
]
},
{
"description": "Duplicate keys should be handled",
"keys": [
"02e6642fd69bd211f93f7f1f36ca51a26a5290eb2dd1b0d8279a87bb0d480c8443",
"02e6642fd69bd211f93f7f1f36ca51a26a5290eb2dd1b0d8279a87bb0d480c8443"
],
"decryption_secret": "9628546fe8fbf82fb10ff692d82953fa2db546275be9ce1b00134aff1a8bacdd",
"individual_secrets": [
"c14d5bfeb7f9709e996c6696959107d4c57d367d2aee207d5361f116e3c4708b"
]
},
{
"description": "Keys sharing an x coordinate normalize to a single key",
"keys": [
"02e6642fd69bd211f93f7f1f36ca51a26a5290eb2dd1b0d8279a87bb0d480c8443",
"03e6642fd69bd211f93f7f1f36ca51a26a5290eb2dd1b0d8279a87bb0d480c8443"
],
"decryption_secret": "9628546fe8fbf82fb10ff692d82953fa2db546275be9ce1b00134aff1a8bacdd",
"individual_secrets": [
"c14d5bfeb7f9709e996c6696959107d4c57d367d2aee207d5361f116e3c4708b"
]
}
]

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,47 @@
[
{
"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
}
]