xref: /minix3/external/bsd/bind/dist/lib/isc/hash.c (revision 00b67f09dd46474d133c95011a48590a8e8f94c7)
1*00b67f09SDavid van Moolenbroek /*	$NetBSD: hash.c,v 1.9 2015/07/08 17:28:59 christos Exp $	*/
2*00b67f09SDavid van Moolenbroek 
3*00b67f09SDavid van Moolenbroek /*
4*00b67f09SDavid van Moolenbroek  * Copyright (C) 2004-2007, 2009, 2013-2015  Internet Systems Consortium, Inc. ("ISC")
5*00b67f09SDavid van Moolenbroek  * Copyright (C) 2003  Internet Software Consortium.
6*00b67f09SDavid van Moolenbroek  *
7*00b67f09SDavid van Moolenbroek  * Permission to use, copy, modify, and/or distribute this software for any
8*00b67f09SDavid van Moolenbroek  * purpose with or without fee is hereby granted, provided that the above
9*00b67f09SDavid van Moolenbroek  * copyright notice and this permission notice appear in all copies.
10*00b67f09SDavid van Moolenbroek  *
11*00b67f09SDavid van Moolenbroek  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12*00b67f09SDavid van Moolenbroek  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13*00b67f09SDavid van Moolenbroek  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14*00b67f09SDavid van Moolenbroek  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15*00b67f09SDavid van Moolenbroek  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16*00b67f09SDavid van Moolenbroek  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17*00b67f09SDavid van Moolenbroek  * PERFORMANCE OF THIS SOFTWARE.
18*00b67f09SDavid van Moolenbroek  */
19*00b67f09SDavid van Moolenbroek 
20*00b67f09SDavid van Moolenbroek /* Id: hash.c,v 1.16 2009/09/01 00:22:28 jinmei Exp  */
21*00b67f09SDavid van Moolenbroek 
22*00b67f09SDavid van Moolenbroek /*! \file
23*00b67f09SDavid van Moolenbroek  * Some portion of this code was derived from universal hash function
24*00b67f09SDavid van Moolenbroek  * libraries of Rice University.
25*00b67f09SDavid van Moolenbroek \section license UH Universal Hashing Library
26*00b67f09SDavid van Moolenbroek 
27*00b67f09SDavid van Moolenbroek Copyright ((c)) 2002, Rice University
28*00b67f09SDavid van Moolenbroek All rights reserved.
29*00b67f09SDavid van Moolenbroek 
30*00b67f09SDavid van Moolenbroek Redistribution and use in source and binary forms, with or without
31*00b67f09SDavid van Moolenbroek modification, are permitted provided that the following conditions are
32*00b67f09SDavid van Moolenbroek met:
33*00b67f09SDavid van Moolenbroek 
34*00b67f09SDavid van Moolenbroek     * Redistributions of source code must retain the above copyright
35*00b67f09SDavid van Moolenbroek     notice, this list of conditions and the following disclaimer.
36*00b67f09SDavid van Moolenbroek 
37*00b67f09SDavid van Moolenbroek     * Redistributions in binary form must reproduce the above
38*00b67f09SDavid van Moolenbroek     copyright notice, this list of conditions and the following
39*00b67f09SDavid van Moolenbroek     disclaimer in the documentation and/or other materials provided
40*00b67f09SDavid van Moolenbroek     with the distribution.
41*00b67f09SDavid van Moolenbroek 
42*00b67f09SDavid van Moolenbroek     * Neither the name of Rice University (RICE) nor the names of its
43*00b67f09SDavid van Moolenbroek     contributors may be used to endorse or promote products derived
44*00b67f09SDavid van Moolenbroek     from this software without specific prior written permission.
45*00b67f09SDavid van Moolenbroek 
46*00b67f09SDavid van Moolenbroek 
47*00b67f09SDavid van Moolenbroek This software is provided by RICE and the contributors on an "as is"
48*00b67f09SDavid van Moolenbroek basis, without any representations or warranties of any kind, express
49*00b67f09SDavid van Moolenbroek or implied including, but not limited to, representations or
50*00b67f09SDavid van Moolenbroek warranties of non-infringement, merchantability or fitness for a
51*00b67f09SDavid van Moolenbroek particular purpose. In no event shall RICE or contributors be liable
52*00b67f09SDavid van Moolenbroek for any direct, indirect, incidental, special, exemplary, or
53*00b67f09SDavid van Moolenbroek consequential damages (including, but not limited to, procurement of
54*00b67f09SDavid van Moolenbroek substitute goods or services; loss of use, data, or profits; or
55*00b67f09SDavid van Moolenbroek business interruption) however caused and on any theory of liability,
56*00b67f09SDavid van Moolenbroek whether in contract, strict liability, or tort (including negligence
57*00b67f09SDavid van Moolenbroek or otherwise) arising in any way out of the use of this software, even
58*00b67f09SDavid van Moolenbroek if advised of the possibility of such damage.
59*00b67f09SDavid van Moolenbroek */
60*00b67f09SDavid van Moolenbroek 
61*00b67f09SDavid van Moolenbroek #include <config.h>
62*00b67f09SDavid van Moolenbroek 
63*00b67f09SDavid van Moolenbroek #include <isc/entropy.h>
64*00b67f09SDavid van Moolenbroek #include <isc/hash.h>
65*00b67f09SDavid van Moolenbroek #include <isc/mem.h>
66*00b67f09SDavid van Moolenbroek #include <isc/magic.h>
67*00b67f09SDavid van Moolenbroek #include <isc/mutex.h>
68*00b67f09SDavid van Moolenbroek #include <isc/once.h>
69*00b67f09SDavid van Moolenbroek #include <isc/random.h>
70*00b67f09SDavid van Moolenbroek #include <isc/refcount.h>
71*00b67f09SDavid van Moolenbroek #include <isc/string.h>
72*00b67f09SDavid van Moolenbroek #include <isc/util.h>
73*00b67f09SDavid van Moolenbroek 
74*00b67f09SDavid van Moolenbroek #define HASH_MAGIC		ISC_MAGIC('H', 'a', 's', 'h')
75*00b67f09SDavid van Moolenbroek #define VALID_HASH(h)		ISC_MAGIC_VALID((h), HASH_MAGIC)
76*00b67f09SDavid van Moolenbroek 
77*00b67f09SDavid van Moolenbroek /*%
78*00b67f09SDavid van Moolenbroek  * A large 32-bit prime number that specifies the range of the hash output.
79*00b67f09SDavid van Moolenbroek  */
80*00b67f09SDavid van Moolenbroek #define PRIME32 0xFFFFFFFB              /* 2^32 -  5 */
81*00b67f09SDavid van Moolenbroek 
82*00b67f09SDavid van Moolenbroek /*@{*/
83*00b67f09SDavid van Moolenbroek /*%
84*00b67f09SDavid van Moolenbroek  * Types of random seed and hash accumulator.  Perhaps they can be system
85*00b67f09SDavid van Moolenbroek  * dependent.
86*00b67f09SDavid van Moolenbroek  */
87*00b67f09SDavid van Moolenbroek typedef isc_uint32_t hash_accum_t;
88*00b67f09SDavid van Moolenbroek typedef isc_uint16_t hash_random_t;
89*00b67f09SDavid van Moolenbroek /*@}*/
90*00b67f09SDavid van Moolenbroek 
91*00b67f09SDavid van Moolenbroek /*% isc hash structure */
92*00b67f09SDavid van Moolenbroek struct isc_hash {
93*00b67f09SDavid van Moolenbroek 	unsigned int	magic;
94*00b67f09SDavid van Moolenbroek 	isc_mem_t	*mctx;
95*00b67f09SDavid van Moolenbroek 	isc_mutex_t	lock;
96*00b67f09SDavid van Moolenbroek 	isc_boolean_t	initialized;
97*00b67f09SDavid van Moolenbroek 	isc_refcount_t	refcnt;
98*00b67f09SDavid van Moolenbroek 	isc_entropy_t	*entropy; /*%< entropy source */
99*00b67f09SDavid van Moolenbroek 	size_t		limit;	/*%< upper limit of key length */
100*00b67f09SDavid van Moolenbroek 	size_t		vectorlen; /*%< size of the vector below */
101*00b67f09SDavid van Moolenbroek 	hash_random_t	*rndvector; /*%< random vector for universal hashing */
102*00b67f09SDavid van Moolenbroek };
103*00b67f09SDavid van Moolenbroek 
104*00b67f09SDavid van Moolenbroek static isc_mutex_t createlock;
105*00b67f09SDavid van Moolenbroek static isc_once_t once = ISC_ONCE_INIT;
106*00b67f09SDavid van Moolenbroek static isc_hash_t *hash = NULL;
107*00b67f09SDavid van Moolenbroek 
108*00b67f09SDavid van Moolenbroek static unsigned char maptolower[] = {
109*00b67f09SDavid van Moolenbroek 	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
110*00b67f09SDavid van Moolenbroek 	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
111*00b67f09SDavid van Moolenbroek 	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
112*00b67f09SDavid van Moolenbroek 	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
113*00b67f09SDavid van Moolenbroek 	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
114*00b67f09SDavid van Moolenbroek 	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
115*00b67f09SDavid van Moolenbroek 	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
116*00b67f09SDavid van Moolenbroek 	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
117*00b67f09SDavid van Moolenbroek 	0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
118*00b67f09SDavid van Moolenbroek 	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
119*00b67f09SDavid van Moolenbroek 	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
120*00b67f09SDavid van Moolenbroek 	0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
121*00b67f09SDavid van Moolenbroek 	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
122*00b67f09SDavid van Moolenbroek 	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
123*00b67f09SDavid van Moolenbroek 	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
124*00b67f09SDavid van Moolenbroek 	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
125*00b67f09SDavid van Moolenbroek 	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
126*00b67f09SDavid van Moolenbroek 	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
127*00b67f09SDavid van Moolenbroek 	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
128*00b67f09SDavid van Moolenbroek 	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
129*00b67f09SDavid van Moolenbroek 	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
130*00b67f09SDavid van Moolenbroek 	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
131*00b67f09SDavid van Moolenbroek 	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
132*00b67f09SDavid van Moolenbroek 	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
133*00b67f09SDavid van Moolenbroek 	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
134*00b67f09SDavid van Moolenbroek 	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
135*00b67f09SDavid van Moolenbroek 	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
136*00b67f09SDavid van Moolenbroek 	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
137*00b67f09SDavid van Moolenbroek 	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
138*00b67f09SDavid van Moolenbroek 	0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
139*00b67f09SDavid van Moolenbroek 	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
140*00b67f09SDavid van Moolenbroek 	0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
141*00b67f09SDavid van Moolenbroek };
142*00b67f09SDavid van Moolenbroek 
143*00b67f09SDavid van Moolenbroek isc_result_t
isc_hash_ctxcreate(isc_mem_t * mctx,isc_entropy_t * entropy,size_t limit,isc_hash_t ** hctxp)144*00b67f09SDavid van Moolenbroek isc_hash_ctxcreate(isc_mem_t *mctx, isc_entropy_t *entropy,
145*00b67f09SDavid van Moolenbroek 		   size_t limit, isc_hash_t **hctxp)
146*00b67f09SDavid van Moolenbroek {
147*00b67f09SDavid van Moolenbroek 	isc_result_t result;
148*00b67f09SDavid van Moolenbroek 	isc_hash_t *hctx;
149*00b67f09SDavid van Moolenbroek 	size_t vlen;
150*00b67f09SDavid van Moolenbroek 	hash_random_t *rv;
151*00b67f09SDavid van Moolenbroek 	hash_accum_t overflow_limit;
152*00b67f09SDavid van Moolenbroek 
153*00b67f09SDavid van Moolenbroek 	REQUIRE(mctx != NULL);
154*00b67f09SDavid van Moolenbroek 	REQUIRE(hctxp != NULL && *hctxp == NULL);
155*00b67f09SDavid van Moolenbroek 
156*00b67f09SDavid van Moolenbroek 	/*
157*00b67f09SDavid van Moolenbroek 	 * Overflow check.  Since our implementation only does a modulo
158*00b67f09SDavid van Moolenbroek 	 * operation at the last stage of hash calculation, the accumulator
159*00b67f09SDavid van Moolenbroek 	 * must not overflow.
160*00b67f09SDavid van Moolenbroek 	 */
161*00b67f09SDavid van Moolenbroek 	overflow_limit =
162*00b67f09SDavid van Moolenbroek 		1 << (((sizeof(hash_accum_t) - sizeof(hash_random_t))) * 8);
163*00b67f09SDavid van Moolenbroek 	if (overflow_limit < (limit + 1) * 0xff)
164*00b67f09SDavid van Moolenbroek 		return (ISC_R_RANGE);
165*00b67f09SDavid van Moolenbroek 
166*00b67f09SDavid van Moolenbroek 	hctx = isc_mem_get(mctx, sizeof(isc_hash_t));
167*00b67f09SDavid van Moolenbroek 	if (hctx == NULL)
168*00b67f09SDavid van Moolenbroek 		return (ISC_R_NOMEMORY);
169*00b67f09SDavid van Moolenbroek 
170*00b67f09SDavid van Moolenbroek 	vlen = sizeof(hash_random_t) * (limit + 1);
171*00b67f09SDavid van Moolenbroek 	rv = isc_mem_get(mctx, vlen);
172*00b67f09SDavid van Moolenbroek 	if (rv == NULL) {
173*00b67f09SDavid van Moolenbroek 		result = ISC_R_NOMEMORY;
174*00b67f09SDavid van Moolenbroek 		goto errout;
175*00b67f09SDavid van Moolenbroek 	}
176*00b67f09SDavid van Moolenbroek 
177*00b67f09SDavid van Moolenbroek 	/*
178*00b67f09SDavid van Moolenbroek 	 * We need a lock.
179*00b67f09SDavid van Moolenbroek 	 */
180*00b67f09SDavid van Moolenbroek 	result = isc_mutex_init(&hctx->lock);
181*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
182*00b67f09SDavid van Moolenbroek 		goto errout;
183*00b67f09SDavid van Moolenbroek 
184*00b67f09SDavid van Moolenbroek 	/*
185*00b67f09SDavid van Moolenbroek 	 * From here down, no failures will/can occur.
186*00b67f09SDavid van Moolenbroek 	 */
187*00b67f09SDavid van Moolenbroek 	hctx->magic = HASH_MAGIC;
188*00b67f09SDavid van Moolenbroek 	hctx->mctx = NULL;
189*00b67f09SDavid van Moolenbroek 	isc_mem_attach(mctx, &hctx->mctx);
190*00b67f09SDavid van Moolenbroek 	hctx->initialized = ISC_FALSE;
191*00b67f09SDavid van Moolenbroek 	result = isc_refcount_init(&hctx->refcnt, 1);
192*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
193*00b67f09SDavid van Moolenbroek 		goto cleanup_lock;
194*00b67f09SDavid van Moolenbroek 	hctx->entropy = NULL;
195*00b67f09SDavid van Moolenbroek 	hctx->limit = limit;
196*00b67f09SDavid van Moolenbroek 	hctx->vectorlen = vlen;
197*00b67f09SDavid van Moolenbroek 	hctx->rndvector = rv;
198*00b67f09SDavid van Moolenbroek 
199*00b67f09SDavid van Moolenbroek 	if (entropy != NULL)
200*00b67f09SDavid van Moolenbroek 		isc_entropy_attach(entropy, &hctx->entropy);
201*00b67f09SDavid van Moolenbroek 
202*00b67f09SDavid van Moolenbroek 	*hctxp = hctx;
203*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
204*00b67f09SDavid van Moolenbroek 
205*00b67f09SDavid van Moolenbroek  cleanup_lock:
206*00b67f09SDavid van Moolenbroek 	DESTROYLOCK(&hctx->lock);
207*00b67f09SDavid van Moolenbroek  errout:
208*00b67f09SDavid van Moolenbroek 	isc_mem_put(mctx, hctx, sizeof(isc_hash_t));
209*00b67f09SDavid van Moolenbroek 	if (rv != NULL)
210*00b67f09SDavid van Moolenbroek 		isc_mem_put(mctx, rv, vlen);
211*00b67f09SDavid van Moolenbroek 
212*00b67f09SDavid van Moolenbroek 	return (result);
213*00b67f09SDavid van Moolenbroek }
214*00b67f09SDavid van Moolenbroek 
215*00b67f09SDavid van Moolenbroek static void
initialize_lock(void)216*00b67f09SDavid van Moolenbroek initialize_lock(void) {
217*00b67f09SDavid van Moolenbroek 	RUNTIME_CHECK(isc_mutex_init(&createlock) == ISC_R_SUCCESS);
218*00b67f09SDavid van Moolenbroek }
219*00b67f09SDavid van Moolenbroek 
220*00b67f09SDavid van Moolenbroek isc_result_t
isc_hash_create(isc_mem_t * mctx,isc_entropy_t * entropy,size_t limit)221*00b67f09SDavid van Moolenbroek isc_hash_create(isc_mem_t *mctx, isc_entropy_t *entropy, size_t limit) {
222*00b67f09SDavid van Moolenbroek 	isc_result_t result = ISC_R_SUCCESS;
223*00b67f09SDavid van Moolenbroek 
224*00b67f09SDavid van Moolenbroek 	REQUIRE(mctx != NULL);
225*00b67f09SDavid van Moolenbroek 	INSIST(hash == NULL);
226*00b67f09SDavid van Moolenbroek 
227*00b67f09SDavid van Moolenbroek 	RUNTIME_CHECK(isc_once_do(&once, initialize_lock) == ISC_R_SUCCESS);
228*00b67f09SDavid van Moolenbroek 
229*00b67f09SDavid van Moolenbroek 	LOCK(&createlock);
230*00b67f09SDavid van Moolenbroek 
231*00b67f09SDavid van Moolenbroek 	if (hash == NULL)
232*00b67f09SDavid van Moolenbroek 		result = isc_hash_ctxcreate(mctx, entropy, limit, &hash);
233*00b67f09SDavid van Moolenbroek 
234*00b67f09SDavid van Moolenbroek 	UNLOCK(&createlock);
235*00b67f09SDavid van Moolenbroek 
236*00b67f09SDavid van Moolenbroek 	return (result);
237*00b67f09SDavid van Moolenbroek }
238*00b67f09SDavid van Moolenbroek 
239*00b67f09SDavid van Moolenbroek void
isc_hash_ctxinit(isc_hash_t * hctx)240*00b67f09SDavid van Moolenbroek isc_hash_ctxinit(isc_hash_t *hctx) {
241*00b67f09SDavid van Moolenbroek 	LOCK(&hctx->lock);
242*00b67f09SDavid van Moolenbroek 
243*00b67f09SDavid van Moolenbroek 	if (hctx->initialized == ISC_TRUE)
244*00b67f09SDavid van Moolenbroek 		goto out;
245*00b67f09SDavid van Moolenbroek 
246*00b67f09SDavid van Moolenbroek 	if (hctx->entropy != NULL) {
247*00b67f09SDavid van Moolenbroek 		isc_result_t result;
248*00b67f09SDavid van Moolenbroek 
249*00b67f09SDavid van Moolenbroek 		result = isc_entropy_getdata(hctx->entropy,
250*00b67f09SDavid van Moolenbroek 					     hctx->rndvector,
251*00b67f09SDavid van Moolenbroek 					     (unsigned int)hctx->vectorlen,
252*00b67f09SDavid van Moolenbroek 					     NULL, 0);
253*00b67f09SDavid van Moolenbroek 		INSIST(result == ISC_R_SUCCESS);
254*00b67f09SDavid van Moolenbroek 	} else {
255*00b67f09SDavid van Moolenbroek 		isc_uint32_t pr;
256*00b67f09SDavid van Moolenbroek 		size_t i, copylen;
257*00b67f09SDavid van Moolenbroek 		unsigned char *p;
258*00b67f09SDavid van Moolenbroek 
259*00b67f09SDavid van Moolenbroek 		p = (unsigned char *)hctx->rndvector;
260*00b67f09SDavid van Moolenbroek 		for (i = 0; i < hctx->vectorlen; i += copylen, p += copylen) {
261*00b67f09SDavid van Moolenbroek 			isc_random_get(&pr);
262*00b67f09SDavid van Moolenbroek 			if (i + sizeof(pr) <= hctx->vectorlen)
263*00b67f09SDavid van Moolenbroek 				copylen = sizeof(pr);
264*00b67f09SDavid van Moolenbroek 			else
265*00b67f09SDavid van Moolenbroek 				copylen = hctx->vectorlen - i;
266*00b67f09SDavid van Moolenbroek 
267*00b67f09SDavid van Moolenbroek 			memmove(p, &pr, copylen);
268*00b67f09SDavid van Moolenbroek 		}
269*00b67f09SDavid van Moolenbroek 		INSIST(p == (unsigned char *)hctx->rndvector +
270*00b67f09SDavid van Moolenbroek 		       hctx->vectorlen);
271*00b67f09SDavid van Moolenbroek 	}
272*00b67f09SDavid van Moolenbroek 
273*00b67f09SDavid van Moolenbroek 	hctx->initialized = ISC_TRUE;
274*00b67f09SDavid van Moolenbroek 
275*00b67f09SDavid van Moolenbroek  out:
276*00b67f09SDavid van Moolenbroek 	UNLOCK(&hctx->lock);
277*00b67f09SDavid van Moolenbroek }
278*00b67f09SDavid van Moolenbroek 
279*00b67f09SDavid van Moolenbroek void
isc_hash_init(void)280*00b67f09SDavid van Moolenbroek isc_hash_init(void) {
281*00b67f09SDavid van Moolenbroek 	INSIST(hash != NULL && VALID_HASH(hash));
282*00b67f09SDavid van Moolenbroek 
283*00b67f09SDavid van Moolenbroek 	isc_hash_ctxinit(hash);
284*00b67f09SDavid van Moolenbroek }
285*00b67f09SDavid van Moolenbroek 
286*00b67f09SDavid van Moolenbroek void
isc_hash_ctxattach(isc_hash_t * hctx,isc_hash_t ** hctxp)287*00b67f09SDavid van Moolenbroek isc_hash_ctxattach(isc_hash_t *hctx, isc_hash_t **hctxp) {
288*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_HASH(hctx));
289*00b67f09SDavid van Moolenbroek 	REQUIRE(hctxp != NULL && *hctxp == NULL);
290*00b67f09SDavid van Moolenbroek 
291*00b67f09SDavid van Moolenbroek 	isc_refcount_increment(&hctx->refcnt, NULL);
292*00b67f09SDavid van Moolenbroek 	*hctxp = hctx;
293*00b67f09SDavid van Moolenbroek }
294*00b67f09SDavid van Moolenbroek 
295*00b67f09SDavid van Moolenbroek static void
destroy(isc_hash_t ** hctxp)296*00b67f09SDavid van Moolenbroek destroy(isc_hash_t **hctxp) {
297*00b67f09SDavid van Moolenbroek 	isc_hash_t *hctx;
298*00b67f09SDavid van Moolenbroek 	isc_mem_t *mctx;
299*00b67f09SDavid van Moolenbroek 
300*00b67f09SDavid van Moolenbroek 	REQUIRE(hctxp != NULL && *hctxp != NULL);
301*00b67f09SDavid van Moolenbroek 	hctx = *hctxp;
302*00b67f09SDavid van Moolenbroek 	*hctxp = NULL;
303*00b67f09SDavid van Moolenbroek 
304*00b67f09SDavid van Moolenbroek 	LOCK(&hctx->lock);
305*00b67f09SDavid van Moolenbroek 
306*00b67f09SDavid van Moolenbroek 	isc_refcount_destroy(&hctx->refcnt);
307*00b67f09SDavid van Moolenbroek 
308*00b67f09SDavid van Moolenbroek 	mctx = hctx->mctx;
309*00b67f09SDavid van Moolenbroek 	if (hctx->entropy != NULL)
310*00b67f09SDavid van Moolenbroek 		isc_entropy_detach(&hctx->entropy);
311*00b67f09SDavid van Moolenbroek 	if (hctx->rndvector != NULL)
312*00b67f09SDavid van Moolenbroek 		isc_mem_put(mctx, hctx->rndvector, hctx->vectorlen);
313*00b67f09SDavid van Moolenbroek 
314*00b67f09SDavid van Moolenbroek 	UNLOCK(&hctx->lock);
315*00b67f09SDavid van Moolenbroek 
316*00b67f09SDavid van Moolenbroek 	DESTROYLOCK(&hctx->lock);
317*00b67f09SDavid van Moolenbroek 
318*00b67f09SDavid van Moolenbroek 	memset(hctx, 0, sizeof(isc_hash_t));
319*00b67f09SDavid van Moolenbroek 	isc_mem_put(mctx, hctx, sizeof(isc_hash_t));
320*00b67f09SDavid van Moolenbroek 	isc_mem_detach(&mctx);
321*00b67f09SDavid van Moolenbroek }
322*00b67f09SDavid van Moolenbroek 
323*00b67f09SDavid van Moolenbroek void
isc_hash_ctxdetach(isc_hash_t ** hctxp)324*00b67f09SDavid van Moolenbroek isc_hash_ctxdetach(isc_hash_t **hctxp) {
325*00b67f09SDavid van Moolenbroek 	isc_hash_t *hctx;
326*00b67f09SDavid van Moolenbroek 	unsigned int refs;
327*00b67f09SDavid van Moolenbroek 
328*00b67f09SDavid van Moolenbroek 	REQUIRE(hctxp != NULL && VALID_HASH(*hctxp));
329*00b67f09SDavid van Moolenbroek 	hctx = *hctxp;
330*00b67f09SDavid van Moolenbroek 
331*00b67f09SDavid van Moolenbroek 	isc_refcount_decrement(&hctx->refcnt, &refs);
332*00b67f09SDavid van Moolenbroek 	if (refs == 0)
333*00b67f09SDavid van Moolenbroek 		destroy(&hctx);
334*00b67f09SDavid van Moolenbroek 
335*00b67f09SDavid van Moolenbroek 	*hctxp = NULL;
336*00b67f09SDavid van Moolenbroek }
337*00b67f09SDavid van Moolenbroek 
338*00b67f09SDavid van Moolenbroek void
isc_hash_destroy(void)339*00b67f09SDavid van Moolenbroek isc_hash_destroy(void) {
340*00b67f09SDavid van Moolenbroek 	unsigned int refs;
341*00b67f09SDavid van Moolenbroek 
342*00b67f09SDavid van Moolenbroek 	INSIST(hash != NULL && VALID_HASH(hash));
343*00b67f09SDavid van Moolenbroek 
344*00b67f09SDavid van Moolenbroek 	isc_refcount_decrement(&hash->refcnt, &refs);
345*00b67f09SDavid van Moolenbroek 	INSIST(refs == 0);
346*00b67f09SDavid van Moolenbroek 
347*00b67f09SDavid van Moolenbroek 	destroy(&hash);
348*00b67f09SDavid van Moolenbroek }
349*00b67f09SDavid van Moolenbroek 
350*00b67f09SDavid van Moolenbroek static inline unsigned int
hash_calc(isc_hash_t * hctx,const unsigned char * key,unsigned int keylen,isc_boolean_t case_sensitive)351*00b67f09SDavid van Moolenbroek hash_calc(isc_hash_t *hctx, const unsigned char *key, unsigned int keylen,
352*00b67f09SDavid van Moolenbroek 	  isc_boolean_t case_sensitive)
353*00b67f09SDavid van Moolenbroek {
354*00b67f09SDavid van Moolenbroek 	hash_accum_t partial_sum = 0;
355*00b67f09SDavid van Moolenbroek 	hash_random_t *p = hctx->rndvector;
356*00b67f09SDavid van Moolenbroek 	unsigned int i = 0;
357*00b67f09SDavid van Moolenbroek 
358*00b67f09SDavid van Moolenbroek 	/* Make it sure that the hash context is initialized. */
359*00b67f09SDavid van Moolenbroek 	if (hctx->initialized == ISC_FALSE)
360*00b67f09SDavid van Moolenbroek 		isc_hash_ctxinit(hctx);
361*00b67f09SDavid van Moolenbroek 
362*00b67f09SDavid van Moolenbroek 	if (case_sensitive) {
363*00b67f09SDavid van Moolenbroek 		for (i = 0; i < keylen; i++)
364*00b67f09SDavid van Moolenbroek 			partial_sum += key[i] * (hash_accum_t)p[i];
365*00b67f09SDavid van Moolenbroek 	} else {
366*00b67f09SDavid van Moolenbroek 		for (i = 0; i < keylen; i++)
367*00b67f09SDavid van Moolenbroek 			partial_sum += maptolower[key[i]] * (hash_accum_t)p[i];
368*00b67f09SDavid van Moolenbroek 	}
369*00b67f09SDavid van Moolenbroek 
370*00b67f09SDavid van Moolenbroek 	partial_sum += p[i];
371*00b67f09SDavid van Moolenbroek 
372*00b67f09SDavid van Moolenbroek 	return ((unsigned int)(partial_sum % PRIME32));
373*00b67f09SDavid van Moolenbroek }
374*00b67f09SDavid van Moolenbroek 
375*00b67f09SDavid van Moolenbroek unsigned int
isc_hash_ctxcalc(isc_hash_t * hctx,const unsigned char * key,unsigned int keylen,isc_boolean_t case_sensitive)376*00b67f09SDavid van Moolenbroek isc_hash_ctxcalc(isc_hash_t *hctx, const unsigned char *key,
377*00b67f09SDavid van Moolenbroek 		 unsigned int keylen, isc_boolean_t case_sensitive)
378*00b67f09SDavid van Moolenbroek {
379*00b67f09SDavid van Moolenbroek 	REQUIRE(hctx != NULL && VALID_HASH(hctx));
380*00b67f09SDavid van Moolenbroek 	REQUIRE(keylen <= hctx->limit);
381*00b67f09SDavid van Moolenbroek 
382*00b67f09SDavid van Moolenbroek 	return (hash_calc(hctx, key, keylen, case_sensitive));
383*00b67f09SDavid van Moolenbroek }
384*00b67f09SDavid van Moolenbroek 
385*00b67f09SDavid van Moolenbroek unsigned int
isc_hash_calc(const unsigned char * key,unsigned int keylen,isc_boolean_t case_sensitive)386*00b67f09SDavid van Moolenbroek isc_hash_calc(const unsigned char *key, unsigned int keylen,
387*00b67f09SDavid van Moolenbroek 	      isc_boolean_t case_sensitive)
388*00b67f09SDavid van Moolenbroek {
389*00b67f09SDavid van Moolenbroek 	INSIST(hash != NULL && VALID_HASH(hash));
390*00b67f09SDavid van Moolenbroek 	REQUIRE(keylen <= hash->limit);
391*00b67f09SDavid van Moolenbroek 
392*00b67f09SDavid van Moolenbroek 	return (hash_calc(hash, key, keylen, case_sensitive));
393*00b67f09SDavid van Moolenbroek }
394*00b67f09SDavid van Moolenbroek 
395*00b67f09SDavid van Moolenbroek void
isc__hash_setvec(const isc_uint16_t * vec)396*00b67f09SDavid van Moolenbroek isc__hash_setvec(const isc_uint16_t *vec) {
397*00b67f09SDavid van Moolenbroek 	int i;
398*00b67f09SDavid van Moolenbroek 	hash_random_t *p;
399*00b67f09SDavid van Moolenbroek 
400*00b67f09SDavid van Moolenbroek 	if (hash == NULL)
401*00b67f09SDavid van Moolenbroek 		return;
402*00b67f09SDavid van Moolenbroek 
403*00b67f09SDavid van Moolenbroek 	p = hash->rndvector;
404*00b67f09SDavid van Moolenbroek 	for (i = 0; i < 256; i++) {
405*00b67f09SDavid van Moolenbroek 		p[i] = vec[i];
406*00b67f09SDavid van Moolenbroek 	}
407*00b67f09SDavid van Moolenbroek }
408