feat(dice): opt-in verifiable dice modes, MIXED and DICE ONLY (7.14.3) - #758
Draft
BitHighlander wants to merge 3 commits into
Draft
feat(dice): opt-in verifiable dice modes, MIXED and DICE ONLY (7.14.3)#758BitHighlander wants to merge 3 commits into
BitHighlander wants to merge 3 commits into
Conversation
… consent Port of the 7.15 unit (audit/715-dice-only @ bedb6ee) to the bitcoin-only product, which the owner named as the primary target for this feature. dice_input.c/.h, dice.cpp, the capture script, the verifier and both docs are byte-identical to the 7.15 unit. reset.c is identical except where the two products already differed: 7.15 shares the mnemonic pager's scratch with its BIP-85 flow through file-scope buffers, and this product has no BIP-85, so show_mnemonic_pages() owns its scratch as function-local statics here, as the backup pager did before it was factored. Nothing else diverges. What the unit does, on both products: - ResetDevice.dice_entropy alone is MIXED: the device shows its 32-byte draw as 24 BIP-39 words BEFORE the rolls are entered, then seed = SHA256d("KK\x01SM" || draw || SHA256("KK\x01D" || rolls)). - dice_entropy + dice_only is ONLY: seed = SHA256(rolls). Coldcard's Dice-Rolls-Only byte for byte. dice_only without dice_entropy is refused. - The device shows a consent screen naming the mode the host asked for; holding proceeds, the only "no" is cancelling the reset. - The host's EntropyAck is consumed and its bytes dropped in both modes, so the wire flow is unchanged. The default no-dice reset is untouched. - Rolls with any face over 30% are refused before a digest is drawn; the digest is shown in full; tools/verify_dice_seed.py recomputes the wallet offline from the roll string (plus the 24 words for MIXED). Pins, as on the 7.15 unit: deps/device-protocol -> 5517c8de3 (feat/dice-only-field-7.14.3): the dice_only field cherry-picked onto this product's current pin 8545cd5b6. Not canonical up/release-protocol, because the twelve commits between carry EIP-712 streaming fields with no .options here and the pb_callback_t gate would fail. Retires when the product advances its pin. deps/python-keepkey -> c0e9bd8 (feat/dice-modes): host tests for both modes.
Findings from an adversarial review of the unit (86 agents, 3 refuters per finding) and from the first CI runs, all confirmed against the code: - The full 7.15 image failed to link: "Insufficient runtime SRAM: require 16 KiB stack/heap reserve". Its base reserve was 16,420 B against a 16,384 B floor, and the unit had added a 128-byte static for the digest page. That page is now formatted into current_words -- 265 bytes, already CONFIDENTIAL, idle between roll entry and the backup pager -- so the unit adds no static RAM beyond the 4-byte mode. - dice with no_backup is refused with SyntaxError before any screen, as display_random with no_backup was: the modes exist to be checked against the backup words, and a reset that never shows them would put seed material on the OLED under a WARNING that recovery is impossible. - The MIXED consent screen now says the 24 entropy words are NOT a backup, since the pages that follow are otherwise indistinguishable from the backup pages. Both consent bodies are shortened so neither can ever paginate. - Features.supports_dice_modes (28) is reported. Older firmware skips the unknown dice_only field and derives a different wallet without complaint, so hosts and the test suite gate on this bit rather than on a version. - dice_mix() was dead once the modes replaced it; removed with its tests. The non-collision test now compares against the old formula's Python-computed vector instead. A unit test that placed its invalid byte past `count` is corrected. - tools/verify_dice_seed.py looked for a wordlist file the repo does not ship; it now reads the firmware's own bip39_english.c (slicing "abandon" to "zoo", since the file quotes other strings too) and was checked to yield exactly the reference English list. - Stale comments describing an on-device mode selector are corrected; docs/DiceEntropy.md "What happens" now describes the shipped ceremony. Pins: deps/device-protocol -> 0848887cf04a67342c468a40b36fa67d15cdca9b (feat/dice-only-field-7.14.3, adds Features.supports_dice_modes = 28 on the products' dp base); deps/python-keepkey -> 51d7cd112aee21daea44c124310c7b08e921ee07 (feat/dice-modes: capability-gated tests, the digest-subpage and roll-injection driver fixes, no_backup and consent-cancel tests, atlas entries).
feat/dice-modes @ 03c2fe11f704720c7a0230908ae9971717765aa5: the report atlas names the unit's eight Dice gtests in place of the four removed with dice_mix(), which the 7.15 bitcoin-only catalog validation had flagged as missing.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #755 (
audit/7143-scope-repair). Three commits; the tree is byte-identical to the one that went green on run 34568532481 before the rebase. This is the primary target — the bitcoin-only product.What
Two opt-in ways to seed a device from dice, selected by the host on
ResetDeviceand confirmed on the device before anything is collected:dice_entropy=trueSHA256d(tagM ‖ device_draw ‖ SHA256(tagU ‖ rolls))— the device shows its 32-byte draw as 24 words before you rolldice_entropy=true, dice_only=trueSHA256(rolls)— byte-for-byte ColdCard Dice-Rolls-OnlyCancelaborts the ceremony.dice_onlywithoutdice_entropy, and either mode withno_backup, are refused withSyntaxError.EntropyAckis still consumed in both dice modes and its bytes discarded. The default (no-dice) reset is unchanged:SHA256(device ‖ host), as it has been since 2014 — seedocs/dice-vs-coldcard.mdfor why that stays.Features.supports_dice_modes(field 28) so hosts gate on capability, never version: older firmware silently skips the unknowndice_onlyfield and derives a different wallet.tools/verify_dice_seed.py --rolls … --words 24 [--device-words "…"]recomputes the mnemonic from what the user wrote down. No device secret, no network.SHA256(draw ‖ rolls)) is replaced; the tagged derivation is proven not to collide with it (native K6).Evidence
Pins
keepkey:feat/dice-modes@ 03c2fe1 (test(reset): host-selected dice modes, verified against the published derivations keepkey/python-keepkey#222, →reconcile/upstream-sync)keepkey:feat/dice-only-field-7.14.3@ 0848887 — the same commit as feat(reset): ResetDevice.dice_only selects the dice-only derivation keepkey/device-protocol#122 (→up/release-protocol) cherry-picked onto the products' current pin, because the products carry no.optionsfor canonical's EIP-712 streaming fields yet.Twin of the 7.15 unit; the two products'
reset.c/dice_input.c/docs/tests are identical apart from the mnemonic-pager scratch buffers.