Skip to content

create: Draw randomness from Core and the OS - #145

Open
BenWestgate wants to merge 4 commits into
reviewability-v1from
claude/core-entropy
Open

BenWestgate wants to merge 4 commits into
reviewability-v1from
claude/core-entropy

Conversation

@BenWestgate

@BenWestgate BenWestgate commented Oct 14, 2026 •

Copy link
Copy Markdown
Owner

Fresh creation now takes all seed, share, identifier, index and redraw randomness through an injected entropy source. The CLI combines each fresh Bitcoin Core xprv with 32 OS random bytes using SHA-256; a Core failure stops creation rather than falling back. This uses Core's generator while retaining OS protection if a temporary wallet's public data is later recovered.

CoreEntropy creates an encrypted temporary wallet for each draw, relocks and unloads it, and removes its files before returning bytes. Linux uses /dev/shm, macOS uses a RAM disk, and other systems warn before using disk-backed temporary storage. Passphrases travel through stdin. Creation handles supported termination signals and reports incomplete cleanup before another card is emitted. The API, CLI, unit tests, real-Core regtest and security documentation change together.

Review the injected-source boundary in generation.py, the mixed draw and cleanup in _bitcoin_core.py, and interruption handling in cli.py. PRs #159 and #160 build on this change.

Validation: commit 7cb2ae6 has exactly the same complete Git tree as bea2914, which passed the Python matrix, Bitcoin Core fixture job and CodeQL. git diff --check passes. The reported 25-check Linux Core 32.0rc3 run was performed by the implementation's author; macOS and Windows were covered with fakes rather than real Core.

Remaining before merge:

  • Publish the requested standalone 25-check verification script under tools/, with reproducible invocation instructions, and verify that committed tool.
    • tools/bitcoin_core_entropy.py (31ef005); its docstring says how to run it (753eded). Overlapping checks from the 25 were merged, leaving 22.
    • The Core fixtures job now installs codex32 (56181f2), and it passed 22 of 22 against Core 32.0rc2. It also passed 22 of 22 locally against 32.0rc3, following the docstring in a fresh venv.
    • 56181f2 and 753eded fold into 31ef005 once a force-push is OK'd.
  • Complete independent security review of the CoreEntropy boundary.
  • Confirm CI passes on the squashed commit.

Copy link
Copy Markdown
Owner Author

@codex security-review


Generated by Claude Code

@chatgpt-codex-connector

Copy link
Copy Markdown

Summary

  • Completed the security review and fixed a fail-open cleanup condition: failures from Bitcoin Core’s unloadwallet RPC are no longer silently ignored. Filesystem and RAM-disk cleanup is still attempted, after which the operator receives actionable guidance to stop Bitcoin Core. src/codex32/_bitcoin_core.pyL516-L535
  • Preserved the cleanup state when the temporary wallet directory cannot be removed, allowing a subsequent cleanup attempt rather than prematurely treating the entropy wallet as closed. src/codex32/_bitcoin_core.pyL528-L531
  • Updated the regression test to verify that an unload failure is surfaced while the temporary wallet directory is still removed on a best-effort basis. tests/test_bitcoin_core.pyL909-L925
  • Committed the changes as d47ef3e (Report entropy wallet unload failures) and created the follow-up pull request metadata with title “security: Surface entropy wallet unload failures.”

Testing

  • ✅ PYTHONPATH=src python -m pytest -q tests/test_bitcoin_core.py — 52 passed.
  • ✅ python -m ruff check .
  • ✅ python -m ruff format --check .
  • ✅ PYTHONPATH=src python -m mypy src/codex32
  • ✅ git diff --check
  • ⚠️ python -m pip install -e '.[dev]' — package-index access was blocked by the environment with HTTP 403, so missing development dependencies could not be installed.
  • ⚠️ PYTHONPATH=src python -m pytest -q tests/test_cli.py — could not run correctly without installed codex32 distribution metadata after the blocked installation.
  • ✅ git status --short --branch — working tree is clean on branch work.

View task →

@BenWestgate

Copy link
Copy Markdown
Owner Author

@codex we don't see the changes you speak of.

@BenWestgate
BenWestgate marked this pull request as ready for review October 22, 2026 05:53
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-23T21:31:31.564539Z 753eded Manual request
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@BenWestgate

Copy link
Copy Markdown
Owner Author

cACK # Hashing keeps the plaintext xpub in the wallet file from checking guesses of a share.

The question then becomes, how much entropy is in an xprv and why SHA256 instead of another hash function for example SHA512? And why just one round?

@chatgpt-codex-connector

Copy link
Copy Markdown

