示例#1
0
        private static string[] GetWordList(WordListLanguage wordList)
        {
            var wordLists = new Dictionary <string, string>
            {
                { WordListLanguage.ChineseSimplified.ToString(), "chinese_simplified" },
                { WordListLanguage.ChineseTraditional.ToString(), "chinese_traditional" },
                { WordListLanguage.English.ToString(), "english" },
                { WordListLanguage.French.ToString(), "french" },
                { WordListLanguage.Italian.ToString(), "italian" },
                { WordListLanguage.Japanese.ToString(), "japanese" },
                { WordListLanguage.Korean.ToString(), "korean" },
                { WordListLanguage.Spanish.ToString(), "spanish" }
            };

            var wordListFile = wordLists[wordList.ToString()];

            var wordListFileStream = Assembly.GetAssembly(typeof(WordListLanguage))
                                     .GetManifestResourceStream($"{typeof(WordListLanguage).Namespace}.Words.{wordListFile}.txt");

            var words = new List <string>();

            using (StreamReader reader = new StreamReader(wordListFileStream ?? throw new InvalidOperationException($"could not load word list for {wordList}")))
            {
                while (reader.Peek() >= 0)
                {
                    words.Add(reader.ReadLine());
                }
            }

            var wordListResults = words.ToArray();

            return(wordListResults);
        }
示例#2
0
        public static string EntropyToMnemonic(string entropy, WordListLanguage wordListType)
        {
            var wordList = GetWordList(wordListType);

            //How can I do this more efficiently, the multiple substrings I don't like...
            var entropyBytes = Enumerable.Range(0, entropy.Length / 2)
                               .Select(x => Convert.ToByte(entropy.Substring(x * 2, 2), 16))
                               .ToArray();

            CheckValidEntropy(entropyBytes);

            var entropyBits  = BytesToBinary(entropyBytes);
            var checksumBits = DeriveChecksumBits(entropyBytes);

            var bits = entropyBits + checksumBits;

            var chunks = Regex.Matches(bits, "(.{1,11})")
                         .OfType <Match>()
                         .Select(m => m.Groups[0].Value)
                         .ToArray();

            var words = chunks.Select(binary =>
            {
                var index = Convert.ToInt32(binary, 2);
                return(wordList[index]);
            });

            var joinedText = String.Join((wordListType == WordListLanguage.Japanese ? "\u3000" : " "), words);

            return(joinedText);
        }
示例#3
0
        private (string entropy, string seedHex, string mnemonic) TestVector(WordListLanguage wordList, string password,
                                                                             string entropy, string mnemonic, string seedHex)
        {
            var entropyResult  = Mnemonic.MnemonicToEntropy(mnemonic, wordList);
            var seedResult     = Mnemonic.MnemonicToSeedHex(mnemonic, password);
            var mnemonicResult = Mnemonic.EntropyToMnemonic(entropy, wordList);

            return(entropyResult, seedResult, mnemonicResult);
        }
示例#4
0
        public static string MnemonicToEntropy(string mnemonic, WordListLanguage wordListType)
        {
            var wordList = GetWordList(wordListType);
            var words    = mnemonic.Normalize(NormalizationForm.FormKD).Split(new[] { ' ' },
                                                                              StringSplitOptions.RemoveEmptyEntries);

            if (words.Length % 3 != 0)
            {
                throw new ArgumentException(InvalidMnemonic);
            }

            var bits = string.Join("", words.Select(word =>
            {
                var index = Array.IndexOf(wordList, word);
                if (index == -1)
                {
                    throw new ArgumentException(InvalidMnemonic);
                }

                return(LeftPad(Convert.ToString(index, 2), "0", 11));
            }));

            // split the binary string into ENT/CS
            var dividerIndex = (int)Math.Floor((double)bits.Length / 33) * 32;
            var entropyBits  = bits.Substring(0, dividerIndex);
            var checksumBits = bits.Substring(dividerIndex);

            // calculate the checksum and compare
            var entropyBytesMatch = Regex.Matches(entropyBits, "(.{1,8})")
                                    .OfType <Match>()
                                    .Select(m => m.Groups[0].Value)
                                    .ToArray();

            var entropyBytes = entropyBytesMatch
                               .Select(bytes => Convert.ToByte(bytes, 2)).ToArray();

            CheckValidEntropy(entropyBytes);


            var newChecksum = DeriveChecksumBits(entropyBytes);

            if (newChecksum != checksumBits)
            {
                throw new Exception(InvalidChecksum);
            }

            var result = BitConverter
                         .ToString(entropyBytes)
                         .Replace("-", "")
                         .ToLower();

            return(result);
        }
示例#5
0
 public static bool ValidateMnemonic(string mnemonic, WordListLanguage wordList)
 {
     try
     {
         MnemonicToEntropy(mnemonic, wordList);
     }
     catch
     {
         return(false);
     }
     return(true);
 }
示例#6
0
        public static string GenerateMnemonic(int strength, WordListLanguage wordListType)
        {
            if (strength % 32 != 0)
            {
                throw new NotSupportedException(InvalidEntropy);
            }

            RNGCryptoServiceProvider rngCryptoServiceProvider = new RNGCryptoServiceProvider();

            byte[] buffer = new byte[strength / 8];
            rngCryptoServiceProvider.GetBytes(buffer);

            var entropyHex = BitConverter.ToString(buffer).Replace("-", "");

            return(EntropyToMnemonic(entropyHex, wordListType));
        }
示例#7
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);
        }
示例#8
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);
        }
示例#9
0
 public static HDAccountDerivation Create(WordListLanguage language = WordListLanguage.English)
 {
     return(new HDAccountDerivation(new MnemonicPhrase(language)));
 }
示例#10
0
文件: WordList.cs 项目: zutobg/Meadow
 /// <summary>
 /// Initializes a word list to represent the given language, with the given words.
 /// </summary>
 /// <param name="language">The language which this word list will represent.</param>
 /// <param name="words">The words which constitute the word list to initialize.</param>
 private WordList(WordListLanguage language, string words) : this(language)
 {
     // Split our words out
     Words = words.Split(new string[] { "\r\n", "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries);
 }
示例#11
0
文件: WordList.cs 项目: zutobg/Meadow
 /// <summary>
 /// Initializes a word list to represent the given language, with the given words.
 /// </summary>
 /// <param name="language">The language which this word list will represent.</param>
 /// <param name="words">The words which constitute the word list to initialize.</param>
 private WordList(WordListLanguage language, string[] words) : this(language)
 {
     // Set our words (normalized).
     Words = words.Select(s => MnemonicPhrase.NormalizeString(s)).ToArray();
 }
示例#12
0
文件: WordList.cs 项目: zutobg/Meadow
 /// <summary>
 /// Base constructor to initialize a word list to represent the given language.
 /// </summary>
 /// <param name="language">The language which this word list will represent.</param>
 private WordList(WordListLanguage language)
 {
     // Set our language
     Language = language;
 }
示例#13
0
文件: WordList.cs 项目: zutobg/Meadow
        /// <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);
            }
        }
示例#14
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);
        }