verify_file_signature

The timeline below displays how wordpress function verify_file_signature has changed across different WordPress versions. If a version is not listed, refer to the next available version below.

WordPress Version: 6.4

/**
 * Verifies the contents of a file against its ED25519 signature.
 *
 * @since 5.2.0
 *
 * @param string       $filename            The file to validate.
 * @param string|array $signatures          A Signature provided for the file.
 * @param string|false $filename_for_errors Optional. A friendly filename for errors.
 * @return bool|WP_Error True on success, false if verification not attempted,
 *                       or WP_Error describing an error condition.
 */
function verify_file_signature($filename, $signatures, $filename_for_errors = false)
{
    if (!$filename_for_errors) {
        $filename_for_errors = wp_basename($filename);
    }
    // Check we can process signatures.
    if (!function_exists('sodium_crypto_sign_verify_detached') || !in_array('sha384', array_map('strtolower', hash_algos()), true)) {
        return new WP_Error('signature_verification_unsupported', sprintf(
            /* translators: %s: The filename of the package. */
            __('The authenticity of %s could not be verified as signature verification is unavailable on this system.'),
            '<span class="code">' . esc_html($filename_for_errors) . '</span>'
        ), (!function_exists('sodium_crypto_sign_verify_detached')) ? 'sodium_crypto_sign_verify_detached' : 'sha384');
    }
    // Check for an edge-case affecting PHP Maths abilities.
    if (!extension_loaded('sodium') && in_array(PHP_VERSION_ID, array(70200, 70201, 70202), true) && extension_loaded('opcache')) {
        /*
         * Sodium_Compat isn't compatible with PHP 7.2.0~7.2.2 due to a bug in the PHP Opcache extension, bail early as it'll fail.
         * https://bugs.php.net/bug.php?id=75938
         */
        return new WP_Error('signature_verification_unsupported', sprintf(
            /* translators: %s: The filename of the package. */
            __('The authenticity of %s could not be verified as signature verification is unavailable on this system.'),
            '<span class="code">' . esc_html($filename_for_errors) . '</span>'
        ), array('php' => PHP_VERSION, 'sodium' => defined('SODIUM_LIBRARY_VERSION') ? SODIUM_LIBRARY_VERSION : (defined('ParagonIE_Sodium_Compat::VERSION_STRING') ? ParagonIE_Sodium_Compat::VERSION_STRING : false)));
    }
    // Verify runtime speed of Sodium_Compat is acceptable.
    if (!extension_loaded('sodium') && !ParagonIE_Sodium_Compat::polyfill_is_fast()) {
        $sodium_compat_is_fast = false;
        // Allow for an old version of Sodium_Compat being loaded before the bundled WordPress one.
        if (method_exists('ParagonIE_Sodium_Compat', 'runtime_speed_test')) {
            /*
             * Run `ParagonIE_Sodium_Compat::runtime_speed_test()` in optimized integer mode,
             * as that's what WordPress utilizes during signing verifications.
             */
            // phpcs:disable WordPress.NamingConventions.ValidVariableName
            $old_fastMult = ParagonIE_Sodium_Compat::$fastMult;
            ParagonIE_Sodium_Compat::$fastMult = true;
            $sodium_compat_is_fast = ParagonIE_Sodium_Compat::runtime_speed_test(100, 10);
            ParagonIE_Sodium_Compat::$fastMult = $old_fastMult;
            // phpcs:enable
        }
        /*
         * This cannot be performed in a reasonable amount of time.
         * https://github.com/paragonie/sodium_compat#help-sodium_compat-is-slow-how-can-i-make-it-fast
         */
        if (!$sodium_compat_is_fast) {
            return new WP_Error('signature_verification_unsupported', sprintf(
                /* translators: %s: The filename of the package. */
                __('The authenticity of %s could not be verified as signature verification is unavailable on this system.'),
                '<span class="code">' . esc_html($filename_for_errors) . '</span>'
            ), array('php' => PHP_VERSION, 'sodium' => defined('SODIUM_LIBRARY_VERSION') ? SODIUM_LIBRARY_VERSION : (defined('ParagonIE_Sodium_Compat::VERSION_STRING') ? ParagonIE_Sodium_Compat::VERSION_STRING : false), 'polyfill_is_fast' => false, 'max_execution_time' => ini_get('max_execution_time')));
        }
    }
    if (!$signatures) {
        return new WP_Error('signature_verification_no_signature', sprintf(
            /* translators: %s: The filename of the package. */
            __('The authenticity of %s could not be verified as no signature was found.'),
            '<span class="code">' . esc_html($filename_for_errors) . '</span>'
        ), array('filename' => $filename_for_errors));
    }
    $trusted_keys = wp_trusted_keys();
    $file_hash = hash_file('sha384', $filename, true);
    mbstring_binary_safe_encoding();
    $skipped_key = 0;
    $skipped_signature = 0;
    foreach ((array) $signatures as $signature) {
        $signature_raw = base64_decode($signature);
        // Ensure only valid-length signatures are considered.
        if (SODIUM_CRYPTO_SIGN_BYTES !== strlen($signature_raw)) {
            ++$skipped_signature;
            continue;
        }
        foreach ((array) $trusted_keys as $key) {
            $key_raw = base64_decode($key);
            // Only pass valid public keys through.
            if (SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES !== strlen($key_raw)) {
                ++$skipped_key;
                continue;
            }
            if (sodium_crypto_sign_verify_detached($signature_raw, $file_hash, $key_raw)) {
                reset_mbstring_encoding();
                return true;
            }
        }
    }
    reset_mbstring_encoding();
    return new WP_Error(
        'signature_verification_failed',
        sprintf(
            /* translators: %s: The filename of the package. */
            __('The authenticity of %s could not be verified.'),
            '<span class="code">' . esc_html($filename_for_errors) . '</span>'
        ),
        // Error data helpful for debugging:
        array('filename' => $filename_for_errors, 'keys' => $trusted_keys, 'signatures' => $signatures, 'hash' => bin2hex($file_hash), 'skipped_key' => $skipped_key, 'skipped_sig' => $skipped_signature, 'php' => PHP_VERSION, 'sodium' => defined('SODIUM_LIBRARY_VERSION') ? SODIUM_LIBRARY_VERSION : (defined('ParagonIE_Sodium_Compat::VERSION_STRING') ? ParagonIE_Sodium_Compat::VERSION_STRING : false))
    );
}

WordPress Version: 6.3

/**
 * Verifies the contents of a file against its ED25519 signature.
 *
 * @since 5.2.0
 *
 * @param string       $filename            The file to validate.
 * @param string|array $signatures          A Signature provided for the file.
 * @param string|false $filename_for_errors Optional. A friendly filename for errors.
 * @return bool|WP_Error True on success, false if verification not attempted,
 *                       or WP_Error describing an error condition.
 */
