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