Repository navigation
feat(7.15): integrate reviewed Python stack through block 08 - #229
BitHighlander merged 28 commits into
Conversation
…oder Array-of-structs, Permit2 batch and multidimensional device walks now compare the device's domain/message hashes with a spec-derived reference encoder and recover the signature to the device address. The multidim walk is Stack 07 work and is gated by the structured-EIP-712 probe, not by the later evm-unknown-token-review capability.
…e wire set_expected_responses() raised a CallException whose text embedded the expected message, so the old assertIn passed whatever the device sent. Send EthereumSignTx with call_raw and require the first response to be Failure_ActionCancelled with the exact message (no ButtonRequest first).
…nputs The firmware-validation step ran only behind 'if validator:' so compile tests passed without ever reaching firmware. Missing validator or registry is now an explicit skip, and a failure when CI sets KK_REQUIRE_ERC7730_EVIDENCE=1.
…ong bytes Every signing walk now requires exactly one ButtonRequest_SignTx "Sign Typed Data" screen at the end. New device tests: declining that screen returns ActionCancelled and no signature; primaryType EIP712Domain signs keccak(0x1901||domainSeparator) (checked by the independent encoder and signer recovery); unlimited EIP-2612 and Permit2 amounts are refused before their leaf is displayed; a 1024-byte bytes leaf signs and verifies independently.
The registry conformance test had never run against a firmware validator. Run through the firmware's own catalog verifier, 56 of the 1,450 official calldata formats compiled to programs the device refuses: - 46 tokenAmount fields with no token compiled to formatter kind 3, which the verifier refuses without a token argument. With no token the device can only show the raw integer, so compile the raw formatter. - 8 paths iterated two nested arrays; the verifier accepts one "[]" step per path. Refuse them by name. - 2 ABIs nested deeper than the device's 8 levels. Refuse them by name. The registry test now requires every format to pass the firmware validator or be refused for one of those named device limits, and pins that count at 10.
The device response buffer is shared with DebugLink, and a state read during the final sign screen erased an address written before it. The signature still recovered to the right key, so only the reported address was wrong. Under screenshot capture the unfixed firmware returns an empty address and these assertions fail.
Firmware calldata and typed-data captures refuse ERC7730_ABI_MAX_DEPTH (8) or more path steps, and the catalog verifier now does too. Refuse such paths by name at compile time. No official registry format is affected.
Firmware now refuses at preload every ERC-7730 program its runtime cannot finish, using one capability table shared by the verifier and the runtime. Mirror that table here as DEVICE_CAPABILITIES: - compile_calldata/compile_eip712 raise DeviceCannotExecute with the exact reason unless executable_only=False; - device_refusal() reports why a compiled program would be refused; - the registry test asserts that the device verifier and this mirror agree on every compiled format in both directions, and that exactly 92 of the 1,450 official formats are signable (not 94: two raw fields read the @.from container, which the runtime never captured). Also pin device-protocol at the canonical release protocol plus the Solana LUT merge and DebugLinkState.confirm_title/confirm_body, and add DebugLink.read_confirm_text() so tests can assert exact screen text.
…actly The capability mirror treated every permitted role as required, walked non-value paths against the ABI and read an index after every step opcode. None of that could fire under the Phase 0 table, but each would misfire as soon as the table widens. Separate required roles, list executable containers, and parse whole-array and slice steps as the firmware does.
…ants Phase A of the ERC-7730 formatter plan. The device now executes tokenAmount (value, token, threshold, message, native aliases), addressName, @.from/@.to (calldata only) and signed constants, and type-checks every argument at preload. Mirror that table, including the value classes: amount and threshold are integers, token and addressName values are addresses, raw literals are integers, addresses or strings, and an alias set names at most four addresses. The registry test now asserts 812 signable formats (from 92). The device still refuses addressName and tokenAmount over bytes32/uint256 words that pack an address or an encrypted amount.
Phase B. The device executes display opcodes 2 and 3 as one run directly after the plain intent, showing each fragment and value as a numbered part. Mirror the opcodes and the run rule, and trim fragment edges: each part is its own screen, and the device escapes edge spaces. The registry test now asserts 954 signable formats.
Phase C. Mirror the device's new formatters and their argument classes: a date encoding must be the string "timestamp" or "blockheight", unit decimals a one-byte literal and the prefix a flag, an enum map at most 16 entries, an NFT collection an address, and @.value an unsigned value. The registry test now asserts 1,138 signable formats.
…715-stack07b3r-embedded-mirror
Python canonical integration completed — 2026-09-27T21:16:03.158649+00:00Owner explicitly authorized merging the reviewed Python work into canonical. Upstream PR #229 is merged into Includes accepted Stack 07, consolidated 7b, and Stack 08 Python work through reviewed Final candidate CI 36350596825 passed lint, full 7.14.3, staged full 7.15, and both Bitcoin-only variants. CircleCI 812 passed. Staged full 7.15: 778 passed, 110 skipped under version/product/accepted staged guards, zero failures, 188 subtests passed. This is staged qualification and does not certify deferred release capabilities. Local focused checks: 51 passed, 17 subtests, two generator skips from incomplete local ethereum-lists checkout due disk exhaustion; hosted recursive-checkout lint passed generator checks. Workflow syntax passed; optional shellcheck's inherited info/style diagnostics were recorded. Initial CI 36349775654 failed 54 full-7.15 cases against the historical firmware pin. Run 36350138324 reduced that to 13 cases after pinning accepted 7b; all were covered by its explicit deferred-capability ledger. The final run applies that immutable ledger and is green. No test assertions were weakened. Canonical integration was not merged until final checks passed. Upstream #197 remains the separate canonical-to-master PR. Firmware Stack 08 B's local-preflight ancestry issue remains unresolved, with its review budget exhausted; this Python merge does not mark that firmware audit complete or change its pinned Python SHA. No additional Copilot request, firmware merge, master merge or repository-setting change was made. |
Merges, into one head, everything a firmware pin has used: - reconcile/upstream-sync 76d876a: the canonical upstream PR (keepkey#197), with the reviewed stack through 08 (keepkey#229) and its CI workflow changes - 010cdd3: the 7.15/7.16 line, with the staged-capability gates (b47769e) - dabf5a4 and 6dd8503: the b13 and b14 firmware pins, which sit on side branches and are patch-equivalent to commits already on the line The merged tree differs from 010cdd3 only by canonical's own workflow and whitespace changes (2 files). Every firmware pin from b1 to b15 is now an ancestor of this head, with its tree unchanged.
Canonical Python integration through Stack 08
Owner explicitly authorized merging into
keepkey/python-keepkey:reconcile/upstream-sync. Canonical base98c717ff2204124bf67cc78cab8ca1d501fd4e92is an ancestor; there are no conflicting canonical changes. Candidate6033aab2116b89abb6e1df6afed9e1321481ec19integrates accepted Stack 07, consolidated 7b and Stack 08 from fork #119/#120. No Stack 09 changes are included.Changes after reviewed Python d9a02d9
Production/library files, runtime test semantics and dependency pins equal reviewed
d9a02d981ee43fe3e80b28ba02466670e6e8409d(clean review 5329239805). Nine trailing-whitespace occurrences were removed from compiler tests; parsed AST is identical. The workflow aligns both full/BTC 7.15 CI firmware pins with accepted consolidated 7b2483977523d9b6beab52a69429ace9aeefd00f76(#871). The 7.14.3 pins remain unchanged.Initial CI 36349775654 passed lint, 7.14.3 full and both BTC jobs, but full 7.15 reported 54 failures against the historical firmware #843 pin, which predates these test contracts. The pin update qualifies the tests against their accepted implementation. No assertion, skip or product gate was weakened. New exact-head CI must pass before merge.
Verification
This integrates Python only. Firmware B's separate local-preflight ancestry issue remains recorded and is not declared repaired or accepted. Canonical-to-master remains separate upstream PR #197. No extra Copilot request or repository-setting change.
Staged qualification boundary
Run 36350138324 against accepted 7b passed 782 tests and skipped 93, with 13 failures in capabilities explicitly deferred by the accepted firmware ledger. The final workflow reads that ledger from the immutable firmware checkout into only the full staged 7.15 job; it rejects missing/duplicate ledger declarations. No waiver is invented in the Python branch. Ledger:
evm-max-amount-review,evm-unknown-token-review,entropy-audit-budget,osmosis-wire-guards,hive-release-review,storage-v19-kdf,solana-lut-attestation. The job summary publishes these omissions. Test assertions and default release behavior are unchanged; this is staged 7.15 qualification, not approval of deferred release features. 7.14.3 remains fully unchanged.