Esempio n. 1
0
        /// <summary>
        /// Obtains the word list for a given language for mnemonic phrases, or if it does not exist,
        /// creates one from the given words.
        /// </summary>
        /// <param name="language">The language of the word list to obtain.</param>
        /// <param name="words">The array of words to use to create the word list if one was not already parsed.</param>
        /// <returns>Returns a word list for the given language, used for mnemonic phrases.</returns>
        public static WordList GetWordList(WordListLanguage language, string[] words)
        {
            // Try to get our word list
            bool success = _cachedWordLists.TryGetValue(language, out WordList result);

            if (success)
            {
                return(result);
            }

            // If we couldn't get it, parse a new one
            WordList wordList = new WordList(language, words);

            // Set it in our lookup
            _cachedWordLists[language] = wordList;

            // Return our word list.
            return(wordList);
        }
Esempio n. 2
0
        /// <summary>
        /// Obtains the word list for a given language for mnemonic phrases, or if it does not exist,
        /// reads one from the given filename.
        /// </summary>
        /// <param name="language">The language of the word list to obtain.</param>
        /// <param name="fileName">The filename of the word list to read from if one was not already parsed.</param>
        /// <returns>Returns a word list for the given language, used for mnemonic phrases.</returns>
        public static WordList GetWordList(WordListLanguage language, string fileName)
        {
            // Try to get our word list
            bool success = _cachedWordLists.TryGetValue(language, out WordList result);

            if (success)
            {
                return(result);
            }

            // If we couldn't get it, parse a new one
            string   allText  = File.ReadAllText(fileName);
            WordList wordList = new WordList(language, allText);

            // Set it in our lookup
            _cachedWordLists[language] = wordList;

            // Return our word list.
            return(wordList);
        }
Esempio n. 3
0
        /// <summary>
        /// Initializes a mnemonic phrase from the given mnemonic string.
        /// </summary>
        /// <param name="mnemonic">The mnemonic string to initialize this mnemonic phrase from, for key derivation.</param>
        public MnemonicPhrase(string mnemonic)
        {
            // If our argument is null, we throw an exception, otherwise we set our mnemonic string.
            MnemonicString = mnemonic.Trim() ?? throw new ArgumentException("Provided mnemonic string was null or empty.");

            // Determine the word list (language) the mnemonic string belongs to by checking indicies.
            WordList = WordList.GetWordList(MnemonicString);

            // Obtain our words from our mnemonic.
            MnemonicWords = WordList.SplitMnemonic(MnemonicString);

            // Verify our word count is valid
            if (MnemonicWords.Length < MNEMONIC_WORDS_MINIMUM || MnemonicWords.Length > MNEMONIC_WORDS_MAXIMUM)
            {
                throw new ArgumentException($"Provided entropy data of this size would represent {MnemonicWords.Length} words. Should be between {MNEMONIC_WORDS_MINIMUM}-{MNEMONIC_WORDS_MAXIMUM} (inclusive).");
            }

            // Initialize our indices array.
            Indices = new int[MnemonicWords.Length];

            // Loop for each index we want to resolve for the words in our mnemonics
            for (int i = 0; i < Indices.Length; i++)
            {
                // Determine the word index for the indexed word.
                int currentWordIndex = WordList.GetWordIndex(MnemonicWords[i]);

                // If the index is invalid, throw an exception.
                if (currentWordIndex < 0)
                {
                    throw new ArgumentException($"Could not resolve word \"{MnemonicWords[i]}\" in word list for language \"{WordList.Language}\".");
                }

                // Set the word index.
                Indices[i] = currentWordIndex;
            }
        }
