final private static function streamEncrypt(
        ReadOnlyFile $input,
        MutableFile $output,
        EncryptionKey $encKey,
        string $nonce,
        string $mac,
        Config $config
    ): int {
        $initHash = $input->getHash();
        // Begin the streaming decryption
        $size = $input->getSize();
        $written = 0;
        while ($input->remainingBytes() > 0) {
            $read = $input->readBytes(
                ($input->getPos() + (int) $config->BUFFER) > $size
                    ? ($size - $input->getPos())
                    : (int) $config->BUFFER
            );

            $encrypted = \sodium_crypto_stream_xor(
                $read,
                (string) $nonce,
                $encKey->getRawKeyMaterial()
            );
            \sodium_crypto_generichash_update($mac, $encrypted);
            $written += $output->writeBytes($encrypted);
            \sodium_increment($nonce);
        }
        if (\is_string($nonce)) {
            \sodium_memzero($nonce);
        }

        // Check that our input file was not modified before we MAC it
        if (!\hash_equals($input->getHash(), $initHash)) {
            // @codeCoverageIgnoreStart
            throw new FileModified(
                'Read-only file has been modified since it was opened for reading'
            );
            // @codeCoverageIgnoreEnd
        }
        $written += $output->writeBytes(
            \sodium_crypto_generichash_final($mac, (int) $config->MAC_SIZE),
            (int) $config->MAC_SIZE
        );
        return $written;
    }