public async Task<BlobFingerprint> GetFingerprintAsync(Stream stream, CancellationToken cancellationToken)
        {
            using (var sha3 = new Keccak())
            using (var sha256 = SHA256.Create())
            using (var md5 = MD5.Create())
            {
                var buffers = new[] { AllocateBuffer(), AllocateBuffer() };
                var index = 0;

                var totalLength = 0L;

                var readTask = stream.ReadAsync(buffers[index], 0, buffers[index].Length, cancellationToken);

                for (;;)
                {
                    var length = await readTask.ConfigureAwait(false);

                    if (length < 1)
                        break;

                    var buffer = buffers[index];

                    if (++index >= buffers.Length)
                        index = 0;

                    readTask = stream.ReadAsync(buffers[index], 0, buffers[index].Length, cancellationToken);

                    totalLength += length;

                    sha3.TransformBlock(buffer, 0, length, null, 0);

                    sha256.TransformBlock(buffer, 0, length, null, 0);

                    md5.TransformBlock(buffer, 0, length, null, 0);
                }

                sha3.TransformFinalBlock(buffers[0], 0, 0);

                sha256.TransformFinalBlock(buffers[0], 0, 0);

                md5.TransformFinalBlock(buffers[0], 0, 0);

                foreach (var buffer in buffers)
                    FreeBuffer(buffer);

                var fingerprint = new BlobFingerprint(totalLength, sha3.Hash, sha256.Hash, md5.Hash);

                return fingerprint;
            }
        }
        public async Task <BlobFingerprint> GetFingerprintAsync(Stream stream, CancellationToken cancellationToken)
        {
            using (var sha3 = new Keccak())
                using (var sha256 = SHA256.Create())
                    using (var md5 = MD5.Create())
                    {
                        var buffers = new[] { AllocateBuffer(), AllocateBuffer() };
                        var index   = 0;

                        var totalLength = 0L;

                        var readTask = stream.ReadAsync(buffers[index], 0, buffers[index].Length, cancellationToken);

                        for (; ;)
                        {
                            var length = await readTask.ConfigureAwait(false);

                            if (length < 1)
                            {
                                break;
                            }

                            var buffer = buffers[index];

                            if (++index >= buffers.Length)
                            {
                                index = 0;
                            }

                            readTask = stream.ReadAsync(buffers[index], 0, buffers[index].Length, cancellationToken);

                            totalLength += length;

                            sha3.TransformBlock(buffer, 0, length, buffer, 0);

                            sha256.TransformBlock(buffer, 0, length, buffer, 0);

                            md5.TransformBlock(buffer, 0, length, buffer, 0);
                        }

                        sha3.TransformFinalBlock(buffers[0], 0, 0);

                        sha256.TransformFinalBlock(buffers[0], 0, 0);

                        md5.TransformFinalBlock(buffers[0], 0, 0);

                        foreach (var buffer in buffers)
                        {
                            FreeBuffer(buffer);
                        }

                        var fingerprint = new BlobFingerprint(totalLength, sha3.Hash, sha256.Hash, md5.Hash);

                        return(fingerprint);
                    }
        }