fix(core): improve confirmation UX in super-shamir
What changed, and why it matters
This commit improves the on-screen confirmation experience when creating an advanced Shamir backup on a Trezor device. It adds extra prompts that show the user how many backup groups exist, how many groups are needed to recover the wallet, and the threshold for each individual group. There is no security vulnerability here; it is purely a user-interface improvement to help people verify their backup settings.
No security action required. This is a normal UX improvement. Reviewers may optionally verify that the new confirmation strings render correctly on device and that translation signature updates are consistent with the changed strings.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The change modifies reset_device/init.py so that, during a multi-group (super-shamir) backup, the firmware now calls confirm_action with a new translation string backup__info_multi_group_backup and then confirm_properties with per-group threshold/share-count pairs using backup__info_n_of_m_template. Previously only a single generic confirmation was shown regardless of whether the backup had one group or many. New translation keys and localized strings are added, and the per-model variant of recovery__group_num_template is collapsed to a single string. The changelog entry describes this as a UX improvement, not a security fix.
Changed components
core/src/apps/management/reset_device/__init__.pycore/translations/en.jsoncore/translations/cs.jsoncore/translations/de.jsoncore/translations/es.jsoncore/translations/fr.jsoncore/translations/pt.jsoncore/translations/order.jsoncore/translations/signatures.jsoncore/translations/blank_translations_rules.jsoncore/embed/rust/librust_qstr.hcore/mocks/trezortranslate_keys.pyicore/embed/rust/src/translations/generated/translated_string.rscore/.changelog.d/7678.fixedInspect captured patch +3141 / −3059
### core/.changelog.d/7678.fixed
@@ -0,0 +1 @@
+Show the group threshold and individual groups thresholds in Advanced Shamir backup.
### core/embed/rust/librust_qstr.h
@@ -157,7 +157,9 @@ static void _librust_qstrs(void) {
MP_QSTR_backlight_set;
MP_QSTR_backup__can_back_up_anytime;
MP_QSTR_backup__create_backup_to_prevent_loss;
+ MP_QSTR_backup__info_multi_group_backup;
MP_QSTR_backup__info_multi_share_backup;
+ MP_QSTR_backup__info_n_of_m_template;
MP_QSTR_backup__info_single_share_backup;
MP_QSTR_backup__it_should_be_backed_up;
MP_QSTR_backup__it_should_be_backed_up_now;
### core/embed/rust/src/translations/generated/translated_string.rs
[binary or diff unavailable]
### core/mocks/trezortranslate_keys.pyi
@@ -37,7 +37,9 @@ class TR:
auto_lock__title: str = "Auto-lock delay"
backup__can_back_up_anytime: str = "You can back up your Trezor once, at any time."
backup__create_backup_to_prevent_loss: str = "Create a wallet backup to avoid losing access to your funds."
+ backup__info_multi_group_backup: str = "Your wallet backup contains {0} groups with a group threshold of {1}."
backup__info_multi_share_backup: str = "Your wallet backup contains multiple lists of words in a specific order (shares)."
+ backup__info_n_of_m_template: str = "{0}-of-{1}"
backup__info_single_share_backup: str = "Your wallet backup contains {0} words in a specific order."
backup__it_should_be_backed_up: str = "You should back up your new wallet right now."
backup__it_should_be_backed_up_now: str = "It should be backed up now!"
### core/src/apps/management/reset_device/__init__.py
@@ -6,7 +6,7 @@
from trezor import TR
from trezor.crypto import hmac, slip39
from trezor.enums import BackupType, MessageType
-from trezor.ui.layouts import confirm_action
+from trezor.ui.layouts import BR_CODE_OTHER, confirm_action, confirm_properties
from trezor.wire import ProcessError
from apps.common import backup_types
@@ -21,6 +21,7 @@
from buffer_types import AnyBytes
from trezor.messages import ResetDevice, Success
+ from trezor.ui.layouts import PropertyType
BAK_T_BIP39 = BackupType.Bip39 # global_import_cache
@@ -292,17 +293,42 @@ async def backup_slip39_custom(
mnemonics = _get_slip39_mnemonics(
encrypted_master_secret, group_threshold, groups, extendable
)
- await confirm_action(
- "warning_shamir_backup",
- TR.reset__title_shamir_backup,
- description=TR.reset__create_x_of_y_multi_share_backup_template.format(
- groups[0][0], groups[0][1]
- ),
- verb=TR.buttons__continue,
- )
if len(groups) == 1:
+ await confirm_action(
+ "warning_shamir_backup",
+ TR.reset__title_shamir_backup,
+ description=TR.reset__create_x_of_y_multi_share_backup_template.format(
+ groups[0][0], groups[0][1]
+ ),
+ verb=TR.buttons__continue,
+ )
await layout.slip39_basic_show_and_confirm_shares(handler, mnemonics[0])
else:
+ await confirm_action(
+ "warning_shamir_advanced_backup",
+ TR.reset__recovery_wallet_backup_title,
+ description=TR.backup__info_multi_group_backup.format(
+ len(groups), group_threshold
+ ),
+ verb=TR.buttons__continue,
+ )
+
+ props: list[PropertyType] = []
+ for idx, (threshold, n_group) in enumerate(groups):
+ props.append(
+ (
+ TR.recovery__group_num_template.format(idx + 1),
+ TR.backup__info_n_of_m_template.format(threshold, n_group),
+ False,
+ )
+ )
+ await confirm_properties(
+ "shamir_advanced_backup_groups",
+ TR.reset__recovery_wallet_backup_title,
+ props,
+ br_code=BR_CODE_OTHER,
+ verb=TR.buttons__continue,
+ )
await layout.slip39_advanced_show_and_confirm_shares(handler, mnemonics)
### core/translations/blank_translations_rules.json
@@ -137,7 +137,6 @@
"pin__enabled",
"progress__locking_device",
"recovery__enter_different_share",
- "recovery__group_num_template",
"recovery__you_have_entered",
"reset__more_info_at",
"reset__select_word_x_of_y_template",
### core/translations/cs.json
@@ -136,7 +136,9 @@
"Delizia": "Vytvořte si zálohu peněženky, abyste neztratili přístup ke svým prostředkům.",
"Eckhart": "Vytvořte si zálohu peněženky, abyste neztratili přístup ke svým prostředkům."
},
+ "backup__info_multi_group_backup": "Vaše záloha peněženky obsahuje {0} skupin s prahem skupiny {1}.",
"backup__info_multi_share_backup": "Vaše záloha peněženky obsahuje několik seznamů slov v určitém pořadí (podílů).",
+ "backup__info_n_of_m_template": "{0}-z-{1}",
"backup__info_single_share_backup": "Vaše záloha peněženky obsahuje {0} slov v určitém pořadí.",
"backup__it_should_be_backed_up": {
"Bolt": "Novou peněženku byste si měli ihned zálohovat.",
@@ -1979,12 +1981,7 @@
},
"recovery__enter_each_word": "Zadejte popořadě všechna slova vaší zálohy peněženky.",
"recovery__enter_share_from_diff_group": "Zadejte podíl z jiné skupiny.",
- "recovery__group_num_template": {
- "Bolt": "Skupiny {0}",
- "Caesar": "Skupiny {0}",
- "Delizia": "Skupiny {0}",
- "Eckhart": ""
- },
+ "recovery__group_num_template": "Skupiny {0}",
"recovery__group_threshold_reached": "Práh skupiny dosažen.",
"recovery__invalid_share_entered": "Zadali jste neplatný podíl zálohy.",
"recovery__invalid_wallet_backup_entered": "Zadali jste neplatnou zálohu.",
### core/translations/de.json
@@ -146,7 +146,9 @@
"Delizia": "Erstelle ein Backup, um den Zugriff auf deine Assets nicht zu verlieren.",
"Eckhart": "Erstelle ein Backup, um den Zugriff auf deine Assets nicht zu verlieren."
},
+ "backup__info_multi_group_backup": "Dein Wallet-Backup enthält {0} Gruppen mit einem Gruppen-Schwellenwert von {1}.",
"backup__info_multi_share_backup": "Dein Wallet-Backup enthält mehrere Listen von Wörtern in einer bestimmten Reihenfolge (Shares).",
+ "backup__info_n_of_m_template": "{0}-von-{1}",
"backup__info_single_share_backup": "Dein Wallet-Backup enthält {0} Wörter in einer bestimmten Reihenfolge.",
"backup__it_should_be_backed_up": {
"Bolt": "Du solltest jetzt dein neues Wallet sichern.",
@@ -2264,12 +2266,7 @@
},
"recovery__enter_each_word": "Gib jedes Wort aus deinem Wallet-Backup nacheinander ein.",
"recovery__enter_share_from_diff_group": "Share von anderer Gruppe eingeben.",
- "recovery__group_num_template": {
- "Bolt": "Gruppe {0}",
- "Caesar": "Gruppe {0}",
- "Delizia": "Gruppe {0}",
- "Eckhart": ""
- },
+ "recovery__group_num_template": "Gruppe {0}",
"recovery__group_threshold_reached": "Gruppenschwelle wurde erreicht.",
"recovery__invalid_share_entered": "Eingegebener Recovery Share ist ungültig.",
"recovery__invalid_wallet_backup_entered": "Eingegebener Recovery Seed ist ungültig.",
### core/translations/en.json
@@ -104,7 +104,9 @@
"Delizia": "Create a wallet backup to avoid losing access to your funds.",
"Eckhart": "Create a wallet backup to avoid losing access to your funds."
},
+ "backup__info_multi_group_backup": "Your wallet backup contains {0} groups with a group threshold of {1}.",
"backup__info_multi_share_backup": "Your wallet backup contains multiple lists of words in a specific order (shares).",
+ "backup__info_n_of_m_template": "{0}-of-{1}",
"backup__info_single_share_backup": "Your wallet backup contains {0} words in a specific order.",
"backup__it_should_be_backed_up": {
"Bolt": "You should back up your new wallet right now.",
@@ -1987,12 +1989,7 @@
},
"recovery__enter_each_word": "Enter each word of your wallet backup in order.",
"recovery__enter_share_from_diff_group": "Enter share from a different group.",
- "recovery__group_num_template": {
- "Bolt": "Group {0}",
- "Caesar": "Group {0}",
- "Delizia": "Group {0}",
- "Eckhart": ""
- },
+ "recovery__group_num_template": "Group {0}",
"recovery__group_threshold_reached": "Group threshold reached.",
"recovery__invalid_share_entered": "Invalid recovery share entered.",
"recovery__invalid_wallet_backup_entered": "Invalid wallet backup entered.",
### core/translations/es.json
@@ -141,7 +141,9 @@
"Delizia": "Crea una c. seg. para evitar perder el acceso a tus fondos.",
"Eckhart": "Crea una c. seg. para evitar perder el acceso a tus fondos."
},
+ "backup__info_multi_group_backup": "La c. seg. de la billetera contiene {0} grupos con un umbral de grupo de {1}.",
"backup__info_multi_share_backup": "La c. seg. de la billetera contiene varias listas de palabras en un orden concreto (partes).",
+ "backup__info_n_of_m_template": "{0}-de-{1}",
"backup__info_single_share_backup": "La c. seg. de la billetera contiene {0} palabras en un orden concreto.",
"backup__it_should_be_backed_up": {
"Bolt": "Debes realizar una c. seg. de tu billetera.",
@@ -1979,12 +1981,7 @@
},
"recovery__enter_each_word": "Introduce cada palabra de la c. seg. de la billetera en orden.",
"recovery__enter_share_from_diff_group": "Introduce una parte de otro grupo.",
- "recovery__group_num_template": {
- "Bolt": "Grupo {0}",
- "Caesar": "Grupo {0}",
- "Delizia": "Grupo {0}",
- "Eckhart": ""
- },
+ "recovery__group_num_template": "Grupo {0}",
"recovery__group_threshold_reached": "Umbral de grupo alcanzado.",
"recovery__invalid_share_entered": "La parte de recuperación es inválida.",
"recovery__invalid_wallet_backup_entered": "La c. seg. de la billetera es inválida.",
### core/translations/fr.json
@@ -166,12 +166,14 @@
"Delizia": "Créez une sauvegarde pour éviter de perdre l'accès à vos fonds.",
"Eckhart": "Créez une sauvegarde pour éviter de perdre l'accès à vos fonds."
},
+ "backup__info_multi_group_backup": "Votre sauvegarde de portefeuille contient {0} groupes avec un seuil de groupe de {1}.",
"backup__info_multi_share_backup": {
"Bolt": "La sauvegarde contient plusieurs listes dans un ordre spécifique (fragments).",
"Caesar": "La sauvegarde contient plusieurs listes dans un ordre spécifique (fragments).",
"Delizia": "Votre sauvegarde de portefeuille contient plusieurs listes de mots dans un ordre spécifique (fragments).",
"Eckhart": "Votre sauvegarde de portefeuille contient plusieurs listes de mots dans un ordre spécifique (fragments)."
},
+ "backup__info_n_of_m_template": "{0}-sur-{1}",
"backup__info_single_share_backup": "Votre sauvegarde de portefeuille contient {0} mots dans un ordre spécifique.",
"backup__it_should_be_backed_up": {
"Bolt": "Sauvegardez-le dès maintenant.",
@@ -2184,12 +2186,7 @@
"Eckhart": "Saisissez chaque mot de la sauvegarde de votre portefeuille dans l'ordre."
},
"recovery__enter_share_from_diff_group": "Saisissez un fragment d'un autre groupe.",
- "recovery__group_num_template": {
- "Bolt": "Groupe {0}",
- "Caesar": "Groupe {0}",
- "Delizia": "Groupe {0}",
- "Eckhart": ""
- },
+ "recovery__group_num_template": "Groupe {0}",
"recovery__group_threshold_reached": "Seuil de groupe atteint.",
"recovery__invalid_share_entered": "Fragment de récupération saisi invalide.",
"recovery__invalid_wallet_backup_entered": "Sauvegarde de portefeuille saisie invalide.",
### core/translations/order.json
@@ -1282,5 +1282,7 @@
"1280": "stellar__spender",
"1281": "stellar__to",
"1282": "stellar__token_contract",
- "1283": "stellar__transfer_token"
+ "1283": "stellar__transfer_token",
+ "1284": "backup__info_multi_group_backup",
+ "1285": "backup__info_n_of_m_template"
}
### core/translations/pt.json
@@ -146,12 +146,14 @@
"Delizia": "Crie um backup de carteira para evitar perder acesso aos seus fundos.",
"Eckhart": "Crie um backup de carteira para evitar perder acesso aos seus fundos."
},
+ "backup__info_multi_group_backup": "O backup da sua carteira contém {0} grupos com um limite de grupo de {1}.",
"backup__info_multi_share_backup": {
"Bolt": "O backup contém listas de palavras em uma ordem específica (shares).",
"Caesar": "O backup da sua carteira contém diversas listas de palavras em uma ordem específica (shares).",
"Delizia": "O backup da sua carteira contém diversas listas de palavras em uma ordem específica (shares).",
"Eckhart": "O backup da sua carteira contém diversas listas de palavras em uma ordem específica (shares)."
},
+ "backup__info_n_of_m_template": "{0}-de-{1}",
"backup__info_single_share_backup": "O backup da sua carteira contém {0} palavras em uma ordem específica.",
"backup__it_should_be_backed_up": {
"Bolt": "Você deve fazer o backup da sua nova carteira agora.",
@@ -2049,12 +2051,7 @@
},
"recovery__enter_each_word": "Insira, em ordem, cada palavra do backup da sua carteira.",
"recovery__enter_share_from_diff_group": "Insira um share de um grupo diferente.",
- "recovery__group_num_template": {
- "Bolt": "Grupo {0}",
- "Caesar": "Grupo {0}",
- "Delizia": "Grupo {0}",
- "Eckhart": ""
- },
+ "recovery__group_num_template": "Grupo {0}",
"recovery__group_threshold_reached": "Limite mínimo do grupo atingido.",
"recovery__invalid_share_entered": "O share de recuperação inserido é inválido.",
"recovery__invalid_wallet_backup_entered": "O backup de carteira inserido é inválido.",
### core/translations/signatures.json
@@ -1,8 +1,8 @@
{
"current": {
- "merkle_root": "db7c15eb241cdf0ee77b32ccc2379168f8e93c47621dbcfa0617c57d8fae2384",
- "datetime": "2026-08-25T13:51:31.686844+00:00",
- "commit": "81915a0fd96ba810a971a4d051b7829c9a55b0b2"
+ "merkle_root": "94bf8d929cb0d24b92c87ff8f8efc00aee41fb9ef5f6482e1c908ad9605ff768",
+ "datetime": "2026-08-25T15:56:41.250312+00:00",
+ "commit": "4b96a3119828c6862308a52bf3b50c3c73d2d372"
},
"history": [
{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.