function verify_file_signature($filename, $signatures, $filename_for_errors = false)
{
    if (!$filename_for_errors) {
        $filename_for_errors = wp_basename($filename);
    }
    // Check we can process signatures.
    if (!function_exists('sodium_crypto_sign_verify_detached') || !in_array('sha384', array_map('strtolower', hash_algos()), true)) {
        return new WP_Error('signature_verification_unsupported', sprintf(
            /* translators: %s: The filename of the package. */
            __('The authenticity of %s could not be verified as signature verification is unavailable on this system.'),
            '<span class="code">' . esc_html($filename_for_errors) . '</span>'
        ), (!function_exists('sodium_crypto_sign_verify_detached')) ? 'sodium_crypto_sign_verify_detached' : 'sha384');
    }
    // Check for an edge-case affecting PHP Maths abilities.
    if (!extension_loaded('sodium') && in_array(PHP_VERSION_ID, array(70200, 70201, 70202), true) && extension_loaded('opcache')) {
        /*
         * Sodium_Compat isn't compatible with PHP 7.2.0~7.2.2 due to a bug in the PHP Opcache extension, bail early as it'll fail.
         * https://bugs.php.net/bug.php?id=75938
         */
        return new WP_Error('signature_verification_unsupported', sprintf(
            /* translators: %s: The filename of the package. */
            __('The authenticity of %s could not be verified as signature verification is unavailable on this system.'),
            '<span class="code">' . esc_html($filename_for_errors) . '</span>'
        ), array('php' => PHP_VERSION, 'sodium' => defined('SODIUM_LIBRARY_VERSION') ? SODIUM_LIBRARY_VERSION : (defined('ParagonIE_Sodium_Compat::VERSION_STRING') ? ParagonIE_Sodium_Compat::VERSION_STRING : false)));
    }
    // Verify runtime speed of Sodium_Compat is acceptable.
    if (!extension_loaded('sodium') && !ParagonIE_Sodium_Compat::polyfill_is_fast()) {
        $sodium_compat_is_fast = false;
        // Allow for an old version of Sodium_Compat being loaded before the bundled WordPress one.
        if (method_exists('ParagonIE_Sodium_Compat', 'runtime_speed_test')) {
            /*
             * Run `ParagonIE_Sodium_Compat::runtime_speed_test()` in optimized integer mode,
             * as that's what WordPress utilizes during signing verifications.
             */
            // phpcs:disable WordPress.NamingConventions.ValidVariableName
            $old_fastMult = ParagonIE_Sodium_Compat::$fastMult;
            ParagonIE_Sodium_Compat::$fastMult = true;
            $sodium_compat_is_fast = ParagonIE_Sodium_Compat::runtime_speed_test(100, 10);
            ParagonIE_Sodium_Compat::$fastMult = $old_fastMult;
            // phpcs:enable
        }
        /*
         * This cannot be performed in a reasonable amount of time.
         * https://github.com/paragonie/sodium_compat#help-sodium_compat-is-slow-how-can-i-make-it-fast
         */
        if (!$sodium_compat_is_fast) {
            return new WP_Error('signature_verification_unsupported', sprintf(
                /* translators: %s: The filename of the package. */
                __('The authenticity of %s could not be verified as signature verification is unavailable on this system.'),
                '<span class="code">' . esc_html($filename_for_errors) . '</span>'
            ), array('php' => PHP_VERSION, 'sodium' => defined('SODIUM_LIBRARY_VERSION') ? SODIUM_LIBRARY_VERSION : (defined('ParagonIE_Sodium_Compat::VERSION_STRING') ? ParagonIE_Sodium_Compat::VERSION_STRING : false), 'polyfill_is_fast' => false, 'max_execution_time' => ini_get('max_execution_time')));
        }
    }
    if (!$signatures) {
        return new WP_Error('signature_verification_no_signature', sprintf(
            /* translators: %s: The filename of the package. */
            __('The authenticity of %s could not be verified as no signature was found.'),
            '<span class="code">' . esc_html($filename_for_errors) . '</span>'
        ), array('filename' => $filename_for_errors));
    }
    $trusted_keys = wp_trusted_keys();
    $file_hash = hash_file('sha384', $filename, true);
    mbstring_binary_safe_encoding();
    $skipped_key = 0;
    $skipped_signature = 0;
    foreach ((array) $signatures as $signature) {
        $signature_raw = base64_decode($signature);
        // Ensure only valid-length signatures are considered.
        if (SODIUM_CRYPTO_SIGN_BYTES !== strlen($signature_raw)) {
            $skipped_signature++;
            continue;
        }
        foreach ((array) $trusted_keys as $key) {
            $key_raw = base64_decode($key);
            // Only pass valid public keys through.
            if (SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES !== strlen($key_raw)) {
                $skipped_key++;
                continue;
            }
            if (sodium_crypto_sign_verify_detached($signature_raw, $file_hash, $key_raw)) {
                reset_mbstring_encoding();
                return true;
            }
        }
    }
    reset_mbstring_encoding();
    return new WP_Error(
        'signature_verification_failed',
        sprintf(
            /* translators: %s: The filename of the package. */
            __('The authenticity of %s could not be verified.'),
            '<span class="code">' . esc_html($filename_for_errors) . '</span>'
        ),
        // Error data helpful for debugging:
        array('filename' => $filename_for_errors, 'keys' => $trusted_keys, 'signatures' => $signatures, 'hash' => bin2hex($file_hash), 'skipped_key' => $skipped_key, 'skipped_sig' => $skipped_signature, 'php' => PHP_VERSION, 'sodium' => defined('SODIUM_LIBRARY_VERSION') ? SODIUM_LIBRARY_VERSION : (defined('ParagonIE_Sodium_Compat::VERSION_STRING') ? ParagonIE_Sodium_Compat::VERSION_STRING : false))
    );
}

WordPress Version: 6.1

/**
 * Verifies the contents of a file against its ED25519 signature.
 *
 * @since 5.2.0
 *
 * @param string       $filename            The file to validate.
 * @param string|array $signatures          A Signature provided for the file.
 * @param string|false $filename_for_errors Optional. A friendly filename for errors.
 * @return bool|WP_Error True on success, false if verification not attempted,
 *                       or WP_Error describing an error condition.
 */
function verify_file_signature($filename, $signatures, $filename_for_errors = false)
{
    if (!$filename_for_errors) {
        $filename_for_errors = wp_basename($filename);
    }
    // Check we can process signatures.
    if (!function_exists('sodium_crypto_sign_verify_detached') || !in_array('sha384', array_map('strtolower', hash_algos()), true)) {
        return new WP_Error('signature_verification_unsupported', sprintf(
            /* translators: %s: The filename of the package. */
            __('The authenticity of %s could not be verified as signature verification is unavailable on this system.'),
            '<span class="code">' . esc_html($filename_for_errors) . '</span>'
        ), (!function_exists('sodium_crypto_sign_verify_detached')) ? 'sodium_crypto_sign_verify_detached' : 'sha384');
    }
    // Check for a edge-case affecting PHP Maths abilities.
    if (!extension_loaded('sodium') && in_array(PHP_VERSION_ID, array(70200, 70201, 70202), true) && extension_loaded('opcache')) {
        // Sodium_Compat isn't compatible with PHP 7.2.0~7.2.2 due to a bug in the PHP Opcache extension, bail early as it'll fail.
        // https://bugs.php.net/bug.php?id=75938
        return new WP_Error('signature_verification_unsupported', sprintf(
            /* translators: %s: The filename of the package. */
            __('The authenticity of %s could not be verified as signature verification is unavailable on this system.'),
            '<span class="code">' . esc_html($filename_for_errors) . '</span>'
        ), array('php' => PHP_VERSION, 'sodium' => defined('SODIUM_LIBRARY_VERSION') ? SODIUM_LIBRARY_VERSION : (defined('ParagonIE_Sodium_Compat::VERSION_STRING') ? ParagonIE_Sodium_Compat::VERSION_STRING : false)));
    }
    // Verify runtime speed of Sodium_Compat is acceptable.
    if (!extension_loaded('sodium') && !ParagonIE_Sodium_Compat::polyfill_is_fast()) {
        $sodium_compat_is_fast = false;
        // Allow for an old version of Sodium_Compat being loaded before the bundled WordPress one.
        if (method_exists('ParagonIE_Sodium_Compat', 'runtime_speed_test')) {
            /*
             * Run `ParagonIE_Sodium_Compat::runtime_speed_test()` in optimized integer mode,
             * as that's what WordPress utilizes during signing verifications.
             */
            // phpcs:disable WordPress.NamingConventions.ValidVariableName
            $old_fastMult = ParagonIE_Sodium_Compat::$fastMult;
            ParagonIE_Sodium_Compat::$fastMult = true;
            $sodium_compat_is_fast = ParagonIE_Sodium_Compat::runtime_speed_test(100, 10);
            ParagonIE_Sodium_Compat::$fastMult = $old_fastMult;
            // phpcs:enable
        }
        // This cannot be performed in a reasonable amount of time.
        // https://github.com/paragonie/sodium_compat#help-sodium_compat-is-slow-how-can-i-make-it-fast
        if (!$sodium_compat_is_fast) {
            return new WP_Error('signature_verification_unsupported', sprintf(
                /* translators: %s: The filename of the package. */
                __('The authenticity of %s could not be verified as signature verification is unavailable on this system.'),
                '<span class="code">' . esc_html($filename_for_errors) . '</span>'
            ), array('php' => PHP_VERSION, 'sodium' => defined('SODIUM_LIBRARY_VERSION') ? SODIUM_LIBRARY_VERSION : (defined('ParagonIE_Sodium_Compat::VERSION_STRING') ? ParagonIE_Sodium_Compat::VERSION_STRING : false), 'polyfill_is_fast' => false, 'max_execution_time' => ini_get('max_execution_time')));
        }
    }
    if (!$signatures) {
        return new WP_Error('signature_verification_no_signature', sprintf(
            /* translators: %s: The filename of the package. */
            __('The authenticity of %s could not be verified as no signature was found.'),
            '<span class="code">' . esc_html($filename_for_errors) . '</span>'
        ), array('filename' => $filename_for_errors));
    }
    $trusted_keys = wp_trusted_keys();
    $file_hash = hash_file('sha384', $filename, true);
    mbstring_binary_safe_encoding();
    $skipped_key = 0;
    $skipped_signature = 0;
    foreach ((array) $signatures as $signature) {
        $signature_raw = base64_decode($signature);
        // Ensure only valid-length signatures are considered.
        if (SODIUM_CRYPTO_SIGN_BYTES !== strlen($signature_raw)) {
            $skipped_signature++;
            continue;
        }
        foreach ((array) $trusted_keys as $key) {
            $key_raw = base64_decode($key);
            // Only pass valid public keys through.
            if (SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES !== strlen($key_raw)) {
                $skipped_key++;
                continue;
            }
            if (sodium_crypto_sign_verify_detached($signature_raw, $file_hash, $key_raw)) {
                reset_mbstring_encoding();
                return true;
            }
        }
    }
    reset_mbstring_encoding();
    return new WP_Error(
        'signature_verification_failed',
        sprintf(
            /* translators: %s: The filename of the package. */
            __('The authenticity of %s could not be verified.'),
            '<span class="code">' . esc_html($filename_for_errors) . '</span>'
        ),
        // Error data helpful for debugging:
        array('filename' => $filename_for_errors, 'keys' => $trusted_keys, 'signatures' => $signatures, 'hash' => bin2hex($file_hash), 'skipped_key' => $skipped_key, 'skipped_sig' => $skipped_signature, 'php' => PHP_VERSION, 'sodium' => defined('SODIUM_LIBRARY_VERSION') ? SODIUM_LIBRARY_VERSION : (defined('ParagonIE_Sodium_Compat::VERSION_STRING') ? ParagonIE_Sodium_Compat::VERSION_STRING : false))
    );
}

