|
1 | 1 | # Runtime dependency review |
2 | 2 |
|
3 | | -The package has one direct runtime dependency: `bip32>=5,<6`. The compatible |
4 | | -range permits bug-fix releases, but a release must record and review the exact |
5 | | -resolved dependency set. A resolved-version change requires the full BIP32 and |
6 | | -wallet-vector suite before publication. |
| 3 | +The package retains one direct runtime dependency: `bip32>=5,<6`. Only |
| 4 | +`src/codex32/_bip32.py` imports it. That 49-line typed adapter exposes the three |
| 5 | +operations this project needs and converts an invalid master scalar to |
| 6 | +`CodexError`. Bitcoin Core cannot replace it because Core has no interface that |
| 7 | +derives this project's root key or wallet records from raw seed bytes. |
7 | 8 |
|
8 | | -The metadata now reserves `1.0.0rc1`; it is not authorization to publish. The |
9 | | -compatible library range remains deliberate. Gate 2 must add a tested, |
10 | | -hash-pinned CLI installation constraint and reconcile native wheels across |
11 | | -Python 3.12--3.14 before the release candidate can be considered dependency- |
12 | | -assured. Bitcoin Core cannot replace this boundary because it has no interface |
13 | | -that derives this project's root key and wallet records from raw seed bytes. |
| 9 | +Python 3.12 and 3.13 are supported. Python 3.14 is an explicitly non-blocking |
| 10 | +CI probe until the selected Coincurve release publishes 3.14 wheels and the |
| 11 | +required platform matrix passes. It is not a v1 support claim. |
14 | 12 |
|
15 | | -## Reviewed resolution |
| 13 | +## Reviewed Coincurve 21 resolution |
16 | 14 |
|
17 | | -Reviewed on 2026-08-22 with Python 3.13 on Linux x86-64: |
| 15 | +The published `bip32` 5.0.0 metadata says `coincurve>=15,<21`. Upstream owner |
| 16 | +Antoine Poinsot's open [PR #53](https://github.com/darosior/python-bip32/pull/53) |
| 17 | +changes only that range to `<22` and adds Coincurve 21 to upstream CI. The CLI |
| 18 | +constraint carries its exact commit |
| 19 | +`45db547bdf5a5bc19a8c55ef447dbf9169928792`; the archive SHA-256 is |
| 20 | +`a25be30641b381eed9a5249bbc4a73124905223c9c50f93140f519bcf259e415`. |
| 21 | +The compatible library dependency remains unchanged, so this is not a local |
| 22 | +BIP32 fork or a change to the installed implementation. |
18 | 23 |
|
19 | | -| Package | Version | Purpose | |
20 | | -|---|---:|---| |
21 | | -| `bip32` | 5.0.0 | BIP32 root keys, fingerprints, and path derivation | |
22 | | -| `coincurve` | 20.0.0 | secp256k1 implementation selected by `bip32` | |
23 | | -| `asn1crypto` | 1.5.1 | transitive `coincurve` dependency | |
24 | | -| `cffi` | 2.1.1 | Python/native boundary used by `coincurve` | |
25 | | -| `pycparser` | 3.0 | transitive `cffi` dependency | |
| 24 | +The resolution is: |
26 | 25 |
|
27 | | -`bip32` 5.0.0 declares `coincurve>=15,<21`. It does not publish `py.typed` or |
28 | | -type stubs. Only `src/codex32/_bip32.py` imports it; that adapter defines the |
29 | | -three operations used by this project and converts its invalid-seed exception |
30 | | -to `CodexError`. The rest of the package is checked by strict mypy without |
31 | | -import suppression. |
| 26 | +| Package | Version | License | Purpose | |
| 27 | +|---|---:|---|---| |
| 28 | +| `bip32` | 5.0.0 plus PR #53 metadata | BSD-3-Clause | BIP32 private-tree derivation | |
| 29 | +| `coincurve` | 21.0.0 | MIT or Apache-2.0 | libsecp256k1 binding | |
32 | 30 |
|
33 | | -Published `bip32` 5.0.0 artifact SHA-256 hashes: |
| 31 | +The installed dependency license-file SHA-256 values are: |
34 | 32 |
|
35 | | -- sdist: `4caa1f74eed9f2cd4624b55f34a4094f52542552fe3d0cc52e1179b8d6e9f21e` |
36 | | -- wheel: `b20872795ae2bb4e5fac351f53ccdf2b998f82e927413922a2c5473a004bd6d0` |
| 33 | +- BIP32 `LICENCE`: `ba32f1ce36d4b107164ff3b70f145eca686e6e5e74f9080f628545ebe9209dcc`; |
| 34 | +- Coincurve `LICENSE-MIT`: `d502748a33db7ade1318e37f0b5f219f478330ed74a673e387756e53fb516715`; |
| 35 | +- Coincurve `LICENSE-APACHE`: `cebfb5eab4eff50df87c3c5e7eb11a634d0fa32bb4b6380800f82fae606599ae`; |
| 36 | +- Coincurve's retained `LICENSE-cffi` notice: |
| 37 | + `04b80f5b077bbed68808cfebadeb5e3523f2a8c9a96495c587bd96df1eac2a33`. |
37 | 38 |
|
38 | | -The project verifies the official BIP93 BIP32 vectors, mainnet and testnet |
39 | | -extended keys, BIP48 account xpubs, and public/private Bitcoin Core descriptor |
40 | | -fixtures. This is dependency-boundary evidence, not an independent audit of |
41 | | -`bip32`, `coincurve`, or libsecp256k1. |
| 39 | +Coincurve 21 removes the former runtime CFFI and ASN.1 dependencies. Its |
| 40 | +[release notes](https://github.com/ofek/coincurve/releases/tag/v21.0.0) record |
| 41 | +Python 3.13 support and libsecp256k1 0.6.0. Its CPython 3.12 and 3.13 release has |
| 42 | +binary wheels for Intel and ARM macOS, x86-64/ARM/i686 glibc and musl Linux, |
| 43 | +and AMD64/ARM64 Windows. `requirements/cli-dependencies.txt` pins every one of |
| 44 | +those wheel hashes and prohibits a Coincurve source build. |
42 | 45 |
|
43 | | -Sources: [`bip32` on PyPI](https://pypi.org/project/bip32/) and the installed |
44 | | -wheel metadata captured by the clean-environment release check. |
| 46 | +The BIP32 patch archive is pure Python. `requirements/cli-build-dependencies.txt` |
| 47 | +pins the universal Setuptools 80.9.0 wheel used to build it, and the dependency |
| 48 | +installation disables build isolation. A clean Python 3.13 install completed |
| 49 | +without a compiler and `pip check` reported no broken requirements. |
| 50 | +Setting `SOURCE_DATE_EPOCH=1763060600`, the upstream patch commit time, produced |
| 51 | +the same BIP32 wheel twice: SHA-256 |
| 52 | +`637e98a3fc3318d29a6bf69025abe0dbe4a02f5911fabd8443b16ef4f5088176`. |
| 53 | +Without that environment variable, ZIP timestamps make the wheel hash vary even |
| 54 | +though its files are identical. CI sets it explicitly. |
| 55 | + |
| 56 | +## Compatibility evidence |
| 57 | + |
| 58 | +The Coincurve APIs used by `bip32` were inspected at tags v20.0.0 and v21.0.0: |
| 59 | +`PrivateKey`, its `secret` property and `add` method, plus `PublicKey`, |
| 60 | +`from_secret`, `combine_keys`, and `format`. Their signatures, libsecp256k1 |
| 61 | +operations, and `ValueError` failure behavior are unchanged at this boundary. |
| 62 | + |
| 63 | +On 2026-08-24 under Python 3.13.12: |
| 64 | + |
| 65 | +- all seven upstream `bip32` tests passed with Coincurve 21, including the four |
| 66 | + official private-tree BIP32 vectors and invalid extended-key cases; |
| 67 | +- all 499 repository tests passed with the carried patch and Coincurve 21; |
| 68 | +- a deterministic corpus covered all seed lengths 16--64, 64 cases per length, |
| 69 | + both networks, root xprvs, BIP48 account xpubs, and all public/private Core |
| 70 | + descriptors; |
| 71 | +- all 6,272 records matched Coincurve 20 and 21 byte for byte, with SHA-256 |
| 72 | + `a51c9833408bd02d8fbafc339a7d4b48ada02af655e268e0bd165040c45b0249`. |
| 73 | + |
| 74 | +`python tools/differential_wallet.py --verify` reproduces the last check. A |
| 75 | +resolved dependency, adapter, or vector change requires the upstream and local |
| 76 | +suites plus this corpus before publication. |
| 77 | + |
| 78 | +Pip-audit 2.10.1, using its PyPI advisory service on 2026-08-24, reported no |
| 79 | +known vulnerability for exact versions BIP32 5.0.0 and Coincurve 21.0.0. The |
| 80 | +local unpublished codex32 release candidate is necessarily outside that service, |
| 81 | +and this result is a known-advisory check rather than a cryptographic audit. |
| 82 | + |
| 83 | +## Bounded `cryptography` prototype |
| 84 | + |
| 85 | +A private-seed-only prototype using `cryptography` 50.0.0 was evaluated before |
| 86 | +this decision. It matched all 17 official vector path outputs and the complete |
| 87 | +6,272-record corpus. Five forced HMAC cases explicitly checked zero or |
| 88 | +out-of-range master scalars, out-of-range child tweaks, zero child scalars, and |
| 89 | +the valid zero-tweak case. |
| 90 | + |
| 91 | +It did not meet the replacement cut conditions: |
| 92 | + |
| 93 | +- 167 implementation lines would replace the 49-line adapter, taking the |
| 94 | + installed project from 2,999 to about 3,117 physical Python lines; |
| 95 | +- the corpus took about 90 seconds rather than 27 seconds in this diagnostic |
| 96 | + run; |
| 97 | +- the installed cryptography/CFFI surface was about 17 MB, compared with a |
| 98 | + 2.6 MB Coincurve install, and introduced CFFI plus a general OpenSSL binding; |
| 99 | +- cryptography 50.0.0 publishes no Intel macOS or Windows ARM wheel, while |
| 100 | + Coincurve 21 covers both. |
| 101 | + |
| 102 | +The prototype proved feasibility, not a security or performance benchmark. |
| 103 | +Because it is neither materially smaller nor easier to audit and violates the |
| 104 | +line and wheel criteria, the roadmap retains `bip32` behind its narrow adapter. |
45 | 105 |
|
46 | 106 | ## Development-tool baseline |
47 | 107 |
|
48 | 108 | Most development tools remain compatible ranges or unpinned extras rather than |
49 | 109 | a reproducible release environment. Ruff is pinned to 0.16.2 because it defines |
50 | 110 | the formatting baseline. On 2026-08-24 the existing Python 3.13.12 environment |
51 | 111 | also contained pytest 8.4.2, Hypothesis 6.165.2, mypy 2.3.0, build |
52 | | -1.2.2.post1, and Twine 6.2.0. Ruff 0.16.2 reports formatting drift already |
53 | | -present at the Gate 0 starting revision, despite lint passing. A mechanical |
54 | | -110-column Ruff baseline reconciles that drift at 2,970 production lines; a |
55 | | -100-column probe produced 3,021 and was rejected. Gate 2 must freeze the final |
56 | | -cross-platform release-tool and dependency evidence. |
| 112 | +1.2.2.post1, and Twine 6.2.0. A mechanical 110-column Ruff baseline reconciles |
| 113 | +the inherited formatting at 2,970 production lines; a 100-column probe produced |
| 114 | +3,021 and was rejected. New code still prefers lines under 100 characters when |
| 115 | +that preserves readability. |
0 commit comments