[POC] wallet: Enable non-electronic (paper-based) wallet backup with codex32 #33043

pull w0xlt wants to merge 5 commits into bitcoin:master from w0xlt:codex32 changing 31 files +1437 −46
  1. w0xlt commented at 7:36 am on July 23, 2025: contributor

    This PR introduces support for exporting and restoring wallet seeds using the codex32 format, enabling non-electronic (paper-based) wallet backups.

    To accomplish this, the patch ports the codex32.{c,h} implementation from Core Lightning to C++, integrating it with Bitcoin Core’s libraries. Corresponding unit tests for codex32 encoding and decoding are also included.

    Because Bitcoin Core wallets currently do not store the seed material by default, this PR adds support for doing so, along with a new wallet flag to explicitly indicate when this feature is enabled.

    Two new RPCs are introduced:

    exposesecret: exports the wallet seed in codex32 format.

    recoverwalletfromseed: restores a wallet from a codex32-encoded seed.

    A functional test included in the last commit demonstrates the full backup and restore flow. Currently, only the default derivation path is supported.

    This PR is intended as a proposal for feedback—to assess whether this functionality is desirable, and to explore how it might evolve further.

  2. DrahtBot commented at 7:36 am on July 23, 2025: contributor

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    Code Coverage & Benchmarks

    For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/33043.

    Reviews

    See the guideline for information on the review process. A summary of reviews will appear here.

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #33112 (wallet: relax external_signer flag constraints by Sjors)
    • #33034 (wallet: Store transactions in a separate sqlite table by achow101)
    • #32977 (wallet: Remove wallet version and several legacy related functions by w0xlt)
    • #32966 (Silent Payments: Receiving by Eunovo)
    • #32895 (wallet: Prepare for future upgrades by recording versions of last client to open and decrypt by achow101)
    • #32652 (wallet: add codex32 argument to addhdkey by roconnor-blockstream)
    • #32489 (wallet: Add exportwatchonlywallet RPC to export a watchonly version of a wallet by achow101)
    • #28333 (wallet: Construct ScriptPubKeyMans with all data rather than loaded progressively by achow101)
    • #27865 (wallet: Track no-longer-spendable TXOs separately by achow101)
    • #26022 (Add util::ResultPtr class by ryanofsky)

    If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

    LLM Linter (✨ experimental)

    Possible typos and grammar issues:

    • IDENTIFER -> IDENTIFIER [correct spelling in “IDENTIFER := BECH32*4”]
    • in stored -> are stored [grammar fix: “wallet seeds in stored in database”]

    drahtbot_id_4_m

  3. DrahtBot added the label CI failed on Jul 23, 2025
  4. DrahtBot commented at 9:36 am on July 23, 2025: contributor

    🚧 At least one of the CI tasks failed. Task lint: https://github.com/bitcoin/bitcoin/runs/46538554195 LLM reason (✨ experimental): The CI failure is caused by lint errors, including trailing whitespace, locale-dependent functions, spelling errors, incorrect file permissions, and missing include guards.

    Try to run the tests locally, according to the documentation. However, a CI failure may still happen due to a number of reasons, for example:

    • Possibly due to a silent merge conflict (the changes in this pull request being incompatible with the current code in the target branch). If so, make sure to rebase on the latest commit of the target branch.

    • A sanitizer issue, which can only be found by compiling with the sanitizer and running the affected test.

    • An intermittent issue.

    Leave a comment here, if you need help tracking down a confusing failure.

  5. apoelstra commented at 2:35 pm on July 23, 2025: contributor

    For encrypted wallets, recovery requires both the codex32 seed and the original passphrase, enhancing the security.

    If I understand you correctly, the intent is that an attacker needs the wallet passphrase in addition to the seed. But the seed is the seed – once an attacker has it, it’s game over. He doesn’t need the passphrase or any other part of the wallet to sweep coins.

    codex32 itself does not have any notion of passphrases or encryption.

  6. w0xlt commented at 3:57 pm on July 23, 2025: contributor

    Yes, you’re right. I thought the passphrase deterministically modified the seed to create the BIP 32 Extended Key, but that’s not the case. https://github.com/bitcoin/bitcoin/blob/73e754bd01b0653d1fda2d947fcaed0742da81c3/src/wallet/wallet.cpp#L3542

    So the passphrase doesn’t provide any additional security in this case.

  7. w0xlt marked this as a draft on Jul 23, 2025
  8. w0xlt commented at 4:25 pm on July 23, 2025: contributor

    This could still be implemented—even as part of this PR.

    The wallet generates the seed, stores it, and then derives the BIP32 master key by deterministically combining the seed with the user-provided passphrase. This approach allows users to back up the raw seed while still requiring the passphrase for wallet recovery.

    Or am I missing something ?

  9. wallet: Add codex32 files 8b80a59893
  10. wallet: Store seeds in database 2d6b910820
  11. wallet: Add exposesecret RPC 25b0878cff
  12. Add recoverwalletfromseed RPC 27bef167f0
  13. w0xlt force-pushed on Jul 23, 2025
  14. Add codex32 functional test 14f3342262
  15. w0xlt force-pushed on Jul 23, 2025
  16. Sjors commented at 7:20 pm on July 24, 2025: member
    How does this relate to #27351 / #32652? It’s probably easier to support import before export.
  17. w0xlt commented at 8:12 pm on July 24, 2025: contributor

    The emphasis of this PR is on backup functionality: a backup feature isn’t very useful unless you can also restore the wallet reliably.

    By contrast, the other PRs aim only to import a Codex32 secret—presumably from Core Lightning into Bitcoin Core—and each uses a different method. The approach here creates a fresh wallet and rescans the chain, whereas PR  #32652 appears to convert a Codex32 secret into an xpub via the proposed addhdkey RPC.

  18. Sjors commented at 6:39 am on July 25, 2025: member

    It might be useful to open an issue to discuss paper backups in general.

    I think conceptually the are three different things to backup, and each has different requirements and frequencies:

    1. Private key material: backed up once at wallet creation time (or never, in some multisig setups where recovery consists of using the other keys and moving to a fresh wallet). Needs to be kept secure against theft.
    2. Output descriptors: for anything more complicated than a BIP48 multisig setup you have to keep track of this, or you’ll never find your coins. New descriptors may be added later in the life of a wallet (e.g. for our wallet it happened when taproot support was added, albeit in a deterministic way). Backup happens at wallet creation time and each time a new descriptor is added. Needs to be kept secure for privacy reasons, but not for theft
    3. Transaction meta data (labels, etc), see https://github.com/bitcoin/bips/blob/master/bip-0329.mediawiki. Backups happens frequently. Needs to be kept secure for privacy reasons, but also may need to be imported into bookkeeping software. Printing it may be useful so you can still look things up 20 years from now when who knows what the world looks like and what software people use.

    This division borrows heavily from the motivation section of: https://delvingbitcoin.org/t/a-simple-backup-scheme-for-wallet-accounts/1607

    It seems to me that codex32 only plays a role in (1). And so importing it should be done with addhdkey. Exporting could be done with gethdkeys.

    It may be nice to have a more user friendly way to do all or some of (1), (2) and (3). But that I would probably write a markdown document or a Python script. Outside of this project I could imagine a nice tool that calls various RPC methods and generates a pretty PDF, though I would not recommend that for (1).


github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2025-08-12 09:13 UTC

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