Hi,
Earlier on someone on IRC mentioned that ext/hash had no support for the
FNV-1 hash function
(http://en.wikipedia.org/wiki/Fowler-Noll-Vo_hash_function), so I
decided to have a go at adding it. The result of this is the attached
patch. Currently it only supports 32-bit and 64-bit versions. I've
written it against PHP 5.3 SVN, I presume it'll apply to HEAD but I
haven't checked yet. Any comments?

Cheers,
Michael
diff -x run-tests.php -x 'Make*' -x ltmain.sh -x '*.svn*' -x '*config*' -x 
'*.m4' -x '*auto*' -x 'build*' -N -u -r php-src-5.3/ext/hash/hash.c hash/hash.c
--- php-src-5.3/ext/hash/hash.c 2009-09-04 14:22:19.000000000 +0100
+++ hash/hash.c 2009-09-04 11:59:53.000000000 +0100
@@ -74,7 +74,11 @@
        {"RIPEMD320", "ripemd320", 25},
        {NULL, NULL, 26}, /* support needs to be added for snefru 128 */
        {"SNEFRU256", "snefru256", 27},
-       {"MD2", "md2", 28}
+       {"MD2", "md2", 28},
+       {"FNV132", "fnv132", 29},
+       {"FNV1a32", "fnv1a32", 30},
+       {"FNV164", "fnv164", 31},
+       {"FNV1a64", "fnv1a64", 32},
 };
 #endif
 
@@ -841,6 +845,8 @@
        php_hash_register_algo("crc32b",                &php_hash_crc32b_ops);
        php_hash_register_algo("salsa10",               &php_hash_salsa10_ops);
        php_hash_register_algo("salsa20",               &php_hash_salsa20_ops);
+       php_hash_register_algo("fnv132",                &php_hash_fnv132_ops);
+       php_hash_register_algo("fnv164",                &php_hash_fnv164_ops);
 
        PHP_HASH_HAVAL_REGISTER(3,128);
        PHP_HASH_HAVAL_REGISTER(3,160);
