From 451e9a7b3ea3cb0c96549d99bcad3b4d164a5598 Mon Sep 17 00:00:00 2001 From: highlander Date: Thu, 10 Sep 2026 21:04:38 -0700 Subject: [PATCH 1/2] 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. --- messages.proto | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/messages.proto b/messages.proto index 0936cebf..4a93f2e6 100644 --- a/messages.proto +++ b/messages.proto @@ -600,8 +600,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 fbaf8ec6509f85c365856272b75e66825e9ff5f7 Mon Sep 17 00:00:00 2001 From: highlander Date: Thu, 10 Sep 2026 21:38:30 -0700 Subject: [PATCH 2/2] 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. --- messages.proto | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/messages.proto b/messages.proto index 4a93f2e6..d3d30763 100644 --- a/messages.proto +++ b/messages.proto @@ -347,6 +347,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. } /**