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