What changed, and why it matters
This commit only changes how automated tests are run. It builds a C cryptography library during testing so the test environment matches the real firmware more closely. There is no change to the actual Krux firmware or wallet code, and no security vulnerability is being fixed.
No security action needed. This is a test-harness improvement. Reviewers may verify that the new CI steps succeed and that the secp256k1-check task correctly fails the build when the pure-Python fallback is active.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The commit adds CI/test tasks to compile embit’s pinned libsecp256k1 C library and verifies that embit uses the C backend rather than its pure-Python fallback. Previously, the pure-Python fallback caused a test fixture (firmware.bin.bad.sig) to raise during parsing instead of failing verification, meaning a code branch in firmware.py was not exercised. The change is confined to .github/workflows/tests.yml, README.md, and pyproject.toml. No source code under src/ is modified.
Changed components
CI test workflow (.github/workflows/tests.yml)developer documentation (README.md)poe task definitions (pyproject.toml)Inspect captured patch +37 / −0
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 8d3ba91..e6386f0 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -106,6 +106,10 @@ jobs:
run: uv python install ${{ matrix.py-version }}
- name: Sync dependencies
run: uv sync --frozen --python ${{ matrix.py-version }}
+ - name: Build libsecp256k1
+ run: uv run --python ${{ matrix.py-version }} poe secp256k1-build
+ - name: Check embit uses the C secp256k1
+ run: uv run --python ${{ matrix.py-version }} poe secp256k1-check
- name: Run tests
run: uv run --python ${{ matrix.py-version }} poe test-simple
@@ -124,6 +128,10 @@ jobs:
run: uv python install 3.12.13
- name: Sync dependencies
run: uv sync --frozen --python 3.12.13
+ - name: Build libsecp256k1
+ run: uv run --python 3.12.13 poe secp256k1-build
+ - name: Check embit uses the C secp256k1
+ run: uv run --python 3.12.13 poe secp256k1-check
- name: Build coverage file
run: uv run --python 3.12.13 pytest --cache-clear --cov src/krux --cov-report xml tests
- name: Upload coverage reports to Codecov with GitHub Action
diff --git a/README.md b/README.md
index 7d205b9..0dbd20c 100644
--- a/README.md
+++ b/README.md
@@ -97,6 +97,16 @@ uv run poe lint
uv run poe test
```
+Before the first run, build the `libsecp256k1` that the `embit` submodule pins (needs `gcc` and `make`):
+```bash
+uv run poe secp256k1-build
+```
+
+Without it `embit` falls back to its pure Python EC implementation, which is slower and does not always match the C library the firmware runs, so some signature paths get exercised differently than on device. CI builds it and fails if the fallback is in use. To check your own setup:
+```bash
+uv run poe secp256k1-check
+```
+
Note: The coverage report will be created at the `htmlcov` folder `file:///path/to/krux/htmlcov/index.html`.
For more verbose output (e.g., to see the output of print statements):
diff --git a/pyproject.toml b/pyproject.toml
index 38e02ef..6adcf71 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -108,6 +108,25 @@ vulture.ref = "vulture-src vulture_whitelist.py"
vulture-make = { shell = "vulture src --make-whitelist > vulture_whitelist.py" }
vulture-whitelist.ref = "vulture-make"
+# secp256k1 tasks
+# Builds the libsecp256k1-zkp pinned by the embit submodule and drops it where
+# embit's ctypes backend looks for it. Without it embit falls back to its pure
+# Python EC implementation, which is slower and does not always behave like the
+# C library the firmware runs.
+secp256k1-build = { shell = """
+make -C vendor/embit/secp256k1
+mkdir -p vendor/embit/src/embit/util/prebuilt
+cp vendor/embit/secp256k1/build/libsecp256k1_* vendor/embit/src/embit/util/prebuilt/
+""" }
+secp256k1-check = { shell = '''python -c "
+import sys
+from embit.util import secp256k1
+
+using_c = hasattr(secp256k1, '_secp')
+print('embit secp256k1 backend:', 'C library' if using_c else 'pure Python')
+sys.exit(0 if using_c else 1)
+"''' }
+
# test tasks
test-clean = """python -c 'import shutil, os; os.path.exists("htmlcov") and shutil.rmtree("htmlcov")'"""
test-cov = "pytest --cache-clear --cov src/krux --cov-report html ./tests --cov-context=test --cov-report term-missing"
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.