Coverage Report

Created: 2025-06-13 06:43

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