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