From 148e5e7c0c8de057a8829d80e0cedaa4e528cbd8 Mon Sep 17 00:00:00 2001 From: striderDM <51991544+StriderDM@users.noreply.github.com> Date: Thu, 18 Nov 2021 17:06:53 +0200 Subject: [PATCH] feat: language detection for mnemonic seed words Implementation of a basic language detection algorithm for mnemonic words Review comments cleanup --- base_layer/key_manager/src/mnemonic.rs | 54 +++++++++++++++++++++----- 1 file changed, 44 insertions(+), 10 deletions(-) diff --git a/base_layer/key_manager/src/mnemonic.rs b/base_layer/key_manager/src/mnemonic.rs index 4226c8c250..afd0996819 100644 --- a/base_layer/key_manager/src/mnemonic.rs +++ b/base_layer/key_manager/src/mnemonic.rs @@ -33,7 +33,7 @@ use tari_crypto::tari_utilities::bit::*; /// It can autodetect the language of the Mnemonic word sequence // TODO: Develop a language autodetection mechanism to distinguish between ChineseTraditional and ChineseSimplified -#[derive(Clone, Debug, PartialEq, EnumString, Display)] +#[derive(Clone, Debug, PartialEq, EnumString, Display, Copy)] pub enum MnemonicLanguage { ChineseSimplified, English, @@ -47,12 +47,8 @@ pub enum MnemonicLanguage { impl MnemonicLanguage { /// Detects the mnemonic language of a specific word by searching all defined mnemonic word lists pub fn from(mnemonic_word: &str) -> Result { - for language in MnemonicLanguage::iterator() { - if find_mnemonic_index_from_word(mnemonic_word, language).is_ok() { - return Ok((*language).clone()); - } - } - Err(MnemonicError::UnknownLanguage) + let words = vec![mnemonic_word.to_string()]; + detect_language(&words) } /// Returns an iterator for the MnemonicLanguage enum group to allow iteration over all defined languages @@ -158,11 +154,49 @@ pub fn from_bytes(bytes: Vec, language: &MnemonicLanguage) -> Result Result { + if words.iter().len() < 1 { + return Err(MnemonicError::UnknownLanguage); + } + + let mut index: usize = 0; + let count = words.iter().len() - 1; + + while index <= count { + let mut languages = Vec::new(); + let word = words.get(index).ok_or(MnemonicError::EncodeInvalidLength)?; + for language in MnemonicLanguage::iterator() { + if find_mnemonic_index_from_word(word, language).is_ok() { + languages.push(*language); + } + } + + for language in languages { + let mut consistent = true; + for i in 0..count { + // exclude initial word + if i != index { + let compare = words.get(i).ok_or(MnemonicError::EncodeInvalidLength)?; + if find_mnemonic_index_from_word(compare, &language).is_err() { + consistent = false; + } + } + } + if consistent { + return Ok(language); + } + } + + index += 1; + } + + Err(MnemonicError::UnknownLanguage) +} + /// Generates a vector of bytes that represent the provided mnemonic sequence of words, the language of the mnemonic -/// sequence is autodetected +/// sequence is detected pub fn to_bytes(mnemonic_seq: &[String]) -> Result, MnemonicError> { - let first_word = mnemonic_seq.get(0).ok_or(MnemonicError::EncodeInvalidLength)?; - let language = MnemonicLanguage::from(first_word)?; // Autodetect language + let language = self::detect_language(mnemonic_seq)?; to_bytes_with_language(mnemonic_seq, &language) }