Summary

  • Implemented the previously described security changes so a failed Bitcoin Core unloadwallet RPC now raises an actionable error after best-effort filesystem and RAM-disk cleanup, rather than being reduced to a warning. src/codex32/_bitcoin_core.pyL516-L534
  • Preserved the temporary wallet and RAM-disk state when directory removal fails, allowing a subsequent close() call to retry cleanup. src/codex32/_bitcoin_core.pyL525-L530
  • Added regression coverage verifying that unload failures are surfaced even when the temporary files are removed, and that failed directory cleanup can be retried successfully. tests/test_bitcoin_core.pyL910-L946
  • Committed the changes as ad57890 (Report entropy wallet unload failures) and created the follow-up PR metadata titled “security: Surface entropy wallet unload failures.”

Testing

  • ✅ PYTHONPATH=src python -m pytest -q tests/test_bitcoin_core.py — 53 passed.
  • ✅ PYTHONPATH=src python -O -m pytest -q tests/test_bitcoin_core.py — 53 passed, with the expected pytest warning about disabled assertions under optimized Python.
  • ✅ python -m ruff check .
  • ✅ python -m ruff format --check .
  • ✅ PYTHONPATH=src python -m mypy src/codex32
  • ✅ git diff --check
  • ⚠️ PYTHONPATH=src python -m pytest -q && PYTHONPATH=src python -O -m pytest -q — full-suite collection could not complete because the environment does not have the hypothesis dependency installed.
  • ✅ git status --short --branch — working tree is clean on branch work.

View task →

@BenWestgate BenWestgate self-assigned this Oct 22, 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.