WordPress Version: 5.9

/**
 * Verifies the contents of a file against its ED25519 signature.
 *
 * @since 5.2.0
 *
 * @param string       $filename            The file to validate.
 * @param string|array $signatures          A Signature provided for the file.
 * @param string|false $filename_for_errors Optional. A friendly filename for errors.
 * @return bool|WP_Error True on success, false if verification not attempted,
 *                       or WP_Error describing an error condition.
 */
function verify_file_signature($filename, $signatures, $filename_for_errors = false)
{
    if (!$filename_for_errors) {
        $filename_for_errors = wp_basename($filename);
    }
    // Check we can process signatures.
    if (!function_exists('sodium_crypto_sign_verify_detached') || !in_array('sha384', array_map('strtolower', hash_algos()), true)) {
        return new WP_Error('signature_verification_unsupported', sprintf(
            /* translators: %s: The filename of the package. */
            __('The authenticity of %s could not be verified as signature verification is unavailable on this system.'),
            '<span class="code">' . esc_html($filename_for_errors) . '</span>'
        ), (!function_exists('sodium_crypto_sign_verify_detached')) ? 'sodium_crypto_sign_verify_detached' : 'sha384');
    }
    // Check for a edge-case affecting PHP Maths abilities.
    if (!extension_loaded('sodium') && in_array(PHP_VERSION_ID, array(70200, 70201, 70202), true) && extension_loaded('opcache')) {
        // Sodium_Compat isn't compatible with PHP 7.2.0~7.2.2 due to a bug in the PHP Opcache extension, bail early as it'll fail.
        // https://bugs.php.net/bug.php?id=75938
        return new WP_Error('signature_verification_unsupported', sprintf(
            /* translators: %s: The filename of the package. */
            __('The authenticity of %s could not be verified as signature verification is unavailable on this system.'),
            '<span class="code">' . esc_html($filename_for_errors) . '</span>'
        ), array('php' => phpversion(), 'sodium' => defined('SODIUM_LIBRARY_VERSION') ? SODIUM_LIBRARY_VERSION : (defined('ParagonIE_Sodium_Compat::VERSION_STRING') ? ParagonIE_Sodium_Compat::VERSION_STRING : false)));
    }
    // Verify runtime speed of Sodium_Compat is acceptable.
    if (!extension_loaded('sodium') && !ParagonIE_Sodium_Compat::polyfill_is_fast()) {
        $sodium_compat_is_fast = false;
        // Allow for an old version of Sodium_Compat being loaded before the bundled WordPress one.
        if (method_exists('ParagonIE_Sodium_Compat', 'runtime_speed_test')) {
            // Run `ParagonIE_Sodium_Compat::runtime_speed_test()` in optimized integer mode, as that's what WordPress utilises during signing verifications.
            // phpcs:disable WordPress.NamingConventions.ValidVariableName
            $old_fastMult = ParagonIE_Sodium_Compat::$fastMult;
            ParagonIE_Sodium_Compat::$fastMult = true;
            $sodium_compat_is_fast = ParagonIE_Sodium_Compat::runtime_speed_test(100, 10);
            ParagonIE_Sodium_Compat::$fastMult = $old_fastMult;
            // phpcs:enable
        }
        // This cannot be performed in a reasonable amount of time.
        // https://github.com/paragonie/sodium_compat#help-sodium_compat-is-slow-how-can-i-make-it-fast
        if (!$sodium_compat_is_fast) {
            return new WP_Error('signature_verification_unsupported', sprintf(
                /* translators: %s: The filename of the package. */
                __('The authenticity of %s could not be verified as signature verification is unavailable on this system.'),
                '<span class="code">' . esc_html($filename_for_errors) . '</span>'
            ), array('php' => phpversion(), 'sodium' => defined('SODIUM_LIBRARY_VERSION') ? SODIUM_LIBRARY_VERSION : (defined('ParagonIE_Sodium_Compat::VERSION_STRING') ? ParagonIE_Sodium_Compat::VERSION_STRING : false), 'polyfill_is_fast' => false, 'max_execution_time' => ini_get('max_execution_time')));
        }
    }
    if (!$signatures) {
        return new WP_Error('signature_verification_no_signature', sprintf(
            /* translators: %s: The filename of the package. */
            __('The authenticity of %s could not be verified as no signature was found.'),
            '<span class="code">' . esc_html($filename_for_errors) . '</span>'
        ), array('filename' => $filename_for_errors));
    }
    $trusted_keys = wp_trusted_keys();
    $file_hash = hash_file('sha384', $filename, true);
    mbstring_binary_safe_encoding();
    $skipped_key = 0;
    $skipped_signature = 0;
    foreach ((array) $signatures as $signature) {
        $signature_raw = base64_decode($signature);
        // Ensure only valid-length signatures are considered.
        if (SODIUM_CRYPTO_SIGN_BYTES !== strlen($signature_raw)) {
            $skipped_signature++;
            continue;
        }
        foreach ((array) $trusted_keys as $key) {
            $key_raw = base64_decode($key);
            // Only pass valid public keys through.
            if (SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES !== strlen($key_raw)) {
                $skipped_key++;
                continue;
            }
            if (sodium_crypto_sign_verify_detached($signature_raw, $file_hash, $key_raw)) {
                reset_mbstring_encoding();
                return true;
            }
        }
    }
    reset_mbstring_encoding();
    return new WP_Error(
        'signature_verification_failed',
        sprintf(
            /* translators: %s: The filename of the package. */
            __('The authenticity of %s could not be verified.'),
            '<span class="code">' . esc_html($filename_for_errors) . '</span>'
        ),
        // Error data helpful for debugging:
        array('filename' => $filename_for_errors, 'keys' => $trusted_keys, 'signatures' => $signatures, 'hash' => bin2hex($file_hash), 'skipped_key' => $skipped_key, 'skipped_sig' => $skipped_signature, 'php' => phpversion(), 'sodium' => defined('SODIUM_LIBRARY_VERSION') ? SODIUM_LIBRARY_VERSION : (defined('ParagonIE_Sodium_Compat::VERSION_STRING') ? ParagonIE_Sodium_Compat::VERSION_STRING : false))
    );
}

WordPress Version: 5.7

/**
 * Verifies the contents of a file against its ED25519 signature.
 *
 * @since 5.2.0
 *
 * @param string       $filename            The file to validate.
 * @param string|array $signatures          A Signature provided for the file.
 * @param string|false $filename_for_errors Optional. A friendly filename for errors.
 * @return bool|WP_Error True on success, false if verification not attempted,
 *                       or WP_Error describing an error condition.
 */
