/// <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) { MerkleHash testHash = leafHash; // TODO: Inefficient - compute hashes directly. foreach (MerkleProofHash 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."); MerkleHash leftRightHash = MerkleHash.Create(LeftNode.Hash, RightNode.Hash); return(Hash.Equals(leftRightHash)); }
/* * /// <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>>(); * MerkleHash testHash = leafHash; * * // TODO: Inefficient - compute hashes directly. * foreach (MerkleProofHash 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; * } * * public static bool VerifyConsistency(MerkleHash oldRootHash, List<MerkleProofHash> proof) * { * MerkleHash hash, lhash, rhash; * * if (proof.Count > 1) * { * lhash = proof[proof.Count - 2].Hash; * int hidx = proof.Count - 1; * hash = rhash = MerkleTree.ComputeHash(lhash, proof[hidx].Hash); * hidx -= 2; * * // foreach (var nextHashNode in proof.Skip(1)) * while (hidx >= 0) * { * lhash = proof[hidx].Hash; * hash = rhash = MerkleTree.ComputeHash(lhash, rhash); * * --hidx; * } * } * else * { * hash = proof[0].Hash; * } * * return hash == oldRootHash; * } */ public static MerkleHash ComputeHash(MerkleHash left, MerkleHash right) { return(MerkleHash.Create(left.Value.Concat(right.Value).ToArray())); }
public static EventMerkleNode Create(string s) { return(new EventMerkleNode(MerkleHash.Create(s))); }
public MerkleHash ComputeHash(byte[] buffer) { Hash = MerkleHash.Create(buffer); return(Hash); }