test(bitcoin): prove Taproot production paths in release PDF - #204
Merged
BitHighlander merged 7 commits intoAug 2, 2026
Merged
Conversation
Drives the emulator through the full GetAddress path for SPENDTAPROOT -- fsm_msgGetAddress, path_mismatched's m/86' branch, compute_address, the BIP-86 tweak and bech32m encoding -- none of which the firmware's C unit tests reach. Expected values are the three official BIP-86 vectors. BIP-86 publishes them against the "abandon abandon ... about" mnemonic, which is exactly what setup_mnemonic_abandon loads, so these are the spec's constants and not values our implementation produced. Verified against a locally built emulator: 1 passed. Also mutation checked -- flipping one character of the first expected address makes it fail, so the assertions are not vacuous. NOTE: gated at 7.16.0 via TAPROOT_FIRMWARE_VERSION. develop is currently 7.15.0, so this SKIPS until the project version bumps. A gate that is never reached is a test that is silently green forever -- keep the constant in step with CMakeLists.txt.
Spends a P2TR input on the emulator and compares the 64-byte witness byte for byte against a signature computed outside the firmware. The expected value is not a round trip through our own verifier -- that would pass even if the device committed to the wrong transaction. It comes from a standalone Python implementation of BIP-340/341 written from the specs, keyed from BIP-86's own published xprv for m/86'/0'/0'/0/0, and self-checked against BIP-86's published internal and output keys before being used. BIP-340 signing is deterministic given aux_rand, so equality is meaningful. This caught a real bug. BIP-143 hashes prevouts/sequences/outputs with DOUBLE sha256 (hasher_sign is HASHER_SHA2D for Bitcoin) while BIP-341 specifies SINGLE sha256, so reusing the BIP-143 accumulators produced a cryptographically valid signature over the wrong commitment -- exactly the failure a self-consistent test cannot see. Includes a synthetic prev-tx fixture in txcache so the test runs offline.
Both taproot tests gated on requires_firmware("7.16.0") while CMakeLists
said 7.15.0, so they skipped -- and which release taproot ships in is still
undecided. A gate that is never reached is a test that is silently green
forever, which is the failure mode that looks exactly like passing.
Replaces it with requires_taproot(), which asks the device. The tests now
run whenever the firmware reports the capability, whichever release that
turns out to be, and retargeting the release no longer touches them.
- common.py: requires_taproot() helper, alongside requires_firmware and
requires_message
- regenerated messages_pb2.py for Features.supports_taproot (field 27)
- device-protocol bumped to the commit adding it
Adds test_taproot_screens.py for Gate-3 OLED capture: the two places a
62-character bech32m address actually reaches the display -- verifying a
receive address, and the p2wsh multisig case that shares the length. That
capture is what found the address truncation fixed in the firmware repo.
…agent/taproot-tests-staging
BitHighlander
marked this pull request as ready for review
August 2, 2026 21:48
BitHighlander
merged commit Aug 2, 2026
b6e8f01
into
keepkey:reconcile/upstream-sync
2 of 3 checks passed
This was referenced Aug 2, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds BIP-86 address vectors and capability gating, exact independent BIP-340/341 witnesses, real P2TR key-path spend, device-derived P2TR change, mixed P2TR/legacy signing, and missing-amount rejection. Corrects the report catalog so P2TR output creation is not mislabeled as a Taproot spend. The PDF catalog now has explicit Taproot cases and OLED requirements, consumes CI's branch@SHA label, and rejects missing catalog evidence. Also reconciles the stale ClearSign v2 fallback catalog name so the release report has zero unexplained pending cases.\n\nTarget is the existing upstream staging branch; no package publication.\n\nLocal preflight: py_compile passed; report catalog validation is 310 passed, 3 intentional skips, 0 failed, 0 pending against the canonical Docker JUnit artifact. Canonical Docker CI and its generated PDF remain the merge gate.