public MerkleTree(MerkleProof proof) { if (proof == null) { throw new ArgumentNullException(nameof(proof)); } Root = CreateTree(proof, DepthNeeded(proof.LeafCount)); CheckForLeftovers(proof.ProofHashes, nameof(proof.ProofHashes)); CheckForLeftovers(proof.IncludedHashes, nameof(proof.IncludedHashes)); CheckForLeftovers(proof.Flags, nameof(proof.Flags)); }
MerkleNode CreateTree(MerkleProof proof, int depth) { if (proof.Flags.Dequeue()) { return(new(proof.ProofHashes.Dequeue())); } if (depth == 1) { return(new(proof.IncludedHashes.Dequeue())); } var left = CreateTree(proof, depth - 1); var right = proof.Flags.Any() ? CreateTree(proof, depth - 1) : null; return(new(GetParentHash(left, right), left, right)); }
void AddToProof(MerkleNode?node, MerkleProof proof, HashSet <string> includedSet) { if (node != null) { if (ContainsAny(node, includedSet)) { proof.Flags.Enqueue(false); if (node.IsLeaf) { proof.IncludedHashes.Enqueue(node.Hash); } AddToProof(node.Left, proof, includedSet); AddToProof(node.Right, proof, includedSet); } else { proof.Flags.Enqueue(true); proof.ProofHashes.Enqueue(node.Hash); } } }
public MerkleProof CreateProof(IEnumerable <byte[]> includedHashes) { if (includedHashes == null) { throw new ArgumentNullException(nameof(includedHashes)); } var includedSet = new HashSet <string>(includedHashes.Select(b => b.ToHex())); if (!includedSet.Any()) { throw new ArgumentException("Included hashes must not be empty", nameof(includedHashes)); } var proof = new MerkleProof(LeafCount); AddToProof(Root, proof, includedSet); if (proof.IncludedHashes.Count != includedSet.Count) { throw new InvalidOperationException("Not all included hashes were found in the tree"); } return(proof); }