Ejemplo n.º 1
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;
            }
        }
Ejemplo n.º 2
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);
        }