ui/trinary_input_string: merge autocomplete to optimize speed
What changed, and why it matters
This commit is a routine code cleanup in the on-screen keyboard used to type BIP39 wallet recovery words. It merges two functions that both scanned the BIP39 wordlist into one loop, aiming to make typing feel faster. There is no indication in the commit or supplied references that this fixes a security bug.
No security action required. Treat as a normal performance/refactoring commit.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The change refactors trinary_input_string.c by folding _maybe_autocomplete() into _set_alphabet(). Previously, after each letter was chosen, the code ran one full pass over the BIP39 wordlist to find a unique prefix match, then a second pass in _set_alphabet() to restrict the available character set. The merged version tracks the unique-prefix candidate while building the restricted charset in a single pass. The behavior appears functionally equivalent: it still checks for a unique prefix, autocompletes when exactly one word matches, clears the charset after autocomplete, and zeroizes the temporary word buffer. No security-relevant logic was added or removed.
Changed components
src/ui/components/trinary_input_string.cInspect captured patch +39 / −44
diff --git a/src/ui/components/trinary_input_string.c b/src/ui/components/trinary_input_string.c
index 2c3a9ba..9ab0353 100644
--- a/src/ui/components/trinary_input_string.c
+++ b/src/ui/components/trinary_input_string.c
@@ -247,47 +247,19 @@ static void _render(component_t* component)
}
}
-// if the current input uniquely identifies a word from the wordlist by prefix, we autocomplete the
-// word.
-static void _maybe_autocomplete(component_t* trinary_input_string)
-{
- data_t* data = (data_t*)trinary_input_string->data;
- if (data->wordlist == NULL) {
- return;
- }
- // initial value means no word was found yet.
- size_t found_word_idx = data->wordlist_size;
- for (size_t word_idx = 0; word_idx < data->wordlist_size; word_idx++) {
- char word[10];
- if (!keystore_get_bip39_word_stack(data->wordlist[word_idx], word, sizeof(word))) {
- Abort("keystore_get_bip39_word_stack");
- }
- bool is_prefix = strncmp(data->string, word, data->string_index) == 0;
- if (is_prefix) {
- if (found_word_idx != data->wordlist_size) {
- // Not unique.
- return;
- }
- found_word_idx = word_idx;
- }
-
- util_zero(word, sizeof(word));
- }
- char word[10];
- if (!keystore_get_bip39_word_stack(data->wordlist[found_word_idx], word, sizeof(word))) {
- Abort("keystore_get_bip39_word_stack");
- }
-
- data->string_index = snprintf(data->string, sizeof(data->string), "%s", word);
- util_zero(word, sizeof(word));
-}
-
-static void _set_alphabet(component_t* trinary_input_string)
+// maybe_autocomplete: if the current input uniquely identifies a word from the wordlist by prefix,
+// we autocomplete the word.
+static void _set_alphabet(component_t* trinary_input_string, bool maybe_autocomplete)
{
data_t* data = (data_t*)trinary_input_string->data;
component_t* trinary_char = data->trinary_char_component;
data->can_confirm = true;
if (data->wordlist != NULL) {
+ // Initial value means no word was found yet.
+ size_t found_word_idx = data->wordlist_size;
+ // Multiple words found with the same prefix, in which case we don't autocomplete.
+ bool found_word_not_unique = false;
+
data->can_confirm = false;
// Restrict input charset based on the available words with.
@@ -313,8 +285,32 @@ static void _set_alphabet(component_t* trinary_input_string)
charset[strlen(charset)] = include;
}
}
+
+ if (found_word_idx != data->wordlist_size) {
+ found_word_not_unique = true;
+ }
+ found_word_idx = word_idx;
+ }
+
+ util_zero(word, sizeof(word));
+ }
+
+ if (maybe_autocomplete && !found_word_not_unique && found_word_idx != data->wordlist_size) {
+ char word[10];
+ if (!keystore_get_bip39_word_stack(
+ data->wordlist[found_word_idx], word, sizeof(word))) {
+ Abort("keystore_get_bip39_word_stack");
}
+
+ data->string_index = snprintf(data->string, sizeof(data->string), "%s", word);
+ // We autocompleted, so we don't offer any more letters to choose. The charset above
+ // was determined before autocomplete and is not valid after autocomplete.
+ charset[0] = '\0';
+ data->can_confirm = true;
+
+ util_zero(word, sizeof(word));
}
+
// Since wordlist is sorted, charset is sorted automatically.
trinary_input_char_set_alphabet(trinary_char, charset, 1);
} else if (data->number_input) {
@@ -360,11 +356,11 @@ static void _on_event(const event_t* event, component_t* component)
switch (event->id) {
case EVENT_TOGGLE_ALPHANUMERIC:
- _set_alphabet(component);
+ _set_alphabet(component, false);
break;
case EVENT_BACKWARD:
if (trinary_input_char_in_progress(data->trinary_char_component)) {
- _set_alphabet(component);
+ _set_alphabet(component, false);
break;
}
if (data->string_index == 0) {
@@ -386,7 +382,7 @@ static void _on_event(const event_t* event, component_t* component)
// data->target_x += MIN(SCREEN_WIDTH - SCROLL_RIGHT_LIMIT, string_width);
}
}
- _set_alphabet(component);
+ _set_alphabet(component, false);
break;
default:
break;
@@ -409,15 +405,14 @@ static void _letter_chosen(component_t* trinary_char, char chosen)
bool confirm_gesture_active =
data->longtouch && confirm_gesture_is_active(data->confirm_component);
if (confirm_gesture_active) {
- _set_alphabet(trinary_input_string);
+ _set_alphabet(trinary_input_string, false);
return;
}
data->string[data->string_index] = chosen;
data->string_index++;
data->string[data->string_index] = '\0';
data->show_last_character = true;
- _maybe_autocomplete(trinary_input_string);
- _set_alphabet(trinary_input_string);
+ _set_alphabet(trinary_input_string, true);
UG_S16 string_width = _constant_string_width(trinary_input_string);
if (data->target_x + string_width > SCROLL_RIGHT_LIMIT) {
data->target_x = -string_width + SCROLL_LEFT_PAD;
@@ -505,7 +500,7 @@ component_t* trinary_input_string_create(
data->trinary_char_component = trinary_input_char_create(_letter_chosen, component);
ui_util_add_sub_component(component, data->trinary_char_component);
- _set_alphabet(component);
+ _set_alphabet(component, false);
return component;
}
@@ -524,7 +519,7 @@ void trinary_input_string_set_input(component_t* trinary_input_string, const cha
if (STREQ(bip39_word, word)) {
data->string_index = snprintf(data->string, sizeof(data->string), "%s", word);
- _set_alphabet(trinary_input_string);
+ _set_alphabet(trinary_input_string, false);
return;
}
}
Why this scored 12/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.