diff --git a/docs/developer/api.md b/docs/developer/api.md index 50f3250..d031230 100644 --- a/docs/developer/api.md +++ b/docs/developer/api.md @@ -640,10 +640,12 @@ fingerprint consistency, and network xpub/tpub versions, constructs only the fixed descriptor templates, and asks `getdescriptorinfo` to validate and expand their external/internal branches. The adapter then compares the exact eight active public descriptors against `listdescriptors`. It relocks wallets Core -reports as encrypted. Master-fingerprint display is likewise delegated to Core: -a stateless root P2PKH descriptor is normalized, `deriveaddresses` derives its -address, and `validateaddress` returns the script hash whose first four bytes are -the BIP32 fingerprint. +reports as encrypted. Master-fingerprint and graphical recovery-commitment +derivation are likewise delegated to Core. A stateless root P2PKH descriptor is +normalized to its public root xpub. SHA-256 over the domain-separated canonical +xpub supplies the 256-bit recovery commitment; `deriveaddresses` and +`validateaddress` return the script hash whose first four bytes are the BIP32 +fingerprint. Neither operation opens or mutates a wallet. The Core calls are fixed: `getnetworkinfo`, `getblockchaininfo`, `listwallets`, `getwalletinfo`, `listdescriptors`, `getdescriptorinfo`, `deriveaddresses`, diff --git a/docs/security/invariants.md b/docs/security/invariants.md index d82e39e..c2f448b 100644 --- a/docs/security/invariants.md +++ b/docs/security/invariants.md @@ -12,8 +12,10 @@ and evidence. gated by confirmation. Input cannot replace entropy or the original secret. 4. Wallet setup uses the original ceremony result or a validated recovered seed. Graphical recovery derives public wallet identity first and requires the - operator to confirm it against the separately stored wallet record before - any recovered key material may mutate a Bitcoin Core wallet. + operator to enter a separately stored SHA-256 commitment to the canonical + root xpub before any recovered key material may mutate a Bitcoin Core wallet. + The 32-bit BIP32 fingerprint is diagnostic metadata, never the authorization + value for this transition. 5. Correction shares one mass bound and deadline across target lengths. The public API fails closed on incomplete required work; CLI searches may return one primary-best-so-far eligible candidate at the deadline. Incomplete diff --git a/docs/security/model.md b/docs/security/model.md index 03a474c..14ef9f7 100644 --- a/docs/security/model.md +++ b/docs/security/model.md @@ -68,6 +68,10 @@ The operator must: guarantee new physical entropy between calls. - A checksum, generation-padding hint, fingerprint, or correction candidate does not authenticate a backup or prove the operator's intent. +- The graphical recovery commitment is a domain-separated SHA-256 digest of + the canonical root xpub returned by Bitcoin Core. It is public metadata and + authenticates only against the separately stored record; it is not a secret, + a MAC, or proof that the record itself is trustworthy. - Creation feedback identifies correct groups but does not prove the recovery card was corrected. - A fresh unshared master seed exposes a public 20-bit BIP32 fingerprint in its default identifier; fingerprints are metadata, not secrets. @@ -269,13 +273,16 @@ only while more than one answers. On screen a wallet is chosen by the position o its row, never by the text of its label, and Core's text is rendered without Pango markup, so a wallet name cannot hide or impersonate another. -Restore derives the recovered seed's master fingerprint through Bitcoin Core -before destination selection and displays it with the backup identifier. The -operator must explicitly confirm that fingerprint against the separately stored -wallet record before the program lists, creates, unlocks, or imports into a -destination wallet. A mismatch can therefore stop recovery without mutating a -Bitcoin Core wallet. The fingerprint remains only a short diagnostic identifier; -its authentication-strength limitation above still applies. +Restore derives the recovered seed's canonical root xpub and master fingerprint +through Bitcoin Core before destination selection. It computes the recovery +commitment as `SHA256(domain_tag || root_xpub)`, where `domain_tag` is the +ASCII text `codex32 recovery commitment` followed by one NUL byte. It asks the +operator to enter the 256-bit value from the separately stored wallet +record. The expected commitment is not displayed before comparison. Only a +match permits the program to list, create, unlock, or import into a destination +wallet, so a mismatch can stop recovery without mutating one. The fingerprint +is still displayed as a short diagnostic identifier but is not used to authorize +the transition. The program draws no entropy, opens no socket, starts no process of its own, and writes no file: no settings, no recent list, no log, and no clipboard write of diff --git a/docs/user/gui.md b/docs/user/gui.md index 3566a39..540065e 100644 --- a/docs/user/gui.md +++ b/docs/user/gui.md @@ -77,7 +77,10 @@ the seed. It protects the wallet on this computer. Finally, copy the wallet details onto your [wallet record](wallet-verification-record.html) and keep it apart from every -card. The window shows exactly the fields that record asks for. +card. The window shows exactly the fields that record asks for, including a +long recovery commitment. That commitment is public, but it must stay separate +from the cards because the restore screen uses it to reject the wrong recovered +seed before Bitcoin Core is changed. A card never contains **B**, **I**, **O** or **1**: those four are left out of the alphabet precisely because handwriting confuses them with 8, J, L and 0. If @@ -142,11 +145,17 @@ wallet**, which would make a different backup. If the wallet was part-filled before it failed, it is no longer empty, so it will not be offered again: create another one, or ask Bitcoin Core for a fresh blank wallet. -When you restore, the window asks you to **check** the wallet details against -your record rather than copy them onto it. That comparison — the master -fingerprint above all — is the only thing that proves the cards you just typed -belong to that wallet. It shows no creation date on that screen, because the -real one is already on your record and today's would replace it. +When you restore, the window first asks you to type the recovery commitment from +the separate wallet record. It deliberately does not show the value it expects. +If the value does not match, it does not list, create, unlock, or fill a Bitcoin +Core wallet. Do not substitute the shorter master fingerprint. Older wallet +records without a recovery commitment need to be updated before relying on this +pre-import check. + +After a successful restore, the window asks you to check the remaining wallet +details against the record rather than copy them onto it. It shows no creation +date on that screen, because the real one is already on your record and today's +would replace it. The window always uses account 0, which is what it writes onto your wallet record. If you are restoring a wallet whose record shows a different account diff --git a/docs/user/guide.md b/docs/user/guide.md index 1150c66..a6059a9 100644 --- a/docs/user/guide.md +++ b/docs/user/guide.md @@ -168,11 +168,13 @@ wallet should be trusted until initialization completes. ### 4. Complete the record and store the cards -Copy the displayed backup identifier, wallet name, Bitcoin Core version, -master fingerprint, derivation standards, and account number to the wallet -record. Add the approximate -creation / earliest-use date. Do not put a descriptor timestamp on a recovery -card; Core's public descriptor export preserves its stored timestamps. +For graphical setup, copy the displayed backup identifier, wallet name, Bitcoin +Core version, master fingerprint, recovery commitment, derivation standards, +and account number to the wallet record. The command-line workflow does not yet +display the recovery commitment, so do not rely on a CLI-created record for +graphical recovery. Add the approximate creation / earliest-use date. Do not put +a descriptor timestamp on a recovery card; Core's public descriptor export +preserves its stored timestamps. Store each card securely. For a shared backup, use different trusted places. Keep the wallet record separately from all cards. diff --git a/docs/user/wallet-verification-record.html b/docs/user/wallet-verification-record.html index a70ccc2..a60f7db 100644 --- a/docs/user/wallet-verification-record.html +++ b/docs/user/wallet-verification-record.html @@ -33,6 +33,7 @@
Followed the documented Bitcoin Core recovery workflow.
+Entered the recovery commitment before any recovered keys were imported.
Matched the expected master fingerprint.
Matched account, complete policy, history, and balance.
If available, a trusted person reviewed the wallet setup and recovery plan.
@@ -67,8 +69,9 @@- This record cannot authenticate a replaced backup by itself. Treat it as privacy-sensitive: - it can reveal wallet structure, balances, and transaction history even though it cannot spend. + The recovery commitment binds a recovered single-key seed to this separately stored record. + It does not authenticate a multisig policy, descriptor archive, history, or balance. Treat this + record as privacy-sensitive even though it cannot spend.