From a1c0866e970fb168e21afbe3a96ad66da785e131 Mon Sep 17 00:00:00 2001 From: kiwihodl Date: Sat, 31 Jan 2026 15:25:20 -0600 Subject: [PATCH] Add repo infrastructure and cross-platform docs - Add .gitignore for pycache, venv, IDE files - Add root README with ecosystem links - Add run_tests.py script to run all tests - Update codex32_terminal/README.md with macOS/Linux setup instructions --- .gitignore | 30 ++++++++++++++++++ README.md | 31 ++++++++++++++++++ codex32_terminal/README.md | 59 ++++++++++++++++++++++++++++++++++- codex32_terminal/run_tests.py | 59 +++++++++++++++++++++++++++++++++++ 4 files changed, 178 insertions(+), 1 deletion(-) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 codex32_terminal/run_tests.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3c728cb --- /dev/null +++ b/.gitignore @@ -0,0 +1,30 @@ +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so + +# Virtual environments +venv/ +.venv/ +ENV/ + +# IDE +.idea/ +.vscode/ +*.swp +*.swo + +# OS +.DS_Store +Thumbs.db + +# Testing +.pytest_cache/ +.coverage +htmlcov/ + +# Distribution +dist/ +build/ +*.egg-info/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..3f10402 --- /dev/null +++ b/README.md @@ -0,0 +1,31 @@ +# SeedSigner Codex32 + +Convert [Codex32 (BIP-93)](https://github.com/bitcoin/bips/blob/master/bip-0093.mediawiki) shares to BIP39 mnemonics for use with any Bitcoin wallet. + +**→ [Setup & Usage](codex32_terminal/README.md)** + +## Why? + +Codex32 lets you create and verify Bitcoin seed backups entirely by hand—no electronics needed. But wallet support is nearly nonexistent. This tool bridges the gap: enter your Codex32 shares and get a standard 12-word BIP39 mnemonic. + +## Ecosystem + +| Resource | Description | +|----------|-------------| +| [BIP-93](https://github.com/bitcoin/bips/blob/master/bip-0093.mediawiki) | Codex32 specification | +| [secretcodex32.com](https://secretcodex32.com) | Official paper worksheets & volvelles | +| [rust-codex32](https://github.com/apoelstra/rust-codex32) | Rust reference implementation (Andrew Poelstra) | +| [python-codex32](https://github.com/benwestgate/python-codex32) | Python library (Ben Westgate) | +| [Bails](https://github.com/BenWestgate/Bails) | First wallet with native codex32 support | +| [SeedSigner](https://github.com/SeedSigner/seedsigner) | Target platform for this integration | + +## Credits + +- **FractalEncrypt** — This project +- **Leon Olsson Curr & Pearlwort Sneed** — Codex32 creators +- **Andrew Poelstra** — Rust reference, Blockstream Research +- **Ben Westgate** — python-codex32 library, Bails wallet + +## License + +MIT diff --git a/codex32_terminal/README.md b/codex32_terminal/README.md index d7002b6..9b89d4a 100644 --- a/codex32_terminal/README.md +++ b/codex32_terminal/README.md @@ -14,7 +14,18 @@ This folder contains a terminal-based MVP for validating Codex32 shares, recover ⚠️ Not an ECW yet (no error correction). The codex32 Python library does **not** provide substitution/erasure correction, so this tool does not attempt it. Error-correction should be implemented separately before advertising ECW behavior. -## Setup (Windows PowerShell) +## Setup + +### macOS / Linux + +```bash +cd codex32_terminal +python3 -m venv venv +source venv/bin/activate +pip install codex32 embit +``` + +### Windows PowerShell From the repo root: @@ -30,6 +41,13 @@ pip freeze > .\codex32_terminal\requirements.txt ### Box-by-box entry (default) +**macOS / Linux:** +```bash +source venv/bin/activate +python src/main.py +``` + +**Windows PowerShell:** ```powershell .\codex32_terminal\venv\Scripts\Activate.ps1 ; python .\codex32_terminal\src\main.py ``` @@ -43,12 +61,42 @@ Features: ### Full-share paste mode +**macOS / Linux:** +```bash +source venv/bin/activate +python src/main.py --full +``` + +**Windows PowerShell:** ```powershell .\codex32_terminal\venv\Scripts\Activate.ps1 ; python .\codex32_terminal\src\main.py --full ``` Paste full shares in sequence. For `k-of-n` shares, the tool will ask for additional shares until the threshold is met. +## Run Tests + +Run all tests: + +**macOS / Linux:** +```bash +source venv/bin/activate +python run_tests.py +``` + +**Windows PowerShell:** +```powershell +.\codex32_terminal\venv\Scripts\Activate.ps1 ; python .\codex32_terminal\run_tests.py +``` + +Or run individual test files: +```bash +python tests/test_vectors.py +python tests/test_share_recovery.py +python tests/test_validation.py +python tests/test_invalid_vectors.py +``` + ## Test vectors Use BIP-93 test vectors to validate recovery: @@ -96,6 +144,15 @@ Expected output: - `tests/test_vectors.py` - Manual harness for BIP-93 vectors 2/3 +- `tests/test_share_recovery.py` + - Tests 2-of-n and 3-of-n share recovery with BIP-93 vectors + +- `tests/test_validation.py` + - Tests input validation (checksum, length, empty input, sanitization) + +- `tests/test_invalid_vectors.py` + - Tests rejection of BIP-93 invalid test vectors + ### Implementation rationale - **Validation** uses `codex32.Codex32String`, which enforces checksum + header correctness. diff --git a/codex32_terminal/run_tests.py b/codex32_terminal/run_tests.py new file mode 100644 index 0000000..2028e57 --- /dev/null +++ b/codex32_terminal/run_tests.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 +"""Run all tests for codex32_terminal.""" + +from __future__ import annotations + +import subprocess +import sys +from pathlib import Path + +TESTS_DIR = Path(__file__).parent / "tests" + +TEST_FILES = [ + "test_vectors.py", + "test_share_recovery.py", + "test_validation.py", + "test_invalid_vectors.py", +] + + +def main() -> int: + failed = [] + passed = [] + + for test_file in TEST_FILES: + test_path = TESTS_DIR / test_file + if not test_path.exists(): + print(f"SKIP: {test_file} (not found)") + continue + + print(f"\n{'='*60}") + print(f"Running {test_file}") + print('='*60) + + result = subprocess.run( + [sys.executable, str(test_path)], + cwd=Path(__file__).parent, + ) + + if result.returncode == 0: + passed.append(test_file) + else: + failed.append(test_file) + + print(f"\n{'='*60}") + print("SUMMARY") + print('='*60) + print(f"Passed: {len(passed)}") + print(f"Failed: {len(failed)}") + + if failed: + print(f"\nFailed tests: {', '.join(failed)}") + return 1 + + print("\nAll tests passed!") + return 0 + + +if __name__ == "__main__": + sys.exit(main())