Skip to content

hash: Add MurmurHash3 with streaming support #6059

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions ext/hash/config.m4
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,12 @@ fi

EXT_HASH_SOURCES="hash.c hash_md.c hash_sha.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_fnv.c hash_joaat.c $EXT_HASH_SHA3_SOURCES"
hash_crc32.c hash_fnv.c hash_joaat.c $EXT_HASH_SHA3_SOURCES
murmur/PMurHash.c murmur/PMurHash128.c hash_murmur.c"
EXT_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_fnv.h php_hash_joaat.h php_hash_sha3.h"
php_hash_fnv.h php_hash_joaat.h php_hash_sha3.h php_hash_murmur.h"

PHP_NEW_EXTENSION(hash, $EXT_HASH_SOURCES, 0,,$PHP_HASH_CFLAGS)
PHP_INSTALL_HEADERS(ext/hash, $EXT_HASH_HEADERS)
11 changes: 9 additions & 2 deletions ext/hash/config.w32
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ PHP_HASH = 'yes';
EXTENSION('hash', 'hash.c hash_md.c hash_sha.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', false);
'hash_sha3.c hash_murmur.c', false);

var hash_sha3_dir = 'ext/hash/sha3/generic' + (X64 ? '64' : '32') + 'lc';

Expand All @@ -28,7 +28,14 @@ if (!CHECK_HEADER_ADD_INCLUDE('KeccakHash.h', 'CFLAGS_HASH', hash_sha3_dir)) {

ADD_FLAG('CFLAGS_HASH', '/DKeccakP200_excluded /DKeccakP400_excluded /DKeccakP800_excluded /DZEND_ENABLE_STATIC_TSRMLS_CACHE=1');

var hash_murmur_dir = 'ext/hash/murmur';
if (!CHECK_HEADER_ADD_INCLUDE('PMurHash.h', 'CFLAGS_HASH', hash_murmur_dir)) {
ERROR('Unable to locate murmur headers');
}
ADD_SOURCES(hash_murmur_dir, 'PMurHash.c PMurHash128.c', 'hash');

PHP_INSTALL_HEADERS('ext/hash/', '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_sha3.h ' +
'php_hash_murmur.h');
8 changes: 7 additions & 1 deletion ext/hash/hash.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ struct mhash_bc_entry {
int value;
};

#define MHASH_NUM_ALGOS 35
#define MHASH_NUM_ALGOS 38

static struct mhash_bc_entry mhash_to_hash[MHASH_NUM_ALGOS] = {
{"CRC32", "crc32", 0}, /* used by bzip */
Expand Down Expand Up @@ -90,6 +90,9 @@ static struct mhash_bc_entry mhash_to_hash[MHASH_NUM_ALGOS] = {
{"FNV1A64", "fnv1a64", 32},
{"JOAAT", "joaat", 33},
{"CRC32C", "crc32c", 34}, /* Castagnoli's CRC, used by iSCSI, SCTP, Btrfs, ext4, etc */
{"MURMUR3A", "murmur3a", 35},
{"MURMUR3C", "murmur3c", 36},
{"MURMUR3F", "murmur3f", 37},
};
#endif

Expand Down Expand Up @@ -1586,6 +1589,9 @@ PHP_MINIT_FUNCTION(hash)
php_hash_register_algo("fnv164", &php_hash_fnv164_ops);
php_hash_register_algo("fnv1a64", &php_hash_fnv1a64_ops);
php_hash_register_algo("joaat", &php_hash_joaat_ops);
php_hash_register_algo("murmur3a", &php_hash_murmur3a_ops);
php_hash_register_algo("murmur3c", &php_hash_murmur3c_ops);
php_hash_register_algo("murmur3f", &php_hash_murmur3f_ops);

PHP_HASH_HAVAL_REGISTER(3,128);
PHP_HASH_HAVAL_REGISTER(3,160);
Expand Down
186 changes: 186 additions & 0 deletions ext/hash/hash_murmur.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
/*
+----------------------------------------------------------------------+
| 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: |
| http://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: Anatol Belski <ab@php.net> |
+----------------------------------------------------------------------+
*/

#include "php_hash.h"
#include "php_hash_murmur.h"

#include "murmur/PMurHash.h"
#include "murmur/PMurHash128.h"


const php_hash_ops php_hash_murmur3a_ops = {
"murmur3a",
(php_hash_init_func_t) PHP_MURMUR3AInit,
(php_hash_update_func_t) PHP_MURMUR3AUpdate,
(php_hash_final_func_t) PHP_MURMUR3AFinal,
(php_hash_copy_func_t) PHP_MURMUR3ACopy,
php_hash_serialize,
php_hash_unserialize,
PHP_MURMUR3A_SPEC,
4,
4,
sizeof(PHP_MURMUR3A_CTX),
0
};

PHP_HASH_API void PHP_MURMUR3AInit(PHP_MURMUR3A_CTX *ctx)
{
ctx->h = 0;
ctx->carry = 0;
ctx->len = 0;
}

PHP_HASH_API void PHP_MURMUR3AUpdate(PHP_MURMUR3A_CTX *ctx, const unsigned char *in, size_t len)
{
ctx->len += len;
PMurHash32_Process(&ctx->h, &ctx->carry, in, len);
}

PHP_HASH_API void PHP_MURMUR3AFinal(unsigned char digest[4], PHP_MURMUR3A_CTX *ctx)
{
ctx->h = PMurHash32_Result(ctx->h, ctx->carry, ctx->len);

digest[0] = (unsigned char)((ctx->h >> 24) & 0xff);
digest[1] = (unsigned char)((ctx->h >> 16) & 0xff);
digest[2] = (unsigned char)((ctx->h >> 8) & 0xff);
digest[3] = (unsigned char)(ctx->h & 0xff);
}

PHP_HASH_API int PHP_MURMUR3ACopy(const php_hash_ops *ops, PHP_MURMUR3A_CTX *orig_context, PHP_MURMUR3A_CTX *copy_context)
{
copy_context->h = orig_context->h;
copy_context->carry = orig_context->carry;
copy_context->len = orig_context->len;
return SUCCESS;
}

const php_hash_ops php_hash_murmur3c_ops = {
"murmur3c",
(php_hash_init_func_t) PHP_MURMUR3CInit,
(php_hash_update_func_t) PHP_MURMUR3CUpdate,
(php_hash_final_func_t) PHP_MURMUR3CFinal,
(php_hash_copy_func_t) PHP_MURMUR3CCopy,
php_hash_serialize,
php_hash_unserialize,
PHP_MURMUR3C_SPEC,
16,
4,
sizeof(PHP_MURMUR3C_CTX),
0
};

PHP_HASH_API void PHP_MURMUR3CInit(PHP_MURMUR3C_CTX *ctx)
{
memset(&ctx->h, 0, sizeof ctx->h);
memset(&ctx->carry, 0, sizeof ctx->carry);
ctx->len = 0;
}

PHP_HASH_API void PHP_MURMUR3CUpdate(PHP_MURMUR3C_CTX *ctx, const unsigned char *in, size_t len)
{
ctx->len += len;
PMurHash128x86_Process(ctx->h, ctx->carry, in, len);
}

PHP_HASH_API void PHP_MURMUR3CFinal(unsigned char digest[4], PHP_MURMUR3C_CTX *ctx)
{
uint32_t h[4] = {0};
PMurHash128x86_Result(ctx->h, ctx->carry, ctx->len, h);

digest[0] = (unsigned char)((h[0] >> 24) & 0xff);
digest[1] = (unsigned char)((h[0] >> 16) & 0xff);
digest[2] = (unsigned char)((h[0] >> 8) & 0xff);
digest[3] = (unsigned char)(h[0] & 0xff);
digest[4] = (unsigned char)((h[1] >> 24) & 0xff);
digest[5] = (unsigned char)((h[1] >> 16) & 0xff);
digest[6] = (unsigned char)((h[1] >> 8) & 0xff);
digest[7] = (unsigned char)(h[1] & 0xff);
digest[8] = (unsigned char)((h[2] >> 24) & 0xff);
digest[9] = (unsigned char)((h[2] >> 16) & 0xff);
digest[10] = (unsigned char)((h[2] >> 8) & 0xff);
digest[11] = (unsigned char)(h[2] & 0xff);
digest[12] = (unsigned char)((h[3] >> 24) & 0xff);
digest[13] = (unsigned char)((h[3] >> 16) & 0xff);
digest[14] = (unsigned char)((h[3] >> 8) & 0xff);
digest[15] = (unsigned char)(h[3] & 0xff);
}

PHP_HASH_API int PHP_MURMUR3CCopy(const php_hash_ops *ops, PHP_MURMUR3C_CTX *orig_context, PHP_MURMUR3C_CTX *copy_context)
{
memcpy(&copy_context->h, &orig_context->h, sizeof orig_context->h);
memcpy(&copy_context->carry, &orig_context->carry, sizeof orig_context->carry);
copy_context->len = orig_context->len;
return SUCCESS;
}

const php_hash_ops php_hash_murmur3f_ops = {
"murmur3f",
(php_hash_init_func_t) PHP_MURMUR3FInit,
(php_hash_update_func_t) PHP_MURMUR3FUpdate,
(php_hash_final_func_t) PHP_MURMUR3FFinal,
(php_hash_copy_func_t) PHP_MURMUR3FCopy,
php_hash_serialize,
php_hash_unserialize,
PHP_MURMUR3F_SPEC,
16,
8,
sizeof(PHP_MURMUR3F_CTX),
0
};

PHP_HASH_API void PHP_MURMUR3FInit(PHP_MURMUR3F_CTX *ctx)
{
memset(&ctx->h, 0, sizeof ctx->h);
memset(&ctx->carry, 0, sizeof ctx->carry);
ctx->len = 0;
}

PHP_HASH_API void PHP_MURMUR3FUpdate(PHP_MURMUR3F_CTX *ctx, const unsigned char *in, size_t len)
{
ctx->len += len;
PMurHash128x64_Process(ctx->h, ctx->carry, in, len);
}

PHP_HASH_API void PHP_MURMUR3FFinal(unsigned char digest[4], PHP_MURMUR3F_CTX *ctx)
{
uint64_t h[2] = {0};
PMurHash128x64_Result(ctx->h, ctx->carry, ctx->len, h);

digest[0] = (unsigned char)((h[0] >> 56) & 0xff);
digest[1] = (unsigned char)((h[0] >> 48) & 0xff);
digest[2] = (unsigned char)((h[0] >> 40) & 0xff);
digest[3] = (unsigned char)((h[0] >> 32) & 0xff);
digest[4] = (unsigned char)((h[0] >> 24) & 0xff);
digest[5] = (unsigned char)((h[0] >> 16) & 0xff);
digest[6] = (unsigned char)((h[0] >> 8) & 0xff);
digest[7] = (unsigned char)(h[0] & 0xff);
digest[8] = (unsigned char)((h[1] >> 56) & 0xff);
digest[9] = (unsigned char)((h[1] >> 48) & 0xff);
digest[10] = (unsigned char)((h[1] >> 40) & 0xff);
digest[11] = (unsigned char)((h[1] >> 32) & 0xff);
digest[12] = (unsigned char)((h[1] >> 24) & 0xff);
digest[13] = (unsigned char)((h[1] >> 16) & 0xff);
digest[14] = (unsigned char)((h[1] >> 8) & 0xff);
digest[15] = (unsigned char)(h[1] & 0xff);
}

PHP_HASH_API int PHP_MURMUR3FCopy(const php_hash_ops *ops, PHP_MURMUR3F_CTX *orig_context, PHP_MURMUR3F_CTX *copy_context)
{
memcpy(&copy_context->h, &orig_context->h, sizeof orig_context->h);
memcpy(&copy_context->carry, &orig_context->carry, sizeof orig_context->carry);
copy_context->len = orig_context->len;
return SUCCESS;
}
Loading