Beispiel #1
0
        public IntegrityResult VerifyInclusion(byte[] leafHash, ulong leafIndex, byte[][] proof, SignedTreeHead head)
        {
            if (head.TreeSize <= leafIndex)
            {
                throw new ArgumentOutOfRangeException($"Provided STH is for a tree that is smaller than the leaf index. Tree size: {head.TreeSize} Leaf index: {leafIndex}", nameof(head));
            }

            if (head.TreeSize < 0)
            {
                throw new ArgumentOutOfRangeException($"Negative tree size: {head.TreeSize}", nameof(head));
            }

            if (leafIndex < 0)
            {
                throw new ArgumentOutOfRangeException($"Negative leaf index: {leafIndex}", nameof(leafIndex));
            }

            ulong nodeIndex      = leafIndex;
            var   calculatedHash = leafHash;
            var   lastNode       = head.TreeSize - 1;
            var   queue          = new Queue <byte[]>(proof);

            while (lastNode > 0)
            {
                if (queue.Count == 0)
                {
                    return(IntegrityResult.ProofTooShort());
                }

                if ((nodeIndex & 1) != 0)
                {
                    var auditHash = queue.Dequeue();
                    calculatedHash = _hasher.HashNode(auditHash, calculatedHash);
                }
                else if (nodeIndex < lastNode)
                {
                    var audit_hash = queue.Dequeue();
                    calculatedHash = _hasher.HashNode(calculatedHash, audit_hash);
                }

                nodeIndex /= 2;
                lastNode  /= 2;
            }

            if (queue.Count != 0)
            {
                return(IntegrityResult.ProofTooLong());

                throw new MerkleTreeException($"Proof too long: left with {queue.Count} hashes.");
            }

            if (calculatedHash.SequenceEqual(head.Hash))
            {
                return(IntegrityResult.Succeeded());
            }

            return(IntegrityResult.HashMismatch(head.Hash, calculatedHash));
        }
Beispiel #2
0
        public IntegrityResult VerifyConsistency(ulong oldSize, ulong newSize, byte[] oldRoot, byte[] newRoot, byte[][] proof)
        {
            if (oldSize < 0)
            {
                throw new ArgumentOutOfRangeException("Negative tree size", nameof(oldSize));
            }

            if (newSize < 0)
            {
                throw new ArgumentOutOfRangeException("Negative tree size", nameof(newSize));
            }

            if (oldSize > newSize)
            {
                throw new ArgumentOutOfRangeException($"Older tree has bigger size ({oldSize} vs {newSize}), did you supply inputs in the wrong order?", nameof(oldSize));
            }

            if (oldSize == newSize)
            {
                if (oldRoot.SequenceEqual(newRoot))
                {
                    if (proof.Length != 0)
                    {
                        _logger.LogWarning("Trees are identical, ignoring proof");
                    }

                    return(IntegrityResult.Succeeded());
                }
                else
                {
                    return(IntegrityResult.DifferentHashSameSize());
                }
            }

            if (oldSize == 0)
            {
                if (proof.Length != 0)
                {
                    return(IntegrityResult.ProofTooLong());
                }

                return(IntegrityResult.Succeeded());
            }

            var node     = oldSize - 1;
            var lastNode = newSize - 1;

            while ((node & 1) != 0)
            {
                node     /= 2;
                lastNode /= 2;
            }

            var proofQueue = new Queue <byte[]>(proof);

            while (proofQueue.Count != 0)
            {
                byte[] p;

                byte[] computedOldHash;
                byte[] computedNewHash;
                byte[] nextHode;
                if (node != 0)
                {
                    if (!proofQueue.TryDequeue(out p !))
                    {
                        return(IntegrityResult.ProofTooShort());
                    }

                    computedNewHash = computedOldHash = p;
                }
                else
                {
                    computedNewHash = computedOldHash = oldRoot;
                }

                while (node != 0)
                {
                    if ((node & 1) != 0)
                    {
                        if (!proofQueue.TryDequeue(out p !))
                        {
                            return(IntegrityResult.ProofTooShort());
                        }

                        nextHode        = p;
                        computedOldHash = _hasher.HashNode(nextHode, computedOldHash);
                        computedNewHash = _hasher.HashNode(nextHode, computedNewHash);
                    }
                    else if (node < lastNode)
                    {
                        if (!proofQueue.TryDequeue(out p !))
                        {
                            return(IntegrityResult.ProofTooShort());
                        }

                        computedNewHash = _hasher.HashNode(computedNewHash, p);
                    }

                    node     /= 2;
                    lastNode /= 2;
                }

                while (lastNode != 0)
                {
                    if (!proofQueue.TryDequeue(out p !))
                    {
                        return(IntegrityResult.ProofTooShort());
                    }

                    computedNewHash = _hasher.HashNode(computedNewHash, p);
                    lastNode       /= 2;
                }

                if (!computedNewHash.SequenceEqual(newRoot))
                {
                    return(IntegrityResult.HashMismatch(newRoot, computedNewHash));
                }
                else if (!computedOldHash.SequenceEqual(oldRoot))
                {
                    return(IntegrityResult.HashMismatch(oldRoot, computedOldHash));
                }
            }

            if (proofQueue.Count > 0)
            {
                return(IntegrityResult.ProofTooLong());
            }

            return(IntegrityResult.Succeeded());
        }