What changed, and why it matters
This commit updates the user interface and internal checks for generating wallet seed phrases using dice rolls as a source of randomness. It enforces a minimum number of dice rolls depending on the desired seed strength: at least 50 rolls for 12-word (BIP39) or 20-word (SLIP39) seeds, and at least 100 rolls for 24-word (BIP39) or 33-word (SLIP39) seeds. Previously, the firmware only required 50 rolls regardless of seed length. The change is a security hardening measure to ensure that higher-strength seeds receive enough physical entropy, but it is a partial patch because the dice-roll input itself is not fully validated and the entropy extraction method is not visible in this diff.
Review the dice-roll-to-entropy conversion function (not shown in this diff) to ensure it uses a constant-time, unbiased extraction such as SHA-256 over the full dice string, and that the resulting entropy is not truncated or reused. Consider adding input validation to reject characters outside the expected dice alphabet and to warn users about biased dice or repeated sequences. Verify that the fallback from 24/33 words to 12/20 words is clearly communicated so users do not unknowingly create a weaker seed than intended.
Security signals we found
Enforces minimum entropy input length based on target mnemonic strength
Adds server-side/model-layer validation in addition to UI gating
Prevents generation of 256-bit seeds from insufficient dice-roll entropy
Adds user-facing warnings and fallback word-count behavior
Does not validate the character set or distribution of dice-roll input
Does not show the hash/entropy reduction algorithm in the diff
Evidence from the diff
The patch adds a global cache variable g_diceRollsLen to track the number of dice-roll characters entered, along with getter/setter APIs. UI widgets for single BIP39 phrases and SLIP39 shares now check this length before allowing selection of 24-word or 33-word seed types, falling back to a shorter word count or showing a hint if fewer than 100 rolls were entered. The model layer (ModelGenerateEntropyWithDiceRolls and Slip39CreateGenerate) also adds runtime checks that fail if 24/33-word generation is requested with fewer than 100 rolls. The UI hint text is updated to distinguish 50-roll vs 100-roll requirements. No cryptographic routines are changed in this diff; the actual conversion from dice rolls to entropy is not shown.
Changed components
src/crypto/secret_cache.c/hsrc/ui/gui_model/gui_model.csrc/ui/gui_widgets/gui_create_share_widgets.csrc/ui/gui_widgets/gui_dice_rolls_widgets.csrc/ui/gui_widgets/gui_single_phrase_widgets.csrc/ui/lv_i18n/data.csvsrc/ui/lv_i18n/lv_i18n.cInspect captured patch +158 / −16
diff --git a/src/crypto/secret_cache.c b/src/crypto/secret_cache.c
index eefa506..083638a 100644
--- a/src/crypto/secret_cache.c
+++ b/src/crypto/secret_cache.c
@@ -21,6 +21,7 @@ static char *g_slip39MnemonicCache[SLIP39_MAX_MEMBER];
static uint8_t g_walletIconIndex = 0;
static char *g_walletName = NULL;
static uint8_t g_diceRollHashCache[32] = {0};
+static uint32_t g_diceRollsLen = 0;
static uint16_t g_identifier;
static uint16_t g_iteration;
static bool g_extendable;
@@ -226,6 +227,16 @@ uint8_t *SecretCacheGetDiceRollHash()
return g_diceRollHashCache;
}
+void SecretCacheSetDiceRollsLen(uint32_t len)
+{
+ g_diceRollsLen = len;
+}
+
+uint32_t SecretCacheGetDiceRollsLen(void)
+{
+ return g_diceRollsLen;
+}
+
void ClearSecretCache(void)
{
uint32_t len;
@@ -293,4 +304,5 @@ void ClearSecretCache(void)
memset_s(g_checksumCache, 32, 0, 32);
memset_s(g_diceRollHashCache, 32, 0, 32);
+ g_diceRollsLen = 0;
}
diff --git a/src/crypto/secret_cache.h b/src/crypto/secret_cache.h
index e8d2469..5dd6227 100644
--- a/src/crypto/secret_cache.h
+++ b/src/crypto/secret_cache.h
@@ -41,6 +41,8 @@ void SecretCacheSetEms(uint8_t *ems, uint32_t len);
void SecretCacheSetDiceRollHash(uint8_t *hash);
uint8_t *SecretCacheGetDiceRollHash();
+void SecretCacheSetDiceRollsLen(uint32_t len);
+uint32_t SecretCacheGetDiceRollsLen(void);
void SecretCacheSetWalletIndex(uint8_t iconIndex);
uint8_t SecretCacheGetWalletIconIndex();
diff --git a/src/ui/gui_model/gui_model.c b/src/ui/gui_model/gui_model.c
index 14a3d01..d7f51eb 100644
--- a/src/ui/gui_model/gui_model.c
+++ b/src/ui/gui_model/gui_model.c
@@ -488,6 +488,10 @@ static int32_t ModelGenerateEntropyWithDiceRolls(const void *inData, uint32_t in
ret = ERR_GENERAL_FAIL;
break;
}
+ if (mnemonicNum == 24 && SecretCacheGetDiceRollsLen() < 100) {
+ ret = ERR_GENERAL_FAIL;
+ break;
+ }
entropyLen = (mnemonicNum == 24) ? 32 : 16;
hash = SecretCacheGetDiceRollHash();
memcpy_s(entropy, sizeof(entropy), hash, entropyLen);
@@ -812,6 +816,9 @@ static int32_t Slip39CreateGenerate(Slip39Data_t *slip39, bool isDiceRoll)
if (isDiceRoll) {
const uint8_t *dice = SecretCacheGetDiceRollHash();
if (dice == NULL) goto cleanup;
+ if (slip39->wordCnt == SLIP39_MNEMONIC_33_WORDS && SecretCacheGetDiceRollsLen() < 100) {
+ goto cleanup;
+ }
memcpy_s(entropy, sizeof(entropy), dice, entropyLen);
} else {
const char *pwd = SecretCacheGetNewPassword();
diff --git a/src/ui/gui_widgets/gui_create_share_widgets.c b/src/ui/gui_widgets/gui_create_share_widgets.c
index 356e6ec..1f8de4f 100644
--- a/src/ui/gui_widgets/gui_create_share_widgets.c
+++ b/src/ui/gui_widgets/gui_create_share_widgets.c
@@ -16,6 +16,8 @@
#include "gui_page.h"
#include "gui_setting_widgets.h"
+#define DICE_ROLLS_256_BIT_MIN_LEN 100
+
typedef enum {
CREATE_SHARE_SELECT_SLICE = 0,
CREATE_SHARE_CUSTODIAN,
@@ -78,6 +80,28 @@ static PageWidget_t *g_pageWidget;
static void SelectParseCntHandler(lv_event_t *e);
static void SelectCheckBoxHandler(lv_event_t* e);
+static bool DiceRollsNotEnoughForWordCnt(uint8_t wordCnt)
+{
+ return (g_entropyMethod & ENTROPY_TYPE_MASK) &&
+ wordCnt == SLIP39_MNEMONIC_33_WORDS &&
+ SecretCacheGetDiceRollsLen() < DICE_ROLLS_256_BIT_MIN_LEN;
+}
+
+static void ReturnToDiceRollsHandler(lv_event_t *e)
+{
+ GUI_DEL_OBJ(g_noticeWindow)
+ GuiCloseCurrentWorkingView();
+}
+
+static void ShowDiceRollsNotEnoughHint(void)
+{
+ GUI_DEL_OBJ(g_noticeWindow)
+ g_noticeWindow = GuiCreateConfirmHintBox(&imgWarn, _("dice_roll_100_required_title"),
+ _("dice_roll_100_required_desc"), NULL, _("OK"), ORANGE_COLOR);
+ lv_obj_t *btn = GuiGetHintBoxRightBtn(g_noticeWindow);
+ lv_obj_add_event_cb(btn, ReturnToDiceRollsHandler, LV_EVENT_CLICKED, NULL);
+}
+
static void ShareUpdateTileHandler(lv_event_t *e)
{
lv_obj_t *obj = lv_event_get_target(e);
@@ -386,6 +410,9 @@ static void GuiShareConfirmWidget(lv_obj_t *parent)
void GuiCreateShareInit(uint8_t entropyMethod)
{
g_entropyMethod = entropyMethod;
+ if (DiceRollsNotEnoughForWordCnt(g_selectCnt)) {
+ g_selectCnt = SLIP39_MNEMONIC_20_WORDS;
+ }
g_pageWidget = CreatePageWidget();
lv_obj_t *cont = g_pageWidget->contentZone;
lv_obj_t *tileView = GuiCreateTileView(cont);
@@ -647,6 +674,10 @@ static void SelectCheckBoxHandler(lv_event_t* e)
}
}
} else if (!strcmp(currText, _("wallet_phrase_33words"))) {
+ if (DiceRollsNotEnoughForWordCnt(SLIP39_MNEMONIC_33_WORDS)) {
+ ShowDiceRollsNotEnoughHint();
+ return;
+ }
SetRightBtnLabel(g_pageWidget->navBarWidget, NVS_BAR_WORD_SELECT, "33");
if (g_selectCnt != 33) {
g_selectCnt = 33;
diff --git a/src/ui/gui_widgets/gui_dice_rolls_widgets.c b/src/ui/gui_widgets/gui_dice_rolls_widgets.c
index f4c5796..4580cb1 100644
--- a/src/ui/gui_widgets/gui_dice_rolls_widgets.c
+++ b/src/ui/gui_widgets/gui_dice_rolls_widgets.c
@@ -8,6 +8,8 @@
#include "log_print.h"
#include "assert.h"
+#define DICE_ROLLS_128_BIT_MIN_LEN 50
+#define DICE_ROLLS_256_BIT_MIN_LEN 100
#define DICE_ROLLS_MAX_LEN 256
static void GuiCreatePage(lv_obj_t *parent);
@@ -18,6 +20,8 @@ static void OnTextareaValueChangeHandler(lv_event_t *e);
static void QuitConfirmHandler(lv_event_t *e);
static void UndoClickHandler(lv_event_t *e);
static void ConfirmHandler(lv_event_t *e);
+static const char *GetDiceRollHintText(uint32_t length);
+static void UpdateDiceRollHint(uint32_t length);
static PageWidget_t *g_page;
static uint8_t g_seedType;
@@ -142,7 +146,7 @@ static void GuiCreatePage(lv_obj_t *parent)
lv_obj_align(label, LV_ALIGN_BOTTOM_LEFT, 36, -54);
g_rollsLabel = label;
- label = GuiCreateIllustrateLabel(parent, _("dice_roll_hint_label"));
+ label = GuiCreateIllustrateLabel(parent, GetDiceRollHintText(0));
lv_obj_set_style_text_color(label, WHITE_COLOR, LV_PART_MAIN);
lv_obj_align(label, LV_ALIGN_BOTTOM_LEFT, 36, -24);
lv_obj_add_flag(label, LV_OBJ_FLAG_HIDDEN);
@@ -204,11 +208,7 @@ static void OnTextareaValueChangeHandler(lv_event_t *e)
uint32_t length = strnlen_s(txt, DICE_ROLLS_MAX_LEN);
uint32_t lineCount = length / 27 + 1;
- if (length > 0 && length < 50) {
- lv_obj_clear_flag(g_hintLabel, LV_OBJ_FLAG_HIDDEN);
- } else {
- lv_obj_add_flag(g_hintLabel, LV_OBJ_FLAG_HIDDEN);
- }
+ UpdateDiceRollHint(length);
if (length < DICE_ROLLS_MAX_LEN) {
if (!lv_obj_has_flag(g_maxLimitLabel, LV_OBJ_FLAG_HIDDEN)) {
@@ -237,7 +237,7 @@ static void OnTextareaValueChangeHandler(lv_event_t *e)
}
lv_label_set_text_fmt(g_rollsLabel, "%d", length);
- if (length >= 50) {
+ if (length >= DICE_ROLLS_128_BIT_MIN_LEN) {
if (!g_confirmValid) {
g_confirmValid = true;
lv_obj_remove_style(g_confirmBtn, &g_numBtnmDisabledStyle, LV_PART_MAIN);
@@ -289,6 +289,27 @@ static void OnTextareaValueChangeHandler(lv_event_t *e)
}
}
+static const char *GetDiceRollHintText(uint32_t length)
+{
+ bool is128BitTarget = length < DICE_ROLLS_128_BIT_MIN_LEN;
+
+ if (g_seedType == SEED_TYPE_BIP39) {
+ return is128BitTarget ? _("dice_roll_hint_label") : _("dice_roll_hint_24_label");
+ }
+ return is128BitTarget ? _("dice_roll_hint_slip39_20_label") : _("dice_roll_hint_slip39_33_label");
+}
+
+static void UpdateDiceRollHint(uint32_t length)
+{
+ if (length == 0 || length >= DICE_ROLLS_256_BIT_MIN_LEN) {
+ lv_obj_add_flag(g_hintLabel, LV_OBJ_FLAG_HIDDEN);
+ return;
+ }
+
+ lv_label_set_text(g_hintLabel, GetDiceRollHintText(length));
+ lv_obj_clear_flag(g_hintLabel, LV_OBJ_FLAG_HIDDEN);
+}
+
static void UndoClickHandler(lv_event_t *e)
{
lv_obj_t *ta = (lv_obj_t *)lv_event_get_user_data(e);
@@ -320,10 +341,11 @@ static void ConfirmHandler(lv_event_t *e)
SRAM_FREE(temp);
uint8_t entropyMethod = ENTROPY_TYPE_DICE_ROLLS;
SecretCacheSetDiceRollHash(hash);
+ SecretCacheSetDiceRollsLen(rollsLen);
CLEAR_ARRAY(hash);
if (g_seedType == SEED_TYPE_BIP39) {
GuiFrameOpenViewWithParam(&g_singlePhraseView, &entropyMethod, sizeof(entropyMethod));
} else {
GuiFrameOpenViewWithParam(&g_createShareView, &entropyMethod, sizeof(entropyMethod));
}
-}
\ No newline at end of file
+}
diff --git a/src/ui/gui_widgets/gui_single_phrase_widgets.c b/src/ui/gui_widgets/gui_single_phrase_widgets.c
index afaf3f5..3bc8489 100644
--- a/src/ui/gui_widgets/gui_single_phrase_widgets.c
+++ b/src/ui/gui_widgets/gui_single_phrase_widgets.c
@@ -20,6 +20,7 @@
#include "gui_setting_widgets.h"
#define SINGLE_PHRASE_MAX_WORDS 24
+#define DICE_ROLLS_256_BIT_MIN_LEN 100
typedef enum {
SINGLE_PHRASE_RANDOM_PHRASE = 0,
SINGLE_PHRASE_CONFIRM_PHRASE,
@@ -60,6 +61,26 @@ static bool g_isDiceRolls = false;
static void ResetConfirmInput(void);
static void SelectPhraseCntHandler(lv_event_t *e);
+static bool DiceRollsNotEnoughForWordCnt(uint8_t wordCnt)
+{
+ return g_isDiceRolls && wordCnt == 24 && SecretCacheGetDiceRollsLen() < DICE_ROLLS_256_BIT_MIN_LEN;
+}
+
+static void ReturnToDiceRollsHandler(lv_event_t *e)
+{
+ GUI_DEL_OBJ(g_noticeHintBox)
+ GuiCloseCurrentWorkingView();
+}
+
+static void ShowDiceRollsNotEnoughHint(void)
+{
+ GUI_DEL_OBJ(g_noticeHintBox)
+ g_noticeHintBox = GuiCreateConfirmHintBox(&imgWarn, _("dice_roll_100_required_title"),
+ _("dice_roll_100_required_desc"), NULL, _("OK"), ORANGE_COLOR);
+ lv_obj_t *btn = GuiGetHintBoxRightBtn(g_noticeHintBox);
+ lv_obj_add_event_cb(btn, ReturnToDiceRollsHandler, LV_EVENT_CLICKED, NULL);
+}
+
static void UpdatePhraseHandler(lv_event_t *e)
{
GuiModelBip39UpdateMnemonic(g_phraseCnt);
@@ -217,6 +238,9 @@ void GuiSinglePhraseInit(uint8_t entropyMethod)
{
g_entropyMethod = entropyMethod;
g_isDiceRolls = g_entropyMethod & ENTROPY_TYPE_MASK;
+ if (DiceRollsNotEnoughForWordCnt(g_phraseCnt)) {
+ g_phraseCnt = 12;
+ }
CLEAR_OBJECT(g_singlePhraseTileView);
g_pageWidget = CreatePageWidget();
lv_obj_t *cont = g_pageWidget->contentZone;
@@ -282,6 +306,10 @@ static void SelectCheckBoxHandler(lv_event_t* e)
}
}
} else if (!strcmp(currText, _("wallet_phrase_24words"))) {
+ if (DiceRollsNotEnoughForWordCnt(24)) {
+ ShowDiceRollsNotEnoughHint();
+ return;
+ }
SetRightBtnLabel(g_pageWidget->navBarWidget, NVS_BAR_WORD_SELECT, "24");
SetRightBtnCb(g_pageWidget->navBarWidget, SelectPhraseCntHandler, NULL);
if (g_phraseCnt != 24) {
diff --git a/src/ui/lv_i18n/data.csv b/src/ui/lv_i18n/data.csv
index af08196..603afde 100644
--- a/src/ui/lv_i18n/data.csv
+++ b/src/ui/lv_i18n/data.csv
@@ -765,7 +765,12 @@ Change Entropy,20,change_entropy,Change Entropy,Изменение Энтроп
,20,tutorial_change_entropy_desc2,"Computers aren't great at being truly random. Dice rolls provide a physical, unpredictable source of randomness. By using them, you enhance the security of cryptographic processes, making it harder for someone to predict or crack your codes.","Резервная копия Шамира обеспечивает высокобезопасный способ восстановления исходной фразы. Она включает в себя разделение сид фразы на несколько частей и указание необходимого их количества, необходимых для восстановления фразы.",컴퓨터는 진정한 무작위성을 제공할 수 없습니다.주사위는 더 예측 불가능한 무작위성을 제공합니다.주사위를 사용함으로써 암호화 과정의 보안을 강화하여 코드를 예측하거나 깨기 어렵게 만들 수 있습니다.,"计算机并不是真正随机的.骰子数是不可预测的随机性来源.通过使用它们,您可以增强加密过程的安全性,从而使某人更难预测或破解您的代码.","Las computadoras no son excelentes para ser verdaderamente aleatorias. Los lanzamientos de dados proporcionan una fuente física e impredecible de aleatoriedad. Al usarlos, se aumenta la seguridad de los procesos criptográficos, lo que dificulta que alguien pueda predecir o descifrar tus códigos.","Computer sind nicht gut darin, wirklich zufällig zu sein. Würfelwürfe bieten eine physische, unpredictable Quelle der Zufälligkeit. Indem du sie verwendest, erhöhst du die Sicherheit von kryptographischen Prozessen und erschwerst es jemandem, deine Codes vorherzusagen oder zu knacken.",コンピュータは真にランダムな挙動が得意ではありません.サイコロの目は物理的で予測不可能なランダムな要素を提供します.それらを使用することで、あなたの暗号プロセスのセキュリティを強化し、他の人があなたのコードを予測したり解読したりするのをより困難にします.
,28,dice_roll_cancel_title,Cancel Dice Rolls Generation?,Отменить создание через кубики?,주사위 던지기를 취소하시겠습니까?,取消掷骰?,¿Cancelar la generación de tiradas de dados?,Würfelerzeugung abbrechen?,ダイスの出目生成をキャンセルしますか?
,20,dice_roll_cancel_desc,"If you cancel, any numbers you entered will be lost.","Если вы отмените, то все введенные вами номера будут потеряны.",취소하시면 입력하신 문자가 분실됩니다.,"如果取消,输入的任何数字将丢失.","Si cancelas, cualquier número que hayas ingresado se perderá.","Wenn Sie stornieren, gehen alle von Ihnen eingegebenen Nummern verloren.",キャンセルすると、入力した数値は失われます.
-,20,dice_roll_hint_label,At least 50 times,Не менее 50 бросков,최소 50회,至少50次,Al menos 50 veces,Mindestens 50 Mal,最低50回
+,20,dice_roll_hint_label,12-word: at least 50 rolls,12 слов: не менее 50 бросков,12단어: 최소 50회,12词:至少50次,12 palabras: al menos 50 tiradas,12 Wörter: mindestens 50 Würfe,12語:最低50回
+,20,dice_roll_hint_24_label,24-word: at least 100 rolls,24 слова: не менее 100 бросков,24단어: 최소 100회,24词:至少100次,24 palabras: al menos 100 tiradas,24 Wörter: mindestens 100 Würfe,24語:最低100回
+,20,dice_roll_hint_slip39_20_label,20-word: at least 50 rolls,20 слов: не менее 50 бросков,20단어: 최소 50회,20词:至少50次,20 palabras: al menos 50 tiradas,20 Wörter: mindestens 50 Würfe,20語:最低50回
+,20,dice_roll_hint_slip39_33_label,33-word: at least 100 rolls,33 слова: не менее 100 бросков,33단어: 최소 100회,33词:至少100次,33 palabras: al menos 100 tiradas,33 Wörter: mindestens 100 Würfe,33語:最低100回
+,20,dice_roll_100_required_title,More Dice Rolls Required,Требуется больше бросков кубиков,주사위 굴리기가 더 필요합니다,需要更多次掷骰,Se necesitan más tiradas de dados,Mehr Würfelwürfe erforderlich,さらにダイスロールが必要です
+,20,dice_roll_100_required_desc,24-word and 33-word seed phrases require at least 100 dice rolls. Please continue rolling dice.,Для сид-фраз из 24 и 33 слов требуется не менее 100 бросков кубиков. Продолжайте бросать кубики.,24단어 및 33단어 시드 구문에는 최소 100회의 주사위 굴리기가 필요합니다. 계속 주사위를 굴려 주세요.,24词和33词助记词需要至少掷100次骰子.请继续掷骰.,"Las frases semilla de 24 y 33 palabras requieren al menos 100 tiradas de dados. Sigue tirando los dados.","Seed-Phrasen mit 24 und 33 Wörtern erfordern mindestens 100 Würfelwürfe. Bitte würfle weiter.",24語および33語のシードフレーズには最低100回のダイスロールが必要です.続けてダイスを振ってください.
,20,dice_rolls_entropy_hint,Dice rolls as entropy,Кубики выпадают прозвольным образом,주사위를 엔트로피로 사용,骰子作为熵,Los lanzamientos de dados como entropía,Würfelrollen als Entropie,ダイスがエントロピーとして転がる.
,20,dice_roll_max_limit_label,You've reached the max limits,Вы исчерпали лимит,최대 제한에 도달했습니다,您达到了最大限制,Has alcanzado los límites máximos,Du hast die maximalen Grenzen erreicht.,最大限度に到達しました.
,20,dice_roll_error_label,Lack of randomness,Недостаточная случайности,무작위성 부족,缺乏随机性,Falta de aleatoriedad,Fehlende Zufälligkeit,ランダム性の欠如
diff --git a/src/ui/lv_i18n/lv_i18n.c b/src/ui/lv_i18n/lv_i18n.c
index f660eee..a3442d6 100644
--- a/src/ui/lv_i18n/lv_i18n.c
+++ b/src/ui/lv_i18n/lv_i18n.c
@@ -366,7 +366,12 @@ const static lv_i18n_phrase_t en_singulars[] = {
{"dice_roll_cancel_desc", "If you cancel, any numbers you entered will be lost."},
{"dice_roll_cancel_title", "Cancel Dice Rolls Generation?"},
{"dice_roll_error_label", "Lack of randomness"},
- {"dice_roll_hint_label", "At least 50 times"},
+ {"dice_roll_100_required_desc", "24-word and 33-word seed phrases require at least 100 dice rolls. Please continue rolling dice."},
+ {"dice_roll_100_required_title", "More Dice Rolls Required"},
+ {"dice_roll_hint_label", "12-word: at least 50 rolls"},
+ {"dice_roll_hint_24_label", "24-word: at least 100 rolls"},
+ {"dice_roll_hint_slip39_20_label", "20-word: at least 50 rolls"},
+ {"dice_roll_hint_slip39_33_label", "33-word: at least 100 rolls"},
{"dice_roll_max_limit_label", "You've reached the max limits"},
{"dice_rolls_entropy_hint", "Dice rolls as entropy"},
{"disable_passphrase", "Disable Passphrase"},
@@ -1320,7 +1325,12 @@ const static lv_i18n_phrase_t de_singulars[] = {
{"dice_roll_cancel_desc", "Wenn Sie stornieren, gehen alle von Ihnen eingegebenen Nummern verloren."},
{"dice_roll_cancel_title", "Würfelerzeugung abbrechen?"},
{"dice_roll_error_label", "Fehlende Zufälligkeit"},
- {"dice_roll_hint_label", "Mindestens 50 Mal"},
+ {"dice_roll_100_required_desc", "Seed-Phrasen mit 24 und 33 Wörtern erfordern mindestens 100 Würfelwürfe. Bitte würfle weiter."},
+ {"dice_roll_100_required_title", "Mehr Würfelwürfe erforderlich"},
+ {"dice_roll_hint_label", "12 Wörter: mindestens 50 Würfe"},
+ {"dice_roll_hint_24_label", "24 Wörter: mindestens 100 Würfe"},
+ {"dice_roll_hint_slip39_20_label", "20 Wörter: mindestens 50 Würfe"},
+ {"dice_roll_hint_slip39_33_label", "33 Wörter: mindestens 100 Würfe"},
{"dice_roll_max_limit_label", "Du hast die maximalen Grenzen erreicht."},
{"dice_rolls_entropy_hint", "Würfelrollen als Entropie"},
{"disable_passphrase", "Passphrase deaktivieren"},
@@ -2274,7 +2284,12 @@ const static lv_i18n_phrase_t es_singulars[] = {
{"dice_roll_cancel_desc", "Si cancelas, cualquier número que hayas ingresado se perderá."},
{"dice_roll_cancel_title", "¿Cancelar la generación de tiradas de dados?"},
{"dice_roll_error_label", "Falta de aleatoriedad"},
- {"dice_roll_hint_label", "Al menos 50 veces"},
+ {"dice_roll_100_required_desc", "Las frases semilla de 24 y 33 palabras requieren al menos 100 tiradas de dados. Sigue tirando los dados."},
+ {"dice_roll_100_required_title", "Se necesitan más tiradas de dados"},
+ {"dice_roll_hint_label", "12 palabras: al menos 50 tiradas"},
+ {"dice_roll_hint_24_label", "24 palabras: al menos 100 tiradas"},
+ {"dice_roll_hint_slip39_20_label", "20 palabras: al menos 50 tiradas"},
+ {"dice_roll_hint_slip39_33_label", "33 palabras: al menos 100 tiradas"},
{"dice_roll_max_limit_label", "Has alcanzado los límites máximos"},
{"dice_rolls_entropy_hint", "Los lanzamientos de dados como entropía"},
{"disable_passphrase", "Deshabilitar frase de contraseña"},
@@ -3225,7 +3240,12 @@ const static lv_i18n_phrase_t ja_singulars[] = {
{"dice_roll_cancel_desc", "キャンセルすると、入力した数値は失われます."},
{"dice_roll_cancel_title", "ダイスの出目生成をキャンセルしますか?"},
{"dice_roll_error_label", "ランダム性の欠如"},
- {"dice_roll_hint_label", "最低50回"},
+ {"dice_roll_100_required_desc", "24語および33語のシードフレーズには最低100回のダイスロールが必要です.続けてダイスを振ってください."},
+ {"dice_roll_100_required_title", "さらにダイスロールが必要です"},
+ {"dice_roll_hint_label", "12語:最低50回"},
+ {"dice_roll_hint_24_label", "24語:最低100回"},
+ {"dice_roll_hint_slip39_20_label", "20語:最低50回"},
+ {"dice_roll_hint_slip39_33_label", "33語:最低100回"},
{"dice_roll_max_limit_label", "最大限度に到達しました."},
{"dice_rolls_entropy_hint", "ダイスがエントロピーとして転がる."},
{"disable_passphrase", "パスフレーズを無効にする"},
@@ -4174,7 +4194,12 @@ const static lv_i18n_phrase_t ko_singulars[] = {
{"dice_roll_cancel_desc", "취소하시면 입력하신 문자가 분실됩니다."},
{"dice_roll_cancel_title", "주사위 던지기를 취소하시겠습니까?"},
{"dice_roll_error_label", "무작위성 부족"},
- {"dice_roll_hint_label", "최소 50회"},
+ {"dice_roll_100_required_desc", "24단어 및 33단어 시드 구문에는 최소 100회의 주사위 굴리기가 필요합니다. 계속 주사위를 굴려 주세요."},
+ {"dice_roll_100_required_title", "주사위 굴리기가 더 필요합니다"},
+ {"dice_roll_hint_label", "12단어: 최소 50회"},
+ {"dice_roll_hint_24_label", "24단어: 최소 100회"},
+ {"dice_roll_hint_slip39_20_label", "20단어: 최소 50회"},
+ {"dice_roll_hint_slip39_33_label", "33단어: 최소 100회"},
{"dice_roll_max_limit_label", "최대 제한에 도달했습니다"},
{"dice_rolls_entropy_hint", "주사위를 엔트로피로 사용"},
{"disable_passphrase", "패스프레이즈 비활성화"},
@@ -5123,7 +5148,12 @@ const static lv_i18n_phrase_t ru_singulars[] = {
{"dice_roll_cancel_desc", "Если вы отмените, то все введенные вами номера будут потеряны."},
{"dice_roll_cancel_title", "Отменить создание через кубики?"},
{"dice_roll_error_label", "Недостаточная случайности"},
- {"dice_roll_hint_label", "Не менее 50 бросков"},
+ {"dice_roll_100_required_desc", "Для сид-фраз из 24 и 33 слов требуется не менее 100 бросков кубиков. Продолжайте бросать кубики."},
+ {"dice_roll_100_required_title", "Требуется больше бросков кубиков"},
+ {"dice_roll_hint_label", "12 слов: не менее 50 бросков"},
+ {"dice_roll_hint_24_label", "24 слова: не менее 100 бросков"},
+ {"dice_roll_hint_slip39_20_label", "20 слов: не менее 50 бросков"},
+ {"dice_roll_hint_slip39_33_label", "33 слова: не менее 100 бросков"},
{"dice_roll_max_limit_label", "Вы исчерпали лимит"},
{"dice_rolls_entropy_hint", "Кубики выпадают прозвольным образом"},
{"disable_passphrase", "Отключить пароль"},
@@ -6080,7 +6110,12 @@ const static lv_i18n_phrase_t zh_cn_singulars[] = {
{"dice_roll_cancel_desc", "如果取消,输入的任何数字将丢失."},
{"dice_roll_cancel_title", "取消掷骰?"},
{"dice_roll_error_label", "缺乏随机性"},
- {"dice_roll_hint_label", "至少50次"},
+ {"dice_roll_100_required_desc", "24词和33词助记词需要至少掷100次骰子.请继续掷骰."},
+ {"dice_roll_100_required_title", "需要更多次掷骰"},
+ {"dice_roll_hint_label", "12词:至少50次"},
+ {"dice_roll_hint_24_label", "24词:至少100次"},
+ {"dice_roll_hint_slip39_20_label", "20词:至少50次"},
+ {"dice_roll_hint_slip39_33_label", "33词:至少100次"},
{"dice_roll_max_limit_label", "您达到了最大限制"},
{"dice_rolls_entropy_hint", "骰子作为熵"},
{"disable_passphrase", "禁用密码短语"},
Why this scored 35/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.