diff -x run-tests.php -x 'Make*' -x ltmain.sh -x '*.svn*' -x '*config*' -x 
'*.m4' -x '*auto*' -x 'build*' -N -u -r php-src-5.3/ext/hash/hash_fnv.c 
hash/hash_fnv.c
--- php-src-5.3/ext/hash/hash_fnv.c     1970-01-01 01:00:00.000000000 +0100
+++ hash/hash_fnv.c     2009-09-04 15:14:33.000000000 +0100
@@ -0,0 +1,221 @@
+/*
+  +----------------------------------------------------------------------+
+  | PHP Version 5                                                        |
+  +----------------------------------------------------------------------+
+  | Copyright (c) 1997-2009 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          |
+  | lice...@php.net so we can mail you a copy immediately.               |
+  +----------------------------------------------------------------------+
+  | Authors: Michael Wallner <m...@php.net>                              |
+  |          Sara Golemon <poll...@php.net>                              |
+  |          Michael Maclean <m...@php.net>                              |
+  +----------------------------------------------------------------------+
+*/
+
+/* $Id: hash_salsa.c 272370 2008-12-31 11:15:49Z sebastian $ */
+
+#include "php_hash.h"
+#include "php_hash_fnv.h"
+
+const php_hash_ops php_hash_fnv132_ops = {
+       (php_hash_init_func_t) PHP_FNV132Init,
+       (php_hash_update_func_t) PHP_FNV132Update,
+       (php_hash_final_func_t) PHP_FNV132Final,
+       (php_hash_copy_func_t) php_hash_copy,
+       4,
+       4,
+       sizeof(PHP_FNV132_CTX)
+};
+
+    const php_hash_ops php_hash_fnv1a32_ops = {
+       (php_hash_init_func_t) PHP_FNV132Init,
+       (php_hash_update_func_t) PHP_FNV1a32Update,
+       (php_hash_final_func_t) PHP_FNV132Final, 
+       (php_hash_copy_func_t) php_hash_copy,
+       4,
+       4,
+       sizeof(PHP_FNV132_CTX)
+};
+
+const php_hash_ops php_hash_fnv164_ops = {
+       (php_hash_init_func_t) PHP_FNV164Init,
+       (php_hash_update_func_t) PHP_FNV164Update,
+       (php_hash_final_func_t) PHP_FNV164Final, 
+       (php_hash_copy_func_t) php_hash_copy,
+       8,
+       4,
+       sizeof(PHP_FNV164_CTX)
+};
+
+const php_hash_ops php_hash_fnv1a64_ops = {
+       (php_hash_init_func_t) PHP_FNV164Init,
+       (php_hash_update_func_t) PHP_FNV1a64Update,
+       (php_hash_final_func_t) PHP_FNV164Final,  
+       (php_hash_copy_func_t) php_hash_copy,
+       8,
+       4,
+       sizeof(PHP_FNV164_CTX)
+};
+
+/* {{{ PHP_FNV132Init
+ * 32-bit FNV-1 hash initialisation
+ */
+PHP_HASH_API void PHP_FNV132Init(PHP_FNV132_CTX *context)
+{
+    context->state = PHP_FNV1_32_INIT;
+}
+/* }}} */
+
+PHP_HASH_API void PHP_FNV132Update(PHP_FNV132_CTX *context, const unsigned 
char *input,
+        unsigned int inputLen)
+{
+    context->state = fnv_32_buf((void *)input, inputLen, context->state, 0);
+}
+
+PHP_HASH_API void PHP_FNV1a32Update(PHP_FNV132_CTX *context, const unsigned 
char *input,
+        unsigned int inputLen)
+{
+    context->state = fnv_32_buf((void *)input, inputLen, context->state, 1);
+}
+
+PHP_HASH_API void PHP_FNV132Final(unsigned char digest[4], PHP_FNV132_CTX * 
context)
+{
+#ifdef WORDS_BIGENDIAN
+    memcpy(digest, &context->state, 4);
+#else
+    int i = 0;
+    unsigned char *c = (unsigned char *) &context->state;
+
+    for(i = 0; i < 4; i++) {
+        digest[i] = c[3 - i];
+    }
+#endif
+}
+
+/* {{{ PHP_FNV164Init
+ * 64-bit FNV-1 hash initialisation
+ */
+PHP_HASH_API void PHP_FNV164Init(PHP_FNV164_CTX *context)
+{
+    context->state = PHP_FNV1_64_INIT;
+}
+/* }}} */
+
+PHP_HASH_API void PHP_FNV164Update(PHP_FNV164_CTX *context, const unsigned 
char *input,
+        unsigned int inputLen)
+{
+    context->state = fnv_64_buf((void *)input, inputLen, context->state, 0);
+}
+
+PHP_HASH_API void PHP_FNV1a64Update(PHP_FNV164_CTX *context, const unsigned 
char *input,
+        unsigned int inputLen)
+{
+    context->state = fnv_64_buf((void *)input, inputLen, context->state, 1);
+}
+
+PHP_HASH_API void PHP_FNV164Final(unsigned char digest[8], PHP_FNV164_CTX * 
context)
+{
+#ifdef WORDS_BIGENDIAN
+    memcpy(digest, &context->state, 8);
+#else
+    int i = 0;
+    unsigned char *c = (unsigned char *) &context->state;
+
+    for(i = 0; i < 8; i++) {
+        digest[i] = c[7 - i];
+    }
+#endif
+}
+
+
+/*
+ * fnv_32_buf - perform a 32 bit Fowler/Noll/Vo hash on a buffer
+ *
+ * input:
+ *  buf - start of buffer to hash
+ *  len - length of buffer in octets
+ *  hval    - previous hash value or 0 if first call
+ *  alternate - if > 0 use the alternate version
+ *
+ * returns:
+ *  32 bit hash as a static hash type
+ */
+static php_hash_uint32
+fnv_32_buf(void *buf, size_t len, php_hash_uint32 hval, int alternate)
+{
+    unsigned char *bp = (unsigned char *)buf;   /* start of buffer */
+    unsigned char *be = bp + len;       /* beyond end of buffer */
+
+    /*
+     * FNV-1 hash each octet in the buffer
+     */
+    while (bp < be) {
+
+        if(alternate == 0) {
+            /* multiply by the 32 bit FNV magic prime mod 2^32 */
+            hval *= PHP_FNV_32_PRIME;
+
+            /* xor the bottom with the current octet */
+            hval ^= (php_hash_uint32)*bp++;
+        } else {
+            /* xor the bottom with the current octet */
+            hval ^= (php_hash_uint32)*bp++;
+
+            /* multiply by the 32 bit FNV magic prime mod 2^32 */
+            hval *= PHP_FNV_32_PRIME;
+        }
+    }
+
+    /* return our new hash value */
+    return hval;
+}
+
+/*
+ * fnv_64_buf - perform a 64 bit Fowler/Noll/Vo hash on a buffer
+ *
+ * input:
+ *  buf - start of buffer to hash
+ *  len - length of buffer in octets
+ *  hval    - previous hash value or 0 if first call
+ *  alternate - if > 0 use the alternate version
+ *
+ * returns:
+ *  64 bit hash as a static hash type
+ */
+static php_hash_uint64
+fnv_64_buf(void *buf, size_t len, php_hash_uint64 hval, int alternate)
+{
+    unsigned char *bp = (unsigned char *)buf;   /* start of buffer */
+    unsigned char *be = bp + len;       /* beyond end of buffer */
+
+    /*
+     * FNV-1 hash each octet of the buffer
+     */
+    while (bp < be) {
+
+        if(alternate == 0) {
+            /* multiply by the 64 bit FNV magic prime mod 2^64 */
+            hval *= PHP_FNV_64_PRIME;
+
+            /* xor the bottom with the current octet */
+            hval ^= (php_hash_uint64)*bp++;
+         } else {
+            /* xor the bottom with the current octet */
+            hval ^= (php_hash_uint64)*bp++;
+
+            /* multiply by the 64 bit FNV magic prime mod 2^64 */
+            hval *= PHP_FNV_64_PRIME;
+         }
+    }
+
+    /* return our new hash value */
+    return hval;
+}
+
+
diff -x run-tests.php -x 'Make*' -x ltmain.sh -x '*.svn*' -x '*config*' -x 
'*.m4' -x '*auto*' -x 'build*' -N -u -r php-src-5.3/ext/hash/php_hash_fnv.h 
hash/php_hash_fnv.h
--- php-src-5.3/ext/hash/php_hash_fnv.h 1970-01-01 01:00:00.000000000 +0100
+++ hash/php_hash_fnv.h 2009-09-04 15:08:43.000000000 +0100
@@ -0,0 +1,72 @@
+/*
+  +----------------------------------------------------------------------+
+  | PHP Version 5                                                        |
+  +----------------------------------------------------------------------+
+  | Copyright (c) 1997-2009 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          |
+  | lice...@php.net so we can mail you a copy immediately.               |
+  +----------------------------------------------------------------------+
+  | Authors: Michael Wallner <m...@php.net>                              |
+  |          Sara Golemon <poll...@php.net>                              |
+  |          Michael Maclean <m...@php.net>                              |
+  +----------------------------------------------------------------------+
+*/
+
+/* $Id: hash_salsa.c 272370 2008-12-31 11:15:49Z sebastian $ */
+
+#ifndef PHP_HASH_FNV_H
+#define PHP_HASH_FNV_H
+
+#define PHP_FNV1_32_INIT ((php_hash_uint32)0x811c9dc5)
+#define PHP_FNV1_32A_INIT PHP_FNV1_32_INIT
+
+#define PHP_FNV_32_PRIME ((php_hash_uint32)0x01000193)
+
+#define PHP_FNV1_64_INIT ((php_hash_uint64)0xcbf29ce484222325ULL)
+#define PHP_FNV1A_64_INIT FNV1_64_INIT
+
+#define PHP_FNV_64_PRIME ((php_hash_uint64)0x100000001b3ULL)
+
+
+/*
+ * hash types
+ */
+enum php_fnv_type {
+    PHP_FNV_NONE  = 0, /* invalid FNV hash type */
+    PHP_FNV0_32   = 1, /* FNV-0 32 bit hash */
+    PHP_FNV1_32   = 2, /* FNV-1 32 bit hash */
+    PHP_FNV1a_32  = 3, /* FNV-1a 32 bit hash */
+    PHP_FNV0_64   = 4, /* FNV-0 64 bit hash */
+    PHP_FNV1_64   = 5, /* FNV-1 64 bit hash */
+    PHP_FNV1a_64  = 6, /* FNV-1a 64 bit hash */
+};
+
+typedef struct {
+    php_hash_uint32 state;
+} PHP_FNV132_CTX;
+
+typedef struct {
+    php_hash_uint64 state;
+} PHP_FNV164_CTX;
+
+
+PHP_HASH_API void PHP_FNV132Init(PHP_FNV132_CTX *context);
+PHP_HASH_API void PHP_FNV132Update(PHP_FNV132_CTX *context, const unsigned 
char *input, unsigned int inputLen);
+PHP_HASH_API void PHP_FNV1a32Update(PHP_FNV132_CTX *context, const unsigned 
char *input, unsigned int inputLen);
+PHP_HASH_API void PHP_FNV132Final(unsigned char digest[16], PHP_FNV132_CTX * 
context);
+
+PHP_HASH_API void PHP_FNV164Init(PHP_FNV164_CTX *context);
+PHP_HASH_API void PHP_FNV164Update(PHP_FNV164_CTX *context, const unsigned 
char *input, unsigned int inputLen);
+PHP_HASH_API void PHP_FNV1a64Update(PHP_FNV164_CTX *context, const unsigned 
char *input, unsigned int inputLen);
+PHP_HASH_API void PHP_FNV164Final(unsigned char digest[16], PHP_FNV164_CTX * 
context);
+
+static php_hash_uint32 fnv_32_buf(void *buf, size_t len, php_hash_uint32 hval, 
int alternate);
+static php_hash_uint64 fnv_64_buf(void *buf, size_t len, php_hash_uint64 hval, 
int alternate);
+
+#endif
diff -x run-tests.php -x 'Make*' -x ltmain.sh -x '*.svn*' -x '*config*' -x 
'*.m4' -x '*auto*' -x 'build*' -N -u -r php-src-5.3/ext/hash/php_hash.h 
hash/php_hash.h
--- php-src-5.3/ext/hash/php_hash.h     2009-09-04 14:22:19.000000000 +0100
+++ hash/php_hash.h     2009-09-04 11:26:55.000000000 +0100
@@ -80,6 +80,10 @@
 extern const php_hash_ops php_hash_crc32b_ops;
 extern const php_hash_ops php_hash_salsa10_ops;
 extern const php_hash_ops php_hash_salsa20_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;
+extern const php_hash_ops php_hash_fnv1a64_ops;
 
 #define PHP_HASH_HAVAL_OPS(p,b)        extern const php_hash_ops 
php_hash_##p##haval##b##_ops;
 
-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to