From 0f8c26b7c20bab5a58f098ac81f1bb86974c5934 Mon Sep 17 00:00:00 2001 From: Sjors Provoost Date: Tue, 22 Sep 2026 14:52:10 +0200 Subject: [PATCH 1/4] bip138: specify empty associated data Make the associated-data input explicit in the encryption and decryption formulas and specify that it is empty, as used by the existing vectors. --- bip-0138.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bip-0138.md b/bip-0138.md index 90ae803e..d5b2ab5a 100644 --- a/bip-0138.md +++ b/bip-0138.md @@ -196,7 +196,9 @@ and integrity.[^chacha-default] hardware acceleration, making it suitable for hardware wallets and embedded devices. * let $nonce$ = random(96 bits) -* let $ciphertext$ = encrypt($payload$, $secret$, $nonce$) +* let $ciphertext$ = encrypt($payload$, $secret$, $nonce$, $aad$) + +The additional authenticated data ($aad$) is empty. The $nonce$ MUST NOT be all zero. If the random source yields an all-zero nonce, the encoder MUST generate a new one. @@ -210,7 +212,7 @@ computes: * for each `individual_secret_i` generate `reconstructed_secret_i` = `individual_secret_i` ⊕ `si` * for each `reconstructed_secret_i` process $payload$ = -decrypt($ciphertext$, $secret$, $nonce$) +decrypt($ciphertext$, $secret$, $nonce$, $aad$) Decryption will succeed if and only if **p** was one of the keys in the descriptor/wallet policy. From aa098559bf39633a2b424ce60a4b962d6fbe5c93 Mon Sep 17 00:00:00 2001 From: Sjors Provoost Date: Wed, 23 Sep 2026 14:31:54 +0200 Subject: [PATCH 2/4] bip138: clarify that 0x00 ends payload parsing Specify that parsing stops immediately. Add a vector with an item followed by a terminator and ignored bytes. Clarify that TYPE 0x00 also doesn't require TYPE_LENGTH. --- bip-0138.md | 13 ++++++++----- bip-0138/test_vectors/payload.json | 13 +++++++++++++ 2 files changed, 21 insertions(+), 5 deletions(-) create mode 100644 bip-0138/test_vectors/payload.json diff --git a/bip-0138.md b/bip-0138.md index d5b2ab5a..d339bedf 100644 --- a/bip-0138.md +++ b/bip-0138.md @@ -408,7 +408,7 @@ remaining bytes are `PADDING`. A `PAYLOAD` MUST contain at least one item (see `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] +For all `TYPE` values except `0x00` and `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 @@ -417,20 +417,19 @@ For all `TYPE` values except `0x01`, `TYPE_LENGTH` MUST be present.[^length-requ 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. + blindly. `0x00` is a terminator rather than a content item. `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. +- 0x00: parsers MUST stop immediately 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 +For all `TYPE` values except `0x00` and `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 @@ -595,6 +594,10 @@ The version field enables possible future enhancements: vectors for key serialisations. [content_type.json](./bip-0138/test_vectors/content_type.json) contains test vectors for content types serialisations. +[payload.json](./bip-0138/test_vectors/payload.json) contains test vectors for payload parsing. +`payload` and each item's `content` are hexadecimal bytes; `type` is the numeric +type byte, and `items` lists the content items before the terminator. + [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) diff --git a/bip-0138/test_vectors/payload.json b/bip-0138/test_vectors/payload.json new file mode 100644 index 00000000..826c5145 --- /dev/null +++ b/bip-0138/test_vectors/payload.json @@ -0,0 +1,13 @@ +[ + { + "description": "Bytes after terminator are ignored", + "valid": true, + "payload": "030001610080ff", + "items": [ + { + "type": 3, + "content": "61" + } + ] + } +] From bf64a12098691b7ba32444584300addfeec9f445 Mon Sep 17 00:00:00 2001 From: Sjors Provoost Date: Wed, 23 Sep 2026 14:31:54 +0200 Subject: [PATCH 3/4] bip138: clarify rejection of empty payloads Clarify that an empty payload contains zero content items. Add a vector that rejects a payload consisting only of the 0x00 terminator. --- bip-0138.md | 2 +- bip-0138/test_vectors/payload.json | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/bip-0138.md b/bip-0138.md index d339bedf..2cefbe12 100644 --- a/bip-0138.md +++ b/bip-0138.md @@ -338,7 +338,7 @@ 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. +Implementations MUST reject empty payloads (i.e. zero content items). #### Ciphertext diff --git a/bip-0138/test_vectors/payload.json b/bip-0138/test_vectors/payload.json index 826c5145..90ee8f65 100644 --- a/bip-0138/test_vectors/payload.json +++ b/bip-0138/test_vectors/payload.json @@ -9,5 +9,10 @@ "content": "61" } ] + }, + { + "description": "Payload with no content item.", + "valid": false, + "payload": "00" } ] From 62dc1c4e8f4c907a2932318cbd578896cf872590 Mon Sep 17 00:00:00 2001 From: Sjors Provoost Date: Wed, 23 Sep 2026 13:10:31 +0200 Subject: [PATCH 4/4] bip138: record encoding clarifications in changelog --- bip-0138.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bip-0138.md b/bip-0138.md index 2cefbe12..8c5d6cda 100644 --- a/bip-0138.md +++ b/bip-0138.md @@ -10,7 +10,7 @@ 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 - Version: 0.1.1 + Version: 0.1.2 Requires: 32, 340, 380, 388, 389 ``` @@ -633,6 +633,9 @@ their reviews and suggestions. ## Changelog +* __0.1.2__ (2026-09-24): + * Specify empty AEAD associated data. + * Clarify that `0x00` ends payload parsing and add test vectors. * __0.1.1__ (2026-09-23): * Clarify derivation range bounds and zero or omitted birth-time semantics for descriptors and policies. * Clarify receive-only descriptor sets and add a corresponding test vector.