Security review of 40fb74f (PR #145; 13 changed files).

[P2] Treat failure to unload the entropy wallet as a creation failure. In CoreEntropy.close(), unloadwallet errors are reduced to a warning, _folder/_disk are cleared before cleanup succeeds, and rmtree(..., ignore_errors=True) hides filesystem removal failures. _create() can consequently report a successful ceremony (or proceed to wallet initialization) while the entropy wallet remains loaded in Bitcoin Core; callers also lose the state needed to retry cleanup. The source xprvs held in that wallet determine all the generated entropy. Although the wallet is normally relocked after each draw, combined failures of walletlock and unloadwallet can leave the keys RPC-accessible during the 60-second unlock window. Propagate unload failure after best-effort cleanup, preserve failed resource handles for retries, and test this at the CLI boundary. The current unit test explicitly expects a warning and successful close() on unload failure.

Other security boundaries reviewed: Bitcoin Core selection and stdin-only passphrase handling; 256-bit passphrase generation; SHA-256 extraction from each fresh xprv to prevent stored public xpubs from testing guesses of shares; explicit source injection and byte-count checks; unbiased index rejection sampling; confirmation-gated shares; OS-specific RAM/disk paths and signal cleanup. SHA-256 is appropriate here: one invocation already provides 256-bit preimage resistance, and SHA-512 or repeated hashing cannot increase entropy beyond the source. No other actionable vulnerability was identified in these paths.

CI: 10 Python test-matrix jobs and 1 Bitcoin Core fixture job passed. The managed local diff scanner could not start because head 40fb74f is not available in the local Git object database; this review inspected GitHub's exact PR patches and head-revision source. Recommendation: revise before merge and re-review wallet teardown.

Comment thread src/codex32/_bitcoin_core.py Outdated
Comment thread src/codex32/_bitcoin_core.py Outdated
Comment thread src/codex32/_bitcoin_core.py Outdated
Comment thread docs/security/model.md Outdated
@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.

1 similar comment
@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.

@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: d20d70dd00

ℹ️ 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/cli.py Outdated
@BenWestgate BenWestgate changed the title create: Draw randomness only from Bitcoin Core create: Draw randomness from Bitcoin Core Oct 22, 2026
@BenWestgate
BenWestgate marked this pull request as draft October 22, 2026 09:02
@BenWestgate
BenWestgate marked this pull request as ready for review October 22, 2026 10:33

@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 security/code review.

Concept ACK bea2914; not a security ACK yet. Seed, share, index and identifier draws now require injected entropy; each SHA-256 draw combines fresh Core xprv material with independent OS bytes, with no silent fallback on Core failure. Wallet cleanup and interruption handling have tests. Before human approval: independent real-Core 32.0rc3 verification of repeated draws, interruption/unload, disk-fallback warning and secret-file removal, plus security review of the new CoreEntropy boundary.

Copy link
Copy Markdown
Owner Author

This is the real-Core check the review above asks for, run on bea2914 against Bitcoin Core 32.0rc3 regtest on Linux. All 25 checks passed.

  • Repeated draws: 6 draws of 1 to 64 bytes. Each one used a new encrypted wallet in /dev/shm. Each wallet was locked before unload, then unloaded and its folder deleted before the bytes came back. The 64-byte draw took two keys, and all draws differ.
  • Interruption: a real SIGINT landed while each RPC was in flight (createwallet, walletpassphrase, addhdkey, gethdkeys, walletlock, unloadwallet). Each time, no wallet stayed loaded and no folder was left. A SIGINT before Core ran unloadwallet stopped creation with "Restart Core to unload it". That wallet's deleted folder did not come back when Core later unloaded it.
  • Real CLI in a terminal: killed mid-draw by SIGTERM, SIGHUP and SIGINT. Each run exited 130 with the void notice and left nothing.
  • Disk fallback (no /dev/shm): one warning, naming the folder and the TMPDIR fix. Each wallet folder was deleted from disk before the bytes came back.
  • Secrets: Core's debug.log holds no tprv and no passphrase, and Core's wallets folder holds no temporary wallet.

Not covered: the macOS RAM disk and Windows against real Core. CI covers those paths only with fakes. I wrote both the change and this check, so it isn't independent. The script is about 250 lines and could go under tools/ if you want it rerunnable here.


Generated by Claude Code

@BenWestgate

BenWestgate commented Oct 22, 2026 •

Copy link
Copy Markdown
Owner Author

cACK: The script is about 250 lines and could go under tools/ if you want it rerunnable here.

Yes.

@BenWestgate
BenWestgate added this pull request to stack #163 October 22, 2026 14:07
@BenWestgate

Copy link
Copy Markdown
Owner Author

Do the commits follow contributing.md?

Require an injected entropy source throughout master-seed and share
generation, including random identifiers, indices and rejection redraws.
The CLI supplies CoreEntropy, which hashes each fresh Bitcoin Core xprv
together with 32 OS random bytes. Core failure stops creation instead of
falling back.

Use a new encrypted temporary wallet for each draw and finish relocking,
unloading and deleting it before returning bytes. Convert supported
termination signals into interruptions during creation, and report
incomplete cleanup before another card can be emitted. Document RAM-backed
paths, the disk fallback and the limits of leaked wallet files.

Include generation, CLI, cleanup and interruption regressions together
with the existing real-Core regtest coverage and matching API/security
documentation.

Validation: the complete Git tree is identical to
bea2914, whose Python matrix, Core fixture
and CodeQL checks passed. git diff --check passes. This consolidates the
reviewed implementation without changing any file. Refs #145.
@BenWestgate
BenWestgate force-pushed the claude/core-entropy branch 2 times, most recently from bea2914 to 7cb2ae6 Compare October 22, 2026 14:56
@BenWestgate BenWestgate changed the title create: Draw randomness from Bitcoin Core create: Draw randomness from Core and the OS Oct 22, 2026

Copy link
Copy Markdown
Owner Author

The 14-commit history contained repeated fixups and reversals, so it needed consolidation under CONTRIBUTING.md's squashing guidance. It is now one atomic commit, 7cb2ae6, with a short component-prefixed subject and a body explaining the final behavior, security implications and validation.

Verified git diff bea2914 7cb2ae6 is empty and both commits have tree a733bd982033c49f6c8cfb1a020bde376bc29a81. No file changed. The reviewed code and existing passing checks therefore apply to identical contents; fresh CI is running for the new SHA. PRs #159 and #160 were restacked in the same atomic push, with their own complete trees also unchanged.

All six inline threads are resolved. The approved standalone verification script is still absent from the branch, so the PR description now explicitly tracks that request and independent security review as remaining work. This history cleanup does not supply either.

Unit tests fake Core, so nothing showed that a real node really unloads
and forgets each draw's wallet. The new check runs CoreEntropy against
regtest Core on Linux: repeated draws, a real SIGINT while each Core call
is in flight, `ms32 create` in a terminal stopped by SIGTERM, SIGHUP and
SIGINT, and the disk fallback without /dev/shm. After each case no wallet
may stay loaded or on disk, and Core's debug.log must hold no key or
passphrase. The Bitcoin Core fixtures workflow runs it next to the
existing regtest check.

Claude-Session: https://claude.ai/code/session_01T233rKgZqE5wzDm3EVTHL1
The entropy check runs the ms32 CLI, which reads its version from the
installed package's metadata, so PYTHONPATH alone fails with
PackageNotFoundError.

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

@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 incremental review at 753eded: Code ACK for the follow-up test/CI changes. The standalone 22-check Core entropy harness is committed, the workflow installs codex32 before calling its CLI, and both current-head CI jobs passed. Independent security review of CoreEntropy and real-Core macOS/Windows coverage remain outstanding. Not a security/merge ACK.

@BenWestgate

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Another round soon, please!

Reviewed commit: 753eded110

ℹ️ 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".

@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 independent security review at 753eded: 22/22 entropy harness checks passed on real Bitcoin Core 32.0rc4 (Linux regtest), including fresh draws, per-draw wallet cleanup, interruptions, disk fallback and log checks. No confirmed vulnerability in the 15-file diff. Linux Core boundary verified; full Tails creation/restore and macOS/Windows runtime coverage remain open. Not yet a merge ACK.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant