Coverage Report

Created: 2026-06-13 07:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/php-src/ext/hash/hash_fnv.c
Line
Count
Source
1
/*
2
  +----------------------------------------------------------------------+
3
  | Copyright © The PHP Group and Contributors.                          |
4
  +----------------------------------------------------------------------+
5
  | This source file is subject to the Modified BSD License that is      |
6
  | bundled with this package in the file LICENSE, and is available      |
7
  | through the World Wide Web at <https://www.php.net/license/>.        |
8
  |                                                                      |
9
  | SPDX-License-Identifier: BSD-3-Clause                                |
10
  +----------------------------------------------------------------------+
11
  | Author: Michael Maclean <mgdm@php.net>                               |
12
  +----------------------------------------------------------------------+
13
*/
14
15
/*  Based on the public domain algorithm found at
16
  http://www.isthe.com/chongo/tech/comp/fnv/index.html */
17
18
#include "php_hash.h"
19
#include "php_hash_fnv.h"
20
21
const php_hash_ops php_hash_fnv132_ops = {
22
  "fnv132",
23
  (php_hash_init_func_t) PHP_FNV132Init,
24
  (php_hash_update_func_t) PHP_FNV132Update,
25
  (php_hash_final_func_t) PHP_FNV132Final,
26
  php_hash_copy,
27
  php_hash_serialize,
28
  php_hash_unserialize,
29
  PHP_FNV132_SPEC,
30
  4,
31
  4,
32
  sizeof(PHP_FNV132_CTX),
33
  0
34
};
35
36
const php_hash_ops php_hash_fnv1a32_ops = {
37
  "fnv1a32",
38
  (php_hash_init_func_t) PHP_FNV132Init,
39
  (php_hash_update_func_t) PHP_FNV1a32Update,
40
  (php_hash_final_func_t) PHP_FNV132Final,
41
  php_hash_copy,
42
  php_hash_serialize,
43
  php_hash_unserialize,
44
  PHP_FNV132_SPEC,
45
  4,
46
  4,
47
  sizeof(PHP_FNV132_CTX),
48
  0
49
};
50
51
const php_hash_ops php_hash_fnv164_ops = {
52
  "fnv164",
53
  (php_hash_init_func_t) PHP_FNV164Init,
54
  (php_hash_update_func_t) PHP_FNV164Update,
55
  (php_hash_final_func_t) PHP_FNV164Final,
56
  php_hash_copy,
57
  php_hash_serialize,
58
  php_hash_unserialize,
59
  PHP_FNV164_SPEC,
60
  8,
61
  4,
62
  sizeof(PHP_FNV164_CTX),
63
  0
64
};
65
66
const php_hash_ops php_hash_fnv1a64_ops = {
67
  "fnv1a64",
68
  (php_hash_init_func_t) PHP_FNV164Init,
69
  (php_hash_update_func_t) PHP_FNV1a64Update,
70
  (php_hash_final_func_t) PHP_FNV164Final,
71
  php_hash_copy,
72
  php_hash_serialize,
73
  php_hash_unserialize,
74
  PHP_FNV164_SPEC,
75
  8,
76
  4,
77
  sizeof(PHP_FNV164_CTX),
78
  0
79
};
80
81
/* {{{ PHP_FNV132Init
82
 * 32-bit FNV-1 hash initialisation
83
 */
84
PHP_HASH_API void PHP_FNV132Init(PHP_FNV132_CTX *context, ZEND_ATTRIBUTE_UNUSED HashTable *args)
85
22
{
86
22
  context->state = PHP_FNV1_32_INIT;
87
22
}
88
/* }}} */
89
90
PHP_HASH_API void PHP_FNV132Update(PHP_FNV132_CTX *context, const unsigned char *input,
91
    size_t inputLen)
92
14
{
93
14
  context->state = fnv_32_buf((void *)input, inputLen, context->state, 0);
94
14
}
95
96
PHP_HASH_API void PHP_FNV1a32Update(PHP_FNV132_CTX *context, const unsigned char *input,
97
    size_t inputLen)
98
7
{
99
7
  context->state = fnv_32_buf((void *)input, inputLen, context->state, 1);
100
7
}
101
102
PHP_HASH_API void PHP_FNV132Final(unsigned char digest[4], PHP_FNV132_CTX * context)
103
21
{
104
#ifdef WORDS_BIGENDIAN
105
  memcpy(digest, &context->state, 4);
106
#else
107
21
  int i = 0;
108
21
  unsigned char *c = (unsigned char *) &context->state;
109
110
105
  for (i = 0; i < 4; i++) {
111
84
    digest[i] = c[3 - i];
112
84
  }
113
21
#endif
114
21
}
115
116
/* {{{ PHP_FNV164Init
117
 * 64-bit FNV-1 hash initialisation
118
 */
