Coverage Report

Created: 2025-06-13 06:43

/src/php-src/ext/hash/hash_murmur.c
Line
Count
Source (jump to first uncovered line)
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
39
PHP_HASH_API void PHP_MURMUR3AInit(PHP_MURMUR3A_CTX *ctx, HashTable *args)
40
33
{
41
33
  if (args) {
42
0
    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
0
    if (seed) {
46
0
      if (IS_LONG == Z_TYPE_P(seed)) {
47
0
        ctx->h = (uint32_t) Z_LVAL_P(seed);
48
0
      } else {
49
0
        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
0
        ctx->h = 0;
51
0
      }
52
0
    } else {
53
0
      ctx->h = 0;
54
0
    }
55
33
  } else {
56
33
    ctx->h = 0;
57
33
  }
58
33
  ctx->carry = 0;
59
33
  ctx->len = 0;
60
33
}
61
62
PHP_HASH_API void PHP_MURMUR3AUpdate(PHP_MURMUR3A_CTX *ctx, const unsigned char *in, size_t len)
63
28
{
64
28
  ctx->len += len;
65
28
  PMurHash32_Process(&ctx->h, &ctx->carry, in, len);
66
28
}
67
68
PHP_HASH_API void PHP_MURMUR3AFinal(unsigned char digest[4], PHP_MURMUR3A_CTX *ctx)
69
28
{
70
28
  ctx->h = PMurHash32_Result(ctx->h, ctx->carry, ctx->len);
71
72
28
  digest[0] = (unsigned char)((ctx->h >> 24) & 0xff);
73
28
  digest[1] = (unsigned char)((ctx->h >> 16) & 0xff);
74
28
  digest[2] = (unsigned char)((ctx->h >> 8) & 0xff);
75
28
  digest[3] = (unsigned char)(ctx->h & 0xff);
76
28
}
77
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
0
{
80
0
  copy_context->h = orig_context->h;
81
0
  copy_context->carry = orig_context->carry;
82
0
  copy_context->len = orig_context->len;
83
0
  return SUCCESS;
84
0
}
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
101
PHP_HASH_API void PHP_MURMUR3CInit(PHP_MURMUR3C_CTX *ctx, HashTable *args)
102
43
{
103
43
  if (args) {
104
0
    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
0
    if (seed) {
108
0
      if (IS_LONG == Z_TYPE_P(seed)) {
109
0
        uint32_t _seed = (uint32_t)Z_LVAL_P(seed);
110
0
        ctx->h[0] = _seed;
111
0
        ctx->h[1] = _seed;
112
0
        ctx->h[2] = _seed;
113
0
        ctx->h[3] = _seed;
114
0
      } else {
115
0
        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
0
        memset(&ctx->h, 0, sizeof ctx->h);
117
0
      }
118
0
    } else {
119
0
      memset(&ctx->h, 0, sizeof ctx->h);
120
0
    }
121
43
  } else {
122
43
    memset(&ctx->h, 0, sizeof ctx->h);
123
43
  }
124
43
  memset(&ctx->carry, 0, sizeof ctx->carry);
125
43
  ctx->len = 0;
126
43
}
127
128
PHP_HASH_API void PHP_MURMUR3CUpdate(PHP_MURMUR3C_CTX *ctx, const unsigned char *in, size_t len)
129
42
{
130
42
  ctx->len += len;
131
42
  PMurHash128x86_Process(ctx->h, ctx->carry, in, len);
132
42
}
133
134
PHP_HASH_API void PHP_MURMUR3CFinal(unsigned char digest[16], PHP_MURMUR3C_CTX *ctx)
135
42
{
136
42
  uint32_t h[4] = {0, 0, 0, 0};
137
42
  PMurHash128x86_Result(ctx->h, ctx->carry, ctx->len, h);
138
139
42
  digest[0]  = (unsigned char)((h[0] >> 24) & 0xff);
140
42
  digest[1]  = (unsigned char)((h[0] >> 16) & 0xff);
141
42
  digest[2]  = (unsigned char)((h[0] >> 8) & 0xff);
142
42
  digest[3]  = (unsigned char)(h[0] & 0xff);
143
42
  digest[4]  = (unsigned char)((h[1] >> 24) & 0xff);
144
42
  digest[5]  = (unsigned char)((h[1] >> 16) & 0xff);
145
42
  digest[6]  = (unsigned char)((h[1] >> 8) & 0xff);
146
42
  digest[7]  = (unsigned char)(h[1] & 0xff);
147
42
  digest[8]  = (unsigned char)((h[2] >> 24) & 0xff);
148
42
  digest[9]  = (unsigned char)((h[2] >> 16) & 0xff);
149
42
  digest[10] = (unsigned char)((h[2] >> 8) & 0xff);
150
42
  digest[11] = (unsigned char)(h[2] & 0xff);
151
42
  digest[12] = (unsigned char)((h[3] >> 24) & 0xff);
152
42
  digest[13] = (unsigned char)((h[3] >> 16) & 0xff);
153
42
  digest[14] = (unsigned char)((h[3] >> 8) & 0xff);
154
42
  digest[15] = (unsigned char)(h[3] & 0xff);
155
42
}
156
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
0
{
159
0
  memcpy(&copy_context->h, &orig_context->h, sizeof orig_context->h);
160
0
  memcpy(&copy_context->carry, &orig_context->carry, sizeof orig_context->carry);
161
0
  copy_context->len = orig_context->len;
162
0
  return SUCCESS;
163
0
}
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
180
PHP_HASH_API void PHP_MURMUR3FInit(PHP_MURMUR3F_CTX *ctx, HashTable *args)
181
33
{
182
33
  if (args) {
183
0
    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
0
    if (seed) {
187
0
      if (IS_LONG == Z_TYPE_P(seed)) {
188
0
        uint64_t _seed = (uint64_t) Z_LVAL_P(seed);
189
0
        ctx->h[0] = _seed;
190
0
        ctx->h[1] = _seed;
191
0
      } else {
192
0
        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
0
        memset(&ctx->h, 0, sizeof ctx->h);
194
0
      }
195
0
    } else {
196
0
      memset(&ctx->h, 0, sizeof ctx->h);
197
0
    }
198
33
  } else {
199
33
    memset(&ctx->h, 0, sizeof ctx->h);
200
33
  }
201
33
  memset(&ctx->carry, 0, sizeof ctx->carry);
202
33
  ctx->len = 0;
203
33
}
204
205
PHP_HASH_API void PHP_MURMUR3FUpdate(PHP_MURMUR3F_CTX *ctx, const unsigned char *in, size_t len)
206
30
{
207
30
  ctx->len += len;
208
30
  PMurHash128x64_Process(ctx->h, ctx->carry, in, len);
209
30
}
210
211
PHP_HASH_API void PHP_MURMUR3FFinal(unsigned char digest[16], PHP_MURMUR3F_CTX *ctx)
212
30
{
213
30
  uint64_t h[2] = {0, 0};
214
30
  PMurHash128x64_Result(ctx->h, ctx->carry, ctx->len, h);
215
216
30
  digest[0]  = (unsigned char)((h[0] >> 56) & 0xff);
217
30
  digest[1]  = (unsigned char)((h[0] >> 48) & 0xff);
218
30
  digest[2]  = (unsigned char)((h[0] >> 40) & 0xff);
219
30
  digest[3]  = (unsigned char)((h[0] >> 32) & 0xff);
220
30
  digest[4]  = (unsigned char)((h[0] >> 24) & 0xff);
221
30
  digest[5]  = (unsigned char)((h[0] >> 16) & 0xff);
222
30
  digest[6]  = (unsigned char)((h[0] >> 8) & 0xff);
223
30
  digest[7]  = (unsigned char)(h[0] & 0xff);
224
30
  digest[8]  = (unsigned char)((h[1] >> 56) & 0xff);
225
30
  digest[9]  = (unsigned char)((h[1] >> 48) & 0xff);
226
30
  digest[10] = (unsigned char)((h[1] >> 40) & 0xff);
227
30
  digest[11] = (unsigned char)((h[1] >> 32) & 0xff);
228
30
  digest[12] = (unsigned char)((h[1] >> 24) & 0xff);
229
30
  digest[13] = (unsigned char)((h[1] >> 16) & 0xff);
230
30
  digest[14] = (unsigned char)((h[1] >> 8) & 0xff);
231
30
  digest[15] = (unsigned char)(h[1] & 0xff);
232
30
}
233
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
0
{
236
0
  memcpy(&copy_context->h, &orig_context->h, sizeof orig_context->h);
237
0
  memcpy(&copy_context->carry, &orig_context->carry, sizeof orig_context->carry);
238
0
  copy_context->len = orig_context->len;
239
0
  return SUCCESS;
240
0
}