xref: /PHP-8.4/ext/hash/hash_murmur.c (revision c26e77c4)
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) {
46 			if (IS_LONG == Z_TYPE_P(seed)) {
47 				ctx->h = (uint32_t) Z_LVAL_P(seed);
48 			} else {
49 				php_error_docref(NULL, E_DEPRECATED, "Passing a seed of a type other than int is deprecated because it is the same as setting the seed to 0");
50 				ctx->h = 0;
51 			}
52 		} else {
53 			ctx->h = 0;
54 		}
55 	} else {
56 		ctx->h = 0;
57 	}
58 	ctx->carry = 0;
59 	ctx->len = 0;
60 }
61 
PHP_MURMUR3AUpdate(PHP_MURMUR3A_CTX * ctx,const unsigned char * in,size_t len)62 PHP_HASH_API void PHP_MURMUR3AUpdate(PHP_MURMUR3A_CTX *ctx, const unsigned char *in, size_t len)
63 {
64 	ctx->len += len;
65 	PMurHash32_Process(&ctx->h, &ctx->carry, in, len);
66 }
67 
PHP_MURMUR3AFinal(unsigned char digest[4],PHP_MURMUR3A_CTX * ctx)68 PHP_HASH_API void PHP_MURMUR3AFinal(unsigned char digest[4], PHP_MURMUR3A_CTX *ctx)
69 {
70 	ctx->h = PMurHash32_Result(ctx->h, ctx->carry, ctx->len);
71 
72 	digest[0] = (unsigned char)((ctx->h >> 24) & 0xff);
73 	digest[1] = (unsigned char)((ctx->h >> 16) & 0xff);
74 	digest[2] = (unsigned char)((ctx->h >> 8) & 0xff);
75 	digest[3] = (unsigned char)(ctx->h & 0xff);
76 }
77 
PHP_MURMUR3ACopy(const php_hash_ops * ops,const PHP_MURMUR3A_CTX * orig_context,PHP_MURMUR3A_CTX * copy_context)78 PHP_HASH_API zend_result PHP_MURMUR3ACopy(const php_hash_ops *ops, const PHP_MURMUR3A_CTX *orig_context, PHP_MURMUR3A_CTX *copy_context)
79 {
80 	copy_context->h = orig_context->h;
81 	copy_context->carry = orig_context->carry;
82 	copy_context->len = orig_context->len;
83 	return SUCCESS;
84 }
85 
86 const php_hash_ops php_hash_murmur3c_ops = {
87 	"murmur3c",
88 	(php_hash_init_func_t) PHP_MURMUR3CInit,
89 	(php_hash_update_func_t) PHP_MURMUR3CUpdate,
90 	(php_hash_final_func_t) PHP_MURMUR3CFinal,
91 	(php_hash_copy_func_t) PHP_MURMUR3CCopy,
92 	php_hash_serialize,
93 	php_hash_unserialize,
94 	PHP_MURMUR3C_SPEC,
95 	16,
96 	4,
97 	sizeof(PHP_MURMUR3C_CTX),
98 	0
99 };
100 
PHP_MURMUR3CInit(PHP_MURMUR3C_CTX * ctx,HashTable * args)101 PHP_HASH_API void PHP_MURMUR3CInit(PHP_MURMUR3C_CTX *ctx, HashTable *args)
102 {
103 	if (args) {
104 		zval *seed = zend_hash_str_find_deref(args, "seed", sizeof("seed") - 1);
105 		/* This might be a bit too restrictive, but thinking that a seed might be set
106 			once and for all, it should be done a clean way. */
107 		if (seed) {
108 			if (IS_LONG == Z_TYPE_P(seed)) {
109 				uint32_t _seed = (uint32_t)Z_LVAL_P(seed);
110 				ctx->h[0] = _seed;
111 				ctx->h[1] = _seed;
112 				ctx->h[2] = _seed;
113 				ctx->h[3] = _seed;
114 			} else {
115 				php_error_docref(NULL, E_DEPRECATED, "Passing a seed of a type other than int is deprecated because it is the same as setting the seed to 0");
116 				memset(&ctx->h, 0, sizeof ctx->h);
117 			}
118 		} else {
119 			memset(&ctx->h, 0, sizeof ctx->h);
120 		}
121 	} else {
122 		memset(&ctx->h, 0, sizeof ctx->h);
123 	}
124 	memset(&ctx->carry, 0, sizeof ctx->carry);
125 	ctx->len = 0;
126 }
127 
PHP_MURMUR3CUpdate(PHP_MURMUR3C_CTX * ctx,const unsigned char * in,size_t len)128 PHP_HASH_API void PHP_MURMUR3CUpdate(PHP_MURMUR3C_CTX *ctx, const unsigned char *in, size_t len)
129 {
130 	ctx->len += len;
131 	PMurHash128x86_Process(ctx->h, ctx->carry, in, len);
132 }
133 
PHP_MURMUR3CFinal(unsigned char digest[16],PHP_MURMUR3C_CTX * ctx)134 PHP_HASH_API void PHP_MURMUR3CFinal(unsigned char digest[16], PHP_MURMUR3C_CTX *ctx)
135 {
136 	uint32_t h[4] = {0, 0, 0, 0};
137 	PMurHash128x86_Result(ctx->h, ctx->carry, ctx->len, h);
138 
139 	digest[0]  = (unsigned char)((h[0] >> 24) & 0xff);
140 	digest[1]  = (unsigned char)((h[0] >> 16) & 0xff);
141 	digest[2]  = (unsigned char)((h[0] >> 8) & 0xff);
142 	digest[3]  = (unsigned char)(h[0] & 0xff);
143 	digest[4]  = (unsigned char)((h[1] >> 24) & 0xff);
144 	digest[5]  = (unsigned char)((h[1] >> 16) & 0xff);
145 	digest[6]  = (unsigned char)((h[1] >> 8) & 0xff);
146 	digest[7]  = (unsigned char)(h[1] & 0xff);
147 	digest[8]  = (unsigned char)((h[2] >> 24) & 0xff);
148 	digest[9]  = (unsigned char)((h[2] >> 16) & 0xff);
149 	digest[10] = (unsigned char)((h[2] >> 8) & 0xff);
150 	digest[11] = (unsigned char)(h[2] & 0xff);
151 	digest[12] = (unsigned char)((h[3] >> 24) & 0xff);
152 	digest[13] = (unsigned char)((h[3] >> 16) & 0xff);
153 	digest[14] = (unsigned char)((h[3] >> 8) & 0xff);
154 	digest[15] = (unsigned char)(h[3] & 0xff);
155 }
156 
PHP_MURMUR3CCopy(const php_hash_ops * ops,const PHP_MURMUR3C_CTX * orig_context,PHP_MURMUR3C_CTX * copy_context)157 PHP_HASH_API zend_result PHP_MURMUR3CCopy(const php_hash_ops *ops, const PHP_MURMUR3C_CTX *orig_context, PHP_MURMUR3C_CTX *copy_context)
158 {
159 	memcpy(&copy_context->h, &orig_context->h, sizeof orig_context->h);
160 	memcpy(&copy_context->carry, &orig_context->carry, sizeof orig_context->carry);
161 	copy_context->len = orig_context->len;
162 	return SUCCESS;
163 }
164 
165 const php_hash_ops php_hash_murmur3f_ops = {
166 	"murmur3f",
167 	(php_hash_init_func_t) PHP_MURMUR3FInit,
168 	(php_hash_update_func_t) PHP_MURMUR3FUpdate,
169 	(php_hash_final_func_t) PHP_MURMUR3FFinal,
170 	(php_hash_copy_func_t) PHP_MURMUR3FCopy,
171 	php_hash_serialize,
172 	php_hash_unserialize,
173 	PHP_MURMUR3F_SPEC,
174 	16,
175 	8,
176 	sizeof(PHP_MURMUR3F_CTX),
177 	0
178 };
179 
PHP_MURMUR3FInit(PHP_MURMUR3F_CTX * ctx,HashTable * args)180 PHP_HASH_API void PHP_MURMUR3FInit(PHP_MURMUR3F_CTX *ctx, HashTable *args)
181 {
182 	if (args) {
183 		zval *seed = zend_hash_str_find_deref(args, "seed", sizeof("seed") - 1);
184 		/* This might be a bit too restrictive, but thinking that a seed might be set
185 			once and for all, it should be done a clean way. */
186 		if (seed) {
187 			if (IS_LONG == Z_TYPE_P(seed)) {
188 				uint64_t _seed = (uint64_t) Z_LVAL_P(seed);
189 				ctx->h[0] = _seed;
190 				ctx->h[1] = _seed;
191 			} else {
192 				php_error_docref(NULL, E_DEPRECATED, "Passing a seed of a type other than int is deprecated because it is the same as setting the seed to 0");
193 				memset(&ctx->h, 0, sizeof ctx->h);
194 			}
195 		} else {
196 			memset(&ctx->h, 0, sizeof ctx->h);
197 		}
198 	} else {
199 		memset(&ctx->h, 0, sizeof ctx->h);
200 	}
201 	memset(&ctx->carry, 0, sizeof ctx->carry);
202 	ctx->len = 0;
203 }
204 
PHP_MURMUR3FUpdate(PHP_MURMUR3F_CTX * ctx,const unsigned char * in,size_t len)205 PHP_HASH_API void PHP_MURMUR3FUpdate(PHP_MURMUR3F_CTX *ctx, const unsigned char *in, size_t len)
206 {
207 	ctx->len += len;
208 	PMurHash128x64_Process(ctx->h, ctx->carry, in, len);
209 }
210 
PHP_MURMUR3FFinal(unsigned char digest[16],PHP_MURMUR3F_CTX * ctx)211 PHP_HASH_API void PHP_MURMUR3FFinal(unsigned char digest[16], PHP_MURMUR3F_CTX *ctx)
212 {
213 	uint64_t h[2] = {0, 0};
214 	PMurHash128x64_Result(ctx->h, ctx->carry, ctx->len, h);
215 
216 	digest[0]  = (unsigned char)((h[0] >> 56) & 0xff);
217 	digest[1]  = (unsigned char)((h[0] >> 48) & 0xff);
218 	digest[2]  = (unsigned char)((h[0] >> 40) & 0xff);
219 	digest[3]  = (unsigned char)((h[0] >> 32) & 0xff);
220 	digest[4]  = (unsigned char)((h[0] >> 24) & 0xff);
221 	digest[5]  = (unsigned char)((h[0] >> 16) & 0xff);
222 	digest[6]  = (unsigned char)((h[0] >> 8) & 0xff);
223 	digest[7]  = (unsigned char)(h[0] & 0xff);
224 	digest[8]  = (unsigned char)((h[1] >> 56) & 0xff);
225 	digest[9]  = (unsigned char)((h[1] >> 48) & 0xff);
226 	digest[10] = (unsigned char)((h[1] >> 40) & 0xff);
227 	digest[11] = (unsigned char)((h[1] >> 32) & 0xff);
228 	digest[12] = (unsigned char)((h[1] >> 24) & 0xff);
229 	digest[13] = (unsigned char)((h[1] >> 16) & 0xff);
230 	digest[14] = (unsigned char)((h[1] >> 8) & 0xff);
231 	digest[15] = (unsigned char)(h[1] & 0xff);
232 }
233 
PHP_MURMUR3FCopy(const php_hash_ops * ops,const PHP_MURMUR3F_CTX * orig_context,PHP_MURMUR3F_CTX * copy_context)234 PHP_HASH_API zend_result PHP_MURMUR3FCopy(const php_hash_ops *ops, const PHP_MURMUR3F_CTX *orig_context, PHP_MURMUR3F_CTX *copy_context)
235 {
236 	memcpy(&copy_context->h, &orig_context->h, sizeof orig_context->h);
237 	memcpy(&copy_context->carry, &orig_context->carry, sizeof orig_context->carry);
238 	copy_context->len = orig_context->len;
239 	return SUCCESS;
240 }
241