119
PHP_HASH_API void PHP_FNV164Init(PHP_FNV164_CTX *context, ZEND_ATTRIBUTE_UNUSED HashTable *args)
120
19
{
121
19
  context->state = PHP_FNV1_64_INIT;
122
19
}
123
/* }}} */
124
125
PHP_HASH_API void PHP_FNV164Update(PHP_FNV164_CTX *context, const unsigned char *input,
126
    size_t inputLen)
127
8
{
128
8
  context->state = fnv_64_buf((void *)input, inputLen, context->state, 0);
129
8
}
130
131
PHP_HASH_API void PHP_FNV1a64Update(PHP_FNV164_CTX *context, const unsigned char *input,
132
    size_t inputLen)
133
10
{
134
10
  context->state = fnv_64_buf((void *)input, inputLen, context->state, 1);
135
10
}
136
137
PHP_HASH_API void PHP_FNV164Final(unsigned char digest[8], PHP_FNV164_CTX * context)
138
18
{
139
#ifdef WORDS_BIGENDIAN
140
  memcpy(digest, &context->state, 8);
141
#else
142
18
  int i = 0;
143
18
  unsigned char *c = (unsigned char *) &context->state;
144
145
162
  for (i = 0; i < 8; i++) {
146
144
    digest[i] = c[7 - i];
147
144
  }
148
18
#endif
149
18
}
150
151
152
/*
153
 * fnv_32_buf - perform a 32 bit Fowler/Noll/Vo hash on a buffer
154
 *
155
 * input:
156
 *  buf - start of buffer to hash
157
 *  len - length of buffer in octets
158
 *  hval  - previous hash value or 0 if first call
159
 *  alternate - if > 0 use the alternate version
160
 *
161
 * returns:
162
 *  32-bit hash as a static hash type
163
 */
164
static uint32_t
165
fnv_32_buf(void *buf, size_t len, uint32_t hval, int alternate)
166
21
{
167
21
  unsigned char *bp = (unsigned char *)buf;   /* start of buffer */
168
21
  unsigned char *be = bp + len;    /* beyond end of buffer */
169
170
  /*
171
   * FNV-1 hash each octet in the buffer
172
   */
173
21
  if (alternate == 0) {
174
379k
    while (bp < be) {
175
      /* multiply by the 32 bit FNV magic prime mod 2^32 */
176
379k
      hval *= PHP_FNV_32_PRIME;
177
178
      /* xor the bottom with the current octet */
179
379k
      hval ^= (uint32_t)*bp++;
180
379k
    }
181
14
  } else {
182
1.23k
    while (bp < be) {
183
      /* xor the bottom with the current octet */
184
1.22k
      hval ^= (uint32_t)*bp++;
185
186
      /* multiply by the 32 bit FNV magic prime mod 2^32 */
187
1.22k
      hval *= PHP_FNV_32_PRIME;
188
1.22k
    }
189
7
  }
190
191
  /* return our new hash value */
192
21
  return hval;
193
21
}
194
195
/*
196
 * fnv_64_buf - perform a 64 bit Fowler/Noll/Vo hash on a buffer
197
 *
198
 * input:
199
 *  buf - start of buffer to hash
200
 *  len - length of buffer in octets
201
 *  hval  - previous hash value or 0 if first call
202
 *  alternate - if > 0 use the alternate version
203
 *
204
 * returns:
205
 *  64-bit hash as a static hash type
206
 */
207
static uint64_t
208
fnv_64_buf(void *buf, size_t len, uint64_t hval, int alternate)
209
18
{
210
18
  unsigned char *bp = (unsigned char *)buf;   /* start of buffer */
211
18
  unsigned char *be = bp + len;    /* beyond end of buffer */
212
213
  /*
214
   * FNV-1 hash each octet of the buffer
215
   */
216
217
18
  if (alternate == 0) {
218
344
    while (bp < be) {
219
      /* multiply by the 64 bit FNV magic prime mod 2^64 */
220
336
      hval *= PHP_FNV_64_PRIME;
221
222
      /* xor the bottom with the current octet */
223
336
      hval ^= (uint64_t)*bp++;
224
336
    }
225
10
   } else {
226
4.80k
    while (bp < be) {
227
      /* xor the bottom with the current octet */
228
4.79k
      hval ^= (uint64_t)*bp++;
229
230
      /* multiply by the 64 bit FNV magic prime mod 2^64 */
231
4.79k
      hval *= PHP_FNV_64_PRIME;
232
4.79k
     }
233
10
  }
234
235
  /* return our new hash value */
236
18
  return hval;
237
18
}