Skip to content

wallet: Require the recorded fingerprint before import - #57

Merged
BenWestgate merged 3 commits into
reviewability-v1from
30-recorded-fingerprint-gate
Oct 6, 2026
Merged

BenWestgate merged 3 commits into
reviewability-v1from
30-recorded-fingerprint-gate

Conversation

@BenWestgate

@BenWestgate BenWestgate commented Sep 24, 2026 •

Copy link
Copy Markdown
Owner

Fixes #30. Library/CLI half of #26; GUI half is tracked separately.

This adds the restore-time wallet identity gate before Bitcoin Core mutation.

  • BitcoinCore.initialize() accepts an expected fingerprint and checks it before wallet selection, unlock, creation or import.
  • ms32 wallet requires the fingerprint from the wallet record; mismatch retries without changing Core.
  • the recovered fingerprint is not shown before that typed-record gate, including during correction; choosing the no-record fallback is an explicit disclosure path, and declining it ends that restore attempt rather than returning to record-based verification;
  • ms32 create --existing uses the same restore gate and does not expose the recovered fingerprint through correction or rendering before the independent record/no-record decision;
  • wallet: Check existing seed before sharing #81 is the focused follow-up that moves the create --existing record/no-record decision earlier, immediately after parsing the existing seed and before any new share ceremony or output;
  • with no wallet record, the CLI shows the recovered fingerprint, backup identifier and codex32/Bails/Bails-alpha identifier-origin result, then requires the warning/confirmation path;
  • fresh ms32 create only records the new fingerprint; it has no pre-existing wallet identity to authenticate;
  • parse_fingerprint() accepts 8 hex digits in any case or spacing.

#43 tracks checksummed wallet-record fields; #55 tracks the separately planned encrypted full-descriptor backup; #56 tracks identifier-assisted correction ranking. The current release gate is accident safety, not malicious-share-tampering resistance.

Review shape

Current head 554e3e8 is the reviewed restore commit 115f2c2 plus two documentation-only follow-ups. The restore patch has the same stable patch-id as the previously reviewed 054e8d9, 37eef4d, and a7efaae replays; the follow-ups remove the redundant pre-check, document pre-synchronized chain history for offline rescans, follow Core's maintained offline-signing tutorial, identify the trusted offline signer explicitly, and use a watch-only wallet or descriptor backup as the independent fingerprint reference.

The current diff stays within the maintainer-authorized <5200 library budget. Downstream #105 removes reviewed dead paths before the later Core/recovery follow-ups are integrated.

Security verification

  • BitcoinCore.initialize() calls verify_identity() before _select() or any wallet RPC/mutation;
  • test_identity_mismatch_stops_before_any_wallet_call passes and asserts the RPC call log stays empty on mismatch;
  • test_no_record_is_the_operators_choice_and_checks_nothing passes, preserving the explicit fallback contract;
  • CLI source keeps the recovered fingerprint hidden until the independent record/no-record decision for both ms32 wallet and ms32 create --existing.

Validation

Current-head GitHub Python-package run 843 and Bitcoin Core wallet-fixture run 47 both succeeded. The unchanged reviewed patch was also validated on its immediately preceding replay with 40 focused identity/fingerprint/existing/timestamp regressions, 926 tests normally and under python -O, strict mypy, Ruff check/format, correction-constant verification, all 57 frozen differential cases, and git diff --check.

Codex reviewed the restore code at 115f2c2; its later documentation findings are addressed by de569f9 and 554e3e8. Codex then reviewed 554e3e8 with no findings. All inline threads are resolved. #80 remains required downstream because it corrects no-record wording when RIPEMD-160 is unavailable.

Human review/integration order from here is #57 → #105 → #99 → #80 → #81 → #95. #42/#45/#46 and #7/#51 are already in reviewability-v1.

AI assistance was used for authorized mechanical restacks and review follow-ups. The focused source commit retains Ben Westgate as its author and still requires responsible human review before integration.

@BenWestgate BenWestgate added area: cli Command-line interface behavior. area: security Security invariants, hardening, and security-sensitive boundaries. area: wallet/core Wallet integration and Bitcoin Core boundaries. gate: adversarial review Resolve, merge, or explicitly defer before the next full adversarial review. labels Sep 24, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5eaf535bb7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/codex32/_bitcoin_core.py Outdated
Comment thread src/codex32/_bitcoin_core.py Outdated
@BenWestgate

