xref: /netbsd-src/external/bsd/openldap/dist/libraries/liblutil/hash.c (revision 549b59ed3ccf0d36d3097190a0db27b770f3a839)
1*549b59edSchristos /*	$NetBSD: hash.c,v 1.3 2021/08/14 16:14:58 christos Exp $	*/
24e6df137Slukem 
3d11b170bStron /* $OpenLDAP$ */
42de962bdSlukem /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
52de962bdSlukem  *
6*549b59edSchristos  * Copyright 2000-2021 The OpenLDAP Foundation.
72de962bdSlukem  * Portions Copyright 2000-2003 Kurt D. Zeilenga.
82de962bdSlukem  * All rights reserved.
92de962bdSlukem  *
102de962bdSlukem  * Redistribution and use in source and binary forms, with or without
112de962bdSlukem  * modification, are permitted only as authorized by the OpenLDAP
122de962bdSlukem  * Public License.
132de962bdSlukem  *
142de962bdSlukem  * A copy of this license is available in the file LICENSE in the
152de962bdSlukem  * top-level directory of the distribution or, alternatively, at
162de962bdSlukem  * <http://www.OpenLDAP.org/license.html>.
172de962bdSlukem  */
182de962bdSlukem 
192de962bdSlukem /* This implements the Fowler / Noll / Vo (FNV-1) hash algorithm.
202de962bdSlukem  * A summary of the algorithm can be found at:
212de962bdSlukem  *   http://www.isthe.com/chongo/tech/comp/fnv/index.html
222de962bdSlukem  */
232de962bdSlukem 
24376af7d7Schristos #include <sys/cdefs.h>
25*549b59edSchristos __RCSID("$NetBSD: hash.c,v 1.3 2021/08/14 16:14:58 christos Exp $");
26376af7d7Schristos 
272de962bdSlukem #include "portable.h"
282de962bdSlukem 
292de962bdSlukem #include <lutil_hash.h>
302de962bdSlukem 
312de962bdSlukem /* offset and prime for 32-bit FNV-1 */
322de962bdSlukem #define HASH_OFFSET	0x811c9dc5U
332de962bdSlukem #define HASH_PRIME	16777619
342de962bdSlukem 
352de962bdSlukem 
362de962bdSlukem /*
372de962bdSlukem  * Initialize context
382de962bdSlukem  */
392de962bdSlukem void
lutil_HASHInit(lutil_HASH_CTX * ctx)40*549b59edSchristos lutil_HASHInit( lutil_HASH_CTX *ctx )
412de962bdSlukem {
422de962bdSlukem 	ctx->hash = HASH_OFFSET;
432de962bdSlukem }
442de962bdSlukem 
452de962bdSlukem /*
462de962bdSlukem  * Update hash
472de962bdSlukem  */
482de962bdSlukem void
lutil_HASHUpdate(lutil_HASH_CTX * ctx,const unsigned char * buf,ber_len_t len)492de962bdSlukem lutil_HASHUpdate(
50*549b59edSchristos     lutil_HASH_CTX	*ctx,
512de962bdSlukem     const unsigned char		*buf,
522de962bdSlukem     ber_len_t		len )
532de962bdSlukem {
542de962bdSlukem 	const unsigned char *p, *e;
552de962bdSlukem 	ber_uint_t h;
562de962bdSlukem 
572de962bdSlukem 	p = buf;
582de962bdSlukem 	e = &buf[len];
592de962bdSlukem 
602de962bdSlukem 	h = ctx->hash;
612de962bdSlukem 
622de962bdSlukem 	while( p < e ) {
632de962bdSlukem 		h *= HASH_PRIME;
642de962bdSlukem 		h ^= *p++;
652de962bdSlukem 	}
662de962bdSlukem 
672de962bdSlukem 	ctx->hash = h;
682de962bdSlukem }
692de962bdSlukem 
702de962bdSlukem /*
712de962bdSlukem  * Save hash
722de962bdSlukem  */
732de962bdSlukem void
lutil_HASHFinal(unsigned char * digest,lutil_HASH_CTX * ctx)74*549b59edSchristos lutil_HASHFinal( unsigned char *digest, lutil_HASH_CTX *ctx )
752de962bdSlukem {
762de962bdSlukem 	ber_uint_t h = ctx->hash;
772de962bdSlukem 
782de962bdSlukem 	digest[0] = h & 0xffU;
792de962bdSlukem 	digest[1] = (h>>8) & 0xffU;
802de962bdSlukem 	digest[2] = (h>>16) & 0xffU;
812de962bdSlukem 	digest[3] = (h>>24) & 0xffU;
822de962bdSlukem }
83*549b59edSchristos 
84*549b59edSchristos #ifdef HAVE_LONG_LONG
85*549b59edSchristos 
86*549b59edSchristos /* 64 bit Fowler/Noll/Vo-O FNV-1a hash code */
87*549b59edSchristos 
88*549b59edSchristos #define HASH64_OFFSET	0xcbf29ce484222325ULL
89*549b59edSchristos 
90*549b59edSchristos /*
91*549b59edSchristos  * Initialize context
92*549b59edSchristos  */
93*549b59edSchristos void
lutil_HASH64Init(lutil_HASH_CTX * ctx)94*549b59edSchristos lutil_HASH64Init( lutil_HASH_CTX *ctx )
95*549b59edSchristos {
96*549b59edSchristos 	ctx->hash64 = HASH64_OFFSET;
97*549b59edSchristos }
98*549b59edSchristos 
99*549b59edSchristos /*
100*549b59edSchristos  * Update hash
101*549b59edSchristos  */
102*549b59edSchristos void
lutil_HASH64Update(lutil_HASH_CTX * ctx,const unsigned char * buf,ber_len_t len)103*549b59edSchristos lutil_HASH64Update(
104*549b59edSchristos     lutil_HASH_CTX	*ctx,
105*549b59edSchristos     const unsigned char		*buf,
106*549b59edSchristos     ber_len_t		len )
107*549b59edSchristos {
108*549b59edSchristos 	const unsigned char *p, *e;
109*549b59edSchristos 	unsigned long long h;
110*549b59edSchristos 
111*549b59edSchristos 	p = buf;
112*549b59edSchristos 	e = &buf[len];
113*549b59edSchristos 
114*549b59edSchristos 	h = ctx->hash64;
115*549b59edSchristos 
116*549b59edSchristos 	while( p < e ) {
117*549b59edSchristos 		/* xor the bottom with the current octet */
118*549b59edSchristos 		h ^= *p++;
119*549b59edSchristos 
120*549b59edSchristos 		/* multiply by the 64 bit FNV magic prime mod 2^64 */
121*549b59edSchristos 		h += (h << 1) + (h << 4) + (h << 5) +
122*549b59edSchristos 			(h << 7) + (h << 8) + (h << 40);
123*549b59edSchristos 
124*549b59edSchristos 	}
125*549b59edSchristos 
126*549b59edSchristos 	ctx->hash64 = h;
127*549b59edSchristos }
128*549b59edSchristos 
129*549b59edSchristos /*
130*549b59edSchristos  * Save hash
131*549b59edSchristos  */
132*549b59edSchristos void
lutil_HASH64Final(unsigned char * digest,lutil_HASH_CTX * ctx)133*549b59edSchristos lutil_HASH64Final( unsigned char *digest, lutil_HASH_CTX *ctx )
134*549b59edSchristos {
135*549b59edSchristos 	unsigned long long h = ctx->hash64;
136*549b59edSchristos 
137*549b59edSchristos 	digest[0] = h & 0xffU;
138*549b59edSchristos 	digest[1] = (h>>8) & 0xffU;
139*549b59edSchristos 	digest[2] = (h>>16) & 0xffU;
140*549b59edSchristos 	digest[3] = (h>>24) & 0xffU;
141*549b59edSchristos 	digest[4] = (h>>32) & 0xffU;
142*549b59edSchristos 	digest[5] = (h>>40) & 0xffU;
143*549b59edSchristos 	digest[6] = (h>>48) & 0xffU;
144*549b59edSchristos 	digest[7] = (h>>56) & 0xffU;
145*549b59edSchristos }
146*549b59edSchristos #endif /* HAVE_LONG_LONG */
147