Skip to content

test(atlas): catalogue the four 7.15 areas the report could not see - #33

Merged
BitHighlander merged 2 commits into
masterfrom
fix/715-atlas-coverage
Aug 21, 2026
Merged

test(atlas): catalogue the four 7.15 areas the report could not see#33
BitHighlander merged 2 commits into
masterfrom
fix/715-atlas-coverage

Conversation

@BitHighlander

Copy link
Copy Markdown
Owner

The PDF report is generated from SECTIONS, and the screenshot filter is derived from the same list — so a test not in SECTIONS is captured by nothing and appears nowhere. Four things a 7.15 audit needs were in exactly that state.

section tests
F Clear-Sign Provider Context — Additive Invariant 5
I Session and Trust Lifetime 6
L Bitcoin-Only Variant 11
U Storage Upgrade Preservation 8

All min_fw 7.15.0. Verified the cut is exact: at 7.14.2 the active set stays 18 sections with none of F/I/L/U; at 7.15.0 it is 26 with all four.

The headline result

The additive invariant holds — measured on device, not argued from code:

  • Aave supply() baseline = 3 screens
  • VERIFIED v1 decode = 10 screens, with those 3 baseline frames byte-identical at the tail
  • v2 static-schema = 13 screens, same tail
  • signature that fails verification = 3 frames byte-identical to baseline — neither refuses nor leaks partial decoded info
  • all 4 runtime slots identical; no slot verifies without a runtime load, so the suppression branch has no reachable input on this build

A trap worth recording

For a recognized ERC-20, the baseline has no raw-calldata screen at all — ethereum.c's token path skips it before clear-signing is consulted. A v2 test written against a USDC transfer would appear to prove "the raw review survives" when there was no raw review to survive. Section F deliberately uses the unrecognized Aave supply() fixture.

The three additive tests are wired into FULL_SEQUENCE_TESTS — the claim is about order, so a best-of-3 frame sample would hide the thing being proved.

Also: two colliding section letters

Two sections emitted S ids (Display Binding, Solana) and two emitted D (BIP-85, Display Disclosure), so distinct tests shared a label. The disclosure sections are renamed J and Q — safe because they post-date the pyk revision every published report was built from; renaming Solana or BIP-85 would break existing evidence references.

Depends on

keepkey-firmware #495. Two of the eleven bitcoin-only tests fail without it, and both are real firmware defects this suite found: an OP_RETURN output poisoning the duplicate-transaction detector (affects both products), and variant_getName() reporting Emulator for a bitcoin-only build so requires_fullFeature() never skipped anything.

The PDF report is generated from SECTIONS, and the screenshot filter is derived
from the same list — so a test that is not in SECTIONS is captured by nothing and
appears nowhere. Four things a 7.15 audit needs were in exactly that state.

NEW SECTIONS, all min_fw 7.15.0 so a 7.14.x report is unchanged (verified: at
7.14.2 the active set stays 18 sections and none of F/I/L/U appear; at 7.15.0 it
is 26 and all four do):

  F  Clear-Sign Provider Context - Additive Invariant   5 tests
  I  Session and Trust Lifetime                         6 tests
  L  Bitcoin-Only Variant                              11 tests
  U  Storage Upgrade Preservation                       8 tests

THE HEADLINE RESULT: the additive invariant HOLDS, measured on device rather
than argued from code. Aave supply() baseline is 3 screens; a VERIFIED v1 decode
is 10 screens with those same 3 baseline frames BYTE-IDENTICAL at the tail; the
v2 static-schema path is 13 with the same tail; a payload whose signature fails
verification draws 3 frames byte-identical to the baseline — it neither refuses
nor leaks partial decoded information. All four runtime slots behave identically,
and no slot verifies without a runtime load, so the suppression branch has no
reachable input on this build.

A trap worth recording, because it would have made the section look right while
proving nothing: for a RECOGNIZED ERC-20 the baseline has no raw-calldata screen
at all — ethereum.c's token path skips it before clear-signing is consulted. A
v2 test written against a USDC transfer would appear to prove "the raw review
survives" when there was no raw review to survive. Section F deliberately uses
the unrecognized Aave supply() fixture instead.

The three additive tests are added to FULL_SEQUENCE_TESTS: the claim is about
ORDER (decoded screens, then the baseline), so a best-of-3 frame sample would
hide the very thing being proved.

Also fixes two colliding section letters that made the report ambiguous: two
sections emitted 'S' ids (Display Binding and Solana) and two emitted 'D'
(BIP-85 and Display Disclosure), so distinct tests shared a label. The two
disclosure sections are renamed to J and Q — safe because they post-date the pyk
revision every published report was built from, whereas renaming Solana or
BIP-85 would break existing evidence references.

Requires keepkey-firmware PR #495. Two of the eleven bitcoin-only tests fail
without it, and both failures are real firmware defects that this suite found:
an OP_RETURN output poisoning the duplicate-transaction detector (affects BOTH
products), and variant_getName() reporting "Emulator" for a bitcoin-only build
so requires_fullFeature() never skipped anything.
All four are alpha tests asserting behaviour that develop's 7.14.2 line
deliberately changed. In every case the firmware refuses MORE or says MORE than
the test expects, so the tests follow the firmware — never the reverse.

1+2. The blind-sign refusal message (2 files, 3 assertions).
     alpha:   "Blind signing disabled"
     7.14.2:  "Arbitrary contract data signing disabled by policy"
     The newer string names WHICH policy refused and what it refused.

3. Structured EIP-712 (test_ethereum_sign_x402_eip3009).
   7.14.2 disabled it outright -- "Structured EIP-712 disabled pending
   canonical display hardening" -- because the device could not prove that
   what it rendered was what it hashed. The x402 EIP-3009
   TransferWithAuthorization vector is therefore REFUSED, not signed. The test
   asserts the refusal, and the expected domain/message hashes are kept in a
   comment: they are independent EIP-712 V4 reference values and the only
   checked-in oracle for this vector, so they should be re-asserted the day the
   display hardening lands rather than re-derived.

   Same file, second assertion: the typed-hash gate now answers "Enable
   AdvancedMode to blind-sign typed hashes" rather than "disabled by policy" --
   it names the remedy, not just the refusal.

4. test_reset_reentry_disarms_entropy_ack.
   The property under test is the important one and is UNCHANGED: an abandoned
   reset must never leave EntropyAck armed, or a following EntropyAck derives
   the seed from sha256(0*32 || host_bytes) -- entirely host-chosen.

   7.15 closes it earlier and harder than the fix this test was written for.
   #429 replaced the separate awaiting_entropy flag with one armed ceremony,
   and setup_stage() now REFUSES to open a second ceremony on top of an armed
   one. The re-entry this test performed is rejected outright, so there is no
   second ceremony left armed to disarm. The test now asserts BOTH: the refusal
   ("Device is in the middle of setup"), and then the original property --
   EntropyAck refused with "Not in Reset mode", device still uninitialized.

Full local suite against the emulator: 630 passed, 22 skipped, 1 failed, and
that one failure (OP_RETURN poisoning the duplicate detector) is fixed by
keepkey-firmware #495, which is not on the branch this was run against.
@BitHighlander
BitHighlander merged commit cf9dcf6 into master Aug 21, 2026
2 of 5 checks passed
@BitHighlander
BitHighlander deleted the fix/715-atlas-coverage branch August 21, 2026 06:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant