xref: /PHP-7.4/ext/hash/hash_fnv.c (revision 92ac598a)
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