1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 7 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Author: Michael Maclean <mgdm@php.net> |
16 +----------------------------------------------------------------------+
17 */
18
19 /* Based on the public domain algorithm found at
20 http://www.isthe.com/chongo/tech/comp/fnv/index.html */
21
22 #include "php_hash.h"
23 #include "php_hash_fnv.h"
24
25 const php_hash_ops php_hash_fnv132_ops = {
26 (php_hash_init_func_t) PHP_FNV132Init,
27 (php_hash_update_func_t) PHP_FNV132Update,
28 (php_hash_final_func_t) PHP_FNV132Final,
29 (php_hash_copy_func_t) php_hash_copy,
30 4,
31 4,
32 sizeof(PHP_FNV132_CTX),
33 0
34 };
35
36 const php_hash_ops php_hash_fnv1a32_ops = {
37 (php_hash_init_func_t) PHP_FNV132Init,
38 (php_hash_update_func_t) PHP_FNV1a32Update,
39 (php_hash_final_func_t) PHP_FNV132Final,
40 (php_hash_copy_func_t) php_hash_copy,
41 4,
42 4,
43 sizeof(PHP_FNV132_CTX),
44 0
45 };
46
47 const php_hash_ops php_hash_fnv164_ops = {
48 (php_hash_init_func_t) PHP_FNV164Init,
49 (php_hash_update_func_t) PHP_FNV164Update,
50 (php_hash_final_func_t) PHP_FNV164Final,
51 (php_hash_copy_func_t) php_hash_copy,
52 8,
53 4,
54 sizeof(PHP_FNV164_CTX),
55 0
56 };
57
58 const php_hash_ops php_hash_fnv1a64_ops = {
59 (php_hash_init_func_t) PHP_FNV164Init,
60 (php_hash_update_func_t) PHP_FNV1a64Update,
61 (php_hash_final_func_t) PHP_FNV164Final,
62 (php_hash_copy_func_t) php_hash_copy,
63 8,
64 4,
65 sizeof(PHP_FNV164_CTX),
66 0
67 };
68
69 /* {{{ PHP_FNV132Init
70 * 32-bit FNV-1 hash initialisation
71 */
PHP_FNV132Init(PHP_FNV132_CTX * context)72 PHP_HASH_API void PHP_FNV132Init(PHP_FNV132_CTX *context)
73 {
74 context->state = PHP_FNV1_32_INIT;
75 }
76 /* }}} */
77
PHP_FNV132Update(PHP_FNV132_CTX * context,const unsigned char * input,size_t inputLen)78 PHP_HASH_API void PHP_FNV132Update(PHP_FNV132_CTX *context, const unsigned char *input,
79 size_t inputLen)
80 {
81 context->state = fnv_32_buf((void *)input, inputLen, context->state, 0);
82 }
83
PHP_FNV1a32Update(PHP_FNV132_CTX * context,const unsigned char * input,size_t inputLen)84 PHP_HASH_API void PHP_FNV1a32Update(PHP_FNV132_CTX *context, const unsigned char *input,
85 size_t inputLen)
86 {
87 context->state = fnv_32_buf((void *)input, inputLen, context->state, 1);
88 }
89
PHP_FNV132Final(unsigned char digest[4],PHP_FNV132_CTX * context)90 PHP_HASH_API void PHP_FNV132Final(unsigned char digest[4], PHP_FNV132_CTX * context)
91 {
92 #ifdef WORDS_BIGENDIAN
93 memcpy(digest, &context->state, 4);
94 #else
95 int i = 0;
96 unsigned char *c = (unsigned char *) &context->state;
97
98 for (i = 0; i < 4; i++) {
99 digest[i] = c[3 - i];
100 }
101 #endif
102 }
103
104 /* {{{ PHP_FNV164Init
105 * 64-bit FNV-1 hash initialisation
106 */
PHP_FNV164Init(PHP_FNV164_CTX * context)107 PHP_HASH_API void PHP_FNV164Init(PHP_FNV164_CTX *context)
108 {
109 context->state = PHP_FNV1_64_INIT;
110 }
111 /* }}} */
112
PHP_FNV164Update(PHP_FNV164_CTX * context,const unsigned char * input,size_t inputLen)113 PHP_HASH_API void PHP_FNV164Update(PHP_FNV164_CTX *context, const unsigned char *input,
114 size_t inputLen)
115 {
116 context->state = fnv_64_buf((void *)input, inputLen, context->state, 0);
117 }
118
PHP_FNV1a64Update(PHP_FNV164_CTX * context,const unsigned char * input,size_t inputLen)119 PHP_HASH_API void PHP_FNV1a64Update(PHP_FNV164_CTX *context, const unsigned char *input,
120 size_t inputLen)
121 {
122 context->state = fnv_64_buf((void *)input, inputLen, context->state, 1);
123 }
124
PHP_FNV164Final(unsigned char digest[8],PHP_FNV164_CTX * context)125 PHP_HASH_API void PHP_FNV164Final(unsigned char digest[8], PHP_FNV164_CTX * context)
126 {
127 #ifdef WORDS_BIGENDIAN
128 memcpy(digest, &context->state, 8);
129 #else
130 int i = 0;
131 unsigned char *c = (unsigned char *) &context->state;
132
133 for (i = 0; i < 8; i++) {
134 digest[i] = c[7 - i];
135 }
136 #endif
137 }
138
139
140 /*
141 * fnv_32_buf - perform a 32 bit Fowler/Noll/Vo hash on a buffer
142 *
143 * input:
144 * buf - start of buffer to hash
145 * len - length of buffer in octets
146 * hval - previous hash value or 0 if first call
147 * alternate - if > 0 use the alternate version
148 *
149 * returns:
150 * 32 bit hash as a static hash type
151 */
152 static uint32_t
fnv_32_buf(void * buf,size_t len,uint32_t hval,int alternate)153 fnv_32_buf(void *buf, size_t len, uint32_t hval, int alternate)
154 {
155 unsigned char *bp = (unsigned char *)buf; /* start of buffer */
156 unsigned char *be = bp + len; /* beyond end of buffer */
157
158 /*
159 * FNV-1 hash each octet in the buffer
160 */
161 if (alternate == 0) {
162 while (bp < be) {
163 /* multiply by the 32 bit FNV magic prime mod 2^32 */
164 hval *= PHP_FNV_32_PRIME;
165
166 /* xor the bottom with the current octet */
167 hval ^= (uint32_t)*bp++;
168 }
169 } else {
170 while (bp < be) {
171 /* xor the bottom with the current octet */
172 hval ^= (uint32_t)*bp++;
173
174 /* multiply by the 32 bit FNV magic prime mod 2^32 */
175 hval *= PHP_FNV_32_PRIME;
176 }
177 }
178
179 /* return our new hash value */
180 return hval;
181 }
182
183 /*
184 * fnv_64_buf - perform a 64 bit Fowler/Noll/Vo hash on a buffer
185 *
186 * input:
187 * buf - start of buffer to hash
188 * len - length of buffer in octets
189 * hval - previous hash value or 0 if first call
190 * alternate - if > 0 use the alternate version
191 *
192 * returns:
193 * 64 bit hash as a static hash type
194 */
195 static uint64_t
fnv_64_buf(void * buf,size_t len,uint64_t hval,int alternate)196 fnv_64_buf(void *buf, size_t len, uint64_t hval, int alternate)
197 {
198 unsigned char *bp = (unsigned char *)buf; /* start of buffer */
199 unsigned char *be = bp + len; /* beyond end of buffer */
200
201 /*
202 * FNV-1 hash each octet of the buffer
203 */
204
205 if (alternate == 0) {
206 while (bp < be) {
207 /* multiply by the 64 bit FNV magic prime mod 2^64 */
208 hval *= PHP_FNV_64_PRIME;
209
210 /* xor the bottom with the current octet */
211 hval ^= (uint64_t)*bp++;
212 }
213 } else {
214 while (bp < be) {
215 /* xor the bottom with the current octet */
216 hval ^= (uint64_t)*bp++;
217
218 /* multiply by the 64 bit FNV magic prime mod 2^64 */
219 hval *= PHP_FNV_64_PRIME;
220 }
221 }
222
223 /* return our new hash value */
224 return hval;
225 }
226