Copy link
Copy Markdown
Owner Author

Contract clarification applied in b50321a: ms32 create no longer treats the new fingerprint as authentication evidence or asks the user to type it back. It only requires acknowledging that the fingerprint was written on the wallet record. ms32 wallet retains the fingerprint/no-record restore gate. 886 normal + 886 optimized tests pass.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6da1f2a416

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread docs/security/invariants.md

@BenWestgate BenWestgate left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI-generated review (Claude), posted at the maintainer's request. I wrote 5eaf535, so this is partly self-review.

Not ACKing 6da1f2a.

  • 6da1f2a removes identifier_origin/identifier_note, which the no-record path was built to show. If that's intended, invariants.md:16-18 and model.md:232 still promise it (agree with the Codex P2). If not, revert it. Either way #57 now differs from #28, which keeps them.
  • Policy: 6da1f2a is authored by Codex Preflight <codex-preflight@localhost>, and AI_POLICY.md forbids agent authors. Its message also contains a literal \n\n and has no area prefix. 5eaf535 has a Co-Authored-By: Claude trailer, which the same policy forbids. Squash-merge or reword.
  • Q: create --existing imports an existing seed (timestamp 0) with restore=False, so it skips the fingerprint gate. Should it pass restore=True? The Enter-if-none path keeps it usable.

@BenWestgate BenWestgate left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI-generated review, posted at the maintainer's request.

Concept ACK 70a188a. The no-record identifier evidence is restored and matches #28 again.

One correctness item remains: ms32 create --existing supplies an existing seed but still reaches _initialize_wallet(..., restore=False), so it can import without the wallet-record gate. Treat --existing as a restore for wallet initialization.

@BenWestgate BenWestgate left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI-generated review, posted at the maintainer's request.

ACK 795ccdd. Existing-seed initialization now uses the same restore gate before import, including after re-sharing; identifier evidence remains aligned with #28. Full Python package matrix is green.

Copy link
Copy Markdown
Owner Author

Release-gate verification at current head 795ccdd: the authoritative Core boundary calls verify_identity(secret, expected_fingerprint) before _select(), so mismatch occurs before wallet listing/selection, unlock, creation, or descriptor import. The focused regression test_identity_mismatch_stops_before_any_wallet_call asserts the mismatch and rpc.calls == []. The current Python package workflow run 36284182340 completed successfully. This satisfies the verify-before-mutate accident-safety finding for the CLI/library subset; #55 remains the separate malicious-tampering/descriptor-backup design.

Copy link
Copy Markdown
Owner Author

One non-code release-gate item still remains despite the code ACK: the current PR history still contains 5eaf535 with a Co-Authored-By: Claude trailer and 6da1f2a authored/committed by Codex Preflight. docs/developer/AI_POLICY.md says not to include agents as authors or co-authors. Before merge, squash/reword/rebase this branch under the responsible human author while preserving the current 795ccdd tree, then rerun the green package workflow on the rewritten head.

Copy link
Copy Markdown
Owner Author

Release-gate history check: the functional fix is ACKed at 795ccdd, but the commit-policy condition from the earlier review still remains. The branch history still contains 5eaf535 with a Co-Authored-By: Claude ... trailer and 6da1f2a authored by Codex Preflight <codex-preflight@localhost> (later behavior commits correct the code, but do not remove those history records). Before merge, rewrite/squash so the retained release commit is authored by the responsible human and follows AI_POLICY.md. Functionally, the verify-before-mutate boundary and existing-seed restore gate are green.

@BenWestgate
BenWestgate force-pushed the 30-recorded-fingerprint-gate branch from 795ccdd to 53cd58b Compare September 27, 2026 03:21
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@BenWestgate
BenWestgate force-pushed the 30-recorded-fingerprint-gate branch from 53cd58b to dcc0d41 Compare September 27, 2026 03:22
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

Copy link
Copy Markdown
Owner Author

