public function decrypt(string $response, string $publicKey = null, string $nonce = null) : string
    {
        $version = static::getVersion($response);
        if ($version === 2) {
            if (\strlen($response) < 236) {
                throw new InvalidArgumentException(sprintf("Message is %d bytes, however 236+ were expected", \strlen($response)));
            }

            $nonce = \substr($response, 4, 24);

            // Determine the payload size sans the 64 byte checksum at the end
            $payload = \substr($response, 0, \strlen($response) - 64);
            $checksum = \substr($response, -64);

            // Verify the checksum to ensure the headers haven't been tampered with
            if (\sodium_memcmp($checksum, \sodium_crypto_generichash($payload, $nonce, 64)) !== 0) {
                throw new InvalidChecksumException("Calculated checksum differs from the checksum associated with the message.");
            }

            $publicKey = self::getPublicKeyFromResponse($response);
            $signature = \substr($payload, -64);
            $payload = \substr($payload, 0, -64);
            $sigPubKey = self::getSigningPublicKeyFromResponse($response);
            $payload = \substr($payload, 0, -32);
            $body = \substr($payload, 60, \strlen($payload));

            $decryptedPayload = $this->decryptBody($body, $publicKey, $nonce);

            if (!$this->isSignatureValid($decryptedPayload, $signature, $sigPubKey)) {
                throw new InvalidSignatureException('The message signature is not valid.');
            }

            return $decryptedPayload;
        }

        if ($nonce === null) {
            throw new InvalidArgumentException('Nonce is required to decrypt v1 requests.');
        }

        if ($publicKey === null || \strlen($publicKey) !== SODIUM_CRYPTO_BOX_PUBLICKEYBYTES) {
            throw new InvalidArgumentException(sprintf("Public key should be %d bytes.", SODIUM_CRYPTO_BOX_PUBLICKEYBYTES));
        }

        return $this->decryptBody($response, $publicKey, $nonce);
    }