Esempio n. 1
0
        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);
            }
        }
Esempio n. 2
0
        /// <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);
        }