Release-gate history follow-up: the earlier commit-policy blocker is now resolved. Current head dcc0d41 is a single commit directly on cf1a599, authored and committed by Ben Westgate, with no agent author/co-author history retained. The fresh Python package run 36291219348 on dcc0d41 completed successfully. Functionally this preserves the ACKed 795ccdd recovery-gate tree, so #57 is ready for human review on the CLI/library accident-safety scope.

Copy link
Copy Markdown
Owner Author

Security fix-verification refresh at current head dcc0d41: fixed for the CLI/library verify-before-mutate finding. I re-ran the exact current PR archive: test_identity_mismatch_stops_before_any_wallet_call and test_no_record_is_the_operators_choice_and_checks_nothing both pass, and static inspection confirms BitcoinCore.initialize() calls verify_identity(secret, expected_fingerprint) before _select(), so a mismatch precedes wallet selection/listing, unlock, creation, or descriptor import. The no-record legitimate fallback remains functional. This verifies the accident-safety boundary only; #55 remains the separate malicious-tampering/descriptor-backup design.

Gate restore and existing-seed wallet initialization on the independently recorded BIP32 master fingerprint before any Bitcoin Core wallet mutation. Keep the correction path from disclosing or reusing a fingerprint derived from the candidate being authenticated.

Fixes #30.
@BenWestgate
BenWestgate force-pushed the 30-recorded-fingerprint-gate branch from 054e8d9 to 115f2c2 Compare October 2, 2026 08:57
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

BenWestgate pushed a commit that referenced this pull request Oct 2, 2026
Reassign the expected_fingerprint argument instead of copying it into a
local, and give existing_secret its None default before the source
checks instead of in an else branch.

Behavior is unchanged. The installed package drops from 5161 to 5159
logical review lines, which keeps the integrated #7/#42/#57/#46/#80/#81
tip under the <5200 budget.

Security: the record gate still runs before any card is generated or
shown, and interrupts at that gate still raise _WalletSetupInterrupted.

Validation: ruff check, ruff format --check, mypy src/codex32, and
pytest (918 passed, with and without -O).