function verify_file_signature($filename, $signatures, $filename_for_errors = false)
{
    if (!$filename_for_errors) {
        $filename_for_errors = wp_basename($filename);
    }
    // Check we can process signatures.
    if (!function_exists('sodium_crypto_sign_verify_detached') || !in_array('sha384', array_map('strtolower', hash_algos()), true)) {
        return new WP_Error('signature_verification_unsupported', sprintf(
            /* translators: %s: The filename of the package. */
            __('The authenticity of %s could not be verified as signature verification is unavailable on this system.'),
            '<span class="code">' . esc_html($filename_for_errors) . '</span>'
        ), (!function_exists('sodium_crypto_sign_verify_detached')) ? 'sodium_crypto_sign_verify_detached' : 'sha384');
    }
    // Check for a edge-case affecting PHP Maths abilities.
    if (!extension_loaded('sodium') && in_array(PHP_VERSION_ID, array(70200, 70201, 70202), true) && extension_loaded('opcache')) {
        // Sodium_Compat isn't compatible with PHP 7.2.0~7.2.2 due to a bug in the PHP Opcache extension, bail early as it'll fail.
        // https://bugs.php.net/bug.php?id=75938
        return new WP_Error('signature_verification_unsupported', sprintf(
            /* translators: %s: The filename of the package. */
            __('The authenticity of %s could not be verified as signature verification is unavailable on this system.'),
            '<span class="code">' . esc_html($filename_for_errors) . '</span>'
        ), array(
            'php' => phpversion(),
            // phpcs:ignore PHPCompatibility.Constants.NewConstants.sodium_library_versionFound
            'sodium' => defined('SODIUM_LIBRARY_VERSION') ? SODIUM_LIBRARY_VERSION : (defined('ParagonIE_Sodium_Compat::VERSION_STRING') ? ParagonIE_Sodium_Compat::VERSION_STRING : false),
        ));
    }
    // Verify runtime speed of Sodium_Compat is acceptable.
    if (!extension_loaded('sodium') && !ParagonIE_Sodium_Compat::polyfill_is_fast()) {
        $sodium_compat_is_fast = false;
        // Allow for an old version of Sodium_Compat being loaded before the bundled WordPress one.
        if (method_exists('ParagonIE_Sodium_Compat', 'runtime_speed_test')) {
            // Run `ParagonIE_Sodium_Compat::runtime_speed_test()` in optimized integer mode, as that's what WordPress utilises during signing verifications.
            // phpcs:disable WordPress.NamingConventions.ValidVariableName
            $old_fastMult = ParagonIE_Sodium_Compat::$fastMult;
            ParagonIE_Sodium_Compat::$fastMult = true;
            $sodium_compat_is_fast = ParagonIE_Sodium_Compat::runtime_speed_test(100, 10);
            ParagonIE_Sodium_Compat::$fastMult = $old_fastMult;
            // phpcs:enable
        }
        // This cannot be performed in a reasonable amount of time.
        // https://github.com/paragonie/sodium_compat#help-sodium_compat-is-slow-how-can-i-make-it-fast
        if (!$sodium_compat_is_fast) {
            return new WP_Error('signature_verification_unsupported', sprintf(
                /* translators: %s: The filename of the package. */
                __('The authenticity of %s could not be verified as signature verification is unavailable on this system.'),
                '<span class="code">' . esc_html($filename_for_errors) . '</span>'
            ), array(
                'php' => phpversion(),
                // phpcs:ignore PHPCompatibility.Constants.NewConstants.sodium_library_versionFound
                'sodium' => defined('SODIUM_LIBRARY_VERSION') ? SODIUM_LIBRARY_VERSION : (defined('ParagonIE_Sodium_Compat::VERSION_STRING') ? ParagonIE_Sodium_Compat::VERSION_STRING : false),
                'polyfill_is_fast' => false,
                'max_execution_time' => ini_get('max_execution_time'),
            ));
        }
    }
    if (!$signatures) {
        return new WP_Error('signature_verification_no_signature', sprintf(
            /* translators: %s: The filename of the package. */
            __('The authenticity of %s could not be verified as no signature was found.'),
            '<span class="code">' . esc_html($filename_for_errors) . '</span>'
        ), array('filename' => $filename_for_errors));
    }
    $trusted_keys = wp_trusted_keys();
    $file_hash = hash_file('sha384', $filename, true);
    mbstring_binary_safe_encoding();
    $skipped_key = 0;
    $skipped_signature = 0;
    foreach ((array) $signatures as $signature) {
        $signature_raw = base64_decode($signature);
        // Ensure only valid-length signatures are considered.
        if (SODIUM_CRYPTO_SIGN_BYTES !== strlen($signature_raw)) {
            $skipped_signature++;
            continue;
        }
        foreach ((array) $trusted_keys as $key) {
            $key_raw = base64_decode($key);
            // Only pass valid public keys through.
            if (SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES !== strlen($key_raw)) {
                $skipped_key++;
                continue;
            }
            if (sodium_crypto_sign_verify_detached($signature_raw, $file_hash, $key_raw)) {
                reset_mbstring_encoding();
                return true;
            }
        }
    }
    reset_mbstring_encoding();
    return new WP_Error(
        'signature_verification_failed',
        sprintf(
            /* translators: %s: The filename of the package. */
            __('The authenticity of %s could not be verified.'),
            '<span class="code">' . esc_html($filename_for_errors) . '</span>'
        ),
        // Error data helpful for debugging:
        array(
            'filename' => $filename_for_errors,
            'keys' => $trusted_keys,
            'signatures' => $signatures,
            'hash' => bin2hex($file_hash),
            'skipped_key' => $skipped_key,
            'skipped_sig' => $skipped_signature,
            'php' => phpversion(),
            // phpcs:ignore PHPCompatibility.Constants.NewConstants.sodium_library_versionFound
            'sodium' => defined('SODIUM_LIBRARY_VERSION') ? SODIUM_LIBRARY_VERSION : (defined('ParagonIE_Sodium_Compat::VERSION_STRING') ? ParagonIE_Sodium_Compat::VERSION_STRING : false),
        )
    );
}

WordPress Version: 5.5

/**
 * Verifies the contents of a file against its ED25519 signature.
 *
 * @since 5.2.0
 *
 * @param string       $filename            The file to validate.
 * @param string|array $signatures          A Signature provided for the file.
 * @param string       $filename_for_errors A friendly filename for errors. Optional.
 * @return bool|WP_Error True on success, false if verification not attempted,
 *                       or WP_Error describing an error condition.
 */
