diff --git a/ext/hash/config.m4 b/ext/hash/config.m4 index 2da44c503a62e..ec123386000f3 100644 --- a/ext/hash/config.m4 +++ b/ext/hash/config.m4 @@ -3,11 +3,73 @@ PHP_ARG_WITH([mhash], [AS_HELP_STRING([--with-mhash], [Include mhash support])]) +PHP_ARG_WITH([crc-fast], + [for crc-fast support], + [AS_HELP_STRING([--with-crc-fast[=DIR]], + [Include crc-fast support. DIR is the crc-fast install prefix.])]) + AS_VAR_IF([PHP_MHASH], [no],, [ AC_MSG_WARN([The --with-mhash option and mhash* functions are deprecated as of PHP 8.1.0]) AC_DEFINE([PHP_MHASH_BC], [1], [Define to 1 if mhash support is enabled.]) ]) +dnl Check for crc-fast library support +AS_VAR_IF([PHP_CRC_FAST], [no],, [ + AC_MSG_CHECKING([for crc-fast support]) + + dnl Set default search paths + CRC_FAST_SEARCH_PATHS="/usr/local /usr /opt/local" + + dnl If a path was specified, use it + AS_VAR_IF([PHP_CRC_FAST], [yes], [ + CRC_FAST_SEARCH_PATHS="/usr/local /usr /opt/local" + ], [ + CRC_FAST_SEARCH_PATHS="$PHP_CRC_FAST /usr/local /usr /opt/local" + ]) + + dnl Search for header file + CRC_FAST_HEADER_FOUND=no + for i in $CRC_FAST_SEARCH_PATHS; do + AS_IF([test -f "$i/include/libcrc_fast.h"], [ + CRC_FAST_INCDIR="$i/include" + CRC_FAST_HEADER_FOUND=yes + break + ]) + done + + AS_VAR_IF([CRC_FAST_HEADER_FOUND], [no], [ + AC_MSG_ERROR([crc-fast header file libcrc_fast.h not found. Please install crc-fast library or specify correct path with --with-crc-fast=DIR]) + ]) + + dnl Search for library file + CRC_FAST_LIB_FOUND=no + for i in $CRC_FAST_SEARCH_PATHS; do + for j in lib lib64; do + AS_IF([test -f "$i/$j/libcrc_fast.dylib" -o -f "$i/$j/libcrc_fast.so" -o -f "$i/$j/libcrc_fast.a"], [ + CRC_FAST_LIBDIR="$i/$j" + CRC_FAST_LIB_FOUND=yes + break 2 + ]) + done + done + + AS_VAR_IF([CRC_FAST_LIB_FOUND], [no], [ + AC_MSG_ERROR([crc-fast library libcrc_fast not found. Please install crc-fast library or specify correct path with --with-crc-fast=DIR]) + ]) + + dnl Test compilation and linking + PHP_CHECK_LIBRARY([crc_fast], [crc_fast_checksum], [ + AC_DEFINE([HAVE_CRC_FAST], [1], [Define to 1 if crc-fast support is enabled.]) + PHP_ADD_LIBRARY_WITH_PATH([crc_fast], [$CRC_FAST_LIBDIR], [HASH_SHARED_LIBADD]) + PHP_ADD_INCLUDE([$CRC_FAST_INCDIR]) + AC_MSG_RESULT([yes]) + ], [ + AC_MSG_ERROR([crc-fast library test compilation failed. Please check that crc-fast is properly installed.]) + ], [ + -L$CRC_FAST_LIBDIR -I$CRC_FAST_INCDIR + ]) +]) + AS_VAR_IF([ac_cv_c_bigendian_php], [yes], [ EXT_HASH_SHA3_SOURCES= AC_DEFINE([HAVE_SLOW_HASH3], [1], @@ -33,10 +95,20 @@ AS_VAR_IF([ac_cv_c_bigendian_php], [yes], [ PHP_HASH_CFLAGS="$PHP_HASH_CFLAGS -I@ext_srcdir@/$SHA3_DIR -DKeccakP200_excluded -DKeccakP400_excluded -DKeccakP800_excluded" ]) +dnl Set crc-fast sources if enabled +AS_VAR_IF([PHP_CRC_FAST], [no], [ + EXT_HASH_CRC_FAST_SOURCES="" +], [ + EXT_HASH_CRC_FAST_SOURCES="hash_crc_fast.c" +]) + PHP_NEW_EXTENSION([hash], m4_normalize([ $EXT_HASH_SHA3_SOURCES + $EXT_HASH_CRC_FAST_SOURCES hash_adler32.c + hash_crc_common.c hash_crc32.c + hash_crc64.c hash_fnv.c hash_gost.c hash_haval.c @@ -60,9 +132,19 @@ PHP_NEW_EXTENSION([hash], m4_normalize([ [$PHP_HASH_CFLAGS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1]) PHP_ADD_BUILD_DIR([$ext_builddir/murmur]) AS_VAR_IF([SHA3_DIR],,, [PHP_ADD_BUILD_DIR([$ext_builddir/$SHA3_DIR])]) +dnl Set crc-fast headers if enabled +AS_VAR_IF([PHP_CRC_FAST], [no], [ + EXT_HASH_CRC_FAST_HEADERS="" +], [ + EXT_HASH_CRC_FAST_HEADERS="php_hash_crc_fast.h php_hash_crc_common.h" +]) + PHP_INSTALL_HEADERS([ext/hash], m4_normalize([ php_hash_adler32.h php_hash_crc32.h + php_hash_crc64.h + php_hash_crc64_tables.h + $EXT_HASH_CRC_FAST_HEADERS php_hash_fnv.h php_hash_gost.h php_hash_haval.h diff --git a/ext/hash/config.w32 b/ext/hash/config.w32 index dd4c050bcd252..4690e7d29c5f6 100644 --- a/ext/hash/config.w32 +++ b/ext/hash/config.w32 @@ -1,6 +1,7 @@ // vim:ft=javascript ARG_WITH('mhash', 'mhash support (BC via hash)', 'no'); +ARG_WITH('crc-fast', 'crc-fast support', 'no'); if (PHP_MHASH != 'no') { WARNING("mhash* functions are deprecated as of PHP 8.1.0"); @@ -9,10 +10,93 @@ if (PHP_MHASH != 'no') { PHP_HASH = 'yes'; -EXTENSION('hash', 'hash.c hash_md.c hash_sha.c hash_sha_sse2.c hash_sha_ni.c hash_ripemd.c hash_haval.c ' + +// Check for crc-fast library support +var CRC_FAST_ENABLED = false; +if (PHP_CRC_FAST != 'no') { + var lib_found = false; + var header_found = false; + + // Build search paths for library and headers + var lib_search_path = PHP_CRC_FAST; + var include_search_path = PHP_CRC_FAST; + + // Add vcpkg paths if VCPKG_ROOT is set + var vcpkg_root = WshShell.Environment("Process").Item("VCPKG_ROOT"); + if (vcpkg_root) { + lib_search_path += ";" + vcpkg_root + "\\installed\\x64-windows\\lib"; + lib_search_path += ";" + vcpkg_root + "\\installed\\x86-windows\\lib"; + include_search_path += ";" + vcpkg_root + "\\installed\\x64-windows\\include"; + include_search_path += ";" + vcpkg_root + "\\installed\\x86-windows\\include"; + } + + // Add common installation paths + lib_search_path += ";C:\\crc-fast\\lib;C:\\Program Files\\crc-fast\\lib;C:\\Program Files (x86)\\crc-fast\\lib"; + lib_search_path += ";..\\crc-fast\\lib;..\\..\\crc-fast\\lib"; + include_search_path += ";C:\\crc-fast\\include;C:\\Program Files\\crc-fast\\include;C:\\Program Files (x86)\\crc-fast\\include"; + include_search_path += ";..\\crc-fast\\include;..\\..\\crc-fast\\include"; + + // Add parent directory for header search when specific path is given + if (PHP_CRC_FAST != "yes") { + var parent_dir = PHP_CRC_FAST.replace(/\\[^\\]*$/, ""); + include_search_path += ";" + parent_dir; + } + + // Search for library and header + STDOUT.WriteLine("Searching for crc-fast library in: " + lib_search_path); + if (CHECK_LIB("crc_fast.lib", "hash", lib_search_path)) { + lib_found = true; + STDOUT.WriteLine("Found crc-fast library"); + + if (CHECK_HEADER_ADD_INCLUDE("libcrc_fast.h", "CFLAGS_HASH", include_search_path)) { + header_found = true; + } + } + + if (lib_found && header_found) { + AC_DEFINE('HAVE_CRC_FAST', 1, 'Define to 1 if crc-fast support is enabled.'); + CRC_FAST_ENABLED = true; + STDOUT.WriteLine("crc-fast support enabled"); + + // Add required system libraries for Rust crc-fast static library + CHECK_LIB("userenv.lib", "hash"); + CHECK_LIB("ntdll.lib", "hash"); + } else { + var error_msg = "crc-fast library not found. "; + + if (!lib_found) { + error_msg += "Could not find crc_fast.lib. "; + } else { + error_msg += "Library found but libcrc_fast.h header not found. "; + } + + error_msg += "Please ensure crc-fast is properly installed"; + if (PHP_CRC_FAST != "yes") { + error_msg += " in the specified path: " + PHP_CRC_FAST; + } else { + error_msg += ". Consider using vcpkg (vcpkg install crc-fast) or specify the path with --with-crc-fast="; + } + error_msg += "."; + + // If explicitly requested with a path (not just "yes"), this is a fatal error + if (PHP_CRC_FAST != "yes") { + ERROR(error_msg); + } else { + WARNING(error_msg); + } + } +} + +var hash_sources = 'hash.c hash_md.c hash_sha.c hash_sha_sse2.c hash_sha_ni.c hash_ripemd.c hash_haval.c ' + 'hash_tiger.c hash_gost.c hash_snefru.c hash_whirlpool.c ' + - 'hash_adler32.c hash_crc32.c hash_joaat.c hash_fnv.c ' + - 'hash_sha3.c hash_murmur.c hash_xxhash.c', false); + 'hash_adler32.c hash_crc32.c hash_crc64.c hash_joaat.c hash_fnv.c ' + + 'hash_sha3.c hash_murmur.c hash_xxhash.c'; + +// Add crc-fast sources if successfully configured +if (CRC_FAST_ENABLED) { + hash_sources += ' hash_crc_fast.c hash_crc_common.c'; +} + +EXTENSION('hash', hash_sources, false); var hash_sha3_dir = 'ext/hash/sha3/generic' + (X64 ? '64' : '32') + 'lc'; @@ -31,9 +115,16 @@ ADD_FLAG('CFLAGS_HASH', '/DKeccakP200_excluded /DKeccakP400_excluded /DKeccakP80 ADD_SOURCES('ext/hash/murmur', 'PMurHash.c PMurHash128.c', 'hash'); -PHP_INSTALL_HEADERS('ext/hash', 'php_hash.h php_hash_md.h php_hash_sha.h ' + +var hash_headers = 'php_hash.h php_hash_md.h php_hash_sha.h ' + 'php_hash_ripemd.h php_hash_haval.h php_hash_tiger.h ' + 'php_hash_gost.h php_hash_snefru.h php_hash_whirlpool.h ' + - 'php_hash_adler32.h php_hash_crc32.h php_hash_sha3.h ' + + 'php_hash_adler32.h php_hash_crc32.h php_hash_crc64.h php_hash_crc64_tables.h php_hash_sha3.h ' + 'php_hash_murmur.h php_hash_xxhash.h php_hash_fnv.h ' + - 'php_hash_joaat.h xxhash/xxhash.h'); + 'php_hash_joaat.h xxhash/xxhash.h'; + +// Add crc-fast headers if successfully configured +if (CRC_FAST_ENABLED) { + hash_headers += ' php_hash_crc_fast.h php_hash_crc_common.h'; +} + +PHP_INSTALL_HEADERS('ext/hash', hash_headers); diff --git a/ext/hash/hash.c b/ext/hash/hash.c index d255711efbed9..6d9fe933ddaa1 100644 --- a/ext/hash/hash.c +++ b/ext/hash/hash.c @@ -10,8 +10,9 @@ | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ - | Author: Sara Golemon | - | Scott MacVicar | + | Authors: Sara Golemon | + | Scott MacVicar | + | Don MacAskill | +----------------------------------------------------------------------+ */ @@ -32,6 +33,10 @@ #include "hash_arginfo.h" +#ifdef HAVE_CRC_FAST +#include +#endif + #ifdef PHP_WIN32 # define __alignof__ __alignof #else @@ -1624,6 +1629,11 @@ PHP_MINIT_FUNCTION(hash) php_hash_register_algo("crc32", &php_hash_crc32_ops); php_hash_register_algo("crc32b", &php_hash_crc32b_ops); php_hash_register_algo("crc32c", &php_hash_crc32c_ops); + php_hash_register_algo("crc32-iso-hdlc", &php_hash_crc32_iso_hdlc_ops); + php_hash_register_algo("crc32-iscsi", &php_hash_crc32_iscsi_ops); + php_hash_register_algo("crc32-php", &php_hash_crc32_php_ops); + php_hash_register_algo("crc64-nvme", &php_hash_crc64_nvme_ops); + php_hash_register_algo("crc64-ecma-182", &php_hash_crc64_ecma182_ops); php_hash_register_algo("fnv132", &php_hash_fnv132_ops); php_hash_register_algo("fnv1a32", &php_hash_fnv1a32_ops); php_hash_register_algo("fnv164", &php_hash_fnv164_ops); @@ -1698,8 +1708,20 @@ PHP_MINFO_FUNCTION(hash) php_info_print_table_start(); php_info_print_table_row(2, "hash support", "enabled"); php_info_print_table_row(2, "Hashing Engines", buffer); +#ifdef HAVE_CRC_FAST + php_info_print_table_row(2, "crc-fast support", "enabled"); +#else + php_info_print_table_row(2, "crc-fast support", "disabled"); +#endif php_info_print_table_end(); +#ifdef HAVE_CRC_FAST + php_info_print_table_start(); + php_info_print_table_row(2, "crc-fast library version", crc_fast_get_version()); + php_info_print_table_row(2, "crc-fast target", crc_fast_get_calculator_target(Crc32Iscsi)); + php_info_print_table_end(); +#endif + #ifdef PHP_MHASH_BC php_info_print_table_start(); php_info_print_table_row(2, "MHASH support", "Enabled"); diff --git a/ext/hash/hash_crc32.c b/ext/hash/hash_crc32.c index a770d0b554167..d72dd01a2fbb3 100644 --- a/ext/hash/hash_crc32.c +++ b/ext/hash/hash_crc32.c @@ -12,92 +12,229 @@ +----------------------------------------------------------------------+ | Authors: Michael Wallner | | Sara Golemon | + | Don MacAskill | +----------------------------------------------------------------------+ */ #include "php_hash.h" #include "php_hash_crc32.h" #include "php_hash_crc32_tables.h" +#include "php_hash_crc_common.h" #include "ext/standard/crc32_x86.h" +#ifdef HAVE_CRC_FAST +#include "php_hash_crc_fast.h" +#endif + PHP_HASH_API void PHP_CRC32Init(PHP_CRC32_CTX *context, ZEND_ATTRIBUTE_UNUSED HashTable *args) { - context->state = ~0; + PHP_CRC_INIT_CONTEXT(context, ~0, CRC_FAST_CRC32_BZIP2); } -PHP_HASH_API void PHP_CRC32Update(PHP_CRC32_CTX *context, const unsigned char *input, size_t len) +PHP_HASH_API void PHP_CRC32BInit(PHP_CRC32_CTX *context, ZEND_ATTRIBUTE_UNUSED HashTable *args) +{ + PHP_CRC_INIT_CONTEXT(context, ~0, CRC_FAST_CRC32_ISO_HDLC); +} + +PHP_HASH_API void PHP_CRC32CInit(PHP_CRC32_CTX *context, ZEND_ATTRIBUTE_UNUSED HashTable *args) { + PHP_CRC_INIT_CONTEXT(context, ~0, CRC_FAST_CRC32_ISCSI); +} + +/* Software-only CRC32 update function */ +static void php_crc32_software_update(PHP_CRC32_CTX *context, const unsigned char *input, size_t len) +{ + if (UNEXPECTED(len == 0)) return; + size_t i = 0; #if defined(ZEND_INTRIN_SSE4_2_PCLMUL_NATIVE) || defined(ZEND_INTRIN_SSE4_2_PCLMUL_RESOLVER) i += crc32_x86_simd_update(X86_CRC32, &context->state, input, len); #endif - for (; i < len; ++i) { - context->state = (context->state << 8) ^ crc32_table[(context->state >> 24) ^ (input[i] & 0xff)]; + const unsigned char *end = input + len; + const unsigned char *p = input + i; + + while (p < end) { + context->state = (context->state << 8) ^ crc32_table[(context->state >> 24) ^ (*p & 0xff)]; + p++; } } -PHP_HASH_API void PHP_CRC32BUpdate(PHP_CRC32_CTX *context, const unsigned char *input, size_t len) +PHP_HASH_API void PHP_CRC32Update(PHP_CRC32_CTX *context, const unsigned char *input, size_t len) { + PHP_CRC_UPDATE_CONTEXT(context, input, len, php_crc32_software_update); +} + +/* Software-only CRC32B update function */ +static void php_crc32b_software_update(PHP_CRC32_CTX *context, const unsigned char *input, size_t len) +{ + if (UNEXPECTED(len == 0)) return; + size_t i = 0; #if defined(ZEND_INTRIN_SSE4_2_PCLMUL_NATIVE) || defined(ZEND_INTRIN_SSE4_2_PCLMUL_RESOLVER) i += crc32_x86_simd_update(X86_CRC32B, &context->state, input, len); #endif - for (; i < len; ++i) { - context->state = (context->state >> 8) ^ crc32b_table[(context->state ^ input[i]) & 0xff]; + const unsigned char *end = input + len; + const unsigned char *p = input + i; + + while (p < end) { + context->state = (context->state >> 8) ^ crc32b_table[(context->state ^ *p) & 0xff]; + p++; } } -PHP_HASH_API void PHP_CRC32CUpdate(PHP_CRC32_CTX *context, const unsigned char *input, size_t len) +PHP_HASH_API void PHP_CRC32BUpdate(PHP_CRC32_CTX *context, const unsigned char *input, size_t len) { + PHP_CRC_UPDATE_CONTEXT(context, input, len, php_crc32b_software_update); +} + +/* Software-only CRC32C update function */ +static void php_crc32c_software_update(PHP_CRC32_CTX *context, const unsigned char *input, size_t len) +{ + if (UNEXPECTED(len == 0)) return; + size_t i = 0; #if defined(ZEND_INTRIN_SSE4_2_PCLMUL_NATIVE) || defined(ZEND_INTRIN_SSE4_2_PCLMUL_RESOLVER) i += crc32_x86_simd_update(X86_CRC32C, &context->state, input, len); #endif - for (; i < len; ++i) { - context->state = (context->state >> 8) ^ crc32c_table[(context->state ^ input[i]) & 0xff]; + const unsigned char *end = input + len; + const unsigned char *p = input + i; + + while (p < end) { + context->state = (context->state >> 8) ^ crc32c_table[(context->state ^ *p) & 0xff]; + p++; } } +PHP_HASH_API void PHP_CRC32CUpdate(PHP_CRC32_CTX *context, const unsigned char *input, size_t len) +{ + PHP_CRC_UPDATE_CONTEXT(context, input, len, php_crc32c_software_update); +} + +/* Software-only CRC32 little-endian finalization */ +static void php_crc32le_software_final(unsigned char digest[4], PHP_CRC32_CTX *context) +{ + uint32_t final_state = ~context->state; + digest[0] = (unsigned char) (final_state & 0xff); + digest[1] = (unsigned char) ((final_state >> 8) & 0xff); + digest[2] = (unsigned char) ((final_state >> 16) & 0xff); + digest[3] = (unsigned char) ((final_state >> 24) & 0xff); + context->state = 0; +} + PHP_HASH_API void PHP_CRC32LEFinal(unsigned char digest[4], PHP_CRC32_CTX *context) { - context->state=~context->state; - digest[3] = (unsigned char) ((context->state >> 24) & 0xff); - digest[2] = (unsigned char) ((context->state >> 16) & 0xff); - digest[1] = (unsigned char) ((context->state >> 8) & 0xff); - digest[0] = (unsigned char) (context->state & 0xff); +#ifdef HAVE_CRC_FAST + if (EXPECTED(context->using_crc_fast)) { + uint32_t crc32_result = (uint32_t)php_crc_fast_final(&context->crc_fast_ctx); + + /* Store in little-endian format for CRC32 */ + digest[0] = (unsigned char) (crc32_result & 0xff); + digest[1] = (unsigned char) ((crc32_result >> 8) & 0xff); + digest[2] = (unsigned char) ((crc32_result >> 16) & 0xff); + digest[3] = (unsigned char) ((crc32_result >> 24) & 0xff); + + php_crc_fast_free(&context->crc_fast_ctx); + context->state = 0; + return; + } +#endif + php_crc32le_software_final(digest, context); +} + +/* Software-only CRC32 big-endian finalization */ +static void php_crc32be_software_final(unsigned char digest[4], PHP_CRC32_CTX *context) +{ + uint32_t final_state = ~context->state; + digest[0] = (unsigned char) ((final_state >> 24) & 0xff); + digest[1] = (unsigned char) ((final_state >> 16) & 0xff); + digest[2] = (unsigned char) ((final_state >> 8) & 0xff); + digest[3] = (unsigned char) (final_state & 0xff); context->state = 0; } PHP_HASH_API void PHP_CRC32BEFinal(unsigned char digest[4], PHP_CRC32_CTX *context) { - context->state=~context->state; - digest[0] = (unsigned char) ((context->state >> 24) & 0xff); - digest[1] = (unsigned char) ((context->state >> 16) & 0xff); - digest[2] = (unsigned char) ((context->state >> 8) & 0xff); - digest[3] = (unsigned char) (context->state & 0xff); - context->state = 0; +#ifdef HAVE_CRC_FAST + if (EXPECTED(context->using_crc_fast)) { + uint32_t crc32_result = (uint32_t)php_crc_fast_final(&context->crc_fast_ctx); + + /* Store in big-endian format for CRC32B/CRC32C */ + digest[0] = (unsigned char) ((crc32_result >> 24) & 0xff); + digest[1] = (unsigned char) ((crc32_result >> 16) & 0xff); + digest[2] = (unsigned char) ((crc32_result >> 8) & 0xff); + digest[3] = (unsigned char) (crc32_result & 0xff); + + php_crc_fast_free(&context->crc_fast_ctx); + context->state = 0; + return; + } +#endif + php_crc32be_software_final(digest, context); } PHP_HASH_API zend_result PHP_CRC32Copy(const php_hash_ops *ops, const PHP_CRC32_CTX *orig_context, PHP_CRC32_CTX *copy_context) { - copy_context->state = orig_context->state; + PHP_CRC_COPY_CONTEXT(orig_context, copy_context, uint32_t); return SUCCESS; } +/* CRC32 serialization function that handles crc-fast contexts */ +static hash_spec_result php_crc32_serialize(const php_hashcontext_object *hash, zend_long *magic, zval *zv) +{ + const PHP_CRC32_CTX *ctx = (const PHP_CRC32_CTX *) hash->context; + zval tmp; + + *magic = PHP_HASH_SERIALIZE_MAGIC_SPEC; + +#ifdef HAVE_CRC_FAST + uint32_t state_to_serialize = (uint32_t)php_crc_get_serialization_state( + ctx, ctx->using_crc_fast, &ctx->crc_fast_ctx, ctx->state); +#else + uint32_t state_to_serialize = ctx->state; +#endif + + array_init(zv); + ZVAL_LONG(&tmp, (zend_long) state_to_serialize); + zend_hash_next_index_insert(Z_ARRVAL_P(zv), &tmp); + + return HASH_SPEC_SUCCESS; +} + +/* CRC32 unserialization function */ +static hash_spec_result php_crc32_unserialize(php_hashcontext_object *hash, zend_long magic, const zval *zv) +{ + PHP_CRC32_CTX *ctx = (PHP_CRC32_CTX *) hash->context; + zval *tmp; + + if (magic != PHP_HASH_SERIALIZE_MAGIC_SPEC || Z_TYPE_P(zv) != IS_ARRAY) { + return HASH_SPEC_FAILURE; + } + + tmp = zend_hash_index_find(Z_ARRVAL_P(zv), 0); + if (!tmp || Z_TYPE_P(tmp) != IS_LONG) { + return HASH_SPEC_FAILURE; + } + + ctx->state = (uint32_t) Z_LVAL_P(tmp); + PHP_CRC_RESET_CONTEXT_FOR_UNSERIALIZE(ctx); + + return HASH_SPEC_SUCCESS; +} + const php_hash_ops php_hash_crc32_ops = { "crc32", (php_hash_init_func_t) PHP_CRC32Init, (php_hash_update_func_t) PHP_CRC32Update, (php_hash_final_func_t) PHP_CRC32LEFinal, (php_hash_copy_func_t) PHP_CRC32Copy, - php_hash_serialize, - php_hash_unserialize, + php_crc32_serialize, + php_crc32_unserialize, PHP_CRC32_SPEC, 4, /* what to say here? */ 4, @@ -107,12 +244,12 @@ const php_hash_ops php_hash_crc32_ops = { const php_hash_ops php_hash_crc32b_ops = { "crc32b", - (php_hash_init_func_t) PHP_CRC32Init, + (php_hash_init_func_t) PHP_CRC32BInit, (php_hash_update_func_t) PHP_CRC32BUpdate, (php_hash_final_func_t) PHP_CRC32BEFinal, (php_hash_copy_func_t) PHP_CRC32Copy, - php_hash_serialize, - php_hash_unserialize, + php_crc32_serialize, + php_crc32_unserialize, PHP_CRC32_SPEC, 4, /* what to say here? */ 4, @@ -122,15 +259,60 @@ const php_hash_ops php_hash_crc32b_ops = { const php_hash_ops php_hash_crc32c_ops = { "crc32c", - (php_hash_init_func_t) PHP_CRC32Init, + (php_hash_init_func_t) PHP_CRC32CInit, (php_hash_update_func_t) PHP_CRC32CUpdate, (php_hash_final_func_t) PHP_CRC32BEFinal, (php_hash_copy_func_t) PHP_CRC32Copy, - php_hash_serialize, - php_hash_unserialize, + php_crc32_serialize, + php_crc32_unserialize, PHP_CRC32_SPEC, 4, /* what to say here? */ 4, sizeof(PHP_CRC32_CTX), 0 }; + +const php_hash_ops php_hash_crc32_iso_hdlc_ops = { + "crc32-iso-hdlc", + (php_hash_init_func_t) PHP_CRC32BInit, + (php_hash_update_func_t) PHP_CRC32BUpdate, + (php_hash_final_func_t) PHP_CRC32BEFinal, + (php_hash_copy_func_t) PHP_CRC32Copy, + php_crc32_serialize, + php_crc32_unserialize, + PHP_CRC32_SPEC, + 4, + 4, + sizeof(PHP_CRC32_CTX), + 0 +}; + +const php_hash_ops php_hash_crc32_iscsi_ops = { + "crc32-iscsi", + (php_hash_init_func_t) PHP_CRC32CInit, + (php_hash_update_func_t) PHP_CRC32CUpdate, + (php_hash_final_func_t) PHP_CRC32BEFinal, + (php_hash_copy_func_t) PHP_CRC32Copy, + php_crc32_serialize, + php_crc32_unserialize, + PHP_CRC32_SPEC, + 4, + 4, + sizeof(PHP_CRC32_CTX), + 0 +}; + +const php_hash_ops php_hash_crc32_php_ops = { + "crc32-php", + (php_hash_init_func_t) PHP_CRC32Init, + (php_hash_update_func_t) PHP_CRC32Update, + (php_hash_final_func_t) PHP_CRC32LEFinal, + (php_hash_copy_func_t) PHP_CRC32Copy, + php_crc32_serialize, + php_crc32_unserialize, + PHP_CRC32_SPEC, + 4, + 4, + sizeof(PHP_CRC32_CTX), + 0 +}; diff --git a/ext/hash/hash_crc64.c b/ext/hash/hash_crc64.c new file mode 100644 index 0000000000000..a582d98a15d7e --- /dev/null +++ b/ext/hash/hash_crc64.c @@ -0,0 +1,201 @@ +/* + +----------------------------------------------------------------------+ + | Copyright (c) The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | https://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Don MacAskill | + +----------------------------------------------------------------------+ +*/ + +#include "php_hash.h" +#include "php_hash_crc64.h" +#include "php_hash_crc64_tables.h" +#include "php_hash_crc_common.h" + +#ifdef HAVE_CRC_FAST +#include "php_hash_crc_fast.h" +#endif + +/* CRC-64/NVME initialization */ +PHP_HASH_API void PHP_CRC64NVMEInit(PHP_CRC64_CTX *context, ZEND_ATTRIBUTE_UNUSED HashTable *args) +{ + PHP_CRC_INIT_CONTEXT(context, ~0ULL, CRC_FAST_CRC64_NVME); +} + +/* CRC-64/ECMA-182 initialization */ +PHP_HASH_API void PHP_CRC64ECMA182Init(PHP_CRC64_CTX *context, ZEND_ATTRIBUTE_UNUSED HashTable *args) +{ + PHP_CRC_INIT_CONTEXT(context, 0ULL, CRC_FAST_CRC64_ECMA182); +} + +/* Software-only CRC64 NVME update function */ +static void php_crc64_nvme_software_update(PHP_CRC64_CTX *context, const unsigned char *input, size_t len) +{ + if (UNEXPECTED(len == 0)) return; + + const unsigned char *end = input + len; + const unsigned char *p = input; + + while (p < end) { + context->state = (context->state >> 8) ^ crc64_nvme_table[(context->state ^ *p) & 0xff]; + p++; + } +} + +/* CRC-64/NVME update function */ +PHP_HASH_API void PHP_CRC64NVMEUpdate(PHP_CRC64_CTX *context, const unsigned char *input, size_t len) +{ + PHP_CRC_UPDATE_CONTEXT(context, input, len, php_crc64_nvme_software_update); +} + +/* Software-only CRC64 ECMA-182 update function */ +static void php_crc64_ecma182_software_update(PHP_CRC64_CTX *context, const unsigned char *input, size_t len) +{ + if (UNEXPECTED(len == 0)) return; + + const unsigned char *end = input + len; + const unsigned char *p = input; + + while (p < end) { + context->state = (context->state << 8) ^ crc64_ecma182_table[((context->state >> 56) ^ *p) & 0xff]; + p++; + } +} + +/* CRC-64/ECMA-182 update function */ +PHP_HASH_API void PHP_CRC64ECMA182Update(PHP_CRC64_CTX *context, const unsigned char *input, size_t len) +{ + PHP_CRC_UPDATE_CONTEXT(context, input, len, php_crc64_ecma182_software_update); +} + +/* Software-only CRC64 NVME finalization */ +static void php_crc64_nvme_software_final(unsigned char digest[8], PHP_CRC64_CTX *context) +{ + uint64_t final_state = ~context->state; + +#ifdef WORDS_BIGENDIAN + memcpy(digest, &final_state, 8); +#else + final_state = ZEND_BYTES_SWAP64(final_state); + memcpy(digest, &final_state, 8); +#endif + context->state = 0; +} + +/* CRC-64/NVME finalization */ +PHP_HASH_API void PHP_CRC64NVMEFinal(unsigned char digest[8], PHP_CRC64_CTX *context) +{ + PHP_CRC_FINALIZE_CONTEXT(context, digest, 8, php_crc64_nvme_software_final); +} + +/* Software-only CRC64 ECMA-182 finalization */ +static void php_crc64_ecma182_software_final(unsigned char digest[8], PHP_CRC64_CTX *context) +{ +#ifdef WORDS_BIGENDIAN + memcpy(digest, &context->state, 8); +#else + uint64_t final_state = ZEND_BYTES_SWAP64(context->state); + memcpy(digest, &final_state, 8); +#endif + context->state = 0; +} + +/* CRC-64/ECMA-182 finalization */ +PHP_HASH_API void PHP_CRC64ECMA182Final(unsigned char digest[8], PHP_CRC64_CTX *context) +{ + PHP_CRC_FINALIZE_CONTEXT(context, digest, 8, php_crc64_ecma182_software_final); +} + +/* CRC64 context copy function */ +PHP_HASH_API zend_result PHP_CRC64Copy(const php_hash_ops *ops, const PHP_CRC64_CTX *orig_context, PHP_CRC64_CTX *copy_context) +{ + PHP_CRC_COPY_CONTEXT(orig_context, copy_context, uint64_t); + return SUCCESS; +} + +/* CRC64 serialization function that handles crc-fast contexts */ +static hash_spec_result php_crc64_serialize(const php_hashcontext_object *hash, zend_long *magic, zval *zv) +{ + const PHP_CRC64_CTX *ctx = (const PHP_CRC64_CTX *) hash->context; + zval tmp; + + *magic = PHP_HASH_SERIALIZE_MAGIC_SPEC; + +#ifdef HAVE_CRC_FAST + uint64_t state_to_serialize = php_crc_get_serialization_state( + ctx, ctx->using_crc_fast, &ctx->crc_fast_ctx, ctx->state); +#else + uint64_t state_to_serialize = ctx->state; +#endif + + array_init(zv); + /* Serialize 64-bit value as two 32-bit values for compatibility */ + ZVAL_LONG(&tmp, (zend_long) (state_to_serialize & 0xFFFFFFFF)); + zend_hash_next_index_insert(Z_ARRVAL_P(zv), &tmp); + ZVAL_LONG(&tmp, (zend_long) (state_to_serialize >> 32)); + zend_hash_next_index_insert(Z_ARRVAL_P(zv), &tmp); + + return HASH_SPEC_SUCCESS; +} + +/* CRC64 unserialization function */ +static hash_spec_result php_crc64_unserialize(php_hashcontext_object *hash, zend_long magic, const zval *zv) +{ + PHP_CRC64_CTX *ctx = (PHP_CRC64_CTX *) hash->context; + zval *tmp1, *tmp2; + + if (magic != PHP_HASH_SERIALIZE_MAGIC_SPEC || Z_TYPE_P(zv) != IS_ARRAY) { + return HASH_SPEC_FAILURE; + } + + tmp1 = zend_hash_index_find(Z_ARRVAL_P(zv), 0); + tmp2 = zend_hash_index_find(Z_ARRVAL_P(zv), 1); + if (!tmp1 || Z_TYPE_P(tmp1) != IS_LONG || !tmp2 || Z_TYPE_P(tmp2) != IS_LONG) { + return HASH_SPEC_FAILURE; + } + + /* Reconstruct 64-bit value from two 32-bit values */ + ctx->state = ((uint64_t) Z_LVAL_P(tmp2) << 32) | ((uint64_t) Z_LVAL_P(tmp1) & 0xFFFFFFFF); + PHP_CRC_RESET_CONTEXT_FOR_UNSERIALIZE(ctx); + + return HASH_SPEC_SUCCESS; +} + +/* CRC-64/NVME hash operations structure */ +const php_hash_ops php_hash_crc64_nvme_ops = { + "crc64-nvme", + (php_hash_init_func_t) PHP_CRC64NVMEInit, + (php_hash_update_func_t) PHP_CRC64NVMEUpdate, + (php_hash_final_func_t) PHP_CRC64NVMEFinal, + (php_hash_copy_func_t) PHP_CRC64Copy, + php_crc64_serialize, + php_crc64_unserialize, + PHP_CRC64_SPEC, + 8, + 8, + sizeof(PHP_CRC64_CTX), + 0 +}; + +/* CRC-64/ECMA-182 hash operations structure */ +const php_hash_ops php_hash_crc64_ecma182_ops = { + "crc64-ecma-182", + (php_hash_init_func_t) PHP_CRC64ECMA182Init, + (php_hash_update_func_t) PHP_CRC64ECMA182Update, + (php_hash_final_func_t) PHP_CRC64ECMA182Final, + (php_hash_copy_func_t) PHP_CRC64Copy, + php_crc64_serialize, + php_crc64_unserialize, + PHP_CRC64_SPEC, + 8, + 8, + sizeof(PHP_CRC64_CTX), + 0 +}; diff --git a/ext/hash/hash_crc_common.c b/ext/hash/hash_crc_common.c new file mode 100644 index 0000000000000..006bbf11baacc --- /dev/null +++ b/ext/hash/hash_crc_common.c @@ -0,0 +1,34 @@ +/* + +----------------------------------------------------------------------+ + | Copyright (c) The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | https://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Don MacAskill | + +----------------------------------------------------------------------+ +*/ + +#include "php_hash.h" +#include "php_hash_crc_common.h" + +/* CRC64 result storage helper - stores 64-bit results in big-endian format */ +PHP_HASH_API void php_crc_store_result(unsigned char *digest, uint64_t result, size_t digest_size) +{ + /* This function is only used by CRC64 algorithms, which expect big-endian output */ + if (digest_size == 8) { + digest[0] = (unsigned char) ((result >> 56) & 0xff); + digest[1] = (unsigned char) ((result >> 48) & 0xff); + digest[2] = (unsigned char) ((result >> 40) & 0xff); + digest[3] = (unsigned char) ((result >> 32) & 0xff); + digest[4] = (unsigned char) ((result >> 24) & 0xff); + digest[5] = (unsigned char) ((result >> 16) & 0xff); + digest[6] = (unsigned char) ((result >> 8) & 0xff); + digest[7] = (unsigned char) (result & 0xff); + } +} \ No newline at end of file diff --git a/ext/hash/hash_crc_fast.c b/ext/hash/hash_crc_fast.c new file mode 100644 index 0000000000000..fba1bd7ff79c9 --- /dev/null +++ b/ext/hash/hash_crc_fast.c @@ -0,0 +1,129 @@ +/* + +----------------------------------------------------------------------+ + | Copyright (c) The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | https://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Don MacAskill | + +----------------------------------------------------------------------+ +*/ + +#include "php_hash.h" +#include "php_hash_crc_fast.h" +#include "zend_exceptions.h" + +#ifdef HAVE_CRC_FAST + +/* Initialize a crc-fast context with specified algorithm */ +PHP_HASH_API zend_result php_crc_fast_init(php_crc_fast_context *context, enum CrcFastAlgorithm algorithm) +{ + if (!context) { + return FAILURE; + } + + context->digest_handle = crc_fast_digest_new(algorithm); + if (!context->digest_handle) { + return FAILURE; + } + + context->algorithm = algorithm; + context->finalized = false; + + return SUCCESS; +} + +/* Update crc-fast context with new data chunk - optimized for hot path */ +PHP_HASH_API void php_crc_fast_update(php_crc_fast_context *context, const unsigned char *data, size_t len) +{ + /* Fast path: inline common case checks for better performance */ + if (EXPECTED(php_crc_fast_is_available(context) && (data || len == 0))) { + if (len > 0) { + crc_fast_digest_update(context->digest_handle, (const char *)data, len); + } + } +} + +/* Finalize crc-fast context and return computed checksum */ +PHP_HASH_API uint64_t php_crc_fast_final(php_crc_fast_context *context) +{ + uint64_t result; + + if (!context || !context->digest_handle) { + php_crc_fast_throw_exception("Invalid context provided to php_crc_fast_final"); + return 0; + } + + if (context->finalized) { + php_crc_fast_throw_exception("Context already finalized"); + return 0; + } + + result = crc_fast_digest_finalize(context->digest_handle); + context->finalized = true; + + return result; +} + +/* Copy crc-fast context for hash_copy() support */ +PHP_HASH_API zend_result php_crc_fast_copy(const php_crc_fast_context *src, php_crc_fast_context *dest) +{ + if (!src || !dest) { + return FAILURE; + } + + if (src->finalized || !src->digest_handle) { + return FAILURE; + } + + /* Extract current state from source digest */ + uint64_t current_state = crc_fast_digest_get_state(src->digest_handle); + + /* Create new digest with the extracted state */ + dest->digest_handle = crc_fast_digest_new_with_init_state(src->algorithm, current_state); + if (!dest->digest_handle) { + return FAILURE; + } + + dest->algorithm = src->algorithm; + dest->finalized = false; + + return SUCCESS; +} + +/* One-shot checksum calculation for performance optimization */ +PHP_HASH_API uint64_t php_crc_fast_checksum(enum CrcFastAlgorithm algorithm, const unsigned char *data, size_t len) +{ + /* Fast path: optimize for common case */ + if (EXPECTED(data || len == 0)) { + return crc_fast_checksum(algorithm, (const char *)data, len); + } + + /* This should not happen in normal operation since callers validate input */ + return 0; +} + +/* Free crc-fast context resources */ +PHP_HASH_API void php_crc_fast_free(php_crc_fast_context *context) +{ + if (context && context->digest_handle) { + crc_fast_digest_free(context->digest_handle); + context->digest_handle = NULL; + context->finalized = true; + } +} + + + +/* Error handling function */ +PHP_HASH_API void php_crc_fast_throw_exception(const char *message) +{ + zend_throw_exception(zend_ce_error, message, 0); +} + +#endif /* HAVE_CRC_FAST */ \ No newline at end of file diff --git a/ext/hash/php_hash.h b/ext/hash/php_hash.h index f56605a33be6a..bad4536d06a51 100644 --- a/ext/hash/php_hash.h +++ b/ext/hash/php_hash.h @@ -108,6 +108,11 @@ extern const php_hash_ops php_hash_adler32_ops; extern const php_hash_ops php_hash_crc32_ops; extern const php_hash_ops php_hash_crc32b_ops; extern const php_hash_ops php_hash_crc32c_ops; +extern const php_hash_ops php_hash_crc32_iso_hdlc_ops; +extern const php_hash_ops php_hash_crc32_iscsi_ops; +extern const php_hash_ops php_hash_crc32_php_ops; +extern const php_hash_ops php_hash_crc64_nvme_ops; +extern const php_hash_ops php_hash_crc64_ecma182_ops; extern const php_hash_ops php_hash_fnv132_ops; extern const php_hash_ops php_hash_fnv1a32_ops; extern const php_hash_ops php_hash_fnv164_ops; diff --git a/ext/hash/php_hash_crc32.h b/ext/hash/php_hash_crc32.h index b6accea17bb64..6799f7c84feda 100644 --- a/ext/hash/php_hash_crc32.h +++ b/ext/hash/php_hash_crc32.h @@ -10,7 +10,8 @@ | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ - | Author: Michael Wallner | + | Authors: Michael Wallner | + | Don MacAskill | +----------------------------------------------------------------------+ */ @@ -19,12 +20,22 @@ #include "ext/standard/basic_functions.h" +#ifdef HAVE_CRC_FAST +#include "php_hash_crc_fast.h" +#endif + typedef struct { - uint32_t state; +#ifdef HAVE_CRC_FAST + bool using_crc_fast; /* Move bool to beginning for better alignment */ + php_crc_fast_context crc_fast_ctx; +#endif + uint32_t state; /* Keep state at end for cache line optimization */ } PHP_CRC32_CTX; #define PHP_CRC32_SPEC "l." PHP_HASH_API void PHP_CRC32Init(PHP_CRC32_CTX *context, ZEND_ATTRIBUTE_UNUSED HashTable *args); +PHP_HASH_API void PHP_CRC32BInit(PHP_CRC32_CTX *context, ZEND_ATTRIBUTE_UNUSED HashTable *args); +PHP_HASH_API void PHP_CRC32CInit(PHP_CRC32_CTX *context, ZEND_ATTRIBUTE_UNUSED HashTable *args); PHP_HASH_API void PHP_CRC32Update(PHP_CRC32_CTX *context, const unsigned char *input, size_t len); PHP_HASH_API void PHP_CRC32BUpdate(PHP_CRC32_CTX *context, const unsigned char *input, size_t len); PHP_HASH_API void PHP_CRC32CUpdate(PHP_CRC32_CTX *context, const unsigned char *input, size_t len); diff --git a/ext/hash/php_hash_crc64.h b/ext/hash/php_hash_crc64.h new file mode 100644 index 0000000000000..b64736a6a078a --- /dev/null +++ b/ext/hash/php_hash_crc64.h @@ -0,0 +1,43 @@ +/* + +----------------------------------------------------------------------+ + | Copyright (c) The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | https://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Don MacAskill | + +----------------------------------------------------------------------+ +*/ + +#ifndef PHP_HASH_CRC64_H +#define PHP_HASH_CRC64_H + +#include "ext/standard/basic_functions.h" + +#ifdef HAVE_CRC_FAST +#include "php_hash_crc_fast.h" +#endif + +typedef struct { +#ifdef HAVE_CRC_FAST + bool using_crc_fast; /* Move bool to beginning for better alignment */ + php_crc_fast_context crc_fast_ctx; +#endif + uint64_t state; /* Keep state at end for cache line optimization */ +} PHP_CRC64_CTX; +#define PHP_CRC64_SPEC "q." + +PHP_HASH_API void PHP_CRC64NVMEInit(PHP_CRC64_CTX *context, ZEND_ATTRIBUTE_UNUSED HashTable *args); +PHP_HASH_API void PHP_CRC64ECMA182Init(PHP_CRC64_CTX *context, ZEND_ATTRIBUTE_UNUSED HashTable *args); +PHP_HASH_API void PHP_CRC64NVMEUpdate(PHP_CRC64_CTX *context, const unsigned char *input, size_t len); +PHP_HASH_API void PHP_CRC64ECMA182Update(PHP_CRC64_CTX *context, const unsigned char *input, size_t len); +PHP_HASH_API void PHP_CRC64NVMEFinal(unsigned char digest[8], PHP_CRC64_CTX *context); +PHP_HASH_API void PHP_CRC64ECMA182Final(unsigned char digest[8], PHP_CRC64_CTX *context); +PHP_HASH_API zend_result PHP_CRC64Copy(const php_hash_ops *ops, const PHP_CRC64_CTX *orig_context, PHP_CRC64_CTX *copy_context); + +#endif diff --git a/ext/hash/php_hash_crc64_tables.h b/ext/hash/php_hash_crc64_tables.h new file mode 100644 index 0000000000000..34362814047c5 --- /dev/null +++ b/ext/hash/php_hash_crc64_tables.h @@ -0,0 +1,215 @@ +/* + +----------------------------------------------------------------------+ + | Copyright (c) The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | https://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Don MacAskill | + +----------------------------------------------------------------------+ +*/ + +/* CRC-64/NVME lookup table (reflected polynomial 0x9A6C9329AC4BC9B5) */ +static const uint64_t crc64_nvme_table[] = { + 0x0000000000000000ULL,0x7F6EF0C830358979ULL, + 0xFEDDE190606B12F2ULL,0x81B31158505E9B8BULL, + 0xC962E5739841B68FULL,0xB60C15BBA8743FF6ULL, + 0x37BF04E3F82AA47DULL,0x48D1F42BC81F2D04ULL, + 0xA61CECB46814FE75ULL,0xD9721C7C5821770CULL, + 0x58C10D24087FEC87ULL,0x27AFFDEC384A65FEULL, + 0x6F7E09C7F05548FAULL,0x1010F90FC060C183ULL, + 0x91A3E857903E5A08ULL,0xEECD189FA00BD371ULL, + 0x78E0FF3B88BE6F81ULL,0x078E0FF3B88BE6F8ULL, + 0x863D1EABE8D57D73ULL,0xF953EE63D8E0F40AULL, + 0xB1821A4810FFD90EULL,0xCEECEA8020CA5077ULL, + 0x4F5FFBD87094CBFCULL,0x30310B1040A14285ULL, + 0xDEFC138FE0AA91F4ULL,0xA192E347D09F188DULL, + 0x2021F21F80C18306ULL,0x5F4F02D7B0F40A7FULL, + 0x179EF6FC78EB277BULL,0x68F0063448DEAE02ULL, + 0xE943176C18803589ULL,0x962DE7A428B5BCF0ULL, + 0xF1C1FE77117CDF02ULL,0x8EAF0EBF2149567BULL, + 0x0F1C1FE77117CDF0ULL,0x7072EF2F41224489ULL, + 0x38A31B04893D698DULL,0x47CDEBCCB908E0F4ULL, + 0xC67EFA94E9567B7FULL,0xB9100A5CD963F206ULL, + 0x57DD12C379682177ULL,0x28B3E20B495DA80EULL, + 0xA900F35319033385ULL,0xD66E039B2936BAFCULL, + 0x9EBFF7B0E12997F8ULL,0xE1D10778D11C1E81ULL, + 0x606216208142850AULL,0x1F0CE6E8B1770C73ULL, + 0x8921014C99C2B083ULL,0xF64FF184A9F739FAULL, + 0x77FCE0DCF9A9A271ULL,0x08921014C99C2B08ULL, + 0x4043E43F0183060CULL,0x3F2D14F731B68F75ULL, + 0xBE9E05AF61E814FEULL,0xC1F0F56751DD9D87ULL, + 0x2F3DEDF8F1D64EF6ULL,0x50531D30C1E3C78FULL, + 0xD1E00C6891BD5C04ULL,0xAE8EFCA0A188D57DULL, + 0xE65F088B6997F879ULL,0x9931F84359A27100ULL, + 0x1882E91B09FCEA8BULL,0x67EC19D339C963F2ULL, + 0xD75ADABD7A6E2D6FULL,0xA8342A754A5BA416ULL, + 0x29873B2D1A053F9DULL,0x56E9CBE52A30B6E4ULL, + 0x1E383FCEE22F9BE0ULL,0x6156CF06D21A1299ULL, + 0xE0E5DE5E82448912ULL,0x9F8B2E96B271006BULL, + 0x71463609127AD31AULL,0x0E28C6C1224F5A63ULL, + 0x8F9BD7997211C1E8ULL,0xF0F5275142244891ULL, + 0xB824D37A8A3B6595ULL,0xC74A23B2BA0EECECULL, + 0x46F932EAEA507767ULL,0x3997C222DA65FE1EULL, + 0xAFBA2586F2D042EEULL,0xD0D4D54EC2E5CB97ULL, + 0x5167C41692BB501CULL,0x2E0934DEA28ED965ULL, + 0x66D8C0F56A91F461ULL,0x19B6303D5AA47D18ULL, + 0x980521650AFAE693ULL,0xE76BD1AD3ACF6FEAULL, + 0x09A6C9329AC4BC9BULL,0x76C839FAAAF135E2ULL, + 0xF77B28A2FAAFAE69ULL,0x8815D86ACA9A2710ULL, + 0xC0C42C4102850A14ULL,0xBFAADC8932B0836DULL, + 0x3E19CDD162EE18E6ULL,0x41773D1952DB919FULL, + 0x269B24CA6B12F26DULL,0x59F5D4025B277B14ULL, + 0xD846C55A0B79E09FULL,0xA72835923B4C69E6ULL, + 0xEFF9C1B9F35344E2ULL,0x90973171C366CD9BULL, + 0x1124202993385610ULL,0x6E4AD0E1A30DDF69ULL, + 0x8087C87E03060C18ULL,0xFFE938B633338561ULL, + 0x7E5A29EE636D1EEAULL,0x0134D92653589793ULL, + 0x49E52D0D9B47BA97ULL,0x368BDDC5AB7233EEULL, + 0xB738CC9DFB2CA865ULL,0xC8563C55CB19211CULL, + 0x5E7BDBF1E3AC9DECULL,0x21152B39D3991495ULL, + 0xA0A63A6183C78F1EULL,0xDFC8CAA9B3F20667ULL, + 0x97193E827BED2B63ULL,0xE877CE4A4BD8A21AULL, + 0x69C4DF121B863991ULL,0x16AA2FDA2BB3B0E8ULL, + 0xF86737458BB86399ULL,0x8709C78DBB8DEAE0ULL, + 0x06BAD6D5EBD3716BULL,0x79D4261DDBE6F812ULL, + 0x3105D23613F9D516ULL,0x4E6B22FE23CC5C6FULL, + 0xCFD833A67392C7E4ULL,0xB0B6C36E43A74E9DULL, + 0x9A6C9329AC4BC9B5ULL,0xE50263E19C7E40CCULL, + 0x64B172B9CC20DB47ULL,0x1BDF8271FC15523EULL, + 0x530E765A340A7F3AULL,0x2C608692043FF643ULL, + 0xADD397CA54616DC8ULL,0xD2BD67026454E4B1ULL, + 0x3C707F9DC45F37C0ULL,0x431E8F55F46ABEB9ULL, + 0xC2AD9E0DA4342532ULL,0xBDC36EC59401AC4BULL, + 0xF5129AEE5C1E814FULL,0x8A7C6A266C2B0836ULL, + 0x0BCF7B7E3C7593BDULL,0x74A18BB60C401AC4ULL, + 0xE28C6C1224F5A634ULL,0x9DE29CDA14C02F4DULL, + 0x1C518D82449EB4C6ULL,0x633F7D4A74AB3DBFULL, + 0x2BEE8961BCB410BBULL,0x548079A98C8199C2ULL, + 0xD53368F1DCDF0249ULL,0xAA5D9839ECEA8B30ULL, + 0x449080A64CE15841ULL,0x3BFE706E7CD4D138ULL, + 0xBA4D61362C8A4AB3ULL,0xC52391FE1CBFC3CAULL, + 0x8DF265D5D4A0EECEULL,0xF29C951DE49567B7ULL, + 0x732F8445B4CBFC3CULL,0x0C41748D84FE7545ULL, + 0x6BAD6D5EBD3716B7ULL,0x14C39D968D029FCEULL, + 0x95708CCEDD5C0445ULL,0xEA1E7C06ED698D3CULL, + 0xA2CF882D2576A038ULL,0xDDA178E515432941ULL, + 0x5C1269BD451DB2CAULL,0x237C997575283BB3ULL, + 0xCDB181EAD523E8C2ULL,0xB2DF7122E51661BBULL, + 0x336C607AB548FA30ULL,0x4C0290B2857D7349ULL, + 0x04D364994D625E4DULL,0x7BBD94517D57D734ULL, + 0xFA0E85092D094CBFULL,0x856075C11D3CC5C6ULL, + 0x134D926535897936ULL,0x6C2362AD05BCF04FULL, + 0xED9073F555E26BC4ULL,0x92FE833D65D7E2BDULL, + 0xDA2F7716ADC8CFB9ULL,0xA54187DE9DFD46C0ULL, + 0x24F29686CDA3DD4BULL,0x5B9C664EFD965432ULL, + 0xB5517ED15D9D8743ULL,0xCA3F8E196DA80E3AULL, + 0x4B8C9F413DF695B1ULL,0x34E26F890DC31CC8ULL, + 0x7C339BA2C5DC31CCULL,0x035D6B6AF5E9B8B5ULL, + 0x82EE7A32A5B7233EULL,0xFD808AFA9582AA47ULL, + 0x4D364994D625E4DAULL,0x3258B95CE6106DA3ULL, + 0xB3EBA804B64EF628ULL,0xCC8558CC867B7F51ULL, + 0x8454ACE74E645255ULL,0xFB3A5C2F7E51DB2CULL, + 0x7A894D772E0F40A7ULL,0x05E7BDBF1E3AC9DEULL, + 0xEB2AA520BE311AAFULL,0x944455E88E0493D6ULL, + 0x15F744B0DE5A085DULL,0x6A99B478EE6F8124ULL, + 0x224840532670AC20ULL,0x5D26B09B16452559ULL, + 0xDC95A1C3461BBED2ULL,0xA3FB510B762E37ABULL, + 0x35D6B6AF5E9B8B5BULL,0x4AB846676EAE0222ULL, + 0xCB0B573F3EF099A9ULL,0xB465A7F70EC510D0ULL, + 0xFCB453DCC6DA3DD4ULL,0x83DAA314F6EFB4ADULL, + 0x0269B24CA6B12F26ULL,0x7D0742849684A65FULL, + 0x93CA5A1B368F752EULL,0xECA4AAD306BAFC57ULL, + 0x6D17BB8B56E467DCULL,0x12794B4366D1EEA5ULL, + 0x5AA8BF68AECEC3A1ULL,0x25C64FA09EFB4AD8ULL, + 0xA4755EF8CEA5D153ULL,0xDB1BAE30FE90582AULL, + 0xBCF7B7E3C7593BD8ULL,0xC399472BF76CB2A1ULL, + 0x422A5673A732292AULL,0x3D44A6BB9707A053ULL, + 0x759552905F188D57ULL,0x0AFBA2586F2D042EULL, + 0x8B48B3003F739FA5ULL,0xF42643C80F4616DCULL, + 0x1AEB5B57AF4DC5ADULL,0x6585AB9F9F784CD4ULL, + 0xE436BAC7CF26D75FULL,0x9B584A0FFF135E26ULL, + 0xD389BE24370C7322ULL,0xACE74EEC0739FA5BULL, + 0x2D545FB4576761D0ULL,0x523AAF7C6752E8A9ULL, + 0xC41748D84FE75459ULL,0xBB79B8107FD2DD20ULL, + 0x3ACAA9482F8C46ABULL,0x45A459801FB9CFD2ULL, + 0x0D75ADABD7A6E2D6ULL,0x721B5D63E7936BAFULL, + 0xF3A84C3BB7CDF024ULL,0x8CC6BCF387F8795DULL, + 0x620BA46C27F3AA2CULL,0x1D6554A417C62355ULL, + 0x9CD645FC4798B8DEULL,0xE3B8B53477AD31A7ULL, + 0xAB69411FBFB21CA3ULL,0xD407B1D78F8795DAULL, + 0x55B4A08FDFD90E51ULL,0x2ADA5047EFEC8728ULL +}; + +/* CRC-64/ECMA-182 lookup table (non-reflected polynomial 0x42f0e1eba9ea3693) */ +static const uint64_t crc64_ecma182_table[] = { + 0x0000000000000000ULL,0x42F0E1EBA9EA3693ULL,0x85E1C3D753D46D26ULL,0xC711223CFA3E5BB5ULL, + 0x493366450E42ECDFULL,0x0BC387AEA7A8DA4CULL,0xCCD2A5925D9681F9ULL,0x8E224479F47CB76AULL, + 0x9266CC8A1C85D9BEULL,0xD0962D61B56FEF2DULL,0x17870F5D4F51B498ULL,0x5577EEB6E6BB820BULL, + 0xDB55AACF12C73561ULL,0x99A54B24BB2D03F2ULL,0x5EB4691841135847ULL,0x1C4488F3E8F96ED4ULL, + 0x663D78FF90E185EFULL,0x24CD9914390BB37CULL,0xE3DCBB28C335E8C9ULL,0xA12C5AC36ADFDE5AULL, + 0x2F0E1EBA9EA36930ULL,0x6DFEFF5137495FA3ULL,0xAAEFDD6DCD770416ULL,0xE81F3C86649D3285ULL, + 0xF45BB4758C645C51ULL,0xB6AB559E258E6AC2ULL,0x71BA77A2DFB03177ULL,0x334A9649765A07E4ULL, + 0xBD68D2308226B08EULL,0xFF9833DB2BCC861DULL,0x388911E7D1F2DDA8ULL,0x7A79F00C7818EB3BULL, + 0xCC7AF1FF21C30BDEULL,0x8E8A101488293D4DULL,0x499B3228721766F8ULL,0x0B6BD3C3DBFD506BULL, + 0x854997BA2F81E701ULL,0xC7B97651866BD192ULL,0x00A8546D7C558A27ULL,0x4258B586D5BFBCB4ULL, + 0x5E1C3D753D46D260ULL,0x1CECDC9E94ACE4F3ULL,0xDBFDFEA26E92BF46ULL,0x990D1F49C77889D5ULL, + 0x172F5B3033043EBFULL,0x55DFBADB9AEE082CULL,0x92CE98E760D05399ULL,0xD03E790CC93A650AULL, + 0xAA478900B1228E31ULL,0xE8B768EB18C8B8A2ULL,0x2FA64AD7E2F6E317ULL,0x6D56AB3C4B1CD584ULL, + 0xE374EF45BF6062EEULL,0xA1840EAE168A547DULL,0x66952C92ECB40FC8ULL,0x2465CD79455E395BULL, + 0x3821458AADA7578FULL,0x7AD1A461044D611CULL,0xBDC0865DFE733AA9ULL,0xFF3067B657990C3AULL, + 0x711223CFA3E5BB50ULL,0x33E2C2240A0F8DC3ULL,0xF4F3E018F031D676ULL,0xB60301F359DBE0E5ULL, + 0xDA050215EA6C212FULL,0x98F5E3FE438617BCULL,0x5FE4C1C2B9B84C09ULL,0x1D14202910527A9AULL, + 0x93366450E42ECDF0ULL,0xD1C685BB4DC4FB63ULL,0x16D7A787B7FAA0D6ULL,0x5427466C1E109645ULL, + 0x4863CE9FF6E9F891ULL,0x0A932F745F03CE02ULL,0xCD820D48A53D95B7ULL,0x8F72ECA30CD7A324ULL, + 0x0150A8DAF8AB144EULL,0x43A04931514122DDULL,0x84B16B0DAB7F7968ULL,0xC6418AE602954FFBULL, + 0xBC387AEA7A8DA4C0ULL,0xFEC89B01D3679253ULL,0x39D9B93D2959C9E6ULL,0x7B2958D680B3FF75ULL, + 0xF50B1CAF74CF481FULL,0xB7FBFD44DD257E8CULL,0x70EADF78271B2539ULL,0x321A3E938EF113AAULL, + 0x2E5EB66066087D7EULL,0x6CAE578BCFE24BEDULL,0xABBF75B735DC1058ULL,0xE94F945C9C3626CBULL, + 0x676DD025684A91A1ULL,0x259D31CEC1A0A732ULL,0xE28C13F23B9EFC87ULL,0xA07CF2199274CA14ULL, + 0x167FF3EACBAF2AF1ULL,0x548F120162451C62ULL,0x939E303D987B47D7ULL,0xD16ED1D631917144ULL, + 0x5F4C95AFC5EDC62EULL,0x1DBC74446C07F0BDULL,0xDAAD56789639AB08ULL,0x985DB7933FD39D9BULL, + 0x84193F60D72AF34FULL,0xC6E9DE8B7EC0C5DCULL,0x01F8FCB784FE9E69ULL,0x43081D5C2D14A8FAULL, + 0xCD2A5925D9681F90ULL,0x8FDAB8CE70822903ULL,0x48CB9AF28ABC72B6ULL,0x0A3B7B1923564425ULL, + 0x70428B155B4EAF1EULL,0x32B26AFEF2A4998DULL,0xF5A348C2089AC238ULL,0xB753A929A170F4ABULL, + 0x3971ED50550C43C1ULL,0x7B810CBBFCE67552ULL,0xBC902E8706D82EE7ULL,0xFE60CF6CAF321874ULL, + 0xE224479F47CB76A0ULL,0xA0D4A674EE214033ULL,0x67C58448141F1B86ULL,0x253565A3BDF52D15ULL, + 0xAB1721DA49899A7FULL,0xE9E7C031E063ACECULL,0x2EF6E20D1A5DF759ULL,0x6C0603E6B3B7C1CAULL, + 0xF6FAE5C07D3274CDULL,0xB40A042BD4D8425EULL,0x731B26172EE619EBULL,0x31EBC7FC870C2F78ULL, + 0xBFC9838573709812ULL,0xFD39626EDA9AAE81ULL,0x3A28405220A4F534ULL,0x78D8A1B9894EC3A7ULL, + 0x649C294A61B7AD73ULL,0x266CC8A1C85D9BE0ULL,0xE17DEA9D3263C055ULL,0xA38D0B769B89F6C6ULL, + 0x2DAF4F0F6FF541ACULL,0x6F5FAEE4C61F773FULL,0xA84E8CD83C212C8AULL,0xEABE6D3395CB1A19ULL, + 0x90C79D3FEDD3F122ULL,0xD2377CD44439C7B1ULL,0x15265EE8BE079C04ULL,0x57D6BF0317EDAA97ULL, + 0xD9F4FB7AE3911DFDULL,0x9B041A914A7B2B6EULL,0x5C1538ADB04570DBULL,0x1EE5D94619AF4648ULL, + 0x02A151B5F156289CULL,0x4051B05E58BC1E0FULL,0x87409262A28245BAULL,0xC5B073890B687329ULL, + 0x4B9237F0FF14C443ULL,0x0962D61B56FEF2D0ULL,0xCE73F427ACC0A965ULL,0x8C8315CC052A9FF6ULL, + 0x3A80143F5CF17F13ULL,0x7870F5D4F51B4980ULL,0xBF61D7E80F251235ULL,0xFD913603A6CF24A6ULL, + 0x73B3727A52B393CCULL,0x31439391FB59A55FULL,0xF652B1AD0167FEEAULL,0xB4A25046A88DC879ULL, + 0xA8E6D8B54074A6ADULL,0xEA16395EE99E903EULL,0x2D071B6213A0CB8BULL,0x6FF7FA89BA4AFD18ULL, + 0xE1D5BEF04E364A72ULL,0xA3255F1BE7DC7CE1ULL,0x64347D271DE22754ULL,0x26C49CCCB40811C7ULL, + 0x5CBD6CC0CC10FAFCULL,0x1E4D8D2B65FACC6FULL,0xD95CAF179FC497DAULL,0x9BAC4EFC362EA149ULL, + 0x158E0A85C2521623ULL,0x577EEB6E6BB820B0ULL,0x906FC95291867B05ULL,0xD29F28B9386C4D96ULL, + 0xCEDBA04AD0952342ULL,0x8C2B41A1797F15D1ULL,0x4B3A639D83414E64ULL,0x09CA82762AAB78F7ULL, + 0x87E8C60FDED7CF9DULL,0xC51827E4773DF90EULL,0x020905D88D03A2BBULL,0x40F9E43324E99428ULL, + 0x2CFFE7D5975E55E2ULL,0x6E0F063E3EB46371ULL,0xA91E2402C48A38C4ULL,0xEBEEC5E96D600E57ULL, + 0x65CC8190991CB93DULL,0x273C607B30F68FAEULL,0xE02D4247CAC8D41BULL,0xA2DDA3AC6322E288ULL, + 0xBE992B5F8BDB8C5CULL,0xFC69CAB42231BACFULL,0x3B78E888D80FE17AULL,0x7988096371E5D7E9ULL, + 0xF7AA4D1A85996083ULL,0xB55AACF12C735610ULL,0x724B8ECDD64D0DA5ULL,0x30BB6F267FA73B36ULL, + 0x4AC29F2A07BFD00DULL,0x08327EC1AE55E69EULL,0xCF235CFD546BBD2BULL,0x8DD3BD16FD818BB8ULL, + 0x03F1F96F09FD3CD2ULL,0x41011884A0170A41ULL,0x86103AB85A2951F4ULL,0xC4E0DB53F3C36767ULL, + 0xD8A453A01B3A09B3ULL,0x9A54B24BB2D03F20ULL,0x5D45907748EE6495ULL,0x1FB5719CE1045206ULL, + 0x919735E51578E56CULL,0xD367D40EBC92D3FFULL,0x1476F63246AC884AULL,0x568617D9EF46BED9ULL, + 0xE085162AB69D5E3CULL,0xA275F7C11F7768AFULL,0x6564D5FDE549331AULL,0x279434164CA30589ULL, + 0xA9B6706FB8DFB2E3ULL,0xEB46918411358470ULL,0x2C57B3B8EB0BDFC5ULL,0x6EA7525342E1E956ULL, + 0x72E3DAA0AA188782ULL,0x30133B4B03F2B111ULL,0xF7021977F9CCEAA4ULL,0xB5F2F89C5026DC37ULL, + 0x3BD0BCE5A45A6B5DULL,0x79205D0E0DB05DCEULL,0xBE317F32F78E067BULL,0xFCC19ED95E6430E8ULL, + 0x86B86ED5267CDBD3ULL,0xC4488F3E8F96ED40ULL,0x0359AD0275A8B6F5ULL,0x41A94CE9DC428066ULL, + 0xCF8B0890283E370CULL,0x8D7BE97B81D4019FULL,0x4A6ACB477BEA5A2AULL,0x089A2AACD2006CB9ULL, + 0x14DEA25F3AF9026DULL,0x562E43B4931334FEULL,0x913F6188692D6F4BULL,0xD3CF8063C0C759D8ULL, + 0x5DEDC41A34BBEEB2ULL,0x1F1D25F19D51D821ULL,0xD80C07CD676F8394ULL,0x9AFCE626CE85B507ULL +}; diff --git a/ext/hash/php_hash_crc_common.h b/ext/hash/php_hash_crc_common.h new file mode 100644 index 0000000000000..8d53064b7cfb6 --- /dev/null +++ b/ext/hash/php_hash_crc_common.h @@ -0,0 +1,154 @@ +/* ++----------------------------------------------------------------------+ + | Copyright (c) The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | https://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Don MacAskill | + +----------------------------------------------------------------------+ +*/ + +#ifndef PHP_HASH_CRC_COMMON_H +#define PHP_HASH_CRC_COMMON_H + +#include "php.h" + +#ifdef HAVE_CRC_FAST +#include "php_hash_crc_fast.h" +#endif + +/* Common CRC context initialization helper + * Initializes both software state and crc-fast context if available + * Parameters: + * ctx - CRC context to initialize + * initial_state - Initial state value for software implementation + * crc_fast_algo - crc-fast algorithm identifier + */ +#ifdef HAVE_CRC_FAST +#define PHP_CRC_INIT_CONTEXT(ctx, initial_state, crc_fast_algo) do { \ + (ctx)->state = (initial_state); \ + (ctx)->using_crc_fast = false; \ + if (php_crc_fast_init(&(ctx)->crc_fast_ctx, (crc_fast_algo)) == SUCCESS) { \ + (ctx)->using_crc_fast = true; \ + } \ +} while (0) +#else +#define PHP_CRC_INIT_CONTEXT(ctx, initial_state, crc_fast_algo) do { \ + (ctx)->state = (initial_state); \ +} while (0) +#endif + +/* Common CRC context update helper + * Routes to crc-fast or software implementation based on context state + * Parameters: + * ctx - CRC context to update + * input - Input data buffer + * len - Length of input data + * software_update_func - Function to call for software implementation + */ +#ifdef HAVE_CRC_FAST +#define PHP_CRC_UPDATE_CONTEXT(ctx, input, len, software_update_func) do { \ + if (EXPECTED((ctx)->using_crc_fast)) { \ + php_crc_fast_update(&(ctx)->crc_fast_ctx, (input), (len)); \ + return; \ + } \ + software_update_func((ctx), (input), (len)); \ +} while (0) +#else +#define PHP_CRC_UPDATE_CONTEXT(ctx, input, len, software_update_func) do { \ + software_update_func((ctx), (input), (len)); \ +} while (0) +#endif + +/* Common CRC context finalization helper + * Finalizes crc-fast context or calls software implementation + * Parameters: + * ctx - CRC context to finalize + * digest - Output buffer for digest + * digest_size - Size of digest (8 for CRC64) + * software_final_func - Function to call for software implementation + */ +#ifdef HAVE_CRC_FAST +#define PHP_CRC_FINALIZE_CONTEXT(ctx, digest, digest_size, software_final_func) do { \ + if (EXPECTED((ctx)->using_crc_fast)) { \ + uint64_t result = php_crc_fast_final(&(ctx)->crc_fast_ctx); \ + php_crc_store_result((digest), result, (digest_size)); \ + php_crc_fast_free(&(ctx)->crc_fast_ctx); \ + (ctx)->state = 0; \ + return; \ + } \ + software_final_func((digest), (ctx)); \ +} while (0) +#else +#define PHP_CRC_FINALIZE_CONTEXT(ctx, digest, digest_size, software_final_func) do { \ + software_final_func((digest), (ctx)); \ +} while (0) +#endif + +/* Common CRC context copy helper */ +#ifdef HAVE_CRC_FAST +#define PHP_CRC_COPY_CONTEXT(src_ctx, dest_ctx, state_type) do { \ + if (EXPECTED((src_ctx)->using_crc_fast)) { \ + (dest_ctx)->using_crc_fast = false; \ + (dest_ctx)->crc_fast_ctx.digest_handle = NULL; \ + (dest_ctx)->crc_fast_ctx.finalized = false; \ + if (EXPECTED(php_crc_fast_copy(&(src_ctx)->crc_fast_ctx, &(dest_ctx)->crc_fast_ctx) == SUCCESS)) { \ + (dest_ctx)->using_crc_fast = true; \ + (dest_ctx)->state = (state_type)crc_fast_digest_get_state((src_ctx)->crc_fast_ctx.digest_handle); \ + } else { \ + (dest_ctx)->state = (src_ctx)->state; \ + } \ + } else { \ + (dest_ctx)->using_crc_fast = false; \ + (dest_ctx)->crc_fast_ctx.digest_handle = NULL; \ + (dest_ctx)->crc_fast_ctx.finalized = false; \ + (dest_ctx)->state = (src_ctx)->state; \ + } \ +} while (0) +#else +#define PHP_CRC_COPY_CONTEXT(src_ctx, dest_ctx, state_type) do { \ + (dest_ctx)->state = (src_ctx)->state; \ +} while (0) +#endif + +/* CRC64 result storage helper - stores 64-bit results in big-endian format */ +PHP_HASH_API void php_crc_store_result(unsigned char *digest, uint64_t result, size_t digest_size); + +/* Common serialization state extraction helper */ +#ifdef HAVE_CRC_FAST +static inline uint64_t php_crc_get_serialization_state(const void *ctx, bool using_crc_fast, + const php_crc_fast_context *crc_fast_ctx, + uint64_t software_state) { + if (using_crc_fast && crc_fast_ctx->digest_handle) { + return crc_fast_digest_get_state(crc_fast_ctx->digest_handle); + } + return software_state; +} +#else +static inline uint64_t php_crc_get_serialization_state(const void *ctx, bool using_crc_fast, + const void *crc_fast_ctx, + uint64_t software_state) { + return software_state; +} +#endif + +/* Common unserialization context reset helper */ +#ifdef HAVE_CRC_FAST +#define PHP_CRC_RESET_CONTEXT_FOR_UNSERIALIZE(ctx) do { \ + (ctx)->using_crc_fast = false; \ + (ctx)->crc_fast_ctx.digest_handle = NULL; \ + (ctx)->crc_fast_ctx.finalized = false; \ +} while (0) +#else +#define PHP_CRC_RESET_CONTEXT_FOR_UNSERIALIZE(ctx) do { \ + /* No-op for non-crc-fast builds */ \ +} while (0) +#endif + +#endif /* PHP_HASH_CRC_COMMON_H */ diff --git a/ext/hash/php_hash_crc_fast.h b/ext/hash/php_hash_crc_fast.h new file mode 100644 index 0000000000000..b0182cc9e9663 --- /dev/null +++ b/ext/hash/php_hash_crc_fast.h @@ -0,0 +1,62 @@ +/* + +----------------------------------------------------------------------+ + | Copyright (c) The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | https://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Don MacAskill | + +----------------------------------------------------------------------+ +*/ + +#ifndef PHP_HASH_CRC_FAST_H +#define PHP_HASH_CRC_FAST_H + +#include "php.h" + +#ifdef HAVE_CRC_FAST +#include + +/* CRC algorithm constants - these match the actual crc-fast library enum values */ +#define CRC_FAST_CRC32_BZIP2 Crc32Bzip2 +#define CRC_FAST_CRC32_ISO_HDLC Crc32IsoHdlc +#define CRC_FAST_CRC32_ISCSI Crc32Iscsi +#define CRC_FAST_CRC64_NVME Crc64Nvme +#define CRC_FAST_CRC64_ECMA182 Crc64Ecma182 + +/* CRC-Fast context structure for hash operations */ +typedef struct { + struct CrcFastDigestHandle *digest_handle; + enum CrcFastAlgorithm algorithm; + bool finalized; +} php_crc_fast_context; + +/* CRC-Fast wrapper functions */ +PHP_HASH_API zend_result php_crc_fast_init(php_crc_fast_context *context, enum CrcFastAlgorithm algorithm); +PHP_HASH_API void php_crc_fast_update(php_crc_fast_context *context, const unsigned char *data, size_t len); +PHP_HASH_API uint64_t php_crc_fast_final(php_crc_fast_context *context); +PHP_HASH_API zend_result php_crc_fast_copy(const php_crc_fast_context *src, php_crc_fast_context *dest); +PHP_HASH_API uint64_t php_crc_fast_checksum(enum CrcFastAlgorithm algorithm, const unsigned char *data, size_t len); +PHP_HASH_API void php_crc_fast_free(php_crc_fast_context *context); + +/* Optimized inline functions for hot paths */ +static inline bool php_crc_fast_is_available(const php_crc_fast_context *context) { + return context && context->digest_handle && !context->finalized; +} + +static inline bool php_crc_fast_should_use_checksum(size_t len) { + /* Use one-shot checksum for small to medium data sizes for better performance */ + return len <= 8192; /* 8KB threshold - tuned for typical use cases */ +} + +/* Error handling */ +PHP_HASH_API void php_crc_fast_throw_exception(const char *message); + +#endif /* HAVE_CRC_FAST */ + +#endif /* PHP_HASH_CRC_FAST_H */ diff --git a/ext/hash/tests/crc32.phpt b/ext/hash/tests/crc32.phpt index fda63c71360b1..09e6f88b56ab6 100644 --- a/ext/hash/tests/crc32.phpt +++ b/ext/hash/tests/crc32.phpt @@ -102,6 +102,36 @@ echo hash('crc32c', '12345678901234561234567890123456123456789012345612345678901 echo hash('crc32c', '123456789012345612345678901234561234567890123456123456789012345612345678901234561234567890123456123456789012345612345678901234561234567890123456'), "\n"; echo hash('crc32c', '123456789012345612345678901234561234567890123456123456789012345612345678901234561234567890123456123456789012345612345678901234561234567890123456abc'), "\n"; +echo "crc32-iso-hdlc\n"; +echo hash('crc32-iso-hdlc', ''), "\n"; +echo hash('crc32-iso-hdlc', 'a'), "\n"; +echo hash('crc32-iso-hdlc', 'abc'), "\n"; +echo hash('crc32-iso-hdlc', 'message digest'), "\n"; +echo hash('crc32-iso-hdlc', 'abcdefghijklmnopqrstuvwxyz'), "\n"; +echo hash('crc32-iso-hdlc', 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'), "\n"; +echo hash('crc32-iso-hdlc', '12345678901234567890123456789012345678901234567890123456789012345678901234567890'), "\n"; +echo hash('crc32-iso-hdlc', '123456789'), "\n"; + +echo "crc32-iscsi\n"; +echo hash('crc32-iscsi', ''), "\n"; +echo hash('crc32-iscsi', 'a'), "\n"; +echo hash('crc32-iscsi', 'abc'), "\n"; +echo hash('crc32-iscsi', 'message digest'), "\n"; +echo hash('crc32-iscsi', 'abcdefghijklmnopqrstuvwxyz'), "\n"; +echo hash('crc32-iscsi', 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'), "\n"; +echo hash('crc32-iscsi', '12345678901234567890123456789012345678901234567890123456789012345678901234567890'), "\n"; +echo hash('crc32-iscsi', '123456789'), "\n"; + +echo "crc32-php\n"; +echo hash('crc32-php', ''), "\n"; +echo hash('crc32-php', 'a'), "\n"; +echo hash('crc32-php', 'abc'), "\n"; +echo hash('crc32-php', 'message digest'), "\n"; +echo hash('crc32-php', 'abcdefghijklmnopqrstuvwxyz'), "\n"; +echo hash('crc32-php', 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'), "\n"; +echo hash('crc32-php', '12345678901234567890123456789012345678901234567890123456789012345678901234567890'), "\n"; +echo hash('crc32-php', '123456789'), "\n"; + ?> --EXPECT-- crc32 @@ -201,3 +231,30 @@ a0e3e317 c292a38d e3e558ec b6c5e13e +crc32-iso-hdlc +00000000 +e8b7be43 +352441c2 +20159d7f +4c2750bd +1fc2e6d2 +7ca94a72 +cbf43926 +crc32-iscsi +00000000 +c1d04330 +364b3fb7 +02bd79d0 +9ee6ef25 +a245d57d +477a6781 +e3069283 +crc32-php +00000000 +6b9b9319 +73bb8c64 +5703c9bf +9693bf77 +882174a0 +96790816 +181989fc diff --git a/ext/hash/tests/crc64.phpt b/ext/hash/tests/crc64.phpt new file mode 100644 index 0000000000000..4df4ad58e5e6d --- /dev/null +++ b/ext/hash/tests/crc64.phpt @@ -0,0 +1,44 @@ +--TEST-- +Hash: CRC64 algorithms +--FILE-- + +--EXPECT-- +crc64-nvme +0000000000000000 +8c2f8445b4cbfc3c +05e5cabb3fc1faeb +dc4a92ab26fba23f +1a110d6a11fe63a8 +8b8f30cfc6f16409 +24098f6874d98832 +ae8b14860a799888 +crc64-ecma-182 +0000000000000000 +548f120162451c62 +66501a349a0e0855 +c04d61278997ba5e +97a2566b552fcc4e +5ca18585b92c58b9 +be4c46263774953c +6c40df5f0b497347 \ No newline at end of file diff --git a/ext/hash/tests/crc_fast_performance.phpt b/ext/hash/tests/crc_fast_performance.phpt new file mode 100644 index 0000000000000..a5b3307afeae6 --- /dev/null +++ b/ext/hash/tests/crc_fast_performance.phpt @@ -0,0 +1,125 @@ +--TEST-- +Hash: CRC performance with hardware acceleration +--SKIPIF-- + enabled" in phpinfo +ob_start(); +phpinfo(INFO_MODULES); +$info = ob_get_clean(); +if (!preg_match('/crc-fast support\s*=>\s*enabled/', $info)) { + die('skip crc-fast support not enabled'); +} + +// Skip if not on supported hardware platforms (x86, x86_64, aarch64) +$arch = strtolower(php_uname('m')); + +// Normalize architecture names (following PHP's run-extra-tests.php pattern) +$is_x86_64 = in_array($arch, ['x86_64', 'amd64']); +$is_aarch64 = in_array($arch, ['aarch64', 'arm64']); + +// technically, i686 w/SSE2 should also work, but it's difficult to detect and rare +if (!($is_x86_64 || $is_aarch64)) { + die('skip crc-fast hardware acceleration not supported on ' . $arch); +} +?> +--FILE-- +10 GiB/s throughput with hardware acceleration (software is currently at ~0.5GiB/s) +$algorithms = [ + 'crc32-iso-hdlc', + 'crc32-iscsi', + 'crc32', // Standard PHP crc32 + 'crc32-php', + 'crc64-nvme', + 'crc64-ecma-182' +]; + +$data_size = 1048576; // 1 MiB +$test_data = (new \Random\Randomizer())->getBytes($data_size); +$min_throughput_gibps = 10; // Minimum 10 GiB/s + +echo "Testing CRC performance with hardware acceleration\n"; +echo "Minimum required throughput: $min_throughput_gibps GiB/s\n\n"; + +$all_passed = true; + +foreach ($algorithms as $algo) { + $start = microtime(true); + + $hash = hash($algo, $test_data); + + $elapsed = microtime(true) - $start; + + $throughput_mbps = ($data_size / $elapsed) / 1048576; + $throughput_gibps = $throughput_mbps / 1024; + + $status = $throughput_gibps >= $min_throughput_gibps ? 'PASS' : 'FAIL'; + + printf("%-20s: %.2f GiB/s - %s\n", $algo, $throughput_gibps, $status); + + if ($status === 'FAIL') { + $all_passed = false; + } +} + +echo "\n"; +if ($all_passed) { + echo "All CRC algorithms meet performance requirements\n"; +} else { + echo "Some CRC algorithms failed to meet performance requirements\n"; +} + +// Also verify correctness with known test vectors +echo "\nVerifying correctness with test vector '123456789':\n"; +$test_vector = "123456789"; +$expected = [ + 'crc32-iso-hdlc' => 'cbf43926', + 'crc32-iscsi' => 'e3069283', + 'crc32' => '181989fc', + 'crc32-php' => '181989fc', + 'crc64-nvme' => 'ae8b14860a799888', + 'crc64-ecma-182' => '6c40df5f0b497347' +]; + +$correct = true; +foreach ($expected as $algo => $expected_hash) { + $actual = hash($algo, $test_vector); + if ($actual === $expected_hash) { + echo "$algo: OK\n"; + } else { + echo "$algo: FAILED (expected: $expected_hash, got: $actual)\n"; + $correct = false; + } +} + +if ($correct) { + echo "\nAll checksums correct\n"; +} else { + echo "\nChecksum verification failed\n"; +} +?> +--EXPECTF-- +Testing CRC performance with hardware acceleration +Minimum required throughput: 10 GiB/s + +crc32-iso-hdlc : %f GiB/s - PASS +crc32-iscsi : %f GiB/s - PASS +crc32 : %f GiB/s - PASS +crc32-php : %f GiB/s - PASS +crc64-nvme : %f GiB/s - PASS +crc64-ecma-182 : %f GiB/s - PASS + +All CRC algorithms meet performance requirements + +Verifying correctness with test vector '123456789': +crc32-iso-hdlc: OK +crc32-iscsi: OK +crc32: OK +crc32-php: OK +crc64-nvme: OK +crc64-ecma-182: OK + +All checksums correct diff --git a/ext/hash/tests/hash-clone.phpt b/ext/hash/tests/hash-clone.phpt index 32105ae44eef8..609c20fef1361 100644 --- a/ext/hash/tests/hash-clone.phpt +++ b/ext/hash/tests/hash-clone.phpt @@ -128,6 +128,21 @@ string(8) "69147a4e" string(6) "crc32c" string(8) "5e405e93" string(8) "5e405e93" +string(14) "crc32-iso-hdlc" +string(8) "69147a4e" +string(8) "69147a4e" +string(11) "crc32-iscsi" +string(8) "5e405e93" +string(8) "5e405e93" +string(9) "crc32-php" +string(8) "e5cfc160" +string(8) "e5cfc160" +string(10) "crc64-nvme" +string(16) "36eb0383a9995549" +string(16) "36eb0383a9995549" +string(14) "crc64-ecma-182" +string(16) "6d7f573006ab8071" +string(16) "6d7f573006ab8071" string(6) "fnv132" string(8) "98139504" string(8) "98139504" @@ -308,6 +323,21 @@ string(8) "3ee63999" string(6) "crc32c" string(8) "5e405e93" string(8) "516ad412" +string(14) "crc32-iso-hdlc" +string(8) "69147a4e" +string(8) "3ee63999" +string(11) "crc32-iscsi" +string(8) "5e405e93" +string(8) "516ad412" +string(9) "crc32-php" +string(8) "e5cfc160" +string(8) "59f8d3d2" +string(10) "crc64-nvme" +string(16) "36eb0383a9995549" +string(16) "8f7ecfbed3f0cfb2" +string(14) "crc64-ecma-182" +string(16) "6d7f573006ab8071" +string(16) "8715da307cade2fd" string(6) "fnv132" string(8) "98139504" string(8) "59ad036f" diff --git a/ext/hash/tests/hash_algos.phpt b/ext/hash/tests/hash_algos.phpt index e2e51f3c70beb..d85b14c97d8c2 100644 --- a/ext/hash/tests/hash_algos.phpt +++ b/ext/hash/tests/hash_algos.phpt @@ -9,7 +9,7 @@ var_dump(hash_algos()); ?> --EXPECTF-- *** Testing hash_algos() : basic functionality *** -array(60) { +array(65) { [%d]=> string(3) "md2" [%d]=> @@ -77,6 +77,16 @@ array(60) { [%d]=> string(6) "crc32c" [%d]=> + string(14) "crc32-iso-hdlc" + [%d]=> + string(11) "crc32-iscsi" + [%d]=> + string(9) "crc32-php" + [%d]=> + string(10) "crc64-nvme" + [%d]=> + string(14) "crc64-ecma-182" + [%d]=> string(6) "fnv132" [%d]=> string(7) "fnv1a32" diff --git a/ext/hash/tests/hash_copy_001.phpt b/ext/hash/tests/hash_copy_001.phpt index ef0d90f7002a8..e8b350fa1a4ae 100644 --- a/ext/hash/tests/hash_copy_001.phpt +++ b/ext/hash/tests/hash_copy_001.phpt @@ -128,6 +128,21 @@ string(8) "69147a4e" string(6) "crc32c" string(8) "5e405e93" string(8) "5e405e93" +string(14) "crc32-iso-hdlc" +string(8) "69147a4e" +string(8) "69147a4e" +string(11) "crc32-iscsi" +string(8) "5e405e93" +string(8) "5e405e93" +string(9) "crc32-php" +string(8) "e5cfc160" +string(8) "e5cfc160" +string(10) "crc64-nvme" +string(16) "36eb0383a9995549" +string(16) "36eb0383a9995549" +string(14) "crc64-ecma-182" +string(16) "6d7f573006ab8071" +string(16) "6d7f573006ab8071" string(6) "fnv132" string(8) "98139504" string(8) "98139504" @@ -308,6 +323,21 @@ string(8) "3ee63999" string(6) "crc32c" string(8) "5e405e93" string(8) "516ad412" +string(14) "crc32-iso-hdlc" +string(8) "69147a4e" +string(8) "3ee63999" +string(11) "crc32-iscsi" +string(8) "5e405e93" +string(8) "516ad412" +string(9) "crc32-php" +string(8) "e5cfc160" +string(8) "59f8d3d2" +string(10) "crc64-nvme" +string(16) "36eb0383a9995549" +string(16) "8f7ecfbed3f0cfb2" +string(14) "crc64-ecma-182" +string(16) "6d7f573006ab8071" +string(16) "8715da307cade2fd" string(6) "fnv132" string(8) "98139504" string(8) "59ad036f" diff --git a/ext/hash/tests/hash_serialize_001.phpt b/ext/hash/tests/hash_serialize_001.phpt index ed80cdec4963a..aaa1645cc29b4 100644 --- a/ext/hash/tests/hash_serialize_001.phpt +++ b/ext/hash/tests/hash_serialize_001.phpt @@ -146,6 +146,21 @@ string(8) "69147a4e" string(6) "crc32c" string(8) "5e405e93" string(8) "5e405e93" +string(14) "crc32-iso-hdlc" +string(8) "69147a4e" +string(8) "69147a4e" +string(11) "crc32-iscsi" +string(8) "5e405e93" +string(8) "5e405e93" +string(9) "crc32-php" +string(8) "e5cfc160" +string(8) "e5cfc160" +string(10) "crc64-nvme" +string(16) "36eb0383a9995549" +string(16) "36eb0383a9995549" +string(14) "crc64-ecma-182" +string(16) "6d7f573006ab8071" +string(16) "6d7f573006ab8071" string(6) "fnv132" string(8) "98139504" string(8) "98139504" @@ -320,6 +335,21 @@ string(8) "3ee63999" string(6) "crc32c" string(8) "516ad412" string(8) "516ad412" +string(14) "crc32-iso-hdlc" +string(8) "3ee63999" +string(8) "3ee63999" +string(11) "crc32-iscsi" +string(8) "516ad412" +string(8) "516ad412" +string(9) "crc32-php" +string(8) "59f8d3d2" +string(8) "59f8d3d2" +string(10) "crc64-nvme" +string(16) "8f7ecfbed3f0cfb2" +string(16) "8f7ecfbed3f0cfb2" +string(14) "crc64-ecma-182" +string(16) "8715da307cade2fd" +string(16) "8715da307cade2fd" string(6) "fnv132" string(8) "59ad036f" string(8) "59ad036f" diff --git a/ext/hash/tests/hash_serialize_002.phpt b/ext/hash/tests/hash_serialize_002.phpt index 15ecf94c1e5ec..723f9df548326 100644 --- a/ext/hash/tests/hash_serialize_002.phpt +++ b/ext/hash/tests/hash_serialize_002.phpt @@ -4,7 +4,7 @@ Hash: serialize()/unserialize() with HASH_HMAC