/// <summary> /// Verifies ordering and consistency of the first n leaves, such that we reach the expected subroot. /// 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 = RootNode.Leaves().FirstOrDefault(leaf => true); // 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) { Contract(() => sn != 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); }