function verify_file_signature($filename, $signatures, $filename_for_errors = false)
{
    if (!$filename_for_errors) {
        $filename_for_errors = wp_basename($filename);
    }
    // Check we can process signatures.
    if (!function_exists('sodium_crypto_sign_verify_detached') || !in_array('sha384', array_map('strtolower', hash_algos()), true)) {
        return new WP_Error('signature_verification_unsupported', sprintf(
            /* translators: %s: The filename of the package. */
            __('The authenticity of %s could not be verified as signature verification is unavailable on this system.'),
            '<span class="code">' . esc_html($filename_for_errors) . '</span>'
        ), (!function_exists('sodium_crypto_sign_verify_detached')) ? 'sodium_crypto_sign_verify_detached' : 'sha384');
    }
    // Check for a edge-case affecting PHP Maths abilities.
    if (!extension_loaded('sodium') && in_array(PHP_VERSION_ID, array(70200, 70201, 70202), true) && extension_loaded('opcache')) {
        // Sodium_Compat isn't compatible with PHP 7.2.0~7.2.2 due to a bug in the PHP Opcache extension, bail early as it'll fail.
        // https://bugs.php.net/bug.php?id=75938
        return new WP_Error('signature_verification_unsupported', sprintf(
            /* translators: %s: The filename of the package. */
            __('The authenticity of %s could not be verified as signature verification is unavailable on this system.'),
            '<span class="code">' . esc_html($filename_for_errors) . '</span>'
        ), array(
            'php' => phpversion(),
            // phpcs:ignore PHPCompatibility.Constants.NewConstants.sodium_library_versionFound
            'sodium' => defined('SODIUM_LIBRARY_VERSION') ? SODIUM_LIBRARY_VERSION : (defined('ParagonIE_Sodium_Compat::VERSION_STRING') ? ParagonIE_Sodium_Compat::VERSION_STRING : false),
        ));
    }
    // Verify runtime speed of Sodium_Compat is acceptable.
    if (!extension_loaded('sodium') && !ParagonIE_Sodium_Compat::polyfill_is_fast()) {
        $sodium_compat_is_fast = false;
        // Allow for an old version of Sodium_Compat being loaded before the bundled WordPress one.
        if (method_exists('ParagonIE_Sodium_Compat', 'runtime_speed_test')) {
            // Run `ParagonIE_Sodium_Compat::runtime_speed_test()` in optimized integer mode, as that's what WordPress utilises during signing verifications.
            // phpcs:disable WordPress.NamingConventions.ValidVariableName
            $old_fastMult = ParagonIE_Sodium_Compat::$fastMult;
            ParagonIE_Sodium_Compat::$fastMult = true;
            $sodium_compat_is_fast = ParagonIE_Sodium_Compat::runtime_speed_test(100, 10);
            ParagonIE_Sodium_Compat::$fastMult = $old_fastMult;
            // phpcs:enable
        }
        // This cannot be performed in a reasonable amount of time.
        // https://github.com/paragonie/sodium_compat#help-sodium_compat-is-slow-how-can-i-make-it-fast
        if (!$sodium_compat_is_fast) {
            return new WP_Error('signature_verification_unsupported', sprintf(
                /* translators: %s: The filename of the package. */
                __('The authenticity of %s could not be verified as signature verification is unavailable on this system.'),
                '<span class="code">' . esc_html($filename_for_errors) . '</span>'
            ), array(
                'php' => phpversion(),
                // phpcs:ignore PHPCompatibility.Constants.NewConstants.sodium_library_versionFound
                'sodium' => defined('SODIUM_LIBRARY_VERSION') ? SODIUM_LIBRARY_VERSION : (defined('ParagonIE_Sodium_Compat::VERSION_STRING') ? ParagonIE_Sodium_Compat::VERSION_STRING : false),
                'polyfill_is_fast' => false,
                'max_execution_time' => ini_get('max_execution_time'),
            ));
        }
    }
    if (!$signatures) {
        return new WP_Error('signature_verification_no_signature', sprintf(
            /* translators: %s: The filename of the package. */
            __('The authenticity of %s could not be verified as no signature was found.'),
            '<span class="code">' . esc_html($filename_for_errors) . '</span>'
        ), array('filename' => $filename_for_errors));
    }
    $trusted_keys = wp_trusted_keys();
    $file_hash = hash_file('sha384', $filename, true);
    mbstring_binary_safe_encoding();
    $skipped_key = 0;
    $skipped_signature = 0;
    foreach ((array) $signatures as $signature) {
        $signature_raw = base64_decode($signature);
        // Ensure only valid-length signatures are considered.
        if (SODIUM_CRYPTO_SIGN_BYTES !== strlen($signature_raw)) {
            $skipped_signature++;
            continue;
        }
        foreach ((array) $trusted_keys as $key) {
            $key_raw = base64_decode($key);
            // Only pass valid public keys through.
            if (SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES !== strlen($key_raw)) {
                $skipped_key++;
                continue;
            }
            if (sodium_crypto_sign_verify_detached($signature_raw, $file_hash, $key_raw)) {
                reset_mbstring_encoding();
                return true;
            }
        }
    }
    reset_mbstring_encoding();
    return new WP_Error(
        'signature_verification_failed',
        sprintf(
            /* translators: %s: The filename of the package. */
            __('The authenticity of %s could not be verified.'),
            '<span class="code">' . esc_html($filename_for_errors) . '</span>'
        ),
        // Error data helpful for debugging:
        array(
            'filename' => $filename_for_errors,
            'keys' => $trusted_keys,
            'signatures' => $signatures,
            'hash' => bin2hex($file_hash),
            'skipped_key' => $skipped_key,
            'skipped_sig' => $skipped_signature,
            'php' => phpversion(),
            // phpcs:ignore PHPCompatibility.Constants.NewConstants.sodium_library_versionFound
            'sodium' => defined('SODIUM_LIBRARY_VERSION') ? SODIUM_LIBRARY_VERSION : (defined('ParagonIE_Sodium_Compat::VERSION_STRING') ? ParagonIE_Sodium_Compat::VERSION_STRING : false),
        )
    );
}

WordPress Version: 5.4

/**
 * Verifies the contents of a file against its ED25519 signature.
 *
 * @since 5.2.0
 *
 * @param string       $filename            The file to validate.
 * @param string|array $signatures          A Signature provided for the file.
 * @param string       $filename_for_errors A friendly filename for errors. Optional.
 * @return bool|WP_Error True on success, false if verification not attempted,
 *                       or WP_Error describing an error condition.
 */
function verify_file_signature($filename, $signatures, $filename_for_errors = false)
{
    if (!$filename_for_errors) {
        $filename_for_errors = wp_basename($filename);
    }
    // Check we can process signatures.
    if (!function_exists('sodium_crypto_sign_verify_detached') || !in_array('sha384', array_map('strtolower', hash_algos()))) {
        return new WP_Error('signature_verification_unsupported', sprintf(
            /* translators: %s: The filename of the package. */
            __('The authenticity of %s could not be verified as signature verification is unavailable on this system.'),
            '<span class="code">' . esc_html($filename_for_errors) . '</span>'
        ), (!function_exists('sodium_crypto_sign_verify_detached')) ? 'sodium_crypto_sign_verify_detached' : 'sha384');
    }
    // Check for a edge-case affecting PHP Maths abilities.
    if (!extension_loaded('sodium') && in_array(PHP_VERSION_ID, array(70200, 70201, 70202), true) && extension_loaded('opcache')) {
        // Sodium_Compat isn't compatible with PHP 7.2.0~7.2.2 due to a bug in the PHP Opcache extension, bail early as it'll fail.
        // https://bugs.php.net/bug.php?id=75938
        return new WP_Error('signature_verification_unsupported', sprintf(
            /* translators: %s: The filename of the package. */
            __('The authenticity of %s could not be verified as signature verification is unavailable on this system.'),
            '<span class="code">' . esc_html($filename_for_errors) . '</span>'
        ), array(
            'php' => phpversion(),
            // phpcs:ignore PHPCompatibility.Constants.NewConstants.sodium_library_versionFound
            'sodium' => defined('SODIUM_LIBRARY_VERSION') ? SODIUM_LIBRARY_VERSION : (defined('ParagonIE_Sodium_Compat::VERSION_STRING') ? ParagonIE_Sodium_Compat::VERSION_STRING : false),
        ));
    }
    // Verify runtime speed of Sodium_Compat is acceptable.
    if (!extension_loaded('sodium') && !ParagonIE_Sodium_Compat::polyfill_is_fast()) {
        $sodium_compat_is_fast = false;
        // Allow for an old version of Sodium_Compat being loaded before the bundled WordPress one.
        if (method_exists('ParagonIE_Sodium_Compat', 'runtime_speed_test')) {
            // Run `ParagonIE_Sodium_Compat::runtime_speed_test()` in optimized integer mode, as that's what WordPress utilises during signing verifications.
            // phpcs:disable WordPress.NamingConventions.ValidVariableName
            $old_fastMult = ParagonIE_Sodium_Compat::$fastMult;
            ParagonIE_Sodium_Compat::$fastMult = true;
            $sodium_compat_is_fast = ParagonIE_Sodium_Compat::runtime_speed_test(100, 10);
            ParagonIE_Sodium_Compat::$fastMult = $old_fastMult;
            // phpcs:enable
        }
        // This cannot be performed in a reasonable amount of time.
        // https://github.com/paragonie/sodium_compat#help-sodium_compat-is-slow-how-can-i-make-it-fast
        if (!$sodium_compat_is_fast) {
            return new WP_Error('signature_verification_unsupported', sprintf(
                /* translators: %s: The filename of the package. */
                __('The authenticity of %s could not be verified as signature verification is unavailable on this system.'),
                '<span class="code">' . esc_html($filename_for_errors) . '</span>'
            ), array(
                'php' => phpversion(),
                // phpcs:ignore PHPCompatibility.Constants.NewConstants.sodium_library_versionFound
                'sodium' => defined('SODIUM_LIBRARY_VERSION') ? SODIUM_LIBRARY_VERSION : (defined('ParagonIE_Sodium_Compat::VERSION_STRING') ? ParagonIE_Sodium_Compat::VERSION_STRING : false),
                'polyfill_is_fast' => false,
                'max_execution_time' => ini_get('max_execution_time'),
            ));
        }
    }
    if (!$signatures) {
        return new WP_Error('signature_verification_no_signature', sprintf(
            /* translators: %s: The filename of the package. */
            __('The authenticity of %s could not be verified as no signature was found.'),
            '<span class="code">' . esc_html($filename_for_errors) . '</span>'
        ), array('filename' => $filename_for_errors));
    }
    $trusted_keys = wp_trusted_keys();
    $file_hash = hash_file('sha384', $filename, true);
    mbstring_binary_safe_encoding();
    $skipped_key = 0;
    $skipped_signature = 0;
    foreach ((array) $signatures as $signature) {
        $signature_raw = base64_decode($signature);
        // Ensure only valid-length signatures are considered.
        if (SODIUM_CRYPTO_SIGN_BYTES !== strlen($signature_raw)) {
            $skipped_signature++;
            continue;
        }
        foreach ((array) $trusted_keys as $key) {
            $key_raw = base64_decode($key);
            // Only pass valid public keys through.
            if (SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES !== strlen($key_raw)) {
                $skipped_key++;
                continue;
            }
            if (sodium_crypto_sign_verify_detached($signature_raw, $file_hash, $key_raw)) {
                reset_mbstring_encoding();
                return true;
            }
        }
    }
    reset_mbstring_encoding();
    return new WP_Error(
        'signature_verification_failed',
        sprintf(
            /* translators: %s: The filename of the package. */
            __('The authenticity of %s could not be verified.'),
            '<span class="code">' . esc_html($filename_for_errors) . '</span>'
        ),
        // Error data helpful for debugging:
        array(
            'filename' => $filename_for_errors,
            'keys' => $trusted_keys,
            'signatures' => $signatures,
            'hash' => bin2hex($file_hash),
            'skipped_key' => $skipped_key,
            'skipped_sig' => $skipped_signature,
            'php' => phpversion(),
            // phpcs:ignore PHPCompatibility.Constants.NewConstants.sodium_library_versionFound
            'sodium' => defined('SODIUM_LIBRARY_VERSION') ? SODIUM_LIBRARY_VERSION : (defined('ParagonIE_Sodium_Compat::VERSION_STRING') ? ParagonIE_Sodium_Compat::VERSION_STRING : false),
        )
    );
}

