Merge pull request #1579

f5f4109f mnemonics: fix language detection with checksum word (moneromooo-monero)
This commit is contained in:
Riccardo Spagni 2017-01-15 14:58:09 -05:00
commit b2e1568335
No known key found for this signature in database
GPG key ID: 55432DF31CCD4FCD
2 changed files with 45 additions and 1 deletions

View file

@ -64,12 +64,15 @@
namespace namespace
{ {
uint32_t create_checksum_index(const std::vector<std::string> &word_list,
uint32_t unique_prefix_length);
bool checksum_test(std::vector<std::string> seed, uint32_t unique_prefix_length);
/*! /*!
* \brief Finds the word list that contains the seed words and puts the indices * \brief Finds the word list that contains the seed words and puts the indices
* where matches occured in matched_indices. * where matches occured in matched_indices.
* \param seed List of words to match. * \param seed List of words to match.
* \param has_checksum If word list passed checksum test, we need to only do a prefix check. * \param has_checksum The seed has a checksum word (maybe not checked).
* \param matched_indices The indices where the seed words were found are added to this. * \param matched_indices The indices where the seed words were found are added to this.
* \param language Language instance pointer to write to after it is found. * \param language Language instance pointer to write to after it is found.
* \return true if all the words were present in some language false if not. * \return true if all the words were present in some language false if not.
@ -88,6 +91,7 @@ namespace
Language::Singleton<Language::Russian>::instance(), Language::Singleton<Language::Russian>::instance(),
Language::Singleton<Language::OldEnglish>::instance() Language::Singleton<Language::OldEnglish>::instance()
}); });
Language::Base *fallback = NULL;
// Iterate through all the languages and find a match // Iterate through all the languages and find a match
for (std::vector<Language::Base*>::iterator it1 = language_instances.begin(); for (std::vector<Language::Base*>::iterator it1 = language_instances.begin();
@ -125,6 +129,17 @@ namespace
} }
} }
if (full_match) if (full_match)
{
// if we were using prefix only, and we have a checksum, check it now
// to avoid false positives due to prefix set being too common
if (has_checksum)
if (!checksum_test(seed, (*it1)->get_unique_prefix_length()))
{
fallback = *it1;
full_match = false;
}
}
if (full_match)
{ {
*language = *it1; *language = *it1;
return true; return true;
@ -132,6 +147,16 @@ namespace
// Some didn't match. Clear the index array. // Some didn't match. Clear the index array.
matched_indices.clear(); matched_indices.clear();
} }
// if we get there, we've not found a good match, but we might have a fallback,
// if we detected a match which did not fit the checksum, which might be a badly
// typed/transcribed seed in the right language
if (fallback)
{
*language = fallback;
return true;
}
return false; return false;
} }

View file

@ -148,3 +148,22 @@ TEST(mnemonics, all_languages)
test_language(*(*it)); test_language(*(*it));
} }
} }
TEST(mnemonics, language_detection_with_bad_checksum)
{
crypto::secret_key key;
std::string language_name;
bool res;
// This Portuguese (4-prefix) seed has all its words with 3-prefix that's also present in English
const std::string base_seed = "cinzento luxuriante leonardo gnostico digressao cupula fifa broxar iniquo louvor ovario dorsal ideologo besuntar decurso rosto susto lemure unheiro pagodeiro nitroglicerina eclusa mazurca bigorna";
const std::string real_checksum = "gnostico";
res = crypto::ElectrumWords::words_to_bytes(base_seed, key, language_name);
ASSERT_EQ(true, res);
ASSERT_STREQ(language_name.c_str(), "Portuguese");
res = crypto::ElectrumWords::words_to_bytes(base_seed + " " + real_checksum, key, language_name);
ASSERT_EQ(true, res);
ASSERT_STREQ(language_name.c_str(), "Portuguese");
}