/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 | } |