Show Seed Vault names for temporary seeds
What changed, and why it matters
This commit adds a user-facing preference that lets a COLDCARD owner optionally replace the temporary seed's fingerprint (XFP) on the home screen with the friendly name stored in the Seed Vault. It is a cosmetic UI enhancement with no security-relevant behavior change.
No security action required; this is a benign UI feature. Reviewers may verify that the comparison uses the encoded secret (not just XFP) to avoid name collisions if two seeds share the same fingerprint.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch introduces a new setting ‘tsn’ (Temporary Seed Names) persisted in nvstore and treated as a master-seed field. When enabled, make_top_menu() iterates the Seed Vault, compares each stored encoded secret against the currently active temporary seed, and if a matching named entry exists and the label fits the screen width, displays ‘[label]’ instead of ‘[XFP]’. The change includes a buried settings toggle, changelog note, and unit tests covering both name-fits and name-too-long cases.
Changed components
shared/actions.pyshared/flow.pyshared/nvstore.pytesting/test_ephemeral.pyreleases/Next-ChangeLog.mdInspect captured patch +56 / −5
### releases/Next-ChangeLog.md
@@ -19,6 +19,9 @@ your addition and anything else already in this file.**
malformed global input/output count encodings, and files missing the required
global version.
+- Enhancement: Optionally show Seed Vault names for temporary seed fingerprints
+ at the top of the home menu.
+
# Mk Specific Changes
### shared/actions.py
@@ -994,6 +994,19 @@ def make_top_menu():
sl, sr = ("[", "]") if pa.tmp_value else ("<", ">")
if active_xfp:
ui_xfp = sl + xfp2str(active_xfp) + sr
+ if pa.tmp_value and settings.master_get("tsn", False):
+ from seed import seed_vault_iter
+ from utils import deserialize_secret
+
+ for rec in seed_vault_iter():
+ if deserialize_secret(rec.encoded) != pa.tmp_value:
+ continue
+
+ named_xfp = "[" + rec.label + "]"
+ max_name_width = 32 if version.has_qwerty else 16
+ if len(named_xfp) <= max_name_width:
+ ui_xfp = named_xfp
+ break
_cls.insert(0, MenuItem(ui_xfp, f=ready2sign))
if pa.tmp_value:
_cls.append(MenuItem("Restore Master", f=restore_main_secret, shortcut='m'))
### shared/flow.py
@@ -175,6 +175,12 @@ async def goto_home(*a):
'Master seed is displayed as <XFP>, temporary seeds as [XFP].'),
predicate=has_real_secret,
on_change=goto_home),
+ ToggleMenuItem('Temporary Seed Names', 'tsn', ['Use XFP', 'Use Names'],
+ story=("Show a temporary seed's Seed Vault name instead of its XFP "
+ "at the top of the home menu. If the name is too long to "
+ "fit, the XFP is shown."),
+ predicate=has_real_secret,
+ on_change=goto_home),
ToggleMenuItem('Menu Wrapping', 'wa', ['Default', 'Always Wrap'],
story='''When enabled, allows scrolling past menu top/bottom \
(wrap around). By default, this only happens in menus whose length is greater than 10.'''),
### shared/nvstore.py
@@ -63,6 +63,7 @@
# b85max = (bool) allow max BIP-32 int value in BIP-85 derivations
# ptxurl = (str) URL for PushTx feature, clear to disable feature
# hmx = (bool) Force display of current XFP in home menu, even w/o tmp seed active
+# tsn = (bool) Use Seed Vault names for temporary seed XFPs in home menu
# unsort_ms = (bool) Allow unsorted multisig with BIP-67 disabled
# msas = multisig address show (do not censor multisig addresses)
# ccc = (complex) If present, CCC feature is enabled and key details stored here.
@@ -95,7 +96,7 @@
# key value pairs saved directly to master seed settings
# held in RAM for tmp seed sessions
-MASTER_FIELDS = ['seeds', 'seedvault', 'xfp', 'words', "bkpw", "sssp"]
+MASTER_FIELDS = ['seeds', 'seedvault', 'xfp', 'words', "bkpw", "sssp", "tsn"]
NUM_SLOTS = const(100)
SLOTS = range(NUM_SLOTS)
### testing/test_ephemeral.py
@@ -1703,9 +1703,11 @@ def test_import_master_as_tmp(reset_seed_words, goto_eph_seed_menu, cap_story,
story, parsed_ident = get_identity_story()
assert xfp_str == parsed_ident["xfp"]
-def test_home_menu_xfp(goto_home, pick_menu_item, press_select, cap_story, cap_menu,
+@pytest.mark.parametrize('name_fits', [True, False])
+def test_home_menu_xfp(name_fits, goto_home, pick_menu_item, press_select, cap_story, cap_menu,
settings_get, goto_eph_seed_menu, need_keypress,
- enter_mash_entropy):
+ enter_mash_entropy, master_settings_get, sim_exec,
+ has_qwerty):
goto_home()
pick_menu_item("Settings")
pick_menu_item("Buried Settings")
@@ -1738,7 +1740,34 @@ def test_home_menu_xfp(goto_home, pick_menu_item, press_select, cap_story, cap_m
time.sleep(.2)
m = cap_menu()
assert m[1] == "Ready To Sign"
- assert m[0] == "[" + xfp2str(settings_get("xfp")) + "]"
+ tmp_xfp = xfp2str(settings_get("xfp"))
+ assert m[0] == "[" + tmp_xfp + "]"
+
+ original_seeds = master_settings_get("seeds") or []
+ original_tsn = master_settings_get("tsn")
+ sim_exec("from seed import SecretStash; from pincodes import pa; "
+ "encoded = SecretStash.storage_serialize(pa.tmp_value); "
+ "settings.master_set('seeds', %r + [(%r, encoded, 'Travel', 'test')]); "
+ "settings.master_set('tsn', True)" % (original_seeds, tmp_xfp))
+ goto_home()
+ assert cap_menu()[0] == "[Travel]"
+
+ max_name_width = 32 if has_qwerty else 16
+ name_width = max_name_width - 2 + (not name_fits)
+ test_name = 'N' * name_width
+ sim_exec("from seed import SecretStash; from pincodes import pa; "
+ "encoded = SecretStash.storage_serialize(pa.tmp_value); "
+ "settings.master_set('seeds', %r + [(%r, encoded, %r, 'test')])" %
+ (original_seeds, tmp_xfp, test_name))
+ goto_home()
+ expected_name = "[" + test_name + "]" if name_fits else "[" + tmp_xfp + "]"
+ assert cap_menu()[0] == expected_name
+
+ sim_exec("settings.master_set('seeds', %r); settings.master_set('tsn', %r)" %
+ (original_seeds, original_tsn))
+ goto_home()
+ assert cap_menu()[0] == "[" + tmp_xfp + "]"
+
pick_menu_item("Restore Master")
press_select()
@@ -1761,7 +1790,6 @@ def test_home_menu_xfp(goto_home, pick_menu_item, press_select, cap_story, cap_m
m = cap_menu()
assert m[0] == "Ready To Sign"
-
def test_seed_vault_enable_on_tmp(generate_ephemeral_words, reset_seed_words,
goto_eph_seed_menu, ephemeral_seed_disabled,
verify_ephemeral_secret_ui, goto_home, cap_menu,Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.