WordPress Version: 5.3

/**
 * Verifies the contents of a file against its ED25519 signature.
 *
 * @since 5.2.0
 *
 * @param string       $filename            The file to validate.
 * @param string|array $signatures          A Signature provided for the file.
 * @param string       $filename_for_errors A friendly filename for errors. Optional.
 *
 * @return bool|WP_Error true on success, false if verification not attempted, or WP_Error describing an error condition.
 */
function verify_file_signature($filename, $signatures, $filename_for_errors = false)
{
    if (!$filename_for_errors) {
        $filename_for_errors = wp_basename($filename);
    }
    // Check we can process signatures.
    if (!function_exists('sodium_crypto_sign_verify_detached') || !in_array('sha384', array_map('strtolower', hash_algos()))) {
        return new WP_Error('signature_verification_unsupported', sprintf(
            /* translators: %s: The filename of the package. */
            __('The authenticity of %s could not be verified as signature verification is unavailable on this system.'),
            '<span class="code">' . esc_html($filename_for_errors) . '</span>'
        ), (!function_exists('sodium_crypto_sign_verify_detached')) ? 'sodium_crypto_sign_verify_detached' : 'sha384');
    }
    // Check for a edge-case affecting PHP Maths abilities
    if (!extension_loaded('sodium') && in_array(PHP_VERSION_ID, [70200, 70201, 70202], true) && extension_loaded('opcache')) {
        // Sodium_Compat isn't compatible with PHP 7.2.0~7.2.2 due to a bug in the PHP Opcache extension, bail early as it'll fail.
        // https://bugs.php.net/bug.php?id=75938
        return new WP_Error('signature_verification_unsupported', sprintf(
            /* translators: %s: The filename of the package. */
            __('The authenticity of %s could not be verified as signature verification is unavailable on this system.'),
            '<span class="code">' . esc_html($filename_for_errors) . '</span>'
        ), array(
            'php' => phpversion(),
            // phpcs:ignore PHPCompatibility.Constants.NewConstants.sodium_library_versionFound
            'sodium' => defined('SODIUM_LIBRARY_VERSION') ? SODIUM_LIBRARY_VERSION : (defined('ParagonIE_Sodium_Compat::VERSION_STRING') ? ParagonIE_Sodium_Compat::VERSION_STRING : false),
        ));
    }
    // Verify runtime speed of Sodium_Compat is acceptable.
    if (!extension_loaded('sodium') && !ParagonIE_Sodium_Compat::polyfill_is_fast()) {
        $sodium_compat_is_fast = false;
        // Allow for an old version of Sodium_Compat being loaded before the bundled WordPress one.
        if (method_exists('ParagonIE_Sodium_Compat', 'runtime_speed_test')) {
            // Run `ParagonIE_Sodium_Compat::runtime_speed_test()` in optimized integer mode, as that's what WordPress utilises during signing verifications.
            // phpcs:disable WordPress.NamingConventions.ValidVariableName
            $old_fastMult = ParagonIE_Sodium_Compat::$fastMult;
            ParagonIE_Sodium_Compat::$fastMult = true;
            $sodium_compat_is_fast = ParagonIE_Sodium_Compat::runtime_speed_test(100, 10);
            ParagonIE_Sodium_Compat::$fastMult = $old_fastMult;
            // phpcs:enable
        }
        // This cannot be performed in a reasonable amount of time
        // https://github.com/paragonie/sodium_compat#help-sodium_compat-is-slow-how-can-i-make-it-fast
        if (!$sodium_compat_is_fast) {
            return new WP_Error('signature_verification_unsupported', sprintf(
                /* translators: %s: The filename of the package. */
                __('The authenticity of %s could not be verified as signature verification is unavailable on this system.'),
                '<span class="code">' . esc_html($filename_for_errors) . '</span>'
            ), array(
                'php' => phpversion(),
                // phpcs:ignore PHPCompatibility.Constants.NewConstants.sodium_library_versionFound
                'sodium' => defined('SODIUM_LIBRARY_VERSION') ? SODIUM_LIBRARY_VERSION : (defined('ParagonIE_Sodium_Compat::VERSION_STRING') ? ParagonIE_Sodium_Compat::VERSION_STRING : false),
                'polyfill_is_fast' => false,
                'max_execution_time' => ini_get('max_execution_time'),
            ));
        }
    }
    if (!$signatures) {
        return new WP_Error('signature_verification_no_signature', sprintf(
            /* translators: %s: The filename of the package. */
            __('The authenticity of %s could not be verified as no signature was found.'),
            '<span class="code">' . esc_html($filename_for_errors) . '</span>'
        ), array('filename' => $filename_for_errors));
    }
    $trusted_keys = wp_trusted_keys();
    $file_hash = hash_file('sha384', $filename, true);
    mbstring_binary_safe_encoding();
    $skipped_key = 0;
    $skipped_signature = 0;
    foreach ((array) $signatures as $signature) {
        $signature_raw = base64_decode($signature);
        // Ensure only valid-length signatures are considered.
        if (SODIUM_CRYPTO_SIGN_BYTES !== strlen($signature_raw)) {
            $skipped_signature++;
            continue;
        }
        foreach ((array) $trusted_keys as $key) {
            $key_raw = base64_decode($key);
            // Only pass valid public keys through.
            if (SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES !== strlen($key_raw)) {
                $skipped_key++;
                continue;
            }
            if (sodium_crypto_sign_verify_detached($signature_raw, $file_hash, $key_raw)) {
                reset_mbstring_encoding();
                return true;
            }
        }
    }
    reset_mbstring_encoding();
    return new WP_Error(
        'signature_verification_failed',
        sprintf(
            /* translators: %s: The filename of the package. */
            __('The authenticity of %s could not be verified.'),
            '<span class="code">' . esc_html($filename_for_errors) . '</span>'
        ),
        // Error data helpful for debugging:
        array(
            'filename' => $filename_for_errors,
            'keys' => $trusted_keys,
            'signatures' => $signatures,
            'hash' => bin2hex($file_hash),
            'skipped_key' => $skipped_key,
            'skipped_sig' => $skipped_signature,
            'php' => phpversion(),
            // phpcs:ignore PHPCompatibility.Constants.NewConstants.sodium_library_versionFound
            'sodium' => defined('SODIUM_LIBRARY_VERSION') ? SODIUM_LIBRARY_VERSION : (defined('ParagonIE_Sodium_Compat::VERSION_STRING') ? ParagonIE_Sodium_Compat::VERSION_STRING : false),
        )
    );
}

