xref: /php-src/ext/hash/hash_murmur.c (revision 01b3fc03)
1 /*
2    +----------------------------------------------------------------------+
3    | Copyright (c) The PHP Group                                          |
4    +----------------------------------------------------------------------+
5    | This source file is subject to version 3.01 of the PHP license,      |
6    | that is bundled with this package in the file LICENSE, and is        |
7    | available through the world-wide-web at the following url:           |
8    | https://www.php.net/license/3_01.txt                                 |
9    | If you did not receive a copy of the PHP license and are unable to   |
10    | obtain it through the world-wide-web, please send a note to          |
11    | license@php.net so we can mail you a copy immediately.               |
12    +----------------------------------------------------------------------+
13    | Author: Anatol Belski <ab@php.net>                                   |
14    +----------------------------------------------------------------------+
15 */
16 
17 #include "php_hash.h"
18 #include "php_hash_murmur.h"
19 
20 #include "murmur/PMurHash.h"
21 #include "murmur/PMurHash128.h"
22 
23 
24 const php_hash_ops php_hash_murmur3a_ops = {
25 	"murmur3a",
26 	(php_hash_init_func_t) PHP_MURMUR3AInit,
27 	(php_hash_update_func_t) PHP_MURMUR3AUpdate,
28 	(php_hash_final_func_t) PHP_MURMUR3AFinal,
29 	(php_hash_copy_func_t) PHP_MURMUR3ACopy,
30 	php_hash_serialize,
31 	php_hash_unserialize,
32 	PHP_MURMUR3A_SPEC,
33 	4,
34 	4,
35 	sizeof(PHP_MURMUR3A_CTX),
36 	0
37 };
38 
PHP_MURMUR3AInit(PHP_MURMUR3A_CTX * ctx,HashTable * args)39 PHP_HASH_API void PHP_MURMUR3AInit(PHP_MURMUR3A_CTX *ctx, HashTable *args)
40 {
41 	if (args) {
42 		zval *seed = zend_hash_str_find_deref(args, "seed", sizeof("seed") - 1);
43 		/* This might be a bit too restrictive, but thinking that a seed might be set
44 			once and for all, it should be done a clean way. */
45 		if (seed && IS_LONG == Z_TYPE_P(seed)) {
46 			ctx->h = (uint32_t)Z_LVAL_P(seed);
47 		} else {
48 			ctx->h = 0;
49 		}
50 	} else {
51 		ctx->h = 0;
52 	}
53 	ctx->carry = 0;
54 	ctx->len = 0;
55 }
56 
PHP_MURMUR3AUpdate(PHP_MURMUR3A_CTX * ctx,const unsigned char * in,size_t len)57 PHP_HASH_API void PHP_MURMUR3AUpdate(PHP_MURMUR3A_CTX *ctx, const unsigned char *in, size_t len)
58 {
59 	ctx->len += len;
60 	PMurHash32_Process(&ctx->h, &ctx->carry, in, len);
61 }
62 
PHP_MURMUR3AFinal(unsigned char digest[4],PHP_MURMUR3A_CTX * ctx)63 PHP_HASH_API void PHP_MURMUR3AFinal(unsigned char digest[4], PHP_MURMUR3A_CTX *ctx)
64 {
65 	ctx->h = PMurHash32_Result(ctx->h, ctx->carry, ctx->len);
66 
67 	digest[0] = (unsigned char)((ctx->h >> 24) & 0xff);
68 	digest[1] = (unsigned char)((ctx->h >> 16) & 0xff);
69 	digest[2] = (unsigned char)((ctx->h >> 8) & 0xff);
70 	digest[3] = (unsigned char)(ctx->h & 0xff);
71 }
72 
PHP_MURMUR3ACopy(const php_hash_ops * ops,PHP_MURMUR3A_CTX * orig_context,PHP_MURMUR3A_CTX * copy_context)73 PHP_HASH_API int PHP_MURMUR3ACopy(const php_hash_ops *ops, PHP_MURMUR3A_CTX *orig_context, PHP_MURMUR3A_CTX *copy_context)
74 {
75 	copy_context->h = orig_context->h;
76 	copy_context->carry = orig_context->carry;
77 	copy_context->len = orig_context->len;
78 	return SUCCESS;
79 }
80 
81 const php_hash_ops php_hash_murmur3c_ops = {
82 	"murmur3c",
83 	(php_hash_init_func_t) PHP_MURMUR3CInit,
84 	(php_hash_update_func_t) PHP_MURMUR3CUpdate,
85 	(php_hash_final_func_t) PHP_MURMUR3CFinal,
86 	(php_hash_copy_func_t) PHP_MURMUR3CCopy,
87 	php_hash_serialize,
88 	php_hash_unserialize,
89 	PHP_MURMUR3C_SPEC,
90 	16,
91 	4,
92 	sizeof(PHP_MURMUR3C_CTX),
93 	0
94 };
95 
PHP_MURMUR3CInit(PHP_MURMUR3C_CTX * ctx,HashTable * args)96 PHP_HASH_API void PHP_MURMUR3CInit(PHP_MURMUR3C_CTX *ctx, HashTable *args)
97 {
98 	if (args) {
99 		zval *seed = zend_hash_str_find_deref(args, "seed", sizeof("seed") - 1);
100 		/* This might be a bit too restrictive, but thinking that a seed might be set
101 			once and for all, it should be done a clean way. */
102 		if (seed && IS_LONG == Z_TYPE_P(seed)) {
103 			uint32_t _seed = (uint32_t)Z_LVAL_P(seed);
104 			ctx->h[0] = _seed;
105 			ctx->h[1] = _seed;
106 			ctx->h[2] = _seed;
107 			ctx->h[3] = _seed;
108 		} else {
109 			memset(&ctx->h, 0, sizeof ctx->h);
110 		}
111 	} else {
112 		memset(&ctx->h, 0, sizeof ctx->h);
113 	}
114 	memset(&ctx->carry, 0, sizeof ctx->carry);
115 	ctx->len = 0;
116 }
117 
PHP_MURMUR3CUpdate(PHP_MURMUR3C_CTX * ctx,const unsigned char * in,size_t len)118 PHP_HASH_API void PHP_MURMUR3CUpdate(PHP_MURMUR3C_CTX *ctx, const unsigned char *in, size_t len)
119 {
120 	ctx->len += len;
121 	PMurHash128x86_Process(ctx->h, ctx->carry, in, len);
122 }
123 
PHP_MURMUR3CFinal(unsigned char digest[16],PHP_MURMUR3C_CTX * ctx)124 PHP_HASH_API void PHP_MURMUR3CFinal(unsigned char digest[16], PHP_MURMUR3C_CTX *ctx)
125 {
126 	uint32_t h[4] = {0, 0, 0, 0};
127 	PMurHash128x86_Result(ctx->h, ctx->carry, ctx->len, h);
128 
129 	digest[0]  = (unsigned char)((h[0] >> 24) & 0xff);
130 	digest[1]  = (unsigned char)((h[0] >> 16) & 0xff);
131 	digest[2]  = (unsigned char)((h[0] >> 8) & 0xff);
132 	digest[3]  = (unsigned char)(h[0] & 0xff);
133 	digest[4]  = (unsigned char)((h[1] >> 24) & 0xff);
134 	digest[5]  = (unsigned char)((h[1] >> 16) & 0xff);
135 	digest[6]  = (unsigned char)((h[1] >> 8) & 0xff);
136 	digest[7]  = (unsigned char)(h[1] & 0xff);
137 	digest[8]  = (unsigned char)((h[2] >> 24) & 0xff);
138 	digest[9]  = (unsigned char)((h[2] >> 16) & 0xff);
139 	digest[10] = (unsigned char)((h[2] >> 8) & 0xff);
140 	digest[11] = (unsigned char)(h[2] & 0xff);
141 	digest[12] = (unsigned char)((h[3] >> 24) & 0xff);
142 	digest[13] = (unsigned char)((h[3] >> 16) & 0xff);
143 	digest[14] = (unsigned char)((h[3] >> 8) & 0xff);
144 	digest[15] = (unsigned char)(h[3] & 0xff);
145 }
146 
PHP_MURMUR3CCopy(const php_hash_ops * ops,PHP_MURMUR3C_CTX * orig_context,PHP_MURMUR3C_CTX * copy_context)147 PHP_HASH_API int PHP_MURMUR3CCopy(const php_hash_ops *ops, PHP_MURMUR3C_CTX *orig_context, PHP_MURMUR3C_CTX *copy_context)
148 {
149 	memcpy(&copy_context->h, &orig_context->h, sizeof orig_context->h);
150 	memcpy(&copy_context->carry, &orig_context->carry, sizeof orig_context->carry);
151 	copy_context->len = orig_context->len;
152 	return SUCCESS;
153 }
154 
155 const php_hash_ops php_hash_murmur3f_ops = {
156 	"murmur3f",
157 	(php_hash_init_func_t) PHP_MURMUR3FInit,
158 	(php_hash_update_func_t) PHP_MURMUR3FUpdate,
159 	(php_hash_final_func_t) PHP_MURMUR3FFinal,
160 	(php_hash_copy_func_t) PHP_MURMUR3FCopy,
161 	php_hash_serialize,
162 	php_hash_unserialize,
163 	PHP_MURMUR3F_SPEC,
164 	16,
165 	8,
166 	sizeof(PHP_MURMUR3F_CTX),
167 	0
168 };
169 
PHP_MURMUR3FInit(PHP_MURMUR3F_CTX * ctx,HashTable * args)170 PHP_HASH_API void PHP_MURMUR3FInit(PHP_MURMUR3F_CTX *ctx, HashTable *args)
171 {
172 	if (args) {
173 		zval *seed = zend_hash_str_find_deref(args, "seed", sizeof("seed") - 1);
174 		/* This might be a bit too restrictive, but thinking that a seed might be set
175 			once and for all, it should be done a clean way. */
176 		if (seed && IS_LONG == Z_TYPE_P(seed)) {
177 			uint64_t _seed = (uint64_t)Z_LVAL_P(seed);
178 			ctx->h[0] = _seed;
179 			ctx->h[1] = _seed;
180 		} else {
181 			memset(&ctx->h, 0, sizeof ctx->h);
182 		}
183 	} else {
184 		memset(&ctx->h, 0, sizeof ctx->h);
185 	}
186 	memset(&ctx->carry, 0, sizeof ctx->carry);
187 	ctx->len = 0;
188 }
189 
PHP_MURMUR3FUpdate(PHP_MURMUR3F_CTX * ctx,const unsigned char * in,size_t len)190 PHP_HASH_API void PHP_MURMUR3FUpdate(PHP_MURMUR3F_CTX *ctx, const unsigned char *in, size_t len)
191 {
192 	ctx->len += len;
193 	PMurHash128x64_Process(ctx->h, ctx->carry, in, len);
194 }
195 
PHP_MURMUR3FFinal(unsigned char digest[16],PHP_MURMUR3F_CTX * ctx)196 PHP_HASH_API void PHP_MURMUR3FFinal(unsigned char digest[16], PHP_MURMUR3F_CTX *ctx)
197 {
198 	uint64_t h[2] = {0, 0};
199 	PMurHash128x64_Result(ctx->h, ctx->carry, ctx->len, h);
200 
201 	digest[0]  = (unsigned char)((h[0] >> 56) & 0xff);
202 	digest[1]  = (unsigned char)((h[0] >> 48) & 0xff);
203 	digest[2]  = (unsigned char)((h[0] >> 40) & 0xff);
204 	digest[3]  = (unsigned char)((h[0] >> 32) & 0xff);
205 	digest[4]  = (unsigned char)((h[0] >> 24) & 0xff);
206 	digest[5]  = (unsigned char)((h[0] >> 16) & 0xff);
207 	digest[6]  = (unsigned char)((h[0] >> 8) & 0xff);
208 	digest[7]  = (unsigned char)(h[0] & 0xff);
209 	digest[8]  = (unsigned char)((h[1] >> 56) & 0xff);
210 	digest[9]  = (unsigned char)((h[1] >> 48) & 0xff);
211 	digest[10] = (unsigned char)((h[1] >> 40) & 0xff);
212 	digest[11] = (unsigned char)((h[1] >> 32) & 0xff);
213 	digest[12] = (unsigned char)((h[1] >> 24) & 0xff);
214 	digest[13] = (unsigned char)((h[1] >> 16) & 0xff);
215 	digest[14] = (unsigned char)((h[1] >> 8) & 0xff);
216 	digest[15] = (unsigned char)(h[1] & 0xff);
217 }
218 
PHP_MURMUR3FCopy(const php_hash_ops * ops,PHP_MURMUR3F_CTX * orig_context,PHP_MURMUR3F_CTX * copy_context)219 PHP_HASH_API int PHP_MURMUR3FCopy(const php_hash_ops *ops, PHP_MURMUR3F_CTX *orig_context, PHP_MURMUR3F_CTX *copy_context)
220 {
221 	memcpy(&copy_context->h, &orig_context->h, sizeof orig_context->h);
222 	memcpy(&copy_context->carry, &orig_context->carry, sizeof orig_context->carry);
223 	copy_context->len = orig_context->len;
224 	return SUCCESS;
225 }
226