private void BuildAuditTrail(List <MerkleProofHash> auditTrail, MerkleNode?parent, MerkleNode child) { if (parent != null) { child.Verify(nameof(child)).Assert(x => x.Parent == parent, "Parent of child is not expected parent."); var nextChild = parent.LeftNode == child ? parent.RightNode : parent.LeftNode; var direction = parent.LeftNode == child ? MerkleProofHash.Branch.Left : MerkleProofHash.Branch.Right; // For the last leaf, the right node may not exist. In that case, we ignore it because it's // the hash we are given to verify. if (nextChild != null) { auditTrail.Add(new MerkleProofHash(nextChild.Hash, direction)); } BuildAuditTrail(auditTrail, child.Parent !.Parent, child.Parent); } }
/// <summary> /// Verifies ordering and consistency of the first n leaves, such that we reach the expected sub-root. /// This verifies that the prior data has not been changed and that leaf order has been preserved. /// m is the number of leaves for which to do a consistency check. /// </summary> public List <MerkleProofHash> ConsistencyProof(int m) { // Rule 1: // Find the leftmost node of the tree from which we can start our consistency proof. // Set k, the number of leaves for this node. List <MerkleProofHash> hashNodes = new List <MerkleProofHash>(); int idx = (int)Math.Log(m, 2); // Get the leftmost node. MerkleNode node = _leaves[0]; // Traverse up the tree until we get to the node specified by idx. while (idx > 0) { node = node.Parent !; --idx; } int k = node !.Leaves().Count(); hashNodes.Add(new MerkleProofHash(node.Hash, MerkleProofHash.Branch.OldRoot)); if (m == k) { // Continue with Rule 3 -- the remainder is the audit proof } else { // Rule 2: // Set the initial sibling node (SN) to the sibling of the node acquired by Rule 1. // if m-k == # of SN's leaves, concatenate the hash of the sibling SN and exit Rule 2, as this represents the hash of the old root. // if m - k < # of SN's leaves, set SN to SN's left child node and repeat Rule 2. // sibling node: MerkleNode sn = node.Parent !.RightNode !; bool traverseTree = true; while (traverseTree) { sn.Verify(nameof(sn)).Assert(x => x != null, "Sibling node must exist because m != k"); int sncount = sn.Leaves().Count(); if (m - k == sncount) { hashNodes.Add(new MerkleProofHash(sn.Hash, MerkleProofHash.Branch.OldRoot)); break; } if (m - k > sncount) { hashNodes.Add(new MerkleProofHash(sn.Hash, MerkleProofHash.Branch.OldRoot)); sn = sn.Parent !.RightNode !; k += sncount; } else // (m - k < sncount) { sn = sn.LeftNode !; } } } // Rule 3: Apply ConsistencyAuditProof below. return(hashNodes); }