WordPress Version: .10

/**
 * Verifies the contents of a file against its ED25519 signature.
 *
 * @since 5.2.0
 *
 * @param string       $filename            The file to validate.
 * @param string|array $signatures          A Signature provided for the file.
 * @param string       $filename_for_errors A friendly filename for errors. Optional.
 *
 * @return bool|WP_Error true on success, false if verificaiton not attempted, or WP_Error describing an error condition.
 */
function verify_file_signature($filename, $signatures, $filename_for_errors = false)
{
    if (!$filename_for_errors) {
        $filename_for_errors = wp_basename($filename);
    }
    // Check we can process signatures.
    if (!function_exists('sodium_crypto_sign_verify_detached') || !in_array('sha384', array_map('strtolower', hash_algos()))) {
        return new WP_Error('signature_verification_unsupported', sprintf(
            /* translators: %s: The filename of the package. */
            __('The authenticity of %s could not be verified as signature verification is unavailable on this system.'),
            '<span class="code">' . esc_html($filename_for_errors) . '</span>'
        ), (!function_exists('sodium_crypto_sign_verify_detached')) ? 'sodium_crypto_sign_verify_detached' : 'sha384');
    }
    // Check for a edge-case affecting PHP Maths abilities
    if (!extension_loaded('sodium') && in_array(PHP_VERSION_ID, [70200, 70201, 70202], true) && extension_loaded('opcache')) {
        // Sodium_Compat isn't compatible with PHP 7.2.0~7.2.2 due to a bug in the PHP Opcache extension, bail early as it'll fail.
        // https://bugs.php.net/bug.php?id=75938
        return new WP_Error('signature_verification_unsupported', sprintf(
            /* translators: %s: The filename of the package. */
            __('The authenticity of %s could not be verified as signature verification is unavailable on this system.'),
            '<span class="code">' . esc_html($filename_for_errors) . '</span>'
        ), array('php' => phpversion(), 'sodium' => defined('SODIUM_LIBRARY_VERSION') ? SODIUM_LIBRARY_VERSION : (defined('ParagonIE_Sodium_Compat::VERSION_STRING') ? ParagonIE_Sodium_Compat::VERSION_STRING : false)));
    }
    // Verify runtime speed of Sodium_Compat is acceptable.
    if (!extension_loaded('sodium') && !ParagonIE_Sodium_Compat::polyfill_is_fast()) {
        $sodium_compat_is_fast = false;
        // Allow for an old version of Sodium_Compat being loaded before the bundled WordPress one.
        if (method_exists('ParagonIE_Sodium_Compat', 'runtime_speed_test')) {
            // Run `ParagonIE_Sodium_Compat::runtime_speed_test()` in optimized integer mode, as that's what WordPress utilises during signing verifications.
            $old_fastMult = ParagonIE_Sodium_Compat::$fastMult;
            ParagonIE_Sodium_Compat::$fastMult = true;
            $sodium_compat_is_fast = ParagonIE_Sodium_Compat::runtime_speed_test(100, 10);
            ParagonIE_Sodium_Compat::$fastMult = $old_fastMult;
        }
        // This cannot be performed in a reasonable amount of time
        // https://github.com/paragonie/sodium_compat#help-sodium_compat-is-slow-how-can-i-make-it-fast
        if (!$sodium_compat_is_fast) {
            return new WP_Error('signature_verification_unsupported', sprintf(
                /* translators: %s: The filename of the package. */
                __('The authenticity of %s could not be verified as signature verification is unavailable on this system.'),
                '<span class="code">' . esc_html($filename_for_errors) . '</span>'
            ), array('php' => phpversion(), 'sodium' => defined('SODIUM_LIBRARY_VERSION') ? SODIUM_LIBRARY_VERSION : (defined('ParagonIE_Sodium_Compat::VERSION_STRING') ? ParagonIE_Sodium_Compat::VERSION_STRING : false), 'polyfill_is_fast' => false, 'max_execution_time' => ini_get('max_execution_time')));
        }
    }
    if (!$signatures) {
        return new WP_Error('signature_verification_no_signature', sprintf(
            /* translators: %s: The filename of the package. */
            __('The authenticity of %s could not be verified as no signature was found.'),
            '<span class="code">' . esc_html($filename_for_errors) . '</span>'
        ), array('filename' => $filename_for_errors));
    }
    $trusted_keys = wp_trusted_keys();
    $file_hash = hash_file('sha384', $filename, true);
    mbstring_binary_safe_encoding();
    $skipped_key = $skipped_signature = 0;
    foreach ((array) $signatures as $signature) {
        $signature_raw = base64_decode($signature);
        // Ensure only valid-length signatures are considered.
        if (SODIUM_CRYPTO_SIGN_BYTES !== strlen($signature_raw)) {
            $skipped_signature++;
            continue;
        }
        foreach ((array) $trusted_keys as $key) {
            $key_raw = base64_decode($key);
            // Only pass valid public keys through.
            if (SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES !== strlen($key_raw)) {
                $skipped_key++;
                continue;
            }
            if (sodium_crypto_sign_verify_detached($signature_raw, $file_hash, $key_raw)) {
                reset_mbstring_encoding();
                return true;
            }
        }
    }
    reset_mbstring_encoding();
    return new WP_Error(
        'signature_verification_failed',
        sprintf(
            /* translators: %s: The filename of the package. */
            __('The authenticity of %s could not be verified.'),
            '<span class="code">' . esc_html($filename_for_errors) . '</span>'
        ),
        // Error data helpful for debugging:
        array('filename' => $filename_for_errors, 'keys' => $trusted_keys, 'signatures' => $signatures, 'hash' => bin2hex($file_hash), 'skipped_key' => $skipped_key, 'skipped_sig' => $skipped_signature, 'php' => phpversion(), 'sodium' => defined('SODIUM_LIBRARY_VERSION') ? SODIUM_LIBRARY_VERSION : (defined('ParagonIE_Sodium_Compat::VERSION_STRING') ? ParagonIE_Sodium_Compat::VERSION_STRING : false))
    );
}

WordPress Version: 2.1

/**
 * Verifies the contents of a file against its ED25519 signature.
 *
 * @since 5.2.0
 *
 * @param string       $filename            The file to validate.
 * @param string|array $signatures          A Signature provided for the file.
 * @param string       $filename_for_errors A friendly filename for errors. Optional.
 *
 * @return bool|WP_Error true on success, false if verificaiton not attempted, or WP_Error describing an error condition.
 */
