/// <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; } }
/// <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); }