mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-12 18:49:07 +00:00
New Matrix-based recovery
This commit is contained in:
parent
14aa486fa6
commit
acfdb714ff
@ -974,7 +974,8 @@ void fsm_msgRecoveryDevice(RecoveryDevice *msg)
|
||||
msg->has_pin_protection && msg->pin_protection,
|
||||
msg->has_language ? msg->language : 0,
|
||||
msg->has_label ? msg->label : 0,
|
||||
msg->has_enforce_wordlist ? msg->enforce_wordlist : false,
|
||||
msg->has_enforce_wordlist && msg->enforce_wordlist,
|
||||
msg->has_type ? msg->type : 0,
|
||||
msg->has_u2f_counter ? msg->u2f_counter : 0
|
||||
);
|
||||
}
|
||||
|
112
firmware/recovery-table.h
Normal file
112
firmware/recovery-table.h
Normal file
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* This file is part of the TREZOR project.
|
||||
*
|
||||
* Copyright (C) 2016 Jochen Hoenicke <hoenicke@gmail.com>
|
||||
*
|
||||
* This library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* DO NOT EDIT: This file is automatically generated by
|
||||
* cd ../gen/wordlist
|
||||
* perl build-recoverytable.pl recovery_english.txt
|
||||
*/
|
||||
|
||||
static const uint16_t word_table1[82] =
|
||||
{
|
||||
8192, 8200, 8208, 8217, 8225, 8234, 8243, 8250, 8259,
|
||||
12361, 12367, 8280, 8285, 8292, 8297, 8302, 8311, 8318,
|
||||
8325, 12429, 12437, 8347, 8356, 8365, 8373, 8382, 8391,
|
||||
8400, 8409, 8412, 8417, 8426, 8432, 8439, 8447, 8455,
|
||||
8463, 8472, 8480, 8487, 8495, 4408, 4416, 8521, 8530,
|
||||
8539, 8548, 8557, 8564, 8573, 8582, 8589, 8597, 8601,
|
||||
8609, 8618, 8627, 8634, 4545, 8645, 12750, 12759, 8672,
|
||||
8681, 8690, 8695, 8703, 8712, 8721, 8730, 8738, 8746,
|
||||
8751, 8757, 8766, 8775, 8782, 4690, 4699, 8804, 8813,
|
||||
630,
|
||||
};
|
||||
|
||||
static const uint16_t word_table2[631] =
|
||||
{
|
||||
12288, 12293, 12297, 12298, 12302, 12304, 12306, 12307, 12312,
|
||||
12313, 12316, 8225, 8226, 8229, 8233, 8234, 12334, 12337,
|
||||
12342, 12345, 8253, 12354, 12357, 12361, 12365, 8274, 12376,
|
||||
12378, 12380, 12381, 12385, 12386, 12390, 12394, 12396, 12400,
|
||||
8305, 12407, 12410, 8318, 8321, 8327, 12424, 12428, 12433,
|
||||
12439, 12443, 12448, 12451, 12456, 12459, 12463, 12465, 12468,
|
||||
12471, 12476, 12479, 12482, 12485, 12489, 12494, 12498, 12502,
|
||||
12507, 12509, 12515, 12521, 12522, 12527, 12530, 12532, 12535,
|
||||
12538, 12541, 12544, 12545, 12546, 12547, 12549, 16647, 16651,
|
||||
12559, 16658, 16662, 12569, 12574, 12579, 12582, 12583, 12584,
|
||||
12585, 12586, 12588, 16686, 16689, 12599, 12605, 12609, 12611,
|
||||
12612, 12615, 12616, 12617, 12618, 12620, 12621, 12626, 12629,
|
||||
12635, 12641, 12645, 12650, 12655, 16757, 16761, 12669, 12673,
|
||||
12679, 12684, 16782, 16786, 12695, 12699, 12703, 12707, 12713,
|
||||
12715, 12716, 12717, 12719, 12723, 12725, 8630, 12727, 12728,
|
||||
12730, 12732, 12733, 12734, 12735, 12736, 12737, 12738, 12740,
|
||||
12746, 12747, 12750, 12751, 12753, 12755, 12758, 12763, 12764,
|
||||
12770, 12772, 12775, 12779, 12782, 12786, 12788, 16886, 16891,
|
||||
12798, 12801, 12802, 12804, 12805, 12807, 12808, 12811, 12812,
|
||||
12813, 12814, 12815, 12820, 12822, 12827, 12830, 12832, 8741,
|
||||
8742, 12839, 12841, 8751, 8757, 12857, 12859, 12864, 12866,
|
||||
12870, 12874, 12876, 12879, 12884, 12887, 12891, 8799, 8802,
|
||||
8808, 8812, 8814, 12914, 12916, 12921, 12925, 12929, 12935,
|
||||
8841, 12939, 12942, 12943, 12945, 12947, 12950, 12953, 12955,
|
||||
12959, 12961, 12964, 12967, 12973, 12977, 12980, 12985, 12988,
|
||||
12993, 12998, 13001, 13005, 13008, 13012, 17112, 17116, 13023,
|
||||
13027, 13029, 13031, 13033, 13038, 8943, 13045, 13047, 13049,
|
||||
13051, 13056, 13058, 13060, 8966, 8972, 13069, 13070, 13071,
|
||||
13072, 13073, 13075, 13076, 13080, 13082, 13087, 13088, 13090,
|
||||
13093, 13096, 17194, 17197, 13105, 13107, 13110, 13113, 9018,
|
||||
9024, 13121, 13123, 13126, 13128, 13132, 13136, 13140, 13142,
|
||||
13145, 13147, 13149, 13151, 13154, 13156, 13160, 13164, 13167,
|
||||
13172, 13173, 13174, 13177, 13180, 13183, 9088, 9089, 9091,
|
||||
9094, 9095, 13194, 13195, 13196, 13198, 13202, 13206, 13210,
|
||||
13213, 13216, 13219, 13223, 13228, 9138, 9144, 9148, 9152,
|
||||
13253, 13254, 13255, 13256, 13259, 9164, 9165, 13265, 13266,
|
||||
13268, 13270, 13271, 13275, 9180, 13280, 13285, 13288, 13292,
|
||||
13295, 13300, 13304, 13309, 13314, 13318, 13322, 13326, 13330,
|
||||
13335, 13340, 13344, 9253, 9259, 13356, 13360, 13363, 13366,
|
||||
13372, 13373, 13379, 13382, 13387, 13389, 13393, 13394, 13396,
|
||||
13398, 13400, 13402, 13406, 13408, 13410, 13412, 13414, 13415,
|
||||
13419, 13421, 13424, 13427, 13432, 13436, 13440, 13444, 13448,
|
||||
13452, 13457, 9362, 13461, 13463, 13465, 13468, 13470, 13473,
|
||||
13475, 13477, 13480, 9387, 13485, 13489, 13491, 13492, 13496,
|
||||
9402, 9406, 13503, 13506, 9414, 9417, 9418, 9422, 9423,
|
||||
9424, 9427, 9428, 9433, 13534, 13540, 9447, 9448, 9449,
|
||||
9453, 9456, 9458, 13557, 13563, 13568, 13574, 13579, 13582,
|
||||
13586, 13591, 9500, 13600, 13604, 13609, 13614, 13619, 13624,
|
||||
13627, 13632, 13638, 13643, 13645, 17747, 17750, 17755, 17759,
|
||||
17764, 13672, 13674, 13677, 13679, 13681, 13685, 9592, 13689,
|
||||
13692, 13693, 13696, 13697, 13698, 13701, 13703, 13706, 13708,
|
||||
13711, 13713, 13715, 13718, 13721, 13723, 13728, 13729, 13732,
|
||||
13735, 13736, 13740, 13744, 13747, 13748, 13752, 13753, 13759,
|
||||
13762, 13763, 13765, 9670, 13767, 13773, 13778, 13783, 13788,
|
||||
13793, 13798, 13801, 13805, 13810, 13815, 13818, 13822, 13824,
|
||||
13828, 13831, 13835, 13839, 13843, 13847, 13853, 13856, 13862,
|
||||
13866, 13869, 17970, 17972, 13881, 13883, 13884, 13885, 13889,
|
||||
13895, 13899, 13904, 13906, 13911, 13915, 13919, 9827, 9832,
|
||||
13933, 13934, 13937, 13939, 13944, 13947, 13949, 13954, 13958,
|
||||
13963, 13964, 13969, 13970, 13975, 13978, 9883, 18078, 18084,
|
||||
13992, 13997, 14000, 14006, 14011, 14014, 14015, 14018, 14020,
|
||||
14024, 14026, 14029, 14032, 14038, 14040, 14044, 14046, 14050,
|
||||
9955, 14055, 14059, 14064, 14068, 14071, 14075, 14078, 14080,
|
||||
14085, 14088, 14091, 14093, 14095, 14099, 14101, 14104, 14108,
|
||||
14111, 14114, 14117, 14119, 14122, 14125, 14128, 18228, 18233,
|
||||
14142, 14145, 14151, 14153, 14159, 14160, 14165, 10072, 10078,
|
||||
10080, 14178, 14182, 14187, 14191, 10100, 10106, 10108, 10114,
|
||||
14211, 14217, 14223, 14228, 14234, 14239, 14245, 14250, 14253,
|
||||
14257, 14260, 14264, 14267, 14273, 14278, 14281, 14285, 14291,
|
||||
14293, 18394, 18399, 14305, 14310, 14315, 10224, 6134, 6140,
|
||||
2048,
|
||||
};
|
@ -2,6 +2,7 @@
|
||||
* This file is part of the TREZOR project.
|
||||
*
|
||||
* Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
|
||||
* Copyright (C) 2016 Jochen Hoenicke <hoenicke@gmail.com>
|
||||
*
|
||||
* This library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
@ -17,6 +18,7 @@
|
||||
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include "recovery.h"
|
||||
#include "fsm.h"
|
||||
#include "storage.h"
|
||||
@ -26,16 +28,326 @@
|
||||
#include "messages.h"
|
||||
#include "rng.h"
|
||||
#include "bip39.h"
|
||||
#include "oled.h"
|
||||
#include "usb.h"
|
||||
#include "types.pb.h"
|
||||
#include "recovery-table.h"
|
||||
|
||||
/* number of words expected in the new seed */
|
||||
static uint32_t word_count;
|
||||
static bool awaiting_word = false;
|
||||
|
||||
/* recovery mode:
|
||||
* 0: not recovering
|
||||
* 1: recover by scrambled plain text words
|
||||
* 2: recover by matrix entry
|
||||
*/
|
||||
static int awaiting_word = 0;
|
||||
|
||||
/* True if we should check that seed corresponds to bip39.
|
||||
*/
|
||||
static bool enforce_wordlist;
|
||||
|
||||
/* For scrambled recovery Trezor may ask for faked words if
|
||||
* seed is short. This contains the fake word.
|
||||
*/
|
||||
static char fake_word[12];
|
||||
|
||||
/* Word position in the seed that we are currently asking for.
|
||||
* This is 0 if we ask for a fake word. Only for scrambled recovery.
|
||||
*/
|
||||
static uint32_t word_pos;
|
||||
|
||||
/* Scrambled recovery: How many words has the user already entered.
|
||||
* Matrix recovery: How many digits has the user already entered.
|
||||
*/
|
||||
static uint32_t word_index;
|
||||
|
||||
/* Order in which we ask for the words. It holds that
|
||||
* word_order[word_index] == word_pos. Only for scrambled recovery.
|
||||
*/
|
||||
static char word_order[24];
|
||||
|
||||
/* The recovered seed. This is filled during the recovery process.
|
||||
*/
|
||||
static char words[24][12];
|
||||
|
||||
/* The "pincode" of the current word. This is basically the "pin"
|
||||
* that the user would have entered for the current word if the words
|
||||
* were displayed in alphabetical order. Note that it is base 9, not
|
||||
* base 10. Only for matrix recovery.
|
||||
*/
|
||||
static uint16_t word_pincode;
|
||||
|
||||
/* The pinmatrix currently displayed on screen.
|
||||
* Only for matrix recovery.
|
||||
*/
|
||||
static uint8_t word_matrix[9];
|
||||
|
||||
#define MASK_IDX(x) ((x) & 0xfff)
|
||||
#define TABLE1(x) MASK_IDX(word_table1[x])
|
||||
#define TABLE2(x) MASK_IDX(word_table2[x])
|
||||
|
||||
/* Helper function to format a two digit number.
|
||||
* Parameter dest is buffer containing the string. It should already
|
||||
* start with "##th". The number is written in place.
|
||||
* Parameter number gives the number that we should format.
|
||||
*/
|
||||
static void format_number(char *dest, int number) {
|
||||
if (number < 10) {
|
||||
dest[0] = ' ';
|
||||
} else {
|
||||
dest[0] = '0' + number / 10;
|
||||
}
|
||||
dest[1] = '0' + number % 10;
|
||||
if (number == 1 || number == 21) {
|
||||
dest[2] = 's'; dest[3] = 't';
|
||||
} else if (number == 2 || number == 22) {
|
||||
dest[2] = 'n'; dest[3] = 'd';
|
||||
} else if (number == 3 || number == 23) {
|
||||
dest[2] = 'r'; dest[3] = 'd';
|
||||
}
|
||||
}
|
||||
|
||||
/* Send a request for a new word/matrix code to the PC.
|
||||
*/
|
||||
static void recovery_request(void) {
|
||||
WordRequest resp;
|
||||
memset(&resp, 0, sizeof(WordRequest));
|
||||
resp.has_type = true;
|
||||
resp.type = awaiting_word == 1 ? WordRequestType_WordRequestType_Plain
|
||||
: (word_index % 4 == 3) ? WordRequestType_WordRequestType_Matrix6
|
||||
: WordRequestType_WordRequestType_Matrix9;
|
||||
msg_write(MessageType_MessageType_WordRequest, &resp);
|
||||
}
|
||||
|
||||
/* Called when the last word was entered.
|
||||
* Check mnemonic and send success/failure.
|
||||
*/
|
||||
static void recovery_done(void) {
|
||||
uint32_t i;
|
||||
strlcpy(storage.mnemonic, words[0], sizeof(storage.mnemonic));
|
||||
for (i = 1; i < word_count; i++) {
|
||||
strlcat(storage.mnemonic, " ", sizeof(storage.mnemonic));
|
||||
strlcat(storage.mnemonic, words[i], sizeof(storage.mnemonic));
|
||||
}
|
||||
if (!enforce_wordlist || mnemonic_check(storage.mnemonic)) {
|
||||
storage.has_mnemonic = true;
|
||||
if (!enforce_wordlist) {
|
||||
// not enforcing => mark storage as imported
|
||||
storage.has_imported = true;
|
||||
storage.imported = true;
|
||||
}
|
||||
storage_commit();
|
||||
fsm_sendSuccess("Device recovered");
|
||||
} else {
|
||||
storage_reset();
|
||||
fsm_sendFailure(FailureType_Failure_SyntaxError, "Invalid mnemonic, are words in correct order?");
|
||||
}
|
||||
awaiting_word = 0;
|
||||
layoutHome();
|
||||
}
|
||||
|
||||
/* Helper function for matrix recovery:
|
||||
* Formats a string describing the word range from first to last where
|
||||
* prefixlen gives the number of characters in first and last that are
|
||||
* significant, i.e. the word before first or the word after last differ
|
||||
* exactly at the prefixlen-th character.
|
||||
*
|
||||
* Invariants:
|
||||
* memcmp("first - 1", first, prefixlen) != 0
|
||||
* memcmp(last, "last + 1", prefixlen) != 0
|
||||
* first[prefixlen-2] == last[prefixlen-2] except for range WI-Z.
|
||||
*/
|
||||
static void add_choice(char choice[12], int prefixlen, const char *first, const char *last) {
|
||||
// assert prefixlen < 4
|
||||
int i;
|
||||
char *dest = choice;
|
||||
for (i = 0; i < prefixlen; i++) {
|
||||
*dest++ = toupper((int) first[i]);
|
||||
}
|
||||
if (first[0] != last[0]) {
|
||||
/* special case WI-Z; also used for T-Z, etc. */
|
||||
*dest++ = '-';
|
||||
*dest++ = toupper((int) last[0]);
|
||||
} else if (last[prefixlen-1] == first[prefixlen-1]) {
|
||||
/* single prefix */
|
||||
} else if (prefixlen < 3) {
|
||||
/* AB-AC, etc. */
|
||||
*dest++ = '-';
|
||||
for (i = 0; i < prefixlen; i++) {
|
||||
*dest++ = toupper((int) last[i]);
|
||||
}
|
||||
} else {
|
||||
/* RE[A-M] etc. */
|
||||
/* remove last and replace with space */
|
||||
dest[-1] = ' ';
|
||||
if (first[prefixlen - 1]) {
|
||||
/* handle special case: CAN[-D] */
|
||||
*dest++ = toupper((int)first[prefixlen - 1]);
|
||||
}
|
||||
*dest++ = '-';
|
||||
*dest++ = toupper((int) last[prefixlen - 1]);
|
||||
}
|
||||
*dest++ = 0;
|
||||
}
|
||||
|
||||
/* Helper function for matrix recovery:
|
||||
* Display the recovery matrix given in choices. If twoColumn is set
|
||||
* use 2x3 layout, otherwise 3x3 layout. Also generates a random
|
||||
* scrambling and stores it in word_matrix.
|
||||
*/
|
||||
static void display_choices(bool twoColumn, char choices[9][12], int num)
|
||||
{
|
||||
int i;
|
||||
int nColumns = twoColumn ? 2 : 3;
|
||||
int displayedChoices = nColumns * 3;
|
||||
int row, col;
|
||||
for (i = 0; i < displayedChoices; i++) {
|
||||
word_matrix[i] = i;
|
||||
}
|
||||
/* scramble matrix */
|
||||
random_permute((char*)word_matrix, displayedChoices);
|
||||
|
||||
if (word_index % 4 == 0) {
|
||||
char desc[] = "##th word";
|
||||
int nr = (word_index / 4) + 1;
|
||||
format_number(desc, nr);
|
||||
layoutDialogSwipe(&bmp_icon_info, NULL, NULL, NULL, "Please enter the", (nr < 10 ? desc + 1 : desc), "of your mnemonic", NULL, NULL, NULL);
|
||||
} else {
|
||||
oledBox(0, 18, 127, 63, false);
|
||||
}
|
||||
|
||||
for (row = 0; row < 3; row ++) {
|
||||
int y = 55 - row * 11;
|
||||
for (col = 0; col < nColumns; col++) {
|
||||
int x = twoColumn ? 64 * col + 32 : 42 * col + 22;
|
||||
int choice = word_matrix[nColumns*row + col];
|
||||
const char *text = choice < num ? choices[choice] : "-";
|
||||
oledDrawString(x - oledStringWidth(text)/2, y, text);
|
||||
}
|
||||
}
|
||||
oledRefresh();
|
||||
|
||||
/* avoid picking out of range numbers */
|
||||
for (i = 0; i < displayedChoices; i++) {
|
||||
if (word_matrix[i] > num)
|
||||
word_matrix[i] = 0;
|
||||
}
|
||||
/* two column layout: middle column = right column */
|
||||
if (twoColumn) {
|
||||
static const uint8_t twolayout[9] = { 0, 1, 1, 2, 3, 3, 4, 5, 5 };
|
||||
for (i = 8; i >= 2; i--) {
|
||||
word_matrix[i] = word_matrix[twolayout[i]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Helper function for matrix recovery:
|
||||
* Generates a new matrix and requests the next pin.
|
||||
*/
|
||||
static void next_matrix(void) {
|
||||
const char * const *wl = mnemonic_wordlist();
|
||||
char word_choices[9][12];
|
||||
uint32_t i, idx, first, num;
|
||||
bool last = (word_index % 4) == 3;
|
||||
|
||||
switch (word_index % 4) {
|
||||
case 3:
|
||||
idx = TABLE1(word_pincode / 9) + word_pincode % 9;
|
||||
first = word_table2[idx] & 0xfff;
|
||||
num = (word_table2[idx+1] & 0xfff) - first;
|
||||
for (i = 0; i < num; i++) {
|
||||
strlcpy(word_choices[i], wl[first + i], sizeof(word_choices[i]));
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
idx = TABLE1(word_pincode);
|
||||
num = TABLE1(word_pincode + 1) - idx;
|
||||
for (i = 0; i < num; i++) {
|
||||
add_choice(word_choices[i], (word_table2[idx + i] >> 12),
|
||||
wl[TABLE2(idx + i)],
|
||||
wl[TABLE2(idx + i + 1) - 1]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
idx = word_pincode * 9;
|
||||
num = 9;
|
||||
for (i = 0; i < num; i++) {
|
||||
add_choice(word_choices[i], (word_table1[idx + i] >> 12),
|
||||
wl[TABLE2(TABLE1(idx + i))],
|
||||
wl[TABLE2(TABLE1(idx + i + 1)) - 1]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0:
|
||||
num = 9;
|
||||
for (i = 0; i < num; i++) {
|
||||
add_choice(word_choices[i], 1,
|
||||
wl[TABLE2(TABLE1(9*i))],
|
||||
wl[TABLE2(TABLE1(9*(i+1)))-1]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
display_choices(last, word_choices, num);
|
||||
|
||||
recovery_request();
|
||||
}
|
||||
|
||||
/* Function called when a digit was entered by user.
|
||||
* digit: ascii code of the entered digit ('1'-'9') or
|
||||
* '\x08' for backspace.
|
||||
*/
|
||||
static void recovery_digit(const char digit) {
|
||||
if (digit == 8) {
|
||||
/* backspace: undo */
|
||||
if ((word_index % 4) == 0) {
|
||||
/* undo complete word */
|
||||
if (word_index > 0)
|
||||
word_index -= 4;
|
||||
} else {
|
||||
word_index--;
|
||||
word_pincode /= 9;
|
||||
}
|
||||
next_matrix();
|
||||
return;
|
||||
}
|
||||
|
||||
if (digit < '1' || digit > '9') {
|
||||
recovery_request();
|
||||
return;
|
||||
}
|
||||
|
||||
int choice = word_matrix[digit - '1'];
|
||||
if ((word_index % 4) == 3) {
|
||||
/* received final word */
|
||||
int y = 54 - ((digit - '1')/3)*11;
|
||||
int x = 64 * (((digit - '1') % 3) > 0);
|
||||
oledInvert(x, y, x + 63, y + 9);
|
||||
oledRefresh();
|
||||
usbSleep(250);
|
||||
|
||||
int idx = TABLE2(TABLE1(word_pincode / 9) + (word_pincode % 9)) + choice;
|
||||
uint32_t widx = word_index / 4;
|
||||
|
||||
word_pincode = 0;
|
||||
strlcpy(words[widx], mnemonic_wordlist()[idx], sizeof(words[widx]));
|
||||
if (widx + 1 == word_count) {
|
||||
recovery_done();
|
||||
return;
|
||||
}
|
||||
/* next word */
|
||||
} else {
|
||||
word_pincode = word_pincode * 9 + choice;
|
||||
}
|
||||
word_index++;
|
||||
next_matrix();
|
||||
}
|
||||
|
||||
/* Helper function for scrambled recovery:
|
||||
* Ask the user for the next word.
|
||||
*/
|
||||
void next_word(void) {
|
||||
word_pos = word_order[word_index];
|
||||
if (word_pos == 0) {
|
||||
@ -45,29 +357,13 @@ void next_word(void) {
|
||||
} else {
|
||||
fake_word[0] = 0;
|
||||
char desc[] = "##th word";
|
||||
if (word_pos < 10) {
|
||||
desc[0] = ' ';
|
||||
} else {
|
||||
desc[0] = '0' + word_pos / 10;
|
||||
}
|
||||
desc[1] = '0' + word_pos % 10;
|
||||
if (word_pos == 1 || word_pos == 21) {
|
||||
desc[2] = 's'; desc[3] = 't';
|
||||
} else
|
||||
if (word_pos == 2 || word_pos == 22) {
|
||||
desc[2] = 'n'; desc[3] = 'd';
|
||||
} else
|
||||
if (word_pos == 3 || word_pos == 23) {
|
||||
desc[2] = 'r'; desc[3] = 'd';
|
||||
}
|
||||
format_number(desc, word_pos);
|
||||
layoutDialogSwipe(&bmp_icon_info, NULL, NULL, NULL, "Please enter the", NULL, (word_pos < 10 ? desc + 1 : desc), NULL, "of your mnemonic", NULL);
|
||||
}
|
||||
WordRequest resp;
|
||||
memset(&resp, 0, sizeof(WordRequest));
|
||||
msg_write(MessageType_MessageType_WordRequest, &resp);
|
||||
recovery_request();
|
||||
}
|
||||
|
||||
void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_protection, const char *language, const char *label, bool _enforce_wordlist, uint32_t u2f_counter)
|
||||
void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_protection, const char *language, const char *label, bool _enforce_wordlist, uint32_t type, uint32_t u2f_counter)
|
||||
{
|
||||
if (_word_count != 12 && _word_count != 18 && _word_count != 24) return;
|
||||
|
||||
@ -86,27 +382,27 @@ void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_pr
|
||||
storage_setLabel(label);
|
||||
storage_setU2FCounter(u2f_counter);
|
||||
|
||||
uint32_t i;
|
||||
for (i = 0; i < word_count; i++) {
|
||||
word_order[i] = i + 1;
|
||||
if ((type & RecoveryDeviceType_RecoveryDeviceType_Matrix) != 0) {
|
||||
awaiting_word = 2;
|
||||
word_index = 0;
|
||||
next_matrix();
|
||||
} else {
|
||||
uint32_t i;
|
||||
for (i = 0; i < word_count; i++) {
|
||||
word_order[i] = i + 1;
|
||||
}
|
||||
for (i = word_count; i < 24; i++) {
|
||||
word_order[i] = 0;
|
||||
}
|
||||
random_permute(word_order, 24);
|
||||
awaiting_word = 1;
|
||||
word_index = 0;
|
||||
next_word();
|
||||
}
|
||||
for (i = word_count; i < 24; i++) {
|
||||
word_order[i] = 0;
|
||||
}
|
||||
random_permute(word_order, 24);
|
||||
awaiting_word = true;
|
||||
word_index = 0;
|
||||
next_word();
|
||||
}
|
||||
|
||||
void recovery_word(const char *word)
|
||||
static void recovery_scrambledword(const char *word)
|
||||
{
|
||||
if (!awaiting_word) {
|
||||
fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Not in Recovery mode");
|
||||
layoutHome();
|
||||
return;
|
||||
}
|
||||
|
||||
if (word_pos == 0) { // fake word
|
||||
if (strcmp(word, fake_word) != 0) {
|
||||
storage_reset();
|
||||
@ -136,33 +432,38 @@ void recovery_word(const char *word)
|
||||
}
|
||||
|
||||
if (word_index + 1 == 24) { // last one
|
||||
uint32_t i;
|
||||
strlcpy(storage.mnemonic, words[0], sizeof(storage.mnemonic));
|
||||
for (i = 1; i < word_count; i++) {
|
||||
strlcat(storage.mnemonic, " ", sizeof(storage.mnemonic));
|
||||
strlcat(storage.mnemonic, words[i], sizeof(storage.mnemonic));
|
||||
}
|
||||
if (!enforce_wordlist || mnemonic_check(storage.mnemonic)) {
|
||||
storage.has_mnemonic = true;
|
||||
storage_commit();
|
||||
fsm_sendSuccess("Device recovered");
|
||||
} else {
|
||||
storage_reset();
|
||||
fsm_sendFailure(FailureType_Failure_SyntaxError, "Invalid mnemonic, are words in correct order?");
|
||||
}
|
||||
awaiting_word = false;
|
||||
layoutHome();
|
||||
recovery_done();
|
||||
} else {
|
||||
word_index++;
|
||||
next_word();
|
||||
}
|
||||
}
|
||||
|
||||
/* Function called when a word was entered by user. Used
|
||||
* for scrambled recovery.
|
||||
*/
|
||||
void recovery_word(const char *word)
|
||||
{
|
||||
switch (awaiting_word) {
|
||||
case 2:
|
||||
recovery_digit(word[0]);
|
||||
break;
|
||||
case 1:
|
||||
recovery_scrambledword(word);
|
||||
break;
|
||||
default:
|
||||
fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Not in Recovery mode");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Abort recovery.
|
||||
*/
|
||||
void recovery_abort(void)
|
||||
{
|
||||
if (awaiting_word) {
|
||||
layoutHome();
|
||||
awaiting_word = false;
|
||||
awaiting_word = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,7 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_protection, const char *language, const char *label, bool _enforce_wordlist, uint32_t u2f_counter);
|
||||
void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_protection, const char *language, const char *label, bool _enforce_wordlist, uint32_t type, uint32_t u2f_counter);
|
||||
void recovery_word(const char *word);
|
||||
void recovery_abort(void);
|
||||
const char *recovery_get_fake_word(void);
|
||||
|
110
gen/wordlist/build-recovery-table.pl
Normal file
110
gen/wordlist/build-recovery-table.pl
Normal file
@ -0,0 +1,110 @@
|
||||
#!/usr/bin/perl
|
||||
print <<'EOF';
|
||||
/*
|
||||
* This file is part of the TREZOR project.
|
||||
*
|
||||
* Copyright (C) 2016 Jochen Hoenicke <hoenicke@gmail.com>
|
||||
*
|
||||
* This library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
EOF
|
||||
|
||||
my @arr1;
|
||||
my @arr2;
|
||||
my $x = 0;
|
||||
my $l = "00";
|
||||
my @words;
|
||||
while (<>) {
|
||||
$_ =~ /([1-9]{2})[1-9] ([1-6]):(.*)/;
|
||||
my $n = $1;
|
||||
my $c = $2;
|
||||
my @nw = split(",", $3);
|
||||
die if $c != @nw;
|
||||
die if $c > 6;
|
||||
push @words, @nw;
|
||||
if ($n ne $l) {
|
||||
$len = @arr2;
|
||||
die if $len - $arr1[-1] > 9;
|
||||
push @arr1, $len;
|
||||
}
|
||||
push @arr2, $x;
|
||||
$x += $c;
|
||||
$l = $n;
|
||||
}
|
||||
$len = @arr2;
|
||||
push @arr1, $len;
|
||||
push @arr2, $x;
|
||||
|
||||
sub computerange($$$) {
|
||||
my ($i1, $i2, $entries) = @_;
|
||||
$prev = $i1 == 0 ? "_" : $words[$i1 - 1];
|
||||
$first = $words[$i1];
|
||||
$last = $words[$i2-1];
|
||||
$next = $i2 == @words ? "_" : $words[$i2];
|
||||
my $j;
|
||||
for ($j = 0; $j < 5; $j++) {
|
||||
last if substr($first, 0, $j+1) ne substr($last, 0, $j+1);
|
||||
last if substr($prev, 0, $j) ne substr($first, 0, $j)
|
||||
&& substr($next, 0, $j) ne substr($last, 0, $j);
|
||||
}
|
||||
$prefix = substr($first, 0, $j);
|
||||
$range = "";
|
||||
$rng = 0;
|
||||
if (substr($prev, 0, $j) eq substr($first, 0, $j)
|
||||
|| substr($last, 0, $j) eq substr($next, 0, $j)) {
|
||||
$range = "[".substr($first, $j, 1) . "-". substr($last, $j, 1)."]";
|
||||
$rng++;
|
||||
if ($j <= 1) {
|
||||
$range = substr($first,0, $j+1)."-".substr($last,0,$j+1);
|
||||
$prefix= "";
|
||||
}
|
||||
}
|
||||
if (substr($prev, 0, $j+1) eq substr($first, 0, $j+1)
|
||||
|| substr($last, 0, $j+1) eq substr($next, 0, $j+1)) {
|
||||
$j = 0; $rng = 2;
|
||||
}
|
||||
#printf STDERR " # %1d: %9s - %9s = \U$prefix$range\E\n", $entries, $first, $last;
|
||||
return $j + $rng;
|
||||
}
|
||||
|
||||
print << 'EOF';
|
||||
/* DO NOT EDIT: This file is automatically generated by
|
||||
* cd ../gen/wordlist
|
||||
* perl build-recoverytable.pl recovery_english.txt
|
||||
*/
|
||||
|
||||
EOF
|
||||
|
||||
$len = @arr1;
|
||||
print "static const uint16_t word_table1[$len] =\n";
|
||||
print "{";
|
||||
for ($i = 0; $i< @arr1; $i++) {
|
||||
print "\n " if ($i % 9 == 0);
|
||||
$prefixlen = computerange($arr2[$arr1[$i]], $arr2[$arr1[$i+1]], $arr1[$i+1]-$arr1[$i]);
|
||||
$prefixlen = 0 if ($i == @arr1 - 1);
|
||||
printf(" %5d,", $arr1[$i] + 4096 * $prefixlen);
|
||||
}
|
||||
print "\n};\n\n";
|
||||
|
||||
$len = @arr2;
|
||||
print "static const uint16_t word_table2[$len] =\n";
|
||||
print "{";
|
||||
for ($i = 0; $i< @arr2; $i++) {
|
||||
print "\n " if ($i % 9 == 0);
|
||||
$prefixlen = computerange($arr2[$i], $arr2[$i+1], $arr2[$i+1]-$arr2[$i]);
|
||||
$prefixlen = 0 if ($i == @arr2 - 1);
|
||||
printf(" %5d,", $arr2[$i] + 4096 * $prefixlen);
|
||||
}
|
||||
print "\n};\n";
|
630
gen/wordlist/recovery_english.txt
Normal file
630
gen/wordlist/recovery_english.txt
Normal file
@ -0,0 +1,630 @@
|
||||
111 5:abandon,ability,able,about,above
|
||||
112 4:absent,absorb,abstract,absurd
|
||||
113 1:abuse
|
||||
114 4:access,accident,account,accuse
|
||||
115 2:achieve,acid
|
||||
116 2:acoustic,acquire
|
||||
117 1:across
|
||||
118 5:act,action,actor,actress,actual
|
||||
121 1:adapt
|
||||
122 3:add,addict,address
|
||||
123 5:adjust,admit,adult,advance,advice
|
||||
124 1:aerobic
|
||||
125 3:affair,afford,afraid
|
||||
126 4:again,age,agent,agree
|
||||
127 1:ahead
|
||||
128 4:aim,air,airport,aisle
|
||||
131 3:alarm,album,alcohol
|
||||
132 5:alert,alien,all,alley,allow
|
||||
133 3:almost,alone,alpha
|
||||
134 4:already,also,alter,always
|
||||
135 5:amateur,amazing,among,amount,amused
|
||||
136 3:analyst,anchor,ancient
|
||||
137 4:anger,angle,angry,animal
|
||||
138 4:ankle,announce,annual,another
|
||||
139 5:answer,antenna,antique,anxiety,any
|
||||
141 6:apart,apology,appear,apple,approve,april
|
||||
142 2:arch,arctic
|
||||
143 2:area,arena
|
||||
144 1:argue
|
||||
145 4:arm,armed,armor,army
|
||||
146 1:around
|
||||
147 4:arrange,arrest,arrive,arrow
|
||||
148 4:art,artefact,artist,artwork
|
||||
151 2:ask,aspect
|
||||
152 4:assault,asset,assist,assume
|
||||
153 1:asthma
|
||||
154 6:athlete,atom,attack,attend,attitude,attract
|
||||
155 3:auction,audit,august
|
||||
156 4:aunt,author,auto,autumn
|
||||
157 3:average,avocado,avoid
|
||||
158 6:awake,aware,away,awesome,awful,awkward
|
||||
159 1:axis
|
||||
161 4:baby,bachelor,bacon,badge
|
||||
162 5:bag,balance,balcony,ball,bamboo
|
||||
163 6:banana,banner,bar,barely,bargain,barrel
|
||||
164 4:base,basic,basket,battle
|
||||
165 5:beach,bean,beauty,because,become
|
||||
166 3:beef,before,begin
|
||||
167 5:behave,behind,believe,below,belt
|
||||
168 3:bench,benefit,best
|
||||
169 4:betray,better,between,beyond
|
||||
171 2:bicycle,bid
|
||||
172 3:bike,bind,biology
|
||||
173 3:bird,birth,bitter
|
||||
174 5:black,blade,blame,blanket,blast
|
||||
175 3:bleak,bless,blind
|
||||
176 3:blood,blossom,blouse
|
||||
177 3:blue,blur,blush
|
||||
181 4:board,boat,body,boil
|
||||
182 5:bomb,bone,bonus,book,boost
|
||||
183 4:border,boring,borrow,boss
|
||||
184 4:bottom,bounce,box,boy
|
||||
185 5:bracket,brain,brand,brass,brave
|
||||
186 2:bread,breeze
|
||||
187 6:brick,bridge,brief,bright,bring,brisk
|
||||
188 6:broccoli,broken,bronze,broom,brother,brown
|
||||
189 1:brush
|
||||
191 5:bubble,buddy,budget,buffalo,build
|
||||
192 3:bulb,bulk,bullet
|
||||
193 2:bundle,bunker
|
||||
194 3:burden,burger,burst
|
||||
195 3:bus,business,busy
|
||||
196 3:butter,buyer,buzz
|
||||
211 3:cabbage,cabin,cable
|
||||
212 1:cactus
|
||||
213 1:cage
|
||||
214 1:cake
|
||||
215 2:call,calm
|
||||
216 2:camera,camp
|
||||
221 4:can,canal,cancel,candy
|
||||
222 4:cannon,canoe,canvas,canyon
|
||||
223 3:capable,capital,captain
|
||||
224 4:car,carbon,card,cargo
|
||||
225 3:carpet,carry,cart
|
||||
226 5:case,cash,casino,castle,casual
|
||||
227 5:cat,catalog,catch,category,cattle
|
||||
228 3:caught,cause,caution
|
||||
229 1:cave
|
||||
231 1:ceiling
|
||||
232 1:celery
|
||||
233 1:cement
|
||||
234 2:census,century
|
||||
235 2:cereal,certain
|
||||
241 3:chair,chalk,champion
|
||||
243 6:change,chaos,chapter,charge,chase,chat
|
||||
245 6:cheap,check,cheese,chef,cherry,chest
|
||||
246 4:chicken,chief,child,chimney
|
||||
247 2:choice,choose
|
||||
248 1:chronic
|
||||
249 3:chuckle,chunk,churn
|
||||
251 1:cigar
|
||||
252 1:cinnamon
|
||||
253 1:circle
|
||||
254 2:citizen,city
|
||||
255 1:civil
|
||||
261 5:claim,clap,clarify,claw,clay
|
||||
262 3:clean,clerk,clever
|
||||
263 6:click,client,cliff,climb,clinic,clip
|
||||
264 6:clock,clog,close,cloth,cloud,clown
|
||||
265 4:club,clump,cluster,clutch
|
||||
271 5:coach,coast,coconut,code,coffee
|
||||
272 5:coil,coin,collect,color,column
|
||||
273 6:combine,come,comfort,comic,common,company
|
||||
274 4:concert,conduct,confirm,congress
|
||||
275 4:connect,consider,control,convince
|
||||
276 4:cook,cool,copper,copy
|
||||
277 6:coral,core,corn,correct,cost,cotton
|
||||
278 5:couch,country,couple,course,cousin
|
||||
279 2:cover,coyote
|
||||
281 4:crack,cradle,craft,cram
|
||||
283 5:crane,crash,crater,crawl,crazy
|
||||
285 4:cream,credit,creek,crew
|
||||
286 4:cricket,crime,crisp,critic
|
||||
287 4:crop,cross,crouch,crowd
|
||||
288 6:crucial,cruel,cruise,crumble,crunch,crush
|
||||
289 2:cry,crystal
|
||||
291 1:cube
|
||||
292 1:culture
|
||||
293 2:cup,cupboard
|
||||
294 4:curious,current,curtain,curve
|
||||
295 2:cushion,custom
|
||||
296 1:cute
|
||||
299 1:cycle
|
||||
311 1:dad
|
||||
312 2:damage,damp
|
||||
313 2:dance,danger
|
||||
314 1:daring
|
||||
315 1:dash
|
||||
316 1:daughter
|
||||
317 1:dawn
|
||||
318 1:day
|
||||
321 1:deal
|
||||
322 2:debate,debris
|
||||
323 6:decade,december,decide,decline,decorate,decrease
|
||||
324 1:deer
|
||||
325 3:defense,define,defy
|
||||
326 1:degree
|
||||
327 2:delay,deliver
|
||||
328 2:demand,demise
|
||||
331 3:denial,dentist,deny
|
||||
332 5:depart,depend,deposit,depth,deputy
|
||||
333 1:derive
|
||||
334 6:describe,desert,design,desk,despair,destroy
|
||||
335 2:detail,detect
|
||||
336 3:develop,device,devote
|
||||
341 4:diagram,dial,diamond,diary
|
||||
342 3:dice,diesel,diet
|
||||
343 4:differ,digital,dignity,dilemma
|
||||
344 2:dinner,dinosaur
|
||||
345 2:direct,dirt
|
||||
346 5:disagree,discover,disease,dish,dismiss
|
||||
347 3:disorder,display,distance
|
||||
348 3:divert,divide,divorce
|
||||
349 1:dizzy
|
||||
351 2:doctor,document
|
||||
352 1:dog
|
||||
353 2:doll,dolphin
|
||||
354 1:domain
|
||||
355 3:donate,donkey,donor
|
||||
356 1:door
|
||||
357 1:dose
|
||||
358 1:double
|
||||
359 1:dove
|
||||
361 5:draft,dragon,drama,drastic,draw
|
||||
362 2:dream,dress
|
||||
363 5:drift,drill,drink,drip,drive
|
||||
364 3:drop,drum,dry
|
||||
365 2:duck,dumb
|
||||
366 5:dune,during,dust,dutch,duty
|
||||
368 1:dwarf
|
||||
369 1:dynamic
|
||||
371 2:eager,eagle
|
||||
372 6:early,earn,earth,easily,east,easy
|
||||
373 6:echo,ecology,economy,edge,edit,educate
|
||||
374 4:effort,egg,eight,either
|
||||
375 2:elbow,elder
|
||||
376 5:electric,elegant,element,elephant,elevator
|
||||
377 2:elite,else
|
||||
378 4:embark,embody,embrace,emerge
|
||||
379 4:emotion,employ,empower,empty
|
||||
381 2:enable,enact
|
||||
382 3:end,endless,endorse
|
||||
383 5:enemy,energy,enforce,engage,engine
|
||||
384 3:enhance,enjoy,enlist
|
||||
385 4:enough,enrich,enroll,ensure
|
||||
386 4:enter,entire,entry,envelope
|
||||
387 3:episode,equal,equip
|
||||
388 6:era,erase,erode,erosion,error,erupt
|
||||
389 4:escape,essay,essence,estate
|
||||
391 2:eternal,ethics
|
||||
392 4:evidence,evil,evoke,evolve
|
||||
393 2:exact,example
|
||||
394 5:excess,exchange,excite,exclude,excuse
|
||||
395 4:execute,exercise,exhaust,exhibit
|
||||
396 4:exile,exist,exit,exotic
|
||||
397 6:expand,expect,expire,explain,expose,express
|
||||
398 2:extend,extra
|
||||
399 2:eye,eyebrow
|
||||
411 3:fabric,face,faculty
|
||||
412 1:fade
|
||||
413 2:faint,faith
|
||||
414 2:fall,false
|
||||
415 3:fame,family,famous
|
||||
416 3:fan,fancy,fantasy
|
||||
417 2:farm,fashion
|
||||
418 4:fat,fatal,father,fatigue
|
||||
419 2:fault,favorite
|
||||
421 3:feature,february,federal
|
||||
422 3:fee,feed,feel
|
||||
423 6:female,fence,festival,fetch,fever,few
|
||||
431 4:fiber,fiction,field,figure
|
||||
432 3:file,film,filter
|
||||
433 5:final,find,fine,finger,finish
|
||||
434 3:fire,firm,first
|
||||
435 5:fiscal,fish,fit,fitness,fix
|
||||
441 5:flag,flame,flash,flat,flavor
|
||||
442 3:flee,flight,flip
|
||||
443 4:float,flock,floor,flower
|
||||
444 3:fluid,flush,fly
|
||||
445 4:foam,focus,fog,foil
|
||||
446 4:fold,follow,food,foot
|
||||
447 4:force,forest,forget,fork
|
||||
448 3:fortune,forum,forward
|
||||
449 4:fossil,foster,found,fox
|
||||
451 2:fragile,frame
|
||||
452 2:frequent,fresh
|
||||
453 2:friend,fringe
|
||||
454 5:frog,front,frost,frown,frozen
|
||||
455 1:fruit
|
||||
458 6:fuel,fun,funny,furnace,fury,future
|
||||
461 2:gadget,gain
|
||||
462 2:galaxy,gallery
|
||||
463 2:game,gap
|
||||
464 5:garage,garbage,garden,garlic,garment
|
||||
465 2:gas,gasp
|
||||
466 2:gate,gather
|
||||
467 2:gauge,gaze
|
||||
471 6:general,genius,genre,gentle,genuine,gesture
|
||||
472 1:ghost
|
||||
473 1:giant
|
||||
474 1:gift
|
||||
475 1:giggle
|
||||
476 1:ginger
|
||||
477 2:giraffe,girl
|
||||
478 1:give
|
||||
481 4:glad,glance,glare,glass
|
||||
482 2:glide,glimpse
|
||||
483 5:globe,gloom,glory,glove,glow
|
||||
484 1:glue
|
||||
486 2:goat,goddess
|
||||
487 3:gold,good,goose
|
||||
488 3:gorilla,gospel,gossip
|
||||
489 2:govern,gown
|
||||
491 3:grab,grace,grain
|
||||
492 4:grant,grape,grass,gravity
|
||||
493 2:great,green
|
||||
494 3:grid,grief,grit
|
||||
495 3:grocery,group,grow
|
||||
496 1:grunt
|
||||
497 6:guard,guess,guide,guilt,guitar,gun
|
||||
498 1:gym
|
||||
511 2:habit,hair
|
||||
512 3:half,hammer,hamster
|
||||
513 2:hand,happy
|
||||
514 4:harbor,hard,harsh,harvest
|
||||
515 4:hat,have,hawk,hazard
|
||||
516 4:head,health,heart,heavy
|
||||
517 2:hedgehog,height
|
||||
518 3:hello,helmet,help
|
||||
519 2:hen,hero
|
||||
521 2:hidden,high
|
||||
522 2:hill,hint
|
||||
523 3:hip,hire,history
|
||||
524 2:hobby,hockey
|
||||
525 4:hold,hole,holiday,hollow
|
||||
526 4:home,honey,hood,hope
|
||||
527 3:horn,horror,horse
|
||||
528 5:hospital,host,hotel,hour,hover
|
||||
531 1:hub
|
||||
532 1:huge
|
||||
533 3:human,humble,humor
|
||||
534 3:hundred,hungry,hunt
|
||||
535 3:hurdle,hurry,hurt
|
||||
536 1:husband
|
||||
539 1:hybrid
|
||||
541 2:ice,icon
|
||||
542 3:idea,identify,idle
|
||||
543 1:ignore
|
||||
544 3:ill,illegal,illness
|
||||
545 1:image
|
||||
546 1:imitate
|
||||
547 2:immense,immune
|
||||
548 4:impact,impose,improve,impulse
|
||||
551 4:inch,include,income,increase
|
||||
552 4:index,indicate,indoor,industry
|
||||
553 3:infant,inflict,inform
|
||||
554 3:inhale,inherit,initial
|
||||
555 3:inject,injury,inmate
|
||||
556 4:inner,innocent,input,inquiry
|
||||
557 5:insane,insect,inside,inspire,install
|
||||
558 6:intact,interest,into,invest,invite,involve
|
||||
559 6:iron,island,isolate,issue,item,ivory
|
||||
561 4:jacket,jaguar,jar,jazz
|
||||
562 4:jealous,jeans,jelly,jewel
|
||||
563 5:job,join,joke,journey,joy
|
||||
564 1:judge
|
||||
565 1:juice
|
||||
566 1:jump
|
||||
567 3:jungle,junior,junk
|
||||
568 1:just
|
||||
571 1:kangaroo
|
||||
572 4:keen,keep,ketchup,key
|
||||
573 1:kick
|
||||
574 2:kid,kidney
|
||||
575 2:kind,kingdom
|
||||
576 1:kiss
|
||||
577 4:kit,kitchen,kite,kitten
|
||||
578 1:kiwi
|
||||
579 4:knee,knife,knock,know
|
||||
581 5:lab,label,labor,ladder,lady
|
||||
582 3:lake,lamp,language
|
||||
583 4:laptop,large,later,latin
|
||||
584 3:laugh,laundry,lava
|
||||
585 5:law,lawn,lawsuit,layer,lazy
|
||||
586 4:leader,leaf,learn,leave
|
||||
587 5:lecture,left,leg,legal,legend
|
||||
588 5:leisure,lemon,lend,length,lens
|
||||
589 4:leopard,lesson,letter,level
|
||||
591 4:liar,liberty,library,license
|
||||
592 4:life,lift,light,like
|
||||
593 4:limb,limit,link,lion
|
||||
594 5:liquid,list,little,live,lizard
|
||||
595 5:load,loan,lobster,local,lock
|
||||
596 4:logic,lonely,long,loop
|
||||
597 5:lottery,loud,lounge,love,loyal
|
||||
598 6:lucky,luggage,lumber,lunar,lunch,luxury
|
||||
599 1:lyrics
|
||||
611 4:machine,mad,magic,magnet
|
||||
612 3:maid,mail,main
|
||||
613 3:major,make,mammal
|
||||
614 6:man,manage,mandate,mango,mansion,manual
|
||||
615 1:maple
|
||||
616 6:marble,march,margin,marine,market,marriage
|
||||
617 3:mask,mass,master
|
||||
618 5:match,material,math,matrix,matter
|
||||
619 2:maximum,maze
|
||||
621 4:meadow,mean,measure,meat
|
||||
622 1:mechanic
|
||||
623 2:medal,media
|
||||
624 2:melody,melt
|
||||
625 2:member,memory
|
||||
626 2:mention,menu
|
||||
627 4:mercy,merge,merit,merry
|
||||
628 2:mesh,message
|
||||
629 2:metal,method
|
||||
631 2:middle,midnight
|
||||
632 2:milk,million
|
||||
633 1:mimic
|
||||
634 4:mind,minimum,minor,minute
|
||||
635 2:miracle,mirror
|
||||
636 3:misery,miss,mistake
|
||||
637 3:mix,mixed,mixture
|
||||
641 5:mobile,model,modify,mom,moment
|
||||
642 4:monitor,monkey,monster,month
|
||||
643 4:moon,moral,more,morning
|
||||
644 4:mosquito,mother,motion,motor
|
||||
645 4:mountain,mouse,move,movie
|
||||
646 4:much,muffin,mule,multiply
|
||||
647 5:muscle,museum,mushroom,music,must
|
||||
648 1:mutual
|
||||
649 3:myself,mystery,myth
|
||||
651 2:naive,name
|
||||
652 2:napkin,narrow
|
||||
653 3:nasty,nation,nature
|
||||
654 2:near,neck
|
||||
655 3:need,negative,neglect
|
||||
656 2:neither,nephew
|
||||
657 2:nerve,nest
|
||||
658 3:net,network,neutral
|
||||
659 3:never,news,next
|
||||
661 2:nice,night
|
||||
662 4:noble,noise,nominee,noodle
|
||||
663 2:normal,north
|
||||
664 1:nose
|
||||
665 4:notable,note,nothing,notice
|
||||
666 2:novel,now
|
||||
669 4:nuclear,number,nurse,nut
|
||||
671 1:oak
|
||||
672 3:obey,object,oblige
|
||||
673 4:obscure,observe,obtain,obvious
|
||||
675 3:occur,ocean,october
|
||||
676 1:odor
|
||||
677 4:off,offer,office,often
|
||||
678 1:oil
|
||||
679 1:okay
|
||||
681 3:old,olive,olympic
|
||||
682 1:omit
|
||||
683 5:once,one,onion,online,only
|
||||
684 5:open,opera,opinion,oppose,option
|
||||
691 6:orange,orbit,orchard,order,ordinary,organ
|
||||
692 3:orient,original,orphan
|
||||
693 1:ostrich
|
||||
694 1:other
|
||||
695 4:outdoor,outer,output,outside
|
||||
696 3:oval,oven,over
|
||||
697 2:own,owner
|
||||
698 3:oxygen,oyster,ozone
|
||||
711 6:pact,paddle,page,pair,palace,palm
|
||||
712 5:panda,panel,panic,panther,paper
|
||||
713 6:parade,parent,park,parrot,party,pass
|
||||
714 5:patch,path,patient,patrol,pattern
|
||||
715 3:pause,pave,payment
|
||||
716 4:peace,peanut,pear,peasant
|
||||
717 5:pelican,pen,penalty,pencil,people
|
||||
718 5:pepper,perfect,permit,person,pet
|
||||
719 4:phone,photo,phrase,physical
|
||||
721 4:piano,picnic,picture,piece
|
||||
722 5:pig,pigeon,pill,pilot,pink
|
||||
723 5:pioneer,pipe,pistol,pitch,pizza
|
||||
724 5:place,planet,plastic,plate,play
|
||||
725 5:please,pledge,pluck,plug,plunge
|
||||
726 3:poem,poet,point
|
||||
727 5:polar,pole,police,pond,pony
|
||||
728 6:pool,popular,portion,position,possible,post
|
||||
729 5:potato,pottery,poverty,powder,power
|
||||
731 2:practice,praise
|
||||
732 6:predict,prefer,prepare,present,pretty,prevent
|
||||
733 3:price,pride,primary
|
||||
735 5:print,priority,prison,private,prize
|
||||
736 4:problem,process,produce,profit
|
||||
737 5:program,project,promote,proof,property
|
||||
739 4:prosper,protect,proud,provide
|
||||
741 2:public,pudding
|
||||
742 3:pull,pulp,pulse
|
||||
743 2:pumpkin,punch
|
||||
744 2:pupil,puppy
|
||||
745 4:purchase,purity,purpose,purse
|
||||
746 3:push,put,puzzle
|
||||
749 1:pyramid
|
||||
751 3:quality,quantum,quarter
|
||||
752 1:question
|
||||
753 3:quick,quit,quiz
|
||||
754 1:quote
|
||||
761 1:rabbit
|
||||
762 3:raccoon,race,rack
|
||||
763 2:radar,radio
|
||||
764 3:rail,rain,raise
|
||||
765 2:rally,ramp
|
||||
766 3:ranch,random,range
|
||||
767 2:rapid,rare
|
||||
768 2:rate,rather
|
||||
769 3:raven,raw,razor
|
||||
771 3:ready,real,reason
|
||||
772 2:rebel,rebuild
|
||||
773 5:recall,receive,recipe,record,recycle
|
||||
774 1:reduce
|
||||
775 3:reflect,reform,refuse
|
||||
776 3:region,regret,regular
|
||||
777 1:reject
|
||||
778 4:relax,release,relief,rely
|
||||
779 4:remain,remember,remind,remove
|
||||
781 3:render,renew,rent
|
||||
782 1:reopen
|
||||
783 4:repair,repeat,replace,report
|
||||
784 1:require
|
||||
785 6:rescue,resemble,resist,resource,response,result
|
||||
786 3:retire,retreat,return
|
||||
787 1:reunion
|
||||
788 2:reveal,review
|
||||
789 1:reward
|
||||
791 1:rhythm
|
||||
792 6:rib,ribbon,rice,rich,ride,ridge
|
||||
793 5:rifle,right,rigid,ring,riot
|
||||
794 5:ripple,risk,ritual,rival,river
|
||||
795 5:road,roast,robot,robust,rocket
|
||||
796 5:romance,roof,rookie,room,rose
|
||||
797 5:rotate,rough,round,route,royal
|
||||
798 3:rubber,rude,rug
|
||||
799 4:rule,run,runway,rural
|
||||
811 5:sad,saddle,sadness,safe,sail
|
||||
812 5:salad,salmon,salon,salt,salute
|
||||
813 3:same,sample,sand
|
||||
814 4:satisfy,satoshi,sauce,sausage
|
||||
815 2:save,say
|
||||
816 4:scale,scan,scare,scatter
|
||||
817 3:scene,scheme,school
|
||||
818 4:science,scissors,scorpion,scout
|
||||
819 4:scrap,screen,script,scrub
|
||||
821 4:sea,search,season,seat
|
||||
822 4:second,secret,section,security
|
||||
823 6:seed,seek,segment,select,sell,seminar
|
||||
824 3:senior,sense,sentence
|
||||
825 6:series,service,session,settle,setup,seven
|
||||
831 4:shadow,shaft,shallow,share
|
||||
832 3:shed,shell,sheriff
|
||||
833 5:shield,shift,shine,ship,shiver
|
||||
834 2:shock,shoe
|
||||
836 5:shoot,shop,short,shoulder,shove
|
||||
837 2:shrimp,shrug
|
||||
838 1:shuffle
|
||||
839 1:shy
|
||||
841 4:sibling,sick,side,siege
|
||||
842 6:sight,sign,silent,silk,silly,silver
|
||||
843 4:similar,simple,since,sing
|
||||
844 5:siren,sister,situate,six,size
|
||||
845 2:skate,sketch
|
||||
846 5:ski,skill,skin,skirt,skull
|
||||
847 4:slab,slam,sleep,slender
|
||||
848 4:slice,slide,slight,slim
|
||||
849 4:slogan,slot,slow,slush
|
||||
851 5:small,smart,smile,smoke,smooth
|
||||
852 5:snack,snake,snap,sniff,snow
|
||||
853 1:soap
|
||||
854 3:soccer,social,sock
|
||||
855 2:soda,soft
|
||||
856 5:solar,soldier,solid,solution,solve
|
||||
857 3:someone,song,soon
|
||||
858 2:sorry,sort
|
||||
859 5:soul,sound,soup,source,south
|
||||
861 4:space,spare,spatial,spawn
|
||||
862 5:speak,special,speed,spell,spend
|
||||
863 1:sphere
|
||||
864 5:spice,spider,spike,spin,spirit
|
||||
865 1:split
|
||||
866 5:spoil,sponsor,spoon,sport,spot
|
||||
867 3:spray,spread,spring
|
||||
868 1:spy
|
||||
869 3:square,squeeze,squirrel
|
||||
871 6:stable,stadium,staff,stage,stairs,stamp
|
||||
872 4:stand,start,state,stay
|
||||
873 5:steak,steel,stem,step,stereo
|
||||
874 3:stick,still,sting
|
||||
875 6:stock,stomach,stone,stool,story,stove
|
||||
876 5:strategy,street,strike,strong,struggle
|
||||
877 3:student,stuff,stumble
|
||||
878 1:style
|
||||
881 3:subject,submit,subway
|
||||
882 2:success,such
|
||||
883 4:sudden,suffer,sugar,suggest
|
||||
884 2:suit,summer
|
||||
885 3:sun,sunny,sunset
|
||||
886 3:super,supply,supreme
|
||||
887 6:sure,surface,surge,surprise,surround,survey
|
||||
888 2:suspect,sustain
|
||||
891 4:swallow,swamp,swap,swarm
|
||||
892 2:swear,sweet
|
||||
893 4:swift,swim,swing,switch
|
||||
894 1:sword
|
||||
898 4:symbol,symptom,syrup,system
|
||||
911 4:table,tackle,tag,tail,
|
||||
912 5:talent,talk,tank,tape,target
|
||||
913 4:task,taste,tattoo,taxi
|
||||
914 3:teach,team,tell
|
||||
915 4:ten,tenant,tennis,tent
|
||||
916 3:term,test,text
|
||||
921 2:thank,that
|
||||
922 5:theme,then,theory,there,they
|
||||
923 3:thing,this,thought
|
||||
924 3:three,thrive,throw
|
||||
925 2:thumb,thunder
|
||||
926 2:ticket,tide
|
||||
927 4:tiger,tilt,timber,time
|
||||
928 2:tiny,tip
|
||||
929 3:tired,tissue,title
|
||||
931 4:toast,tobacco,today,toddler
|
||||
932 3:toe,together,toilet
|
||||
933 3:token,tomato,tomorrow
|
||||
934 3:tone,tongue,tonight
|
||||
935 2:tool,tooth
|
||||
936 3:top,topic,topple
|
||||
937 3:torch,tornado,tortoise
|
||||
938 3:toss,total,tourist
|
||||
939 4:toward,tower,town,toy
|
||||
941 5:track,trade,traffic,tragic,train
|
||||
942 5:transfer,trap,trash,travel,tray
|
||||
943 3:treat,tree,trend
|
||||
944 6:trial,tribe,trick,trigger,trim,trip
|
||||
945 2:trophy,trouble
|
||||
946 6:truck,true,truly,trumpet,trust,truth
|
||||
947 1:try
|
||||
951 5:tube,tuition,tumble,tuna,tunnel
|
||||
952 3:turkey,turn,turtle
|
||||
953 6:twelve,twenty,twice,twin,twist,two
|
||||
954 2:type,typical
|
||||
961 2:ugly,umbrella
|
||||
962 4:unable,unaware,uncle,uncover
|
||||
963 5:under,undo,unfair,unfold,unhappy
|
||||
964 4:uniform,unique,unit,universe
|
||||
965 5:unknown,unlock,until,unusual,unveil
|
||||
966 6:update,upgrade,uphold,upon,upper,upset
|
||||
967 2:urban,urge
|
||||
968 6:usage,use,used,useful,useless,usual
|
||||
969 1:utility
|
||||
971 6:vacant,vacuum,vague,valid,valley,valve
|
||||
972 6:van,vanish,vapor,various,vast,vault
|
||||
973 5:vehicle,velvet,vendor,venture,venue
|
||||
974 6:verb,verify,version,very,vessel,veteran
|
||||
975 5:viable,vibrant,vicious,victory,video
|
||||
976 6:view,village,vintage,violin,virtual,virus
|
||||
977 5:visa,visit,visual,vital,vivid
|
||||
978 3:vocal,voice,void
|
||||
979 4:volcano,volume,vote,voyage
|
||||
981 3:wage,wagon,wait
|
||||
982 4:walk,wall,walnut,want
|
||||
983 3:warfare,warm,warrior
|
||||
984 6:wash,wasp,waste,water,wave,way
|
||||
985 5:wealth,weapon,wear,weasel,weather
|
||||
986 3:web,wedding,weekend
|
||||
987 4:weird,welcome,west,wet
|
||||
988 6:whale,what,wheat,wheel,when,where
|
||||
989 2:whip,whisper
|
||||
991 5:wide,width,wife,wild,will
|
||||
992 5:win,window,wine,wing,wink
|
||||
993 2:winner,winter
|
||||
994 5:wire,wisdom,wise,wish,witness
|
||||
995 5:wolf,woman,wonder,wood,wool
|
||||
996 5:word,work,world,worry,worth
|
||||
997 6:wrap,wreck,wrestle,wrist,write,wrong
|
||||
998 6:yard,year,yellow,you,young,youth
|
||||
999 4:zebra,zero,zone,zoo
|
Loading…
Reference in New Issue
Block a user