Coverage Report

Created: 2026-06-02 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
};
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
0
{
86
0
  context->state = PHP_FNV1_32_INIT;
87
0
}
88
/* }}} */
89
90
PHP_HASH_API void PHP_FNV132Update(PHP_FNV132_CTX *context, const unsigned char *input,
91
    size_t inputLen)
92
0
{
93
0
  context->state = fnv_32_buf((void *)input, inputLen, context->state, 0);
94
0
}
95
96
PHP_HASH_API void PHP_FNV1a32Update(PHP_FNV132_CTX *context, const unsigned char *input,
97
    size_t inputLen)
98
0
{
99
0
  context->state = fnv_32_buf((void *)input, inputLen, context->state, 1);
100
0
}
101
102
PHP_HASH_API void PHP_FNV132Final(unsigned char digest[4], PHP_FNV132_CTX * context)
103
0
{
104
#ifdef WORDS_BIGENDIAN
105
  memcpy(digest, &context->state, 4);
106
#else
107
0
  int i = 0;
108
0
  unsigned char *c = (unsigned char *) &context->state;
109
110
0
  for (i = 0; i < 4; i++) {
111
0
    digest[i] = c[3 - i];
112
0
  }
113
0
#endif
114
0
}
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
0
{
121
0
  context->state = PHP_FNV1_64_INIT;
122
0
}
123
/* }}} */
124
125
PHP_HASH_API void PHP_FNV164Update(PHP_FNV164_CTX *context, const unsigned char *input,
126
    size_t inputLen)
127
0
{
128
0
  context->state = fnv_64_buf((void *)input, inputLen, context->state, 0);
129
0
}
130
131
PHP_HASH_API void PHP_FNV1a64Update(PHP_FNV164_CTX *context, const unsigned char *input,
132
    size_t inputLen)
133
0
{
134
0
  context->state = fnv_64_buf((void *)input, inputLen, context->state, 1);
135
0
}
136
137
PHP_HASH_API void PHP_FNV164Final(unsigned char digest[8], PHP_FNV164_CTX * context)
138
0
{
139
#ifdef WORDS_BIGENDIAN
140
  memcpy(digest, &context->state, 8);
141
#else
142
0
  int i = 0;
143
0
  unsigned char *c = (unsigned char *) &context->state;
144
145
0
  for (i = 0; i < 8; i++) {
146
0
    digest[i] = c[7 - i];
147
0
  }
148
0
#endif
149
0
}
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
0
{
167
0
  unsigned char *bp = (unsigned char *)buf;   /* start of buffer */
168
0
  unsigned char *be = bp + len;    /* beyond end of buffer */
169
170
  /*
171
   * FNV-1 hash each octet in the buffer
172
   */
173
0
  if (alternate == 0) {
174
0
    while (bp < be) {
175
      /* multiply by the 32 bit FNV magic prime mod 2^32 */
176
0
      hval *= PHP_FNV_32_PRIME;
177
178
      /* xor the bottom with the current octet */
179
0
      hval ^= (uint32_t)*bp++;
180
0
    }
181
0
  } else {
182
0
    while (bp < be) {
183
      /* xor the bottom with the current octet */
184
0
      hval ^= (uint32_t)*bp++;
185
186
      /* multiply by the 32 bit FNV magic prime mod 2^32 */
187
0
      hval *= PHP_FNV_32_PRIME;
188
0
    }
189
0
  }
190
191
  /* return our new hash value */
192
0
  return hval;
193
0
}
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
0
{
210
0
  unsigned char *bp = (unsigned char *)buf;   /* start of buffer */
211
0
  unsigned char *be = bp + len;    /* beyond end of buffer */
212
213
  /*
214
   * FNV-1 hash each octet of the buffer
215
   */
216
217
0
  if (alternate == 0) {
218
0
    while (bp < be) {
219
      /* multiply by the 64 bit FNV magic prime mod 2^64 */
220
0
      hval *= PHP_FNV_64_PRIME;
221
222
      /* xor the bottom with the current octet */
223
0
      hval ^= (uint64_t)*bp++;
224
0
    }
225
0
   } else {
226
0
    while (bp < be) {
227
      /* xor the bottom with the current octet */
228
0
      hval ^= (uint64_t)*bp++;
229
230
      /* multiply by the 64 bit FNV magic prime mod 2^64 */
231
0
      hval *= PHP_FNV_64_PRIME;
232
0
     }
233
0
  }
234
235
  /* return our new hash value */
236
0
  return hval;
237
0
}