Skip to content

tests: cover the two refusals on the two-button devices - #145

Merged
aido merged 1 commit into
aido:bip85from
buzzromain:tests/two-button-refusal-paths-bip85
Aug 4, 2026
Merged

aido merged 1 commit into
aido:bip85from
buzzromain:tests/two-button-refusal-paths-bip85

Conversation

@buzzromain

Copy link
Copy Markdown

Every two-button test walks a path that succeeds: a phrase that matches, shares that recombine, a set that generates. The screens that refuse are a different flow — ux_bip39_invalid_flow and ux_sskr_invalid_flow in src/bagl/ux_nano.c — reached from a different branch of screen_onboarding_restore_word_validate(), and neither had ever been displayed under test on these devices.

They are also the screens with the most at stake. Telling a holder their backup is unreadable when it is fine sends them to re-enter it; telling them it is fine when it is not sends them away with something that will not open their device.

Both cases stop before the seed comparison, and for different reasons, which is why both are here:

  • the phrase is twelve real words whose checksum does not close, so bolos_ux_bip39_mnemonic_check() refuses it and no seed is ever derived;
  • the shares carry one substituted ByteWord, so the CRC-32 over the frame no longer matches and bolos_ux_sskr_hex_check() refuses the set.

Each vector differs from a passing test by exactly one word — planet → zoo against test_bip39_seed_match.py, chef → cost against the shares test_sskr_128bit.py enters — and every word stays in its wordlist, so entry accepts them all and the refusal comes from the check under test rather than from a word the screen would not take.

Both verdicts are asserted on two lines. The first line alone appears on screens that are not these, and the verdict screens of this application differ by their second line rather than their first.

Verification

  • both tests pass on Nano X and Nano S+
  • Stax and Flex unchanged

Not covered

Still uncovered on these devices: too few shares, a duplicated share, a threshold the scheme refuses, and the rest of the suite that skips there.

Every two-button test walks a path that succeeds: a phrase that matches,
shares that recombine, a set that generates. The screens that refuse are a
different flow -- ux_bip39_invalid_flow and ux_sskr_invalid_flow in
src/bagl/ux_nano.c -- reached from a different branch of
screen_onboarding_restore_word_validate(), and neither had ever been displayed
under test on these devices.

They are also the screens with the most at stake. Telling a holder their backup
is unreadable when it is fine sends them to re-enter it; telling them it is
fine when it is not sends them away with something that will not open their
device.

Both cases stop before the seed comparison, and for different reasons, which is
why both are here: the phrase is twelve real words whose checksum does not
close, so bolos_ux_bip39_mnemonic_check() refuses it and no seed is derived;
the shares carry one substituted ByteWord, so the CRC-32 over the frame no
longer matches and bolos_ux_sskr_hex_check() refuses the set.

Each vector differs from a passing test by exactly one word -- "planet" to
"zoo" against test_bip39_seed_match.py, "chef" to "cost" against the shares
test_sskr_128bit.py enters -- and every word stays in its wordlist, so entry
accepts them all and the refusal comes from the check under test rather than
from a word the screen would not take.

Both verdicts are asserted on two lines. The first line alone appears on
screens that are not these, and the verdict screens of this application differ
by their second line rather than their first.
@aido
aido merged commit 0ced6b3 into aido:bip85 Aug 4, 2026
8 checks passed
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.

2 participants