Bip draft: Bitcoin Encrypted Backup #1951

pull pythcoiner wants to merge 1 commits into bitcoin:master from pythcoiner:encrypted_descriptor changing 9 files +1381 −0
  1. pythcoiner commented at 6:47 am on September 4, 2025: none

    This is a bip for encrypted backup, an encryption scheme for bitcoin wallet related metadata.

    Mailing list post: https://groups.google.com/g/bitcoindev/c/5NgJbpVDgEc

  2. pythcoiner marked this as a draft on Sep 4, 2025
  3. pythcoiner force-pushed on Sep 4, 2025
  4. in bip-encrypted-backup.md:4 in d9d02ffc5b outdated
    0@@ -0,0 +1,268 @@
    1+```
    2+BIP: ?  
    3+Layer: Applications  
    4+Title: Bitcoin Encrypted Backup  
    


    Sjors commented at 7:45 am on September 4, 2025:

    How about: Compact encryption scheme for non-seed wallet data

    Or some other wording to make it clear this isn’t for storing keys.


    abrahem79 commented at 4:03 pm on September 14, 2025:
    bip.diff
  5. in bip-encrypted-backup.md:28 in d9d02ffc5b outdated
    24+lexicographically‑sorted public keys inside the descriptor or policy, so any party
    25+who already holds one of those keys can later decrypt the backup without extra secrets
    26+or round‑trips. The format uses AES-GCM-256 with a 96‑bit random nonce and a 128‑bit
    27+authentication tag to provide confidentiality and integrity.
    28+While initially designed for descriptors and policies, the same scheme encrypts labels
    29+and backup metadata, allowing a uniform, vendor‑neutral, and future‑extensible backup format.
    


    Sjors commented at 7:47 am on September 4, 2025:
    The abstract should also explicitly state that it’s not intended for storing private key material.
  6. in bip-encrypted-backup.md:53 in d9d02ffc5b outdated
    48+1. **Descriptors are hard to store offline.**  
    49+   Descriptor string representation can be far longer than a 12/24-word seed phrase.  
    50+Paper, steel, and other long-term analog media quickly become impractical for such
    51+lengths, or error-prone to transcribe.
    52+
    53+2. **Online redundancy carries risk.**  
    


    Sjors commented at 7:48 am on September 4, 2025:
    privacy risk
  7. in bip-encrypted-backup.md:64 in d9d02ffc5b outdated
    59+
    60+These constraints lead to an acute need for an **encrypted**, and
    61+ideally compact backup format that:
    62+
    63+* can be **safely stored in multiple places**, including untrusted on-line services,  
    64+* can be **decrypt only by intended holders** of specified public keys,  
    


    Sjors commented at 7:49 am on September 4, 2025:
    decrypted
  8. in bip-encrypted-backup.md:65 in d9d02ffc5b outdated
    60+These constraints lead to an acute need for an **encrypted**, and
    61+ideally compact backup format that:
    62+
    63+* can be **safely stored in multiple places**, including untrusted on-line services,  
    64+* can be **decrypt only by intended holders** of specified public keys,  
    65+* and keeps both **keys and plaintext** hidden from any party who lacks the
    


    Sjors commented at 7:50 am on September 4, 2025:
    I don’t understand what you mean with this last sentence. Also do “keys” mean private keys or public keys?

    pythcoiner commented at 4:59 am on September 5, 2025:
    I’ll drop this one, it’s redunndant with the previous one
  9. in bip-encrypted-backup.md:37 in d9d02ffc5b outdated
    33+This BIP is licensed under the BSD 2-Clause License.  
    34+Redistribution and use in source and binary forms, with or without modification, are
    35+permitted provided that the above copyright notice and this permission notice appear
    36+in all copies.
    37+
    38+### Motivation
    


    Sjors commented at 7:52 am on September 4, 2025:
    This section could be shorter imo. It feels a bit repetitive. You can also link to the Delving post for more background.
  10. in bip-encrypted-backup.md:116 in d9d02ffc5b outdated
    111+This specification applies to creating, encrypting and decrypting a *Bitcoin Encrypted Backup*
    112+of **public-key-only wallet material**, namely:
    113+
    114+- a **descriptor** (BIP-0380)  
    115+- a **wallet policy** (BIP-0388)  
    116+- **BIP-329 labels** (JSONL)  
    


    Sjors commented at 7:54 am on September 4, 2025:
    Imo the primary motivation for this proposal is to store a descriptor or policy (they’re interchangeable). Storing additional information is nice to have.
  11. in bip-encrypted-backup.md:120 in d9d02ffc5b outdated
    115+- a **wallet policy** (BIP-0388)  
    116+- **BIP-329 labels** (JSONL)  
    117+- **wallet-wide JSON backup metadata**  
    118+
    119+All four payloads are encrypted under the same key derivation rules detailed below.
    120+The scheme is **not** intended for descriptors or policies that contain private keys,
    


    Sjors commented at 7:56 am on September 4, 2025:
    Another way to put this is: private keys and seeds MUST be removed (neutered) from descriptors before storing them in this scheme.
  12. in bip-encrypted-backup.md:132 in d9d02ffc5b outdated
    127+
    128+### Secret generation
    129+
    130+* Let `p_1`, `p_2`, .., `p_n` be the public keys in the descriptor/wallet policy, in
    131+increasing lexicographical order.  
    132+* let `secret` = sha256("BEB_DECRYPTION_SECRET" ‖ `p1` ‖ `p2` ‖ ... ‖ `pn`)  
    


    Sjors commented at 7:57 am on September 4, 2025:
    Instead of BEB I would suggest BIP_XXX (replaced with the BIP number once assigned).

    pythcoiner commented at 5:38 am on September 5, 2025:
    I’ve written w/ BIPxxxx at first, but changes it to BEB then, as we are very likely to ship a feature using this scheme in Liana v13 (so likely before this get assigned a BIP #)…

    Sjors commented at 6:51 am on September 5, 2025:
    Liana could switch to the BIP number once assigned. When reading it could first check BEP and then BIP_XXXX. That also gives you the flexibility to make breaking changes to other parts of this spec without having to bump the version number.

    pythcoiner commented at 10:11 am on September 5, 2025:
    Agree, we are in control of what happen in Liana, but my concern is more about other implementations that will not be able to decrypt early version generated w/ Liana… Btw, we already plan to ship w/ version 0, that’s why this BIP draft define version 1…

    Sjors commented at 4:31 pm on September 5, 2025:
    I would probably just write a Gist documenting the Liana-specific v0 (other mights have tried your code as well), and then maybe link to it from a footnote in the BIP.
  13. in bip-encrypted-backup.md:21 in d9d02ffc5b outdated
    16+### Abstract
    17+
    18+This BIP defines a compact encryption scheme for **wallet descriptors** (BIP-0380),
    19+**wallet policies** (BIP-0388), **labels** (BIP-0329), and
    20+**wallet backup metadata** (json). The encrypted output—called a
    21+*bitcoin encrypted backup* (BEB), enables users to outsource long‑term storage to
    


    Sjors commented at 8:00 am on September 4, 2025:
    This scheme is generic enough that I don’t think it needs the word “bitcoin” in it. I also don’t think we need to pick a “marketing name”, something more boring like “BIP_XXX encrypted backup” should be fine.
  14. in bip-encrypted-backup.md:133 in d9d02ffc5b outdated
    128+### Secret generation
    129+
    130+* Let `p_1`, `p_2`, .., `p_n` be the public keys in the descriptor/wallet policy, in
    131+increasing lexicographical order.  
    132+* let `secret` = sha256("BEB_DECRYPTION_SECRET" ‖ `p1` ‖ `p2` ‖ ... ‖ `pn`)  
    133+* let `si` = sha256("BEB_INDIVIDUAL_SECRET" ‖ `pi`)  
    


    Sjors commented at 8:01 am on September 4, 2025:
    If it’s possible to use subscript in markdown then I would prefer to keep the original notation with small i. Otherwise let’s use an underscore, i.e. s_i

    pythcoiner commented at 9:26 am on September 13, 2025:
    done
  15. in bip-encrypted-backup.md:169 in d9d02ffc5b outdated
    201+`COUNT`: 1-byte unsigned integer (1–255) indicating how many secrets are included.  
    202+`INDIVIDUAL_SECRET`: 32-byte serialization of the derived individual secret.
    203+
    204+#### Content
    205+
    206+`CONTENT`: 1-byte unsigned integer identifying what has been encrypted.
    


    Sjors commented at 8:07 am on September 4, 2025:
    I would prefer to keep this secret and have multiple pieces of content in a single backup. So my suggestion is to move this inside the encrypted payload and then allow for multiple content entries.

    pythcoiner commented at 9:51 am on September 4, 2025:

    and then allow for multiple content entries

    hum, no strong opinion on this, but if the purpose is to have a single encrypted file containing descriptor(380 or 388) + labels + wallet metadata then it should fit into 0x04 Wallet Backup (yeah I’ll have to write a formal spec)


    Sjors commented at 10:27 am on September 4, 2025:
    In the original delving post there’s no specification of the format at all. So you could also just say it should be JSON and leave it up to other BIPs or convention.

    pythcoiner commented at 5:55 am on September 5, 2025:
    Yeah this BIP draft differ a bit from the initial post in the fact it intentionally add some formating convention

    pythcoiner commented at 11:52 am on September 13, 2025:
    @Sjors, in aa37c4b I’ve moved CONTENT to the encrypted part, letting some room for extension, like for embed several content types.
  16. in bip-encrypted-backup.md:177 in d9d02ffc5b outdated
    209+|:-------|:---------------------------------------|
    210+| 0x00   | Undefined                              |
    211+| 0x01   | BIP-0380 Descriptor (string)           |
    212+| 0x02   | BIP-0388 Wallet policy (string)        |
    213+| 0x03   | BIP-0329 Labels (JSONL)                |
    214+| 0x04   | Wallet backup (JSON)                   |
    


    Sjors commented at 8:10 am on September 4, 2025:

    Maybe point out that unlisted types should still be decrypted and that new types may be added to the BIP.

    That said, a more generic approach would be to allow a bit more space for the type. E.g. a ~4 digit number that must represent a BIP number. Or a short string like “BIP-0329”. Both avoid the need to maintain a central register.

    Also, if you allow multiple pieces of content in a single encrypted blob, it’s useful to have a padding type.

  17. in bip-encrypted-backup.md:331 in d9d02ffc5b outdated
    251+### Future Extensions
    252+
    253+The version field enables possible future enhancements:
    254+
    255+- Additional encryption algorithms  
    256+- Support for threshold-based decryption
    


    Sjors commented at 8:11 am on September 4, 2025:
    • hide the number of participants
    • bech32m export (convenient for text based storage like an email to yourself, as well as for printing - if you’re patient)

    pythcoiner commented at 11:05 am on September 4, 2025:

    hide the number of participants

    hum, the number of participant can also be hidden (derivation path are optionals) and one can also add fake ones, how do you think we can enhance this further?


    Sjors commented at 11:07 am on September 4, 2025:
    It’s currently revealed by the number of c_i shares, so it would be a more complicated overhaul. I don’t think it’s urgent.

    pythcoiner commented at 11:10 am on September 4, 2025:
    right

    pythcoiner commented at 9:39 am on September 13, 2025:
    added
  18. pythcoiner commented at 9:42 am on September 4, 2025: none
    thanks for the review! will address comments tmr!
  19. jonatack added the label New BIP on Sep 4, 2025
  20. Sjors commented at 12:52 pm on September 4, 2025: member

    Open questions

    • Deterministic nonce: Currently the nonce is generated randomly. Is it safe to produce a deterministic nonce, e.g. hash("NONCE" || plaintext || key_1 || … || key_n), or are there known security concerns with this approach?

    In general nonce reuse is unsafe because if you make multiple backups over time, e.g. as you add more transaction labels, you would be reusing the nonce with different message. By including the plaintext in the nonce, you do address that concern.

    However it still seems unwise to mess with cryptographic standards. It doesn’t seem worth the risk for saving 32 bytes on something that’s going to be at least a few hundred bytes for a typical multisig.

  21. shocknet-justin commented at 5:09 pm on September 4, 2025: none
    Concept ACK, seems adjacent to how some lightning tools enable users to recover SCB’s with just their seed to identify and decrypt the backup. Makes sense for descriptors to have something similar.
  22. pythcoiner force-pushed on Sep 5, 2025
  23. pythcoiner force-pushed on Sep 5, 2025
  24. pythcoiner force-pushed on Sep 5, 2025
  25. pythcoiner force-pushed on Sep 5, 2025
  26. pythcoiner force-pushed on Sep 5, 2025
  27. pythcoiner force-pushed on Sep 5, 2025
  28. pythcoiner force-pushed on Sep 5, 2025
  29. Sjors commented at 6:59 am on September 5, 2025: member
    Concept ACK
  30. pythcoiner commented at 9:50 am on September 5, 2025: none
    (not yet finish addressing comments)
  31. in bip-encrypted-backup.md:20 in 2ec6487d74 outdated
    15+
    16+### Abstract
    17+
    18+This BIP defines a compact encryption scheme for **wallet descriptors** (BIP-0380),
    19+**wallet policies** (BIP-0388), **labels** (BIP-0329), and
    20+**wallet backup metadata** (json). The payload must not contains any private key material.
    


    torkelrogstad commented at 3:40 pm on September 8, 2025:
    contain, not contains

    pythcoiner commented at 9:28 am on September 13, 2025:
    done
  32. KeysSoze commented at 9:57 pm on September 9, 2025: none

    Hi @pythcoiner,

    By coincidence, two weeks ago I started working on a proposal for a “Standard Encrypted Wallet Payload” to be placed inside an “Encrypted Envelope”. The “Wallet Payload” contains descriptors and metadata but can also act as a full wallet backup including transactions, UTXOs and addresses. The proposal is very much a work in progress.

    I only just found this discussion so am reading through it to compare it to my proposal. The descriptor backup in the “Wallet Payload” of my proposal seems to have some overlap with the BIP proposed here. If there is too much overlap I may reconsider progressing with my proposal.

    As mentioned, my proposal is very much a work in progress but the wallet payload proposal can be found here:

    https://gist.github.com/KeysSoze/7109a7f0455897b1930f851bde6337e3

    Maybe jump to the test vector section to see what a basic backup of a descriptor and some meta data would look like prior to encryption.

    https://gist.github.com/KeysSoze/7109a7f0455897b1930f851bde6337e3#test-vectors

    As my proposal is designed to be modular and extensible the encryption envelopes may be extended to offer Multiparty Encryption and Authentication. See:

    https://gist.github.com/KeysSoze/7109a7f0455897b1930f851bde6337e3#user-content-Expanding_the_Security_Model

    I have already started documenting an encryption envelope that uses AES-256-GCM and password protection:

    https://gist.github.com/KeysSoze/866d009ccd082edf6802df240154b20d

    I have not written a reference implementation yet but there are well established python and Rust libraries for CBOR and COSE that should make implementing the BIPs relatively simple.

  33. pythcoiner force-pushed on Sep 13, 2025
  34. pythcoiner force-pushed on Sep 13, 2025
  35. pythcoiner force-pushed on Sep 13, 2025
  36. pythcoiner force-pushed on Sep 13, 2025
  37. pythcoiner commented at 10:05 am on September 13, 2025: none

    Hi @pythcoiner,

    By coincidence, two weeks ago I started working on a proposal for a “Standard Encrypted Wallet Payload” to be placed inside an “Encrypted Envelope”. The “Wallet Payload” contains descriptors and metadata but can also act as a full wallet backup including transactions, UTXOs and addresses. The proposal is very much a work in progress.

    Hi @KeysSoze, this work seems more related/parallel to the wallet_backup specs I’ve work on few month ago.

    But I’ve adopted a slightly different approach by simply using JSON.

    FYI we already implemented this wallet backup format in Liana wallet and I plan to work on a BIP proposal relatively soon.

  38. abrahem79 commented at 4:02 pm on September 14, 2025: none
    bip-encrypted-backup.md
  39. in bip-encrypted-backup.md:86 in aa37c4bbc1 outdated
    89+
    90+Note: in the followings sections, the operator ⊕  refers to the bitwise XOR operation.
    91+
    92+### Secret generation
    93+
    94+- Let $p_1, p_2, \dots, p_n$, be the public keys in the descriptor/wallet policy, in increasing lexicographical order
    


    jp1ac4 commented at 12:01 pm on September 15, 2025:
    We might like to use a subset of the public keys in some cases, e.g. if a Taproot descriptor contains an unspendable internal key that is commonly used across multiple descriptors. cc @bigspider @darosior

    pythcoiner commented at 3:51 pm on September 15, 2025:
    right, we also need to specify that BIP0341 NUMS MUST be sorted out

    bigspider commented at 8:45 am on September 16, 2025:

    Ideally, for wallet policies, in the long term we might want to introduce a placeholder for a deterministically derived NUMS key, as discussed for example here. So there wouldn’t be any xpub at all. But that’s not currently specified in BIP-388.

    Explicitly excluding all the pubkeys with x coordinate 50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0 seems appropriate and should be forward-compatible with variations of this scheme.

    It might be worth mentioning that one could choose just a subset of it is not intended for some of these keys to be able to recover from the backup. The caveat is that it becomes application-specific which of those keys should be able to recover. So if that’s mentioned, this should be discussed a bit (for example by adding a recommendation to clearly specify the details in the documentation of the application).


    pythcoiner commented at 10:17 am on September 16, 2025:

    what i’m actually wondering: is there any constructions that have an unspendable key NOT using the BIP341 NUMS? @hugohn @ben-kaufman @Rob1Ham

    Is there some Lightning constructions using unspendable keys?


    pythcoiner commented at 9:46 am on October 22, 2025:

    For the record:


    pythcoiner commented at 9:48 am on October 22, 2025:

    The caveat is that it becomes application-specific which of those keys should be able to recover. So if that’s mentioned, this should be discussed a bit (for example by adding a recommendation to clearly specify the details in the documentation of the application).

    I’m quite sure there will be usescases where the user can disable some keys


    Sjors commented at 9:11 am on January 9, 2026:
    If encryption tooling adds an option to you strip specific public keys (in addition to the standard NUMS point), then on the decryption side those keys simply fail to decrypt, which seems fine.
  40. pythcoiner force-pushed on Dec 1, 2025
  41. pythcoiner force-pushed on Dec 1, 2025
  42. pythcoiner force-pushed on Dec 2, 2025
  43. pythcoiner force-pushed on Dec 2, 2025
  44. Sjors commented at 8:38 am on January 9, 2026: member

    The PR is still draft. Are there things you’re still working on?

    What’s the bip.diff file about? Accidentally committed?

    Gathered open issues from the inlines threads:

    • replace BEB with BIP_XXXX once assigned #1951 (review) (and document Liana compatible format)
    • the VARIANT stuff is confusing

    Nit: there’s quite a bit of trailing whitespace (which my editor then automatically tries to fix)


    Maybe this could replace VARIANT:

     0#### Content
     1
     2`CONTENT` is a variable length field defining the type of `PLAINTEXT` being encrypted,
     3it follows this format:
     4
     5`TYPE` (`LENGTH`) `DATA`
     6
     7`TYPE`: 1-byte unsigned integer identifying how to interpret `DATA`.
     8
     9| Value  | Definition                             |
    10|:-------|:---------------------------------------|
    11| 0x00   | Reserved                               |
    12| 0x01   | BIP Number (big-endian uint16)         |
    13| 0x02   | Vendor-Specific Opaque Tag             |
    14
    15`LENGTH`: variable-length integer representing the length of `DATA` in bytes.
    16
    17For all `TYPE` values except `0x01`, `LENGTH` MUST be present.
    18
    19`DATA`: variable-length field whose encoding depends on `TYPE`.
    20
    21For `TYPE` values defined above:
    22- 0x00: parsers MUST reject the payload.
    23- 0x01: `LENGTH` MUST be omitted and `DATA` is a 2-byte big-endian unsigned integer representing the BIP number that defines it.
    24- 0x02: `DATA` MUST be `LENGTH` bytes of opaque, vendor-specific data.
    25
    26For all `TYPE` values except `0x01`, parsers MUST reject `CONTENT` if `LENGTH` exceeds the remaining payload bytes.
    27
    28Parsers MUST skip unknown `TYPE` values less than `0x80`, by consuming `LENGTH` bytes of `DATA`.
    29
    30For unknown `TYPE` values greater than or equal to `0x80`, it MUST stop parsing `CONTENT`.
    

    It might add one extra byte for the BIP case, but that’s negligible compared to the length of a typical descriptor. And it reduces complexity.

    The TYPE >= 0x80 TYPE rule means we’re not stuck with the current TLV encoding. And it has a nice upgrade property: you can still encode backward compatible stuff at the start.

    Let’s also add quick section to encourage base64 encoding:

    0### Text Representation
    1
    2Implementations SHOULD encode and decode the backup using Base64 (RFC 4648).[^psbt-base64]
    3
    4[^psbt-base64]: **Why Base64?**  
    5   PSBT (BIP174) is commonly exchanged as a Base64 string, so wallet software likely already supports this representation.
    

    (the footnote format is the same as in BIP3, I think we should use it for all rationale bits)

  45. in bip-encrypted-backup.md:53 in bfdf6f72a3 outdated
    48+   become impractical or error-prone.  
    49+
    50+2. **Online redundancy carries privacy risk.**  
    51+   USB drives, phones, and cloud storage solve the length problem but expose your
    52+   wallet structure. Plaintext descriptors leak your pubkeys and script details.
    53+   Cloud encryption doesn't help against subpoenas or provider breaches, and each
    


    Sjors commented at 9:03 am on January 9, 2026:

    Let’s not trigger a debate about cloud encryption schemes, maybe say:

    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.

  46. in bip-encrypted-backup.md:56 in bfdf6f72a3 outdated
    51+   USB drives, phones, and cloud storage solve the length problem but expose your
    52+   wallet structure. Plaintext descriptors leak your pubkeys and script details.
    53+   Cloud encryption doesn't help against subpoenas or provider breaches, and each
    54+   copy increases attack surface.  
    55+
    56+These constraints lead to an acute need for an **encrypted**, and
    


    Sjors commented at 9:06 am on January 9, 2026:

    “acute”? It’s been years :-)

    This BIP therefore proposes an encrypted, and compact backup format that:

  47. in bip-encrypted-backup.md:95 in bfdf6f72a3 outdated
    90+
    91+**Note:** To prevent attackers from decrypting the backup using publicly known
    92+keys, explicitly exclude any public keys with x coordinate
    93+`50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0` (the BIP341 NUMS
    94+point, used as a taproot internal key in some applications). Additionally, exclude any
    95+other publicly known keys. In some cases, it may be possible to exclude certain keys
    


    Sjors commented at 9:14 am on January 9, 2026:

    Let’s move this to a new paragraph:

    Applications that exclude additional keys SHOULD document this, although decryption using these keys will simply fail. This does not affect decryption with the remaining keys.

  48. in bip-encrypted-backup.md:101 in bfdf6f72a3 outdated
     96+from this process for customs applications or user needs, it is recommended to document
     97+such decision.
     98+
     99+### Key Normalization
    100+
    101+Before computing the encryption secret, all public keys in the descriptor/wallet policy MUST be normalized to **33-byte compressed public key format** (SEC format with 0x02 or 0x03 prefix).
    


    Sjors commented at 9:16 am on January 9, 2026:

    Why not normalise to x-only keys? 32 bytes is a nice size.

    In any case, it’s good to add a footnote to explain this choice.


    pythcoiner commented at 8:40 am on January 10, 2026:
    yeah if we’re gonna “break” things from what we have actually in Liana, I’m happy with x-only also
  49. Sjors commented at 9:21 am on January 9, 2026: member
    @murchandamus or other editor: I think this has progressed enough to be BIP number worthy. It would make it easier to generate stable test vectors.
  50. in bip-encrypted-backup.md:252 in bfdf6f72a3 outdated
    221+
    222+`CIPHERTEXT` is the encrypted data resulting encryption of `PAYLOAD` with algorithm
    223+defined in `ENCRYPTION` where `PAYLOAD` is encoded following this format:
    224+
    225+`CONTENT` `PLAINTEXT`
    226+
    


    Sjors commented at 10:38 am on January 9, 2026:

    Let’s introduce this here, and not repeat it:

    0#### Integer Encodings
    1
    2All variable-length integers are encoded as [compact size](https://en.bitcoin.it/wiki/Protocol_documentation#Variable_length_integer).
    
  51. in bip-encrypted-backup.md:132 in bfdf6f72a3 outdated
    127+- If y is odd: prefix with 0x03
    128+- Result is 33 bytes (prefix + x-coordinate)
    129+
    130+See [keys_types.json](./bip-encrypted-backup/test_vectors/keys_types.json) for normalization test vectors.
    131+
    132+### AES-GCM Encryption
    


    Sjors commented at 11:17 am on January 9, 2026:

    Above you write:

    The format uses AES-GCM-256 with a 96‑bit random nonce and a 128‑bit authentication tag to provide confidentiality and integrity.

    But this is a better place to specify that. I think it’s good that BIP picks one variant, which allows folks to use a stripped down implementation if needed.

  52. pythcoiner commented at 1:00 pm on January 9, 2026: none

    @Sjors thanks for the comments, will address during the week end or next week.

    The PR is still draft. Are there things you’re still working on?

    I’m working on another BIP draft for the payload of a wallet backup, i’d like to undraft them together, as they are quite related: the payload is expected to be encrypted with this spec…

    In the meantime, I’ve “played” with a C implementation of this BIP draft, I wanted to check how hard it should be to implement in bitcoin core and I figure out something: it seems there is actually no dependency in core for AES-GCM-256, while there is already usage of CHACHA20 so i’m wondering if we should not use CHACHA20 as default encryption algo? (I’ll cross-post to delving)

  53. Sjors commented at 1:30 pm on January 9, 2026: member

    @pythcoiner using AEAD_CHACHA20_POLY1305 is an interesting idea! Would make it very easy in Bitcoin Core, and perfectly doable in other projects since these are standard components. Good idea to ask on Delving.

    In theory we don’t need the Poly1305 part, since we’re not worried about man-in-the-middle attacks on the backup, but I suspect any library with ChaCha20 will also have Poly1305.

    C implementation of this BIP draft

    For Bitcoin Core you can use c++, no need to torture yourself. But if it also works in C that makes it easier for hardware wallets to have low level support - not sure if they needed, but still. You could also try with embedded Rust and MicroPython.

    Perhaps an extension of the protocol could have hardware wallet sign off on the descriptor / policy, by appending CONTENT with e.g. an HMAC field.

  54. pythcoiner force-pushed on Jan 10, 2026
  55. pythcoiner commented at 7:56 am on January 10, 2026: none

    What’s the bip.diff file about? Accidentally committed?

    yes, I’ve dropped it

  56. pythcoiner commented at 8:45 am on January 10, 2026: none

    no need to torture yourself

    not felt the torture part :smile:

    the idea was more, all languages can bind to C, it’s not always the case for c++ (or at least less easy) and maybe it worth to have a single implem to maintain

  57. pythcoiner force-pushed on Jan 14, 2026
  58. pythcoiner commented at 1:38 am on January 14, 2026: none
    @Sjors I think all comments has been addressed, not yet entirely finnish updating the rust implementation. There is still some double trailing spaces, necessary for formating.
  59. bip encrypted_backup 160c34aff1
  60. pythcoiner force-pushed on Jan 14, 2026
  61. in bip-encrypted-backup.md:143 in 160c34aff1
    138+
    139+### Encryption
    140+
    141+The format uses CHACHA20_POLY1305 (RFC 8439) as the default encryption algorithm,
    142+with a 96-bit random nonce and a 128-bit authentication tag to provide confidentiality
    143+and integrity. AES_256_GCM is also supported as an alternative.[^chacha-default]
    


    Sjors commented at 7:39 am on January 14, 2026:

    I’m not sure it’s a good idea to support two formats. On the encryption side there’s no extra burden, since implementers can just pick their favourite. But on the decryption side you kinda have no choice but to support both.

    My preference would be to drop AES_256_GCM entirely. Alternatively to make it a second class citizen, with phrasing along the lines of:

    Implementations MUST support CHACHA20_POLY1305 decryption and MAY also support the alternative AES_256_GCM scheme for decryption .

    Implementations SHOULD use CHACHA20_POLY1305 encryption, but if implementation is problematic they MAY use AES_256_GCM instead.

  62. craigraw commented at 10:11 am on January 14, 2026: contributor
    This proposal makes multiple references to BIP 380 as defining wallet descriptors. This is incorrect - BIP 380 defines output script descriptors. Since we may have a need to define wallet descriptors as specific format in future (including, for example, a wallet birthday) I believe these references should be corrected.
  63. Sjors commented at 4:33 pm on January 14, 2026: member

    I vibe coded an implementation on top of Bitcoin Core: https://github.com/Sjors/bitcoin/pull/109

    It’s nice to see how we can mostly reuse existing tooling. It still adds over 1000 lines of non-test code though.

    Doing so brought up some issues to reconsider:

    • should we just use VarInt everywhere to simplify parsing at the expense of a few extra bytes?
    • tagged hashes seem to deviate from how they work in BIP340, so we can’t use TaggedHash(): (I didn’t investigate), LLM says:
     0/ Current implementation (14 lines):
     1uint256 ComputeDecryptionSecret(const std::vector<uint256>& keys)
     2{
     3    HashWriter hasher{};
     4    hasher << std::span{reinterpret_cast<const uint8_t*>(BIP_DECRYPTION_SECRET_TAG.data()),
     5                        BIP_DECRYPTION_SECRET_TAG.size()};
     6    for (const auto& key : keys) {
     7        hasher << std::span{key.data(), 32};
     8    }
     9    return hasher.GetSHA256();
    10}
    11
    12// With BIP340-style tags (could become):
    13uint256 ComputeDecryptionSecret(const std::vector<uint256>& keys)
    14{
    15    HashWriter hasher = TaggedHash("BIP_XXXX_DECRYPTION_SECRET");
    16    for (const auto& key : keys) hasher << key;
    17    return hasher.GetSHA256();
    18}
    

    (that seems like a fairly trivial difference anyway)

  64. pythcoiner commented at 4:55 pm on January 14, 2026: none

    This proposal makes multiple references to BIP 380 as defining wallet descriptors. This is incorrect - BIP 380 defines output script descriptors. Since we may have a need to define wallet descriptors as specific format in future (including, for example, a wallet birthday) I believe these references should be corrected. @craigraw Right, I’ll change this

    I vibe coded an implementation on top of Bitcoin Core: Sjors/bitcoin#109 @Sjors Thanks for looking on this!

    I’m ok to change stuff if it make integration in core simpler

  65. murchandamus added the label PR Author action required on Jan 27, 2026

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bips. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-02-10 16:10 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me