function verify_file_signature($filename, $signatures, $filename_for_errors = false)
{
    if (!$filename_for_errors) {
        $filename_for_errors = wp_basename($filename);
    }
    // Check we can process signatures.
    if (!function_exists('sodium_crypto_sign_verify_detached') || !in_array('sha384', array_map('strtolower', hash_algos()))) {
        return new WP_Error('signature_verification_unsupported', sprintf(
            /* translators: %s: The filename of the package. */
            __('The authenticity of %s could not be verified as signature verification is unavailable on this system.'),
            '<span class="code">' . esc_html($filename_for_errors) . '</span>'
        ), (!function_exists('sodium_crypto_sign_verify_detached')) ? 'sodium_crypto_sign_verify_detached' : 'sha384');
    }
    // Check for a edge-case affecting PHP Maths abilities
    if (!extension_loaded('sodium') && in_array(PHP_VERSION_ID, [70200, 70201, 70202], true) && extension_loaded('opcache')) {
        // Sodium_Compat isn't compatible with PHP 7.2.0~7.2.2 due to a bug in the PHP Opcache extension, bail early as it'll fail.
        // https://bugs.php.net/bug.php?id=75938
        return new WP_Error('signature_verification_unsupported', sprintf(
            /* translators: 1: The filename of the package. */
            __('The authenticity of %1$s could not be verified as signature verification is unavailable on this system.'),
            '<span class="code">' . esc_html($filename_for_errors) . '</span>'
        ), array('php' => phpversion(), 'sodium' => defined('SODIUM_LIBRARY_VERSION') ? SODIUM_LIBRARY_VERSION : (defined('ParagonIE_Sodium_Compat::VERSION_STRING') ? ParagonIE_Sodium_Compat::VERSION_STRING : false)));
    }
    // Verify runtime speed of Sodium_Compat is acceptable.
    if (!extension_loaded('sodium') && !ParagonIE_Sodium_Compat::polyfill_is_fast()) {
        $sodium_compat_is_fast = false;
        // Allow for an old version of Sodium_Compat being loaded before the bundled WordPress one.
        if (method_exists('ParagonIE_Sodium_Compat', 'runtime_speed_test')) {
            // Run `ParagonIE_Sodium_Compat::runtime_speed_test()` in optimized integer mode, as that's what WordPress utilises during signing verifications.
            $old_fastMult = ParagonIE_Sodium_Compat::$fastMult;
            ParagonIE_Sodium_Compat::$fastMult = true;
            $sodium_compat_is_fast = ParagonIE_Sodium_Compat::runtime_speed_test(100, 10);
            ParagonIE_Sodium_Compat::$fastMult = $old_fastMult;
        }
        // This cannot be performed in a reasonable amount of time
        // https://github.com/paragonie/sodium_compat#help-sodium_compat-is-slow-how-can-i-make-it-fast
        if (!$sodium_compat_is_fast) {
            return new WP_Error('signature_verification_unsupported', sprintf(
                /* translators: 1: The filename of the package. */
                __('The authenticity of %1$s could not be verified as signature verification is unavailable on this system.'),
                '<span class="code">' . esc_html($filename_for_errors) . '</span>'
            ), array('php' => phpversion(), 'sodium' => defined('SODIUM_LIBRARY_VERSION') ? SODIUM_LIBRARY_VERSION : (defined('ParagonIE_Sodium_Compat::VERSION_STRING') ? ParagonIE_Sodium_Compat::VERSION_STRING : false), 'polyfill_is_fast' => false, 'max_execution_time' => ini_get('max_execution_time')));
        }
    }
    if (!$signatures) {
        return new WP_Error('signature_verification_no_signature', sprintf(
            /* translators: %s: The filename of the package. */
            __('The authenticity of %s could not be verified as no signature was found.'),
            '<span class="code">' . esc_html($filename_for_errors) . '</span>'
        ), array('filename' => $filename_for_errors));
    }
    $trusted_keys = wp_trusted_keys();
    $file_hash = hash_file('sha384', $filename, true);
    mbstring_binary_safe_encoding();
    $skipped_key = $skipped_signature = 0;
    foreach ((array) $signatures as $signature) {
        $signature_raw = base64_decode($signature);
        // Ensure only valid-length signatures are considered.
        if (SODIUM_CRYPTO_SIGN_BYTES !== strlen($signature_raw)) {
            $skipped_signature++;
            continue;
        }
        foreach ((array) $trusted_keys as $key) {
            $key_raw = base64_decode($key);
            // Only pass valid public keys through.
            if (SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES !== strlen($key_raw)) {
                $skipped_key++;
                continue;
            }
            if (sodium_crypto_sign_verify_detached($signature_raw, $file_hash, $key_raw)) {
                reset_mbstring_encoding();
                return true;
            }
        }
    }
    reset_mbstring_encoding();
    return new WP_Error(
        'signature_verification_failed',
        sprintf(
            /* translators: %s: The filename of the package. */
            __('The authenticity of %s could not be verified.'),
            '<span class="code">' . esc_html($filename_for_errors) . '</span>'
        ),
        // Error data helpful for debugging:
        array('filename' => $filename_for_errors, 'keys' => $trusted_keys, 'signatures' => $signatures, 'hash' => bin2hex($file_hash), 'skipped_key' => $skipped_key, 'skipped_sig' => $skipped_signature, 'php' => phpversion(), 'sodium' => defined('SODIUM_LIBRARY_VERSION') ? SODIUM_LIBRARY_VERSION : (defined('ParagonIE_Sodium_Compat::VERSION_STRING') ? ParagonIE_Sodium_Compat::VERSION_STRING : false))
    );
}

WordPress Version: 5.2

/**
 * Verifies the contents of a file against its ED25519 signature.
 *
 * @since 5.2.0
 *
 * @param string       $filename            The file to validate.
 * @param string|array $signatures          A Signature provided for the file.
 * @param string       $filename_for_errors A friendly filename for errors. Optional.
 *
 * @return bool|WP_Error true on success, false if verificaiton not attempted, or WP_Error describing an error condition.
 */
function verify_file_signature($filename, $signatures, $filename_for_errors = false)
{
    if (!$filename_for_errors) {
        $filename_for_errors = wp_basename($filename);
    }
    // Check we can process signatures.
    if (!function_exists('sodium_crypto_sign_verify_detached') || !in_array('sha384', array_map('strtolower', hash_algos()))) {
        return new WP_Error('signature_verification_unsupported', sprintf(
            /* translators: %s: The filename of the package. */
            __('The authenticity of %s could not be verified as signature verification is unavailable on this system.'),
            '<span class="code">' . esc_html($filename_for_errors) . '</span>'
        ), (!function_exists('sodium_crypto_sign_verify_detached')) ? 'sodium_crypto_sign_verify_detached' : 'sha384');
    }
    // Check for a edge-case affecting PHP Maths abilities
    if (!extension_loaded('sodium') && in_array(PHP_VERSION_ID, [70200, 70201, 70202], true) && extension_loaded('opcache')) {
        // Sodium_Compat isn't compatible with PHP 7.2.0~7.2.2 due to a bug in the PHP Opcache extension, bail early as it'll fail.
        // https://bugs.php.net/bug.php?id=75938
        return new WP_Error('signature_verification_unsupported', sprintf(
            /* translators: 1: The filename of the package. */
            __('The authenticity of %1$s could not be verified as signature verification is unavailable on this system.'),
            '<span class="code">' . esc_html($filename_for_errors) . '</span>'
        ), array('php' => phpversion(), 'sodium' => defined('SODIUM_LIBRARY_VERSION') ? SODIUM_LIBRARY_VERSION : (defined('ParagonIE_Sodium_Compat::VERSION_STRING') ? ParagonIE_Sodium_Compat::VERSION_STRING : false)));
    }
    if (!$signatures) {
        return new WP_Error('signature_verification_no_signature', sprintf(
            /* translators: %s: The filename of the package. */
            __('The authenticity of %s could not be verified as no signature was found.'),
            '<span class="code">' . esc_html($filename_for_errors) . '</span>'
        ), array('filename' => $filename_for_errors));
    }
    $trusted_keys = wp_trusted_keys();
    $file_hash = hash_file('sha384', $filename, true);
    mbstring_binary_safe_encoding();
    $skipped_key = $skipped_signature = 0;
    foreach ((array) $signatures as $signature) {
        $signature_raw = base64_decode($signature);
        // Ensure only valid-length signatures are considered.
        if (SODIUM_CRYPTO_SIGN_BYTES !== strlen($signature_raw)) {
            $skipped_signature++;
            continue;
        }
        foreach ((array) $trusted_keys as $key) {
            $key_raw = base64_decode($key);
            // Only pass valid public keys through.
            if (SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES !== strlen($key_raw)) {
                $skipped_key++;
                continue;
            }
            if (sodium_crypto_sign_verify_detached($signature_raw, $file_hash, $key_raw)) {
                reset_mbstring_encoding();
                return true;
            }
        }
    }
    reset_mbstring_encoding();
    return new WP_Error(
        'signature_verification_failed',
        sprintf(
            /* translators: %s: The filename of the package. */
            __('The authenticity of %s could not be verified.'),
            '<span class="code">' . esc_html($filename_for_errors) . '</span>'
        ),
        // Error data helpful for debugging:
        array('filename' => $filename_for_errors, 'keys' => $trusted_keys, 'signatures' => $signatures, 'hash' => bin2hex($file_hash), 'skipped_key' => $skipped_key, 'skipped_sig' => $skipped_signature, 'php' => phpversion(), 'sodium' => defined('SODIUM_LIBRARY_VERSION') ? SODIUM_LIBRARY_VERSION : (defined('ParagonIE_Sodium_Compat::VERSION_STRING') ? ParagonIE_Sodium_Compat::VERSION_STRING : false))
    );
}