From 5517c8de31cee85663ff6b3a376f1f97bafb9212 Mon Sep 17 00:00:00 2001 From: highlander Date: Thu, 10 Sep 2026 21:04:38 -0700 Subject: [PATCH 1/4] feat(reset): ResetDevice.dice_only selects the dice-only derivation dice_entropy alone is now the MIXED mode: the device commits its own 32-byte draw as 24 BIP-39 words before the rolls are entered, then derives seed = SHA256d("KK\x01SM" || draw || SHA256("KK\x01D" || rolls)). With dice_only the derivation is seed = SHA256(rolls) and the draw is discarded, matching Coldcard's Dice-Rolls-Only byte for byte. The mode is a host-side selection so a wallet can explain what is coming -- 99 rolls, and for MIXED 24 words to copy down -- before the ceremony starts. The device still shows a consent screen naming the mode the host chose, so a host cannot select dice-only silently. In both modes the host's EntropyAck is consumed and its bytes dropped; the wire flow is otherwise unchanged. dice_only without dice_entropy is rejected with a SyntaxError. (cherry picked from commit 451e9a7b3ea3cb0c96549d99bcad3b4d164a5598) --- messages.proto | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/messages.proto b/messages.proto index 510ab111..9e9daf92 100644 --- a/messages.proto +++ b/messages.proto @@ -582,8 +582,19 @@ message ResetDevice { optional uint32 auto_lock_delay_ms = 8; // Screensaver Timeout optional uint32 u2f_counter = 9; // U2F Counter optional bool dice_entropy = - 10; // collect dice rolls on the device and mix them into the internal - // entropy before it is displayed or committed + 10; // collect dice rolls on the device. On its own this is the MIXED + // mode: the device shows its own 32-byte draw as 24 BIP-39 words + // BEFORE the rolls are entered, then seed = SHA256d("KK\x01SM" || + // draw || SHA256("KK\x01D" || rolls)). The host's EntropyAck is + // consumed and its bytes dropped. Verifiable offline from the words + // and the rolls. + optional bool dice_only = + 11; // with dice_entropy: seed = SHA256(rolls) and nothing else -- the + // device draw is discarded, so the wallet rests entirely on the + // rolls. Coldcard's Dice-Rolls-Only, byte for byte. The device shows + // a consent screen naming the chosen mode before anything happens, + // so a host cannot select this silently. Rejected without + // dice_entropy. } /** From 0848887cf04a67342c468a40b36fa67d15cdca9b Mon Sep 17 00:00:00 2001 From: highlander Date: Thu, 10 Sep 2026 21:38:30 -0700 Subject: [PATCH 2/4] feat(features): supports_dice_modes capability Reports that ResetDevice.dice_only, the on-device consent screen and the tagged MIXED derivation are implemented. Needed because nanopb skips unknown fields: a host that sends dice_only to older firmware gets the older ceremony and a different wallet, with no error. Hosts and the test suite gate on this bit rather than on a version. (cherry picked from commit fbaf8ec6509f85c365856272b75e66825e9ff5f7) --- messages.proto | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/messages.proto b/messages.proto index 9e9daf92..7a0b59fc 100644 --- a/messages.proto +++ b/messages.proto @@ -329,6 +329,11 @@ message Features { // Lets a host detect taproot support directly instead of inferring // it from a firmware version, which breaks whenever the feature is // retargeted to a different release. + optional bool supports_dice_modes = + 28; // ResetDevice.dice_only, the on-device consent screen and the tagged + // MIXED dice derivation are implemented. Hosts MUST check this before + // offering either dice mode: older firmware skips the unknown + // dice_only field and derives a different wallet without complaint. } /** From dd9c85dc747cf965fb0e7bf49615dc9e7568ee65 Mon Sep 17 00:00:00 2001 From: highlander Date: Mon, 21 Sep 2026 02:41:53 -0500 Subject: [PATCH 3/4] feat(protocol): advertise Solana LUT attestation support --- messages.proto | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/messages.proto b/messages.proto index 3c0126ad..3d20fce9 100644 --- a/messages.proto +++ b/messages.proto @@ -356,6 +356,10 @@ message Features { // MIXED dice derivation are implemented. Hosts MUST check this before // offering either dice mode: older firmware skips the unknown // dice_only field and derives a different wallet without complaint. + optional bool supports_solana_lut_attestation = + 29; // Firmware authenticates and presents host-resolved Solana address + // lookup-table accounts. False/absent means LUT data remains opaque + // and must follow the ordinary AdvancedMode blind-signing review. } /** From 5fec9e6906a340be5eb3d795ec746769065b2db8 Mon Sep 17 00:00:00 2001 From: highlander Date: Fri, 25 Sep 2026 03:06:10 -0500 Subject: [PATCH 4/4] feat(debuglink): report the last confirmation title and body Tests could only read OLED pixels, so they asserted screen counts, which passed on unfixed firmware when raw glyphs paged like text. Reporting the formatted title and body lets them assert the exact text shown. --- messages.proto | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/messages.proto b/messages.proto index 3d20fce9..34bfc255 100644 --- a/messages.proto +++ b/messages.proto @@ -1077,6 +1077,11 @@ message DebugLinkState { optional bytes dice_digest = 15; // SHA-256 of the ASCII dice-roll string collected during a // dice_entropy ResetDevice workflow + optional string confirm_title = + 16; // title of the most recent confirmation screen, as formatted + optional string confirm_body = + 17; // body of the most recent confirmation screen, as formatted and + // before pagination; lets tests assert exact displayed text } /**