Esempio n. 4
0
        /// <summary>
        /// Obtains the word list for a given language for mnemonic phrases, or if it does not exist,
        /// parses one from the embedded word list resources in this assembly.
        /// </summary>
        /// <param name="language">The language of the word list to obtain.</param>
        /// <returns>Returns a word list for the given language, used for mnemonic phrases.</returns>
        public static WordList GetWordList(WordListLanguage language)
        {
            lock (_cachedWordLists)
            {
                // Try to get our word list
                bool success = _cachedWordLists.TryGetValue(language, out WordList result);
                if (success)
                {
                    return(result);
                }

                // Obtain the appropriate word list from our resource files.
                Assembly currentAssembly = Assembly.GetExecutingAssembly();
                string   resourceName    = null;
                switch (language)
                {
                case WordListLanguage.Chinese_Simplified:
                    resourceName = "wordlist_chinese_simplified.txt";
                    break;

                case WordListLanguage.Chinese_Traditional:
                    resourceName = "wordlist_chinese_traditional.txt";
                    break;

                case WordListLanguage.English:
                    resourceName = "wordlist_english.txt";
                    break;

                case WordListLanguage.French:
                    resourceName = "wordlist_french.txt";
                    break;

                case WordListLanguage.Italian:
                    resourceName = "wordlist_italian.txt";
                    break;

                case WordListLanguage.Japanese:
                    resourceName = "wordlist_japanese.txt";
                    break;

                case WordListLanguage.Korean:
                    resourceName = "wordlist_korean.txt";
                    break;

                case WordListLanguage.Spanish:
                    resourceName = "wordlist_spanish.txt";
                    break;
                }

                // If our resource name is null, throw an exception
                if (resourceName == null)
                {
                    throw new ArgumentException($"Could not obtain an embedded word list for language \"{resourceName}\".");
                }

                // Obtain our full resource name (it should end with the resource filename).
                resourceName = currentAssembly.GetManifestResourceNames().First(x =>
                {
                    int targetIndex = x.Length - resourceName.Length;
                    if (targetIndex < 0)
                    {
                        return(false);
                    }

                    return(x.LastIndexOf(resourceName, StringComparison.OrdinalIgnoreCase) == targetIndex);
                });

                // Open a stream on the resource
                Stream stream = currentAssembly.GetManifestResourceStream(resourceName);

                // Read all the text from the stream.
                StreamReader streamReader = new StreamReader(stream);
                string       allText      = streamReader.ReadToEnd();
                streamReader.Close();
                stream.Close();

                // Create a word list instance
                WordList wordList = new WordList(language, allText);

                // Set it in our cached word lists
                _cachedWordLists[language] = wordList;

                // Return our word list
                return(wordList);
            }
        }
Esempio n. 5
0
        /// <summary>
        /// Initializes a mnemonic phrase for the given language, with the optionally given entropy data (or newly generated data if none is provided).
        /// </summary>
        /// <param name="wordListLanguage">The language to create a mnemonic phrase in.</param>
        /// <param name="entropy">The optionally given entropy data to generate a mnemonic phrase from. If null, generates new entropy data of the maximum size.</param>
        public MnemonicPhrase(WordListLanguage wordListLanguage, byte[] entropy = null)
        {
            // Set our word list
            WordList = WordList.GetWordList(wordListLanguage);

            // If our entropy is null, initialize a new set.
            if (entropy == null)
            {
                // Create a buffer of random bytes (entropy) using our RNG.
                int maximumEntropySize = (MNEMONIC_ENTROPY_BITS_PER_CHECKSUM_BIT * (MNEMONIC_WORDS_MAXIMUM / MNEMONIC_WORDS_PER_CHECKSUM_BIT)) / 8;
                entropy = new byte[maximumEntropySize];
                _random.GetBytes(entropy);
            }

            // Verify our entropy size is divisible by the range of a checksum.
            int entropySizeBits = (entropy.Length * 8);

            if (entropySizeBits % MNEMONIC_ENTROPY_BITS_PER_CHECKSUM_BIT != 0)
            {
                throw new ArgumentException($"Provided entropy data must be divisible by {MNEMONIC_ENTROPY_BITS_PER_CHECKSUM_BIT}");
            }

            // Calculate our component sizes.
            int checksumBitcount = entropySizeBits / MNEMONIC_ENTROPY_BITS_PER_CHECKSUM_BIT;
            int wordCount        = checksumBitcount * MNEMONIC_WORDS_PER_CHECKSUM_BIT;

            // Verify our word count is valid
            if (wordCount < MNEMONIC_WORDS_MINIMUM || wordCount > MNEMONIC_WORDS_MAXIMUM)
            {
                throw new ArgumentException($"Provided entropy data of this size would represent {wordCount} words. Should be between {MNEMONIC_WORDS_MINIMUM}-{MNEMONIC_WORDS_MAXIMUM} (inclusive).");
            }

            // Calculate our SHA256 hash of the entropy.
            byte[] checksum = sha256Provider.ComputeHash(entropy);

            // Now we write the entropy followed by the checksum bits (which we will use to interpret a mnemonic from later).
            BitStream bitStream = new BitStream();

            bitStream.WriteBytes(entropy);
            bitStream.WriteBytes(checksum, checksumBitcount);

            // Move back to the start of the data
            bitStream.Position    = 0;
            bitStream.BitPosition = 0;

            // Read every word index, which are represented by 11-bit unsigned integers. At the same time, we resolve our mnemonic words.
            int wordIndexCount = (int)(bitStream.BitLength / MNEMONIC_WORD_INDEX_BITCOUNT);

            Indices       = new int[wordIndexCount];
            MnemonicWords = new string[Indices.Length];
            for (int i = 0; i < Indices.Length; i++)
            {
                Indices[i]       = (int)bitStream.ReadUInt64(MNEMONIC_WORD_INDEX_BITCOUNT);
                MnemonicWords[i] = WordList.Words[Indices[i]];
            }

            // Close the bitstream.
            bitStream.Close();

            // Join all strings into a mnemonic sentence.
            MnemonicString = WordList.JoinMnemonic(MnemonicWords);
        }