public static async Task<MnemonicReference> ParseAsync (ChainBase chain, IBlockRepository blockRepository, Wordlist wordList, string sentence) { var w = wordList.GetWords(sentence).Length; var finalAddress = wordList.ToBits(sentence); var rawAddress = DecryptFinalAddress(finalAddress); int blockHeight; int x = DecodeBlockHeight(rawAddress, out blockHeight); var header = chain.GetBlock(blockHeight); if(header == null) throw new InvalidBrainAddressException("This block does not exists"); var block = await blockRepository.GetBlockAsync(header.HashBlock).ConfigureAwait(false); if(block == null || block.GetHash() != header.HashBlock) throw new InvalidBrainAddressException("This block does not exists"); int y1 = BitCount((int)block.Transactions.Count); int y2 = 11 * w - 1 - x - c; int y = Math.Min(y1, y2); int txIndex = Decode(Substring(rawAddress, x, y)); if(txIndex >= block.Transactions.Count) throw new InvalidBrainAddressException("The Transaction Index is out of the bound of the block"); var transaction = block.Transactions[(int)txIndex]; return Parse(chain, wordList, sentence, transaction, block); }
public Mnemonic(string mnemonic, Wordlist wordlist = null) { if (mnemonic == null) { throw new ArgumentNullException("mnemonic"); } this._Mnemonic = mnemonic.Trim(); if (wordlist == null) { wordlist = Wordlist.AutoDetect(mnemonic) ?? Wordlist.English; } string[] words = mnemonic.Split((char[])null, StringSplitOptions.RemoveEmptyEntries); this._Mnemonic = string.Join(wordlist.Space.ToString(), words); //if the sentence is not at least 12 characters or cleanly divisible by 3, it is bad! if (!CorrectWordCount(words.Length)) { throw new FormatException("Word count should be equals to 12,15,18,21 or 24"); } this._Words = words; this._WordList = wordlist; this._Indices = wordlist.ToIndices(words); }
/// <summary> /// Generate a mnemonic /// </summary> /// <param name="wordList"></param> /// <param name="entropy"></param> public Mnemonic(Wordlist wordList, byte[] entropy = null) { wordList = wordList ?? Wordlist.English; _WordList = wordList; if (entropy == null) { entropy = RandomUtils.GetBytes(32); } var i = Array.IndexOf(entArray, entropy.Length * 8); if (i == -1) { throw new ArgumentException("The length for entropy should be : " + String.Join(",", entArray), "entropy"); } int cs = csArray[i]; byte[] checksum = Hashes.SHA256(entropy); BitWriter entcsResult = new BitWriter(); entcsResult.Write(entropy); entcsResult.Write(checksum, cs); _Indices = entcsResult.ToIntegers(); _Words = _WordList.GetWords(_Indices); _Mnemonic = _WordList.GetSentence(_Indices); }
public static async Task <Wordlist> LoadWordList(string name) { if (name == null) { throw new ArgumentNullException("name"); } Wordlist result = null; lock (_LoadedLists) { _LoadedLists.TryGetValue(name, out result); } if (result != null) { return(await Task.FromResult <Wordlist>(result).ConfigureAwait(false)); } if (WordlistSource == null) { throw new InvalidOperationException("Wordlist.WordlistSource is not set, impossible to fetch word list."); } result = await WordlistSource.Load(name).ConfigureAwait(false); if (result != null) { lock (_LoadedLists) { _LoadedLists.AddOrReplace(name, result); } } return(result); }
public static MnemonicReference Parse (ChainBase chain, Wordlist wordList, string sentence, Transaction transaction, Block block) { return(Parse(chain, wordList, sentence, transaction, block.Filter(transaction.GetHash()))); }
private static int[] CreateIndicesArrayFromWords(string[] words, Wordlist wordList) { var indices = new int[words.Length]; for (int i = 0; i < words.Length; i++) { int idx = -1; if (!wordList.WordExists(words[i], out idx)) { throw new FormatException("Word " + words[i] + " is not in the wordlist for this language, cannot continue to rebuild entropy from wordlist"); } indices[i] = idx; } return(indices); }
public Mnemonic(string mnemonic, Wordlist wordlist = null) { if(mnemonic == null) throw new ArgumentNullException("mnemonic"); _Mnemonic = mnemonic.Trim(); if(wordlist == null) wordlist = Wordlist.AutoDetect(mnemonic) ?? Wordlist.English; var words = mnemonic.Split(new char[] { ' ', ' ' }, StringSplitOptions.RemoveEmptyEntries); //if the sentence is not at least 12 characters or cleanly divisible by 3, it is bad! if(!CorrectWordCount(words.Length)) { throw new FormatException("Word count should be equals to 12,15,18,21 or 24"); } _Words = words; _WordList = wordlist; _Indices = wordlist.ToIndices(words); }
/// <summary> /// Generate a mnemonic /// </summary> /// <param name="wordList"></param> /// <param name="entropy"></param> public Mnemonic(Wordlist wordList, byte[] entropy = null) { wordList = wordList ?? Wordlist.English; _WordList = wordList; if(entropy == null) entropy = RandomUtils.GetBytes(32); var i = Array.IndexOf(entArray, entropy.Length * 8); if(i == -1) throw new ArgumentException("The length for entropy should be : " + String.Join(",", entArray), "entropy"); int cs = csArray[i]; byte[] checksum = Hashes.SHA256(entropy); BitWriter entcsResult = new BitWriter(); entcsResult.Write(entropy); entcsResult.Write(checksum, cs); _Indices = entcsResult.ToIntegers(); _Words = _WordList.GetWords(_Indices); _Mnemonic = _WordList.GetSentence(_Indices); }
public static async Task <MnemonicReference> ParseAsync (ChainBase chain, IBlockRepository blockRepository, Wordlist wordList, string sentence) { var w = wordList.GetWords(sentence).Length; var finalAddress = wordList.ToBits(sentence); var rawAddress = DecryptFinalAddress(finalAddress); int blockHeight; int x = DecodeBlockHeight(rawAddress, out blockHeight); var header = chain.GetBlock(blockHeight); if (header == null) { throw new InvalidBrainAddressException("This block does not exists"); } var block = await blockRepository.GetBlockAsync(header.HashBlock).ConfigureAwait(false); if (block == null || block.GetHash() != header.HashBlock) { throw new InvalidBrainAddressException("This block does not exists"); } int y1 = BitCount((int)block.Transactions.Count); int y2 = 11 * w - 1 - x - c; int y = Math.Min(y1, y2); int txIndex = Decode(Substring(rawAddress, x, y)); if (txIndex >= block.Transactions.Count) { throw new InvalidBrainAddressException("The Transaction Index is out of the bound of the block"); } var transaction = block.Transactions[(int)txIndex]; return(Parse(chain, wordList, sentence, transaction, block)); }
public Mnemonic(string mnemonic, Wordlist wordlist = null) { if (mnemonic == null) { throw new ArgumentNullException(nameof(mnemonic)); } _Mnemonic = mnemonic.Trim(); if (wordlist == null) { wordlist = Wordlist.AutoDetect(mnemonic) ?? Wordlist.English; } var words = mnemonic.Split(new char[] { ' ', ' ' }, StringSplitOptions.RemoveEmptyEntries); //if the sentence is not at least 12 characters or cleanly divisible by 3, it is bad! if (!CorrectWordCount(words.Length)) { throw new FormatException("Word count should be 12,15,18,21 or 24"); } _Words = words; _WordList = wordlist; _Indices = wordlist.ToIndices(words); }
public int[] ToIntegers() { var array = new BitArray(this.values.ToArray()); return(Wordlist.ToIntegers(array)); }
public Mnemonic(Wordlist wordList, WordCount wordCount) : this(wordList, GenerateEntropy(wordCount)) { }
public static MnemonicReference Create (ChainBase chain, Transaction transaction, MerkleBlock merkleBlock, int txOutIndex) { var blockId = merkleBlock.Header.GetHash(); var merkleRoot = merkleBlock.PartialMerkleTree.TryGetMerkleRoot(); if (merkleRoot == null || merkleRoot.Hash != merkleBlock.Header.HashMerkleRoot) { throw new InvalidBrainAddressException("Invalid merkle block"); } if (txOutIndex >= transaction.Outputs.Count) { throw new InvalidBrainAddressException("The specified txout index is outside of the transaction bounds"); } var matchedLeaf = merkleRoot.GetLeafs().Select((node, index) => new { node, index }).FirstOrDefault(_ => _.node.Hash == transaction.GetHash()); if (matchedLeaf == null) { throw new InvalidBrainAddressException("Transaction not included in this merkle block"); } var chainedHeader = chain.GetBlock(blockId); if (chainedHeader == null) { throw new InvalidBrainAddressException("The block provided is not in the current chain"); } var blockHeight = chainedHeader.Height; var txIndex = matchedLeaf.index; var txOut = transaction.Outputs[txOutIndex]; var block = chain.GetBlock(blockId); BitArray encodedBlockHeight = EncodeBlockHeight(blockHeight); int x = encodedBlockHeight.Length; //ymin = ceiling(log(txIndex + 1, 2)) int ymin = BitCount(txIndex + 1); //zmin = ceiling(log(outputIndex + 1, 2)) int zmin = BitCount(txOutIndex + 1); //w = ceiling((x + ymin + zmin + c + 1)/11) int w = RoundTo(x + ymin + zmin + c + 1, 11) / 11; int y = 0; int z = 0; for ( ; ; w++) { int y1 = BitCount((int)merkleBlock.PartialMerkleTree.TransactionCount); int y2 = 11 * w - 1 - x - c; y = Math.Min(y1, y2); if (ymin > y) { continue; } int z1 = BitCount(transaction.Outputs.Count); int z2 = 11 * w - 1 - x - y - c; z = Math.Min(z1, z2); if (zmin > z) { continue; } break; } var cs = 11 * w - 1 - x - y - z; var checksum = CalculateChecksum(blockId, txIndex, txOutIndex, txOut.ScriptPubKey, cs); var rawAddress = Concat(encodedBlockHeight, Encode(txIndex, y), Encode(txOutIndex, z), checksum); var finalAddress = EncryptRawAddress(rawAddress); return(new MnemonicReference() { BlockHeight = blockHeight, TransactionIndex = txIndex, OutputIndex = txOutIndex, Checksum = checksum, WordIndices = Wordlist.ToIntegers(finalAddress), Output = transaction.Outputs[txOutIndex], Transaction = transaction, BlockId = blockId }); }
public static MnemonicReference Parse (ChainBase chain, Wordlist wordList, string sentence, Transaction transaction, MerkleBlock merkleBlock) { var indices = wordList.ToIndices(sentence); //Step1: Determine w = number of words in the mnemonic code int w = indices.Length; //Convert mnemonic code into finalAddress following BIP-0039 var finalAddress = Wordlist.ToBits(indices); var rawAddress = DecryptFinalAddress(finalAddress); int blockHeight = 0; var x = DecodeBlockHeight(rawAddress, out blockHeight); var header = chain.GetBlock((int)blockHeight); if (header == null) { throw new InvalidBrainAddressException("This block does not exists"); } if (header.HashBlock != merkleBlock.Header.GetHash()) { throw new InvalidBrainAddressException("The provided merkleblock do not match the block of the sentence"); } var blockId = header.HashBlock; MerkleNode root = merkleBlock.PartialMerkleTree.TryGetMerkleRoot(); if (root == null || root.Hash != header.Header.HashMerkleRoot) { throw new InvalidBrainAddressException("Invalid partial merkle tree"); } int y1 = BitCount((int)merkleBlock.PartialMerkleTree.TransactionCount); int y2 = 11 * w - 1 - x - c; int y = Math.Min(y1, y2); int txIndex = Decode(Substring(rawAddress, x, y)); var txLeaf = root.GetLeafs().Skip((int)txIndex).FirstOrDefault(); if (txLeaf == null || txLeaf.Hash != transaction.GetHash()) { throw new InvalidBrainAddressException("The transaction do not appear in the block"); } int z1 = BitCount(transaction.Outputs.Count); int z2 = 11 * w - 1 - x - y - c; int z = Math.Min(z1, z2); int outputIndex = Decode(Substring(rawAddress, x + y, z)); if (outputIndex >= transaction.Outputs.Count) { throw new InvalidBrainAddressException("The specified txout index is outside of the transaction bounds"); } var txOut = transaction.Outputs[outputIndex]; var cs = 11 * w - 1 - x - y - z; var actualChecksum = Substring(rawAddress, x + y + z, cs); var expectedChecksum = CalculateChecksum(blockId, txIndex, outputIndex, txOut.ScriptPubKey, cs); if (!actualChecksum.OfType <bool>().SequenceEqual(expectedChecksum.OfType <bool>())) { throw new InvalidBrainAddressException("Invalid checksum"); } return(new MnemonicReference() { BlockHeight = (int)blockHeight, TransactionIndex = (int)txIndex, WordIndices = indices, Checksum = actualChecksum, Output = transaction.Outputs[outputIndex], OutputIndex = (int)outputIndex, BlockId = blockId, Transaction = transaction }); }
public string ToString(Wordlist wordlist) { return wordlist.GetSentence(WordIndices); }
public static MnemonicReference Parse (ChainBase chain, Wordlist wordList, string sentence, Transaction transaction, MerkleBlock merkleBlock) { var indices = wordList.ToIndices(sentence); //Step1: Determine w = number of words in the mnemonic code int w = indices.Length; //Convert mnemonic code into finalAddress following BIP-0039 var finalAddress = Wordlist.ToBits(indices); var rawAddress = DecryptFinalAddress(finalAddress); int blockHeight = 0; var x = DecodeBlockHeight(rawAddress, out blockHeight); var header = chain.GetBlock((int)blockHeight); if(header == null) throw new InvalidBrainAddressException("This block does not exists"); if(header.HashBlock != merkleBlock.Header.GetHash()) throw new InvalidBrainAddressException("The provided merkleblock do not match the block of the sentence"); var blockId = header.HashBlock; MerkleNode root = merkleBlock.PartialMerkleTree.TryGetMerkleRoot(); if(root == null || root.Hash != header.Header.HashMerkleRoot) throw new InvalidBrainAddressException("Invalid partial merkle tree"); int y1 = BitCount((int)merkleBlock.PartialMerkleTree.TransactionCount); int y2 = 11 * w - 1 - x - c; int y = Math.Min(y1, y2); int txIndex = Decode(Substring(rawAddress, x, y)); var txLeaf = root.GetLeafs().Skip((int)txIndex).FirstOrDefault(); if(txLeaf == null || txLeaf.Hash != transaction.GetHash()) throw new InvalidBrainAddressException("The transaction do not appear in the block"); int z1 = BitCount(transaction.Outputs.Count); int z2 = 11 * w - 1 - x - y - c; int z = Math.Min(z1, z2); int outputIndex = Decode(Substring(rawAddress, x + y, z)); if(outputIndex >= transaction.Outputs.Count) throw new InvalidBrainAddressException("The specified txout index is outside of the transaction bounds"); var txOut = transaction.Outputs[outputIndex]; var cs = 11 * w - 1 - x - y - z; var actualChecksum = Substring(rawAddress, x + y + z, cs); var expectedChecksum = CalculateChecksum(blockId, txIndex, outputIndex, txOut.ScriptPubKey, cs); if(!actualChecksum.OfType<bool>().SequenceEqual(expectedChecksum.OfType<bool>())) throw new InvalidBrainAddressException("Invalid checksum"); return new MnemonicReference() { BlockHeight = (int)blockHeight, TransactionIndex = (int)txIndex, WordIndices = indices, Checksum = actualChecksum, Output = transaction.Outputs[outputIndex], OutputIndex = (int)outputIndex, BlockId = blockId, Transaction = transaction }; }
public static MnemonicReference Parse (ChainBase chain, Wordlist wordList, string sentence, Transaction transaction, Block block) { return Parse(chain, wordList, sentence, transaction, block.Filter(transaction.GetHash())); }
public string ToString(Wordlist wordlist) { return(wordlist.GetSentence(WordIndices)); }
/// <summary> /// Generate a mnemonic /// </summary> /// <param name="wordList"></param> /// <param name="entropy"></param> public Mnemonic(Wordlist wordList, byte[] entropy = null) { wordList = wordList ?? Wordlist.English; _WordList = wordList; if (entropy == null) { entropy = RandomUtils.GetBytes(32); } byte[] allChecksumBytes = Hashes.SHA256(entropy); //sha256 the entropy bytes to get all the checksum bits int numberOfChecksumBits = (entropy.Length * 8) / 32; //number of bits to take from the checksum bits, varies on entropy size as per spec BitArray entropyConcatChecksumBits = new BitArray((entropy.Length * 8) + numberOfChecksumBits); allChecksumBytes = SwapEndianBytes(allChecksumBytes); //yet another endianess change of some different bytes to match the test vectors..... entropy = SwapEndianBytes(entropy); int index = 0; foreach (bool b in new BitArray(entropy)) { entropyConcatChecksumBits.Set(index, b); index++; } /*sooooo I'm doing below for future proofing....I know right now we are using up to 256 bits entropy in real world implementation and therefore max 8 bits (1 byte) of checksum....buuuut I figgure it's easy enough * to accomodate more entropy by chaining more checksum bytes so maximum 256 * 32 = 8192 theoretical maximum entropy (plus CS).*/ List <byte> checksumBytesToUse = new List <byte>(); double byteCount = Math.Ceiling((double)numberOfChecksumBits / 8); for (int i = 0; i < byteCount; i++) { checksumBytesToUse.Add(allChecksumBytes[i]); } BitArray ba = new BitArray(checksumBytesToUse.ToArray()); //add checksum bits for (int i = 0; i < numberOfChecksumBits; i++) { entropyConcatChecksumBits.Set(index, ba.Get(i)); index++; } List <int> wordIndexList = new List <int>(); //yea....loop in a loop....what of it!!! Outer loop is segregating bits into 11 bit groups and the inner loop is processing the 11 bits before sending them to be encoded as an int. for (int i = 0; i < entropyConcatChecksumBits.Length; i = i + 11) { BitArray toInt = new BitArray(11); for (int i2 = 0; i2 < 11 && i < entropyConcatChecksumBits.Length; i2++) { toInt.Set(i2, entropyConcatChecksumBits.Get(i + i2)); } wordIndexList.Add(ToInt(toInt)); //adding encoded int to word index } _Indices = wordIndexList.ToArray(); _Words = new string[_Indices.Length]; StringBuilder builder = new StringBuilder(); for (int i = 0; i < _Indices.Length; i++) { var word = _WordList.GetWordAtIndex(_Indices[i]); _Words[i] = word; builder.Append(word); if (i + 1 < _Indices.Length) { builder.Append(_WordList.Space); } } _Mnemonic = builder.ToString(); }