Skip to content

test(solana): certified SoltoshiDICE join asserted screen by screen - #112

Merged
BitHighlander merged 4 commits into
alphafrom
test/solana-schema-v2-certified
Sep 19, 2026
Merged

BitHighlander merged 4 commits into
alphafrom
test/solana-schema-v2-certified

Conversation

@BitHighlander

@BitHighlander BitHighlander commented Sep 19, 2026 •

Copy link
Copy Markdown
Owner

What

Emulator coverage for the certified SoltoshiDICE "Blackjack join", using the material the deployed ClearSign Worker returns for it. The four new tests are in tests/test_msg_solana_schema_v2.py (class TestSolanaSchemaCertified) and are catalogued as S30-S33 in scripts/generate-test-report.py.

  • Transaction: the real dapp message (legacy, no lookup tables, byte-identical to Vault's __tests__/fixtures/solana/soltoshidice-blackjack-join.json). Account 0, the fee payer and only signer, is replaced with the emulator's key.
  • Certified material: the delegate's signature over the 154-byte KKSOLSC1 v2 schema (schema_signer_key_id=128), the public 501-scope certificate, and the KeepKeySolanaTokenDef/2 definition of SDICE (6 decimals, key id 128). None of these signatures covers a transaction, so they still apply after the re-key.
  • Policy: AdvancedMode stays off.

Tests

ID Test Asserts
S30 test_certified_soltoshi_join_reviews_every_screen The text of all 14 screens, in order: Set compute unit limit to 200000?, Funding account <device>, Send 0.002000000 SOL to BqtZ8PRQywD9Z5xXeB5112wtPG3xtj7TqF56hroicGjX?, KeepKey Vault / Signer A9531B9D, SoltoshiDICE / Blackjack join, Round 86, Revision 980, Seat 1, Buy-in / Allowance / Max wager 1000.000000 SDICE with the full mint on the next line, Session key BqtZ8..., Expires in 1 h, Sign this Solana transaction?. Then it checks a 64-byte ed25519 signature against the device key over the message (pycryptodome eddsa, which the CI test image already installs).
S31 test_certified_soltoshi_join_priority_fee_names_fee_payer The real join has no compute-unit price, so it has no Fee payer screen (fsm_msg_solana.h solana_confirmPriorityFee returns early). This test adds a SetComputeUnitPrice and checks all 17 screens, including Fee payer <device> and Max priority fee 0.000200000 SOL right before the sign prompt.
S32 test_certified_soltoshi_join_untrusted_definition_shows_base_units With no token_info, all three amounts show 1000000000 base units of mint plus the mint. A definition with one byte of its signature changed produces frames identical to that. Both still sign.
S33 test_certified_soltoshi_join_ignores_blind_sign_policy With AdvancedMode on, the frames match the policy-off run exactly and there is no BLIND SIGN screen.

Report catalog

  • S30 declares its 14 screens and is in FULL_SEQUENCE_TESTS, so the PDF shows every review screen in order.
  • S30-S33 appear only for firmware 7.16.0 and later (_TEST_MIN_VERSION).
  • On 7.16+ a build that refuses the alpha-root certificate FAILS the whole certified class through _require_alpha_root ("7.16+ firmware must embed the ClearSign root"). It used to skip, and a skip passes both validation and the audit (see round 2 below).

Verification (local)

All runs used kkemu built from a git archive export of keepkey-firmware 4e2fd13a7 (draft PR #829 head) with KK_CLEARSIGN_ALPHA_ROOT=ON. Every run set KK_FORCE_UDP=1 and used private UDP ports 24844/24845.

  • Solana suite: all six tests/test_msg_solana_*.py files ran with 63 passed, 0 skipped. That is round 3's 59 plus these 4.
  • Screenshot audit:
    • The Section S screenshot run selected 22 tests via --section S --screenshot-test-list; all passed, with 113 PNGs.
    • --section S --screenshot-audit then reported "every declared screen was captured".
    • Control: with one of S30's frames deleted, the audit fails with "declared 14, captured 13".
  • JUnit validation: --section S --validate-junit passes for full and bitcoin-only at 7.16.0, and for 7.15.0. Control: with the four tests removed from the JUnit, it fails with S30-S33 missing.
  • PDF render: the Section S PDF renders all 14 S30 frames in order. tests/test_report_variant_validation.py has 4 passed.
  • Firmware mutations: 9 mutations, each built into a separate kkemu in the export tree, and each caught; the control passed.
    • TokenDef/2 signature not checked
    • tag /1
    • decimals big-endian
    • certified=false at the fsm call site
    • Blind Sign screen when AdvancedMode is on
    • companions unscreened
    • no Fee screens on certified reviews
    • trusted symbol drops the mint
    • wrong duration unit
  • Stability: the file ran 3 more times with 10 passed each.

Round 2: refusals, and fail instead of skip (adfa293, 61cb412)

An adversarial check found that deleting clearsign_root_verify_delegate_attestation(...) from the certified branch of fsm_msg_solana.h (fw 88ed0390c) left 200/200 unit and 63 pyk tests green, and that firmware signed the join under a schema renamed Claim airdrop! with a signature of 64 x 0x01.

New tests in TestSolanaSchemaCertified. Each uses the real join re-keyed to the device, with the SDICE definition, and asserts the exact Failure (code 3 and message), that no screen was shown, and that no signature came back:

Test Proof Refusal
test_certified_schema_signature_one_byte_changed_refused schema signature with byte 0 flipped Certified Solana schema does not match transaction
test_certified_edited_schema_refused Blackjack join renamed Claim airdrop! (same length), original signature Certified Solana schema does not match transaction
test_certified_proof_without_schema_signature_refused no schema_signature Incomplete certified Solana ClearSign proof

There is no case for a schema signed under another scope. The delegate signs sha256(schema), which carries no scope, and the alpha root has issued no public certificate for any scope except 501.

_require_alpha_root now fails instead of skipping. The version and bitcoin-only skips are unchanged. No other pyk test skips when the root is missing; test_relay_certified_v0_no_lookup_proof_reaches_signer_check already fails.

Alpha only: CERT_501 chains to the ALPHA ClearSign root (02de9231...dae7). Production gets its own root key after the 7.15 re-release, not before, so this certified tier stays alpha-only. This is documented in the test module and in the S30 report text.

Verification: native kkemu builds of fw 88ed0390c, run with KK_FORCE_UDP=1 on private UDP ports:

  • Control (root on): test_msg_solana_schema_v2.py 13 passed. All six test_msg_solana_*.py files: 66 passed, 0 skipped.
  • Mutant without the attestation check: the first two new tests fail with signed after 14 screens. The third passes, because it guards the completeness check, which that mutant keeps.
  • Root flag OFF: all 10 certified tests FAIL with 7.16+ firmware must embed the ClearSign root (they skipped before). The 3 runtime and attestor tests pass.
  • Python 3.6 was checked by grammar only (ast.parse(feature_version=(3,6))).

Not done here

  • For firmware CI to run these tests, keepkey-firmware PR #829 (deps/python-keepkey) needs to pin this commit. pyk's own CI does not trigger for a PR into alpha.
  • Python 3.6, which CI uses, was checked only by grammar (ast.parse(feature_version=(3,6))). No local 3.6 interpreter was available.

The real SoltoshiDICE "Blackjack join" (legacy, no lookup tables), re-keyed
so its fee payer is the emulator's key, signed through the certified path
with the deployed ClearSign Worker's material: the delegate signature over
the 154-byte KKSOLSC1 v2 schema, the public 501-scope certificate, and the
KeepKeySolanaTokenDef/2 definition of SDICE. None of it binds a
transaction. AdvancedMode stays off.

- every screen's text, in order: compute-unit limit, the Transfer companion
  (funding account, then 0.002 SOL to the session key), the certified
  signer, Round 86, Revision 980, Seat 1, Buy-in / Allowance / Max wager as
  1000.000000 SDICE over the full mint, the session key, Expires in 1 h,
  the sign prompt; then the ed25519 signature is verified over the message
- the real join sets no compute-unit price, so it has no Fee screens; a
  priced variant shows Fee payer and Max priority fee before the sign prompt
- no definition, or a one-byte-changed definition signature: raw base units
  beside the mint, identical frames, still signs
- AdvancedMode on: the same certified review frame for frame, no Blind Sign

Catalogued as S30-S33 (7.16.0+); S30 declares its 14 screens and shows them
all, in order, in the report.
…t skips

TestSolanaSchemaCertified skipped whenever the device refused the public
501-scope certificate ("Invalid certified Solana certificate"). Every 7.16
build embeds the ClearSign root, so that refusal is a regression, and the
skip turned it into a green run: a scope mutant turned all seven certified
tests into skips. setUp now fails with "7.16+ firmware must embed the
ClearSign root". The version and bitcoin-only skips are unchanged.

No other pyk test skips on a missing root.
test_relay_certified_v0_no_lookup_proof_reaches_signer_check already fails.

Documented: CERT_501 chains to the ALPHA root. Production gets its own
root key after the 7.15 re-release, not before, so the certified tier is
alpha-only. The S30 report text no longer says root-less builds skip.
…efused

An adversarial check found that deleting the delegate-attestation check
from the certified branch of fsm_msg_solana.h (fw 88ed0390c) left every
unit and pyk test green: that firmware signed the SoltoshiDICE join under
a schema renamed "Claim airdrop!" with a signature of 64 x 0x01, AdvancedMode
off, under the "KeepKey Vault / Signer A9531B9D" header.

Three refusals on the real join re-keyed to this device, with the SDICE
definition, so the schema proof is the only thing wrong. Each asserts the
exact Failure (code and message), that no screen was shown, and that no
signature came back:

- the delegate's schema signature with one byte changed:
  "Certified Solana schema does not match transaction"
- the instruction renamed (same length) under the original signature:
  "Certified Solana schema does not match transaction"
- no schema_signature: "Incomplete certified Solana ClearSign proof"

There is no case for a schema signed under another scope: the delegate
signs sha256(schema), which carries no scope, and the alpha root has
issued no public certificate for any scope but 501.

Proven on native kkemu builds of fw 88ed0390c: all pass on the control;
the first two fail on the mutant without the check ("signed after 14
screens"); the third guards the completeness check, which that mutant
keeps.
…ture

Adversarial mutants of fw 88ed0390c lib/firmware/fsm_msg_solana.h left
every pyk and unit test green:

- Sf passes the certificate's own scope instead of 501 (:882, :927).
- L passes a fixed 64 instead of msg->schema_signature.size (:928).

Both signed the SoltoshiDICE join after 14 screens. Two refusals now
cover them, on the real join re-keyed to this device with the SDICE
definition:

- test_certified_wrong_scope_certificate_refused: the delegate's real
  schema signature under CERT_SCOPE1, the public alpha EVM-scope (scope 1)
  certificate for the same delegate 0342f5f9. The delegate signs
  sha256(schema), which carries no scope, so only the scope check refuses
  it: "Invalid certified Solana certificate".
- test_certified_short_schema_signature_refused: SOLTOSHI_SCHEMA_SIG[:63].
  Its last byte is 0x00, so the zeroed 64-byte field holds the real
  signature again: "Certified Solana schema does not match transaction".

CERT_SCOPE1 is a fixed constant, fetched once on 2026-09-19 from POST
https://keepkey-clearsign.bithighlander.workers.dev/v1/evm/schema (the
chainId 1 Relay bridgeDeposit shape): bytes [1:140] of its signedPayload.
Nothing is fetched at test time.

This also corrects the comment that said the alpha root had issued no
public certificate for any scope but 501.

Proven on native kkemu builds of fw 88ed0390c (KK_FORCE_UDP=1):
test_msg_solana_schema_v2.py passes 15/15 on the control. The scope test
fails on Sf and on S (the scope comparison dropped from clearsign_root.c).
The length test fails on L. Each failure is "signed after 14 screens".
All six test_msg_solana_*.py files pass 68/68 on the control.
@BitHighlander
BitHighlander merged commit 16a88ef into alpha Sep 19, 2026
1 check failed
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