Refs #81, #38.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018az69UX4773mYohXAtE8kD
BenWestgate pushed a commit that referenced this pull request Oct 2, 2026
`ms32 wallet` and `ms32 create --existing` hid the recovered master
fingerprint while confirming a correction (#57), so a wrong correction
was caught only after the operator accepted it and typed the record.

Ask for the record first: before the shares in `ms32 wallet` and before
the seed in `ms32 create --existing`. A correction that completes the
secret then says whether it matches the record, without showing the
fingerprint, and the record picks between equally likely corrections.
The final identity check, the retry on mismatch and the Enter path for
no record work as before; without a record nothing is shown until the
recordless gate. Ctrl-C at the moved prompt still says the existing
cards are valid.

Closes #91

Claude-Session: https://claude.ai/code/session_015CuLXqAvAovfoVcUmmogwa

@BenWestgate BenWestgate left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Codex current-head release-gate re-review: ACK 115f2c2 as the restore-authentication stack unit.

The current diff still enforces the key invariant: BitcoinCore.initialize() calls verify_identity() before wallet selection or mutation; ms32 wallet and ms32 create --existing suppress recovered-fingerprint disclosure until the independent record/no-record decision; declining the recordless path terminates the attempt. All existing inline findings are resolved. Exact-head Python-package run 658 and Bitcoin Core wallet-fixture run 32 both succeeded.

Known downstream requirement: #80 must remain in the frozen stack because it corrects the no-record wording when RIPEMD-160 is unavailable. That does not weaken this PR's verify-before-mutate behavior. No new blocker found in this current diff; human review remains required before integration.

BenWestgate pushed a commit that referenced this pull request Oct 4, 2026
A tester asked why the fingerprint stays off the cards, why restore
asks for it, how long a string is, which share indices create uses,
and whether letter case matters. Answer each in a short section.

The restore answer describes the typed-fingerprint step from #57, so
this sits on that branch.

Closes #90

Claude-Session: https://claude.ai/code/session_015CuLXqAvAovfoVcUmmogwa
@BenWestgate BenWestgate self-assigned this Oct 5, 2026

@BenWestgate BenWestgate left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Documentation only review for now.

Will code review after the documentation is good enough.

Comment thread docs/user/guide.md Outdated
Comment thread docs/user/guide.md Outdated
Comment thread docs/user/guide.md Outdated
Comment thread docs/user/guide.md
Comment thread docs/user/guide.md Outdated

@BenWestgate BenWestgate left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Codex current-head review at 115f2c2: documentation cleanup remains. The guide still duplicates ms32 wallet validation with ms32 check, does not explain that an offline rescan needs pre-synchronized chain history, and still pins the maintained Core offline-signing tutorial to v32.0rc1 instead of master.

Clarify the wallet-record fingerprint wording, remove the redundant pre-check, require chain history before offline rescans, and follow the maintained Core offline-signing tutorial.

Refs #57.
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@BenWestgate BenWestgate left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI-assisted current-head review, posted at the maintainer's request.

ACK de569f9. The docs-only follow-up addresses the remaining guide feedback: clearer record wording, no duplicate pre-check, explicit offline-rescan prerequisite, and the maintained Core tutorial link. Exact-head package and wallet-fixture CI pass. No new blocker found.

BenWestgate pushed a commit that referenced this pull request Oct 6, 2026
Reassign the expected_fingerprint argument instead of copying it into a
local, and give existing_secret its None default before the source
checks instead of in an else branch.

Behavior is unchanged. The installed package drops from 5161 to 5159
logical review lines, which keeps the integrated #7/#42/#57/#46/#80/#81
tip under the <5200 budget.

Security: the record gate still runs before any card is generated or
shown, and interrupts at that gate still raise _WalletSetupInterrupted.

Validation: ruff check, ruff format --check, mypy src/codex32, and
pytest (918 passed, with and without -O).

Refs #81, #38.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018az69UX4773mYohXAtE8kD

@BenWestgate BenWestgate left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM after the requested changes

Comment thread docs/user/guide.md Outdated
Comment thread src/codex32/_bitcoin_core.py Outdated
Make the recovery guide explicitly identify the trusted offline signer when loading the blank descriptor wallet. Replace the hardware-wallet example in the no-record warning with a watch-only wallet, which is the intended independent fingerprint reference.
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

Copy link
Copy Markdown
Owner Author

@codex review

Please review the current head only. The latest commit is a narrow follow-up to two resolved reviewer comments: it clarifies the trusted offline signer wording and replaces the hardware-wallet example in the no-record warning with a watch-only wallet. Focus on correctness/security blockers; avoid style churn.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@BenWestgate BenWestgate left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Codex current-head review at 554e3e8: no findings. The only delta since the prior ACK is recovery guidance wording: it identifies the trusted offline signer explicitly and uses a watch-only wallet/descriptor backup as the independent fingerprint reference. Exact-head Python-package and Bitcoin Core wallet-fixture workflows are green, and all inline review threads are resolved.

@BenWestgate BenWestgate left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good enough. We will do another pass on guide.md for the strang "before filling" and "before entering" sentences.

Copy link
Copy Markdown
Owner Author

@codex review

Please review current head 554e3e8720 only. This is the final current-head audit check before human review; do not reopen superseded design debates unless there is a correctness, security, or release-blocking issue.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@BenWestgate
BenWestgate merged commit 1eed32c into reviewability-v1 Oct 6, 2026
24 checks passed
@BenWestgate
BenWestgate deleted the 30-recorded-fingerprint-gate branch October 6, 2026 14:09
BenWestgate pushed a commit that referenced this pull request Oct 7, 2026
Reassign the expected_fingerprint argument instead of copying it into a
local, and give existing_secret its None default before the source
checks instead of in an else branch.

Behavior is unchanged. The installed package drops from 5161 to 5159
logical review lines, which keeps the integrated #7/#42/#57/#46/#80/#81
tip under the <5200 budget.

Security: the record gate still runs before any card is generated or
shown, and interrupts at that gate still raise _WalletSetupInterrupted.

Validation: ruff check, ruff format --check, mypy src/codex32, and
pytest (918 passed, with and without -O).

Refs #81, #38.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018az69UX4773mYohXAtE8kD
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: cli Command-line interface behavior. area: security Security invariants, hardening, and security-sensitive boundaries. area: wallet/core Wallet integration and Bitcoin Core boundaries. gate: adversarial review Resolve, merge, or explicitly defer before the next full adversarial review.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant