Coverage Report

Created: 2026-07-25 06:39

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
  0
35
};
36
37
const php_hash_ops php_hash_fnv1a32_ops = {
38
  "fnv1a32",
39
  (php_hash_init_func_t) PHP_FNV132Init,
40
  (php_hash_update_func_t) PHP_FNV1a32Update,
41
  (php_hash_final_func_t) PHP_FNV132Final,
42
  php_hash_copy,
43
  php_hash_serialize,
44
  php_hash_unserialize,
45
  PHP_FNV132_SPEC,
46
  4,
47
  4,
48
  sizeof(PHP_FNV132_CTX),
49
  0,
50
  0
51
};
52
53
const php_hash_ops php_hash_fnv164_ops = {
54
  "fnv164",
55
  (php_hash_init_func_t) PHP_FNV164Init,
56
  (php_hash_update_func_t) PHP_FNV164Update,
57
  (php_hash_final_func_t) PHP_FNV164Final,
58
  php_hash_copy,
59
  php_hash_serialize,
60
  php_hash_unserialize,
61
  PHP_FNV164_SPEC,
62
  8,
63
  4,
64
  sizeof(PHP_FNV164_CTX),
65
  0,
66
  0
67
};
68
69
const php_hash_ops php_hash_fnv1a64_ops = {
70
  "fnv1a64",
71
  (php_hash_init_func_t) PHP_FNV164Init,
72
  (php_hash_update_func_t) PHP_FNV1a64Update,
73
  (php_hash_final_func_t) PHP_FNV164Final,
74
  php_hash_copy,
75
  php_hash_serialize,
76
  php_hash_unserialize,
77
  PHP_FNV164_SPEC,
78
  8,
79
  4,
80
  sizeof(PHP_FNV164_CTX),
81
  0,
82
  0
83
};
84
85
/* {{{ PHP_FNV132Init
86
 * 32-bit FNV-1 hash initialisation
87
 */
88
PHP_HASH_API void PHP_FNV132Init(PHP_FNV132_CTX *context, ZEND_ATTRIBUTE_UNUSED HashTable *args)
89
24
{
90
24
  context->state = PHP_FNV1_32_INIT;
91
24
}
92
/* }}} */
93
94
PHP_HASH_API void PHP_FNV132Update(PHP_FNV132_CTX *context, const unsigned char *input,
95
    size_t inputLen)
96
14
{
97
14
  context->state = fnv_32_buf((void *)input, inputLen, context->state, 0);
98
14
}
99
100
PHP_HASH_API void PHP_FNV1a32Update(PHP_FNV132_CTX *context, const unsigned char *input,
101
    size_t inputLen)
102
10
{
103
10
  context->state = fnv_32_buf((void *)input, inputLen, context->state, 1);
104
10
}
105
106
PHP_HASH_API void PHP_FNV132Final(unsigned char digest[4], PHP_FNV132_CTX * context)
107
24
{
108
#ifdef WORDS_BIGENDIAN
109
  memcpy(digest, &context->state, 4);
110
#else
111
24
  int i = 0;
112
24
  unsigned char *c = (unsigned char *) &context->state;
113
114
120
  for (i = 0; i < 4; i++) {
115
96
    digest[i] = c[3 - i];
116
96
  }
117
24
#endif
118
24
}
119
120
/* {{{ PHP_FNV164Init
121
 * 64-bit FNV-1 hash initialisation
122
 */
123
PHP_HASH_API void PHP_FNV164Init(PHP_FNV164_CTX *context, ZEND_ATTRIBUTE_UNUSED HashTable *args)
124
21
{
125
21
  context->state = PHP_FNV1_64_INIT;
126
21
}
127
/* }}} */
128
129
PHP_HASH_API void PHP_FNV164Update(PHP_FNV164_CTX *context, const unsigned char *input,
130
    size_t inputLen)
131
10
{
132
10
  context->state = fnv_64_buf((void *)input, inputLen, context->state, 0);
133
10
}
134
135
PHP_HASH_API void PHP_FNV1a64Update(PHP_FNV164_CTX *context, const unsigned char *input,
136
    size_t inputLen)
137
10
{
138
10
  context->state = fnv_64_buf((void *)input, inputLen, context->state, 1);
139
10
}
140
141
PHP_HASH_API void PHP_FNV164Final(unsigned char digest[8], PHP_FNV164_CTX * context)
142
20
{
143
#ifdef WORDS_BIGENDIAN
144
  memcpy(digest, &context->state, 8);
145
#else
146
20
  int i = 0;
147
20
  unsigned char *c = (unsigned char *) &context->state;
148
149
180
  for (i = 0; i < 8; i++) {
150
160
    digest[i] = c[7 - i];
151
160
  }
152
20
#endif
153
20
}
154
155
156
/*
157
 * fnv_32_buf - perform a 32 bit Fowler/Noll/Vo hash on a buffer
158
 *
159
 * input:
160
 *  buf - start of buffer to hash
161
 *  len - length of buffer in octets
162
 *  hval  - previous hash value or 0 if first call
163
 *  alternate - if > 0 use the alternate version
164
 *
165
 * returns:
166
 *  32-bit hash as a static hash type
167
 */
168
static uint32_t
169
fnv_32_buf(void *buf, size_t len, uint32_t hval, int alternate)
170
24
{
171
24
  unsigned char *bp = (unsigned char *)buf;   /* start of buffer */
172
24
  unsigned char *be = bp + len;    /* beyond end of buffer */
173
174
  /*
175
   * FNV-1 hash each octet in the buffer
176
   */
177
24
  if (alternate == 0) {
178
513k
    while (bp < be) {
179
      /* multiply by the 32 bit FNV magic prime mod 2^32 */
180
513k
      hval *= PHP_FNV_32_PRIME;
181
182
      /* xor the bottom with the current octet */
183
513k
      hval ^= (uint32_t)*bp++;
184
513k
    }
185
14
  } else {
186
1.49k
    while (bp < be) {
187
      /* xor the bottom with the current octet */
188
1.48k
      hval ^= (uint32_t)*bp++;
189
190
      /* multiply by the 32 bit FNV magic prime mod 2^32 */
191
1.48k
      hval *= PHP_FNV_32_PRIME;
192
1.48k
    }
193
10
  }
194
195
  /* return our new hash value */
196
24
  return hval;
197
24
}
198
199
/*
200
 * fnv_64_buf - perform a 64 bit Fowler/Noll/Vo hash on a buffer
201
 *
202
 * input:
203
 *  buf - start of buffer to hash
204
 *  len - length of buffer in octets
205
 *  hval  - previous hash value or 0 if first call
206
 *  alternate - if > 0 use the alternate version
207
 *
208
 * returns:
209
 *  64-bit hash as a static hash type
210
 */
211
static uint64_t
212
fnv_64_buf(void *buf, size_t len, uint64_t hval, int alternate)
213
20
{
214
20
  unsigned char *bp = (unsigned char *)buf;   /* start of buffer */
215
20
  unsigned char *be = bp + len;    /* beyond end of buffer */
216
217
  /*
218
   * FNV-1 hash each octet of the buffer
219
   */
220
221
20
  if (alternate == 0) {
222
728
    while (bp < be) {
223
      /* multiply by the 64 bit FNV magic prime mod 2^64 */
224
718
      hval *= PHP_FNV_64_PRIME;
225
226
      /* xor the bottom with the current octet */
227
718
      hval ^= (uint64_t)*bp++;
228
718
    }
229
10
   } else {
230
726
    while (bp < be) {
231
      /* xor the bottom with the current octet */
232
716
      hval ^= (uint64_t)*bp++;
233
234
      /* multiply by the 64 bit FNV magic prime mod 2^64 */
235
716
      hval *= PHP_FNV_64_PRIME;
236
716
     }
237
10
  }
238
239
  /* return our new hash value */
240
20
  return hval;
241
20
}