/// <summary> /// Builds merkle tree. /// </summary> /// <remarks>To get a better understanding of merkle trees check: http://www.youtube.com/watch?v=gUwXCt1qkBU#t=09m09s </remarks> /// <param name="hashList"></param> /// <returns></returns> public static IList<byte[]> Build(List<byte[]> hashList) { // The Merkle root is based on a tree of hashes calculated from the transactions: // // root // /\ // / \ // A B // / \ / \ // t1 t2 t3 t4 // // The tree is represented as a list: t1,t2,t3,t4,A,B,root where each entry is a hash. // // The hashing algorithm is double SHA-256. The leaves are a hash of the serialized contents of the // transaction. The interior nodes are hashes of the concentration of the two child hashes. // // This structure allows the creation of proof that a transaction was included into a block without having to // provide the full block contents. Instead, you can provide only a Merkle branch. For example to prove tx2 was // in a block you can just provide tx2, the hash(tx1) and B. Now the other party has everything they need to // derive the root, which can be checked against the block header. These proofs aren't used right now but // will be helpful later when we want to download partial block contents. // // Note that if the number of transactions is not even the last tx is repeated to make it so (see // tx3 above). A tree with 5 transactions would look like this: // // root // / \ // 1 \ // / \ \ // 2 3 4 // / \ / \ / \ // t1 t2 t3 t4 t5 t5 var tree = new List<byte[]>(); // Start by adding all the hashes of the transactions as leaves of the tree. foreach (var item in hashList) { var hash = new Sha256Hash(item.DoubleDigest().ReverseBytes()); tree.Add(hash.Bytes); } var levelOffset = 0; // Offset in the list where the currently processed level starts. // Step through each level, stopping when we reach the root (levelSize == 1). for (var levelSize = hashList.Count; levelSize > 1; levelSize = (levelSize + 1) / 2) { // For each pair of nodes on that level: for (var left = 0; left < levelSize; left += 2) { // The right hand node can be the same as the left hand, in the case where we don't have enough transactions. var right = Math.Min(left + 1, levelSize - 1); var leftBytes = tree[levelOffset + left].ReverseBytes(); var rightBytes = tree[levelOffset + right].ReverseBytes(); tree.Add(Utils.DoubleDigestTwoBuffers(leftBytes, 0, 32, rightBytes, 0, 32).ReverseBytes()); } // Move to the next level. levelOffset += levelSize; } return tree; }
/// <summary> /// Builds merkle tree. /// </summary> /// <remarks>To get a better understanding of merkle trees check: http://www.youtube.com/watch?v=gUwXCt1qkBU#t=09m09s </remarks> /// <param name="hashList"></param> /// <returns></returns> public static IList <byte[]> Build(List <byte[]> hashList) { // The Merkle root is based on a tree of hashes calculated from the transactions: // // root // /\ // / \ // A B // / \ / \ // t1 t2 t3 t4 // // The tree is represented as a list: t1,t2,t3,t4,A,B,root where each entry is a hash. // // The hashing algorithm is double SHA-256. The leaves are a hash of the serialized contents of the // transaction. The interior nodes are hashes of the concentration of the two child hashes. // // This structure allows the creation of proof that a transaction was included into a block without having to // provide the full block contents. Instead, you can provide only a Merkle branch. For example to prove tx2 was // in a block you can just provide tx2, the hash(tx1) and B. Now the other party has everything they need to // derive the root, which can be checked against the block header. These proofs aren't used right now but // will be helpful later when we want to download partial block contents. // // Note that if the number of transactions is not even the last tx is repeated to make it so (see // tx3 above). A tree with 5 transactions would look like this: // // root // / \ // 1 \ // / \ \ // 2 3 4 // / \ / \ / \ // t1 t2 t3 t4 t5 t5 var tree = new List <byte[]>(); // Start by adding all the hashes of the transactions as leaves of the tree. foreach (var item in hashList) { var hash = new Sha256Hash(item.DoubleDigest().ReverseBytes()); tree.Add(hash.Bytes); } var levelOffset = 0; // Offset in the list where the currently processed level starts. // Step through each level, stopping when we reach the root (levelSize == 1). for (var levelSize = hashList.Count; levelSize > 1; levelSize = (levelSize + 1) / 2) { // For each pair of nodes on that level: for (var left = 0; left < levelSize; left += 2) { // The right hand node can be the same as the left hand, in the case where we don't have enough transactions. var right = Math.Min(left + 1, levelSize - 1); var leftBytes = tree[levelOffset + left].ReverseBytes(); var rightBytes = tree[levelOffset + right].ReverseBytes(); tree.Add(Utils.DoubleDigestTwoBuffers(leftBytes, 0, 32, rightBytes, 0, 32).ReverseBytes()); } // Move to the next level. levelOffset += levelSize; } return(tree); }