/// <summary> /// For demo / debugging purposes, we return the pairs of hashes used to verify the audit proof. /// </summary> public static List <Tuple <MerkleHash, MerkleHash> > AuditHashPairs(MerkleHash leafHash, List <MerkleProofHash> auditTrail) { Contract(() => auditTrail.Count > 0, "Audit trail cannot be empty."); var auditPairs = new List <Tuple <MerkleHash, MerkleHash> >(); var testHash = leafHash; // TODO: Inefficient - compute hashes directly. foreach (var auditHash in auditTrail) { switch (auditHash.Direction) { case MerkleProofHash.Branch.Left: auditPairs.Add(new Tuple <MerkleHash, MerkleHash>(testHash, auditHash.Hash)); testHash = MerkleHash.Create(testHash.Value.Concat(auditHash.Hash.Value).ToArray()); break; case MerkleProofHash.Branch.Right: auditPairs.Add(new Tuple <MerkleHash, MerkleHash>(auditHash.Hash, testHash)); testHash = MerkleHash.Create(auditHash.Hash.Value.Concat(testHash.Value).ToArray()); break; } } return(auditPairs); }
private void BuildMerkleTree() { merkleTree = new MerkleTree(); foreach (var txn in Transactions) { merkleTree.AppendLeaf(MerkleHash.Create(txn.CalculateTransactionHash())); } merkleTree.BuildTree(); }
/// <summary> /// Verify that if we walk up the tree from a particular leaf, we encounter the expected root hash. /// </summary> public static bool VerifyAudit(MerkleHash rootHash, MerkleHash leafHash, List <MerkleProofHash> auditTrail) { Contract(() => auditTrail.Count > 0, "Audit trail cannot be empty."); var testHash = leafHash; // TODO: Inefficient - compute hashes directly. foreach (var auditHash in auditTrail) { testHash = auditHash.Direction == MerkleProofHash.Branch.Left ? MerkleHash.Create(testHash.Value.Concat(auditHash.Hash.Value).ToArray()) : MerkleHash.Create(auditHash.Hash.Value.Concat(testHash.Value).ToArray()); } return(rootHash == testHash); }
protected void ComputeHash() { // Repeat the left node if the right node doesn't exist. // This process breaks the case of doing a consistency check on 3 leaves when there are only 3 leaves in the tree. //MerkleHash rightHash = RightNode == null ? LeftNode.Hash : RightNode.Hash; //Hash = MerkleHash.Create(LeftNode.Hash.Value.Concat(rightHash.Value).ToArray()); // Alternativately, do not repeat the left node, but carry the left node's hash up. // This process does not break the edge case described above. // We're implementing this version because the consistency check unit tests pass when we don't simulate // a right-hand node. Hash = RightNode == null ? LeftNode.Hash : //MerkleHash.Create(LeftNode.Hash.Value.Concat(LeftNode.Hash.Value).ToArray()) : MerkleHash.Create(LeftNode.Hash.Value.Concat(RightNode.Hash.Value).ToArray()); Parent?.ComputeHash(); // Recurse, because out hash has changed. }
/// <summary> /// Verifies the hash for this node against the computed hash for our child nodes. /// If we don't have any children, the return is always true because we have nothing to verify against. /// </summary> public bool VerifyHash() { if (LeftNode == null && RightNode == null) { return(true); } if (RightNode == null) { return(Hash.Equals(LeftNode.Hash)); } MerkleTree.Contract(() => LeftNode != null, "Left branch must be a node if right branch is a node."); var leftRightHash = MerkleHash.Create(LeftNode.Hash, RightNode.Hash); return(Hash.Equals(leftRightHash)); }
public static MerkleHash ComputeHash(MerkleHash left, MerkleHash right) { return(MerkleHash.Create(left.Value.Concat(right.Value).ToArray())); }
public MerkleHash ComputeHash(byte[] buffer) { Hash = MerkleHash.Create(buffer); return(Hash); }