Codebase list mksh / f89bb451-b7fc-45de-a9c6-a82414ca1aa3/main mirhash.h
f89bb451-b7fc-45de-a9c6-a82414ca1aa3/main

Tree @f89bb451-b7fc-45de-a9c6-a82414ca1aa3/main (Download .tar.gz)

mirhash.h @f89bb451-b7fc-45de-a9c6-a82414ca1aa3/mainraw · history · blame

/*-
 * Copyright © 2011, 2014, 2015, 2021, 2022
 *	mirabilos <m@mirbsd.org>
 *
 * Provided that these terms and disclaimer and all copyright notices
 * are retained or reproduced in an accompanying document, permission
 * is granted to deal in this work without restriction, including un‐
 * limited rights to use, publicly perform, distribute, sell, modify,
 * merge, give away, or sublicence.
 *
 * This work is provided “AS IS” and WITHOUT WARRANTY of any kind, to
 * the utmost extent permitted by applicable law, neither express nor
 * implied; without malicious intent or gross negligence. In no event
 * may a licensor, author or contributor be held liable for indirect,
 * direct, other damage, loss, or other issues arising in any way out
 * of dealing in the work, even if advised of the possibility of such
 * damage or existence of a defect, except proven that it results out
 * of said person’s immediate fault when using the work as intended.
 *-
 * This file provides BAFH1-0 (Better Avalanche for the Jenkins Hash)
 * as macro bodies operating on “register k32” variables (from sh.h).
 *-
 * Little quote gem:
 *	We are looking into it. Changing the core
 *	hash function in PHP isn't a trivial change
 *	and will take us some time.
 *		-- Rasmus Lerdorf
 */

#ifndef MKSH_MIRHASH_H
#define MKSH_MIRHASH_H

#include <sys/types.h>

__RCSID("$MirOS: src/bin/mksh/mirhash.h,v 1.14 2022/01/27 14:15:41 tg Exp $");

/*-
 * BAFH1-0 is defined by the following primitives:
 *
 * • BAFHInit(ctx) initialises the hash context, which consists of a
 *   sole 32-bit unsigned integer (ideally in a register), to 0^H1.
 *   It is possible to use any initial value out of [0; 2³²[ — which
 *   is, in fact, recommended if using BAFH for entropy distribution
 *   — but for a regular stable hash, the IV 0^H1 is needed.
 *
 * • BAFHUpdateOctet(ctx,val) compresses the unsigned 8-bit quantity
 *   into the hash context using Jenkins’ one-at-a-time algorithm.
 *
 * • BAFHror(eax,cl) evaluates to the unsigned 32-bit integer “eax”,
 *   rotated right by “cl” ∈ [1; 31] (no casting, be careful!) where
 *   “eax” is K32()d and “cl” must be within range.
 *
 * • BAFHFinish(ctx) avalanches the context around so every sub-byte
 *   depends on all input octets; afterwards, the context variable’s
 *   value is the hash output. BAFH does not use any padding, nor is
 *   the input length added; this is due to the common use case (for
 *   quick entropy distribution and use with a hashtable).
 *   Warning: BAFHFinish uses the MixColumn algorithm of AES — which
 *   is reversible (to avoid introducing funnels and reducing entro‐
 *   py), so blinding may need to be employed for some uses, e.g. in
 *   mksh, after a fork.
 *
 * The following high-level macros are available:
 *
 * • BAFHUpdateMem(ctx,buf,len) adds a memory block to a context.
 * • BAFHUpdateStr(ctx,buf) is equivalent to using len=strlen(buf).
 *
 * All macros may use ctx multiple times in their expansion, but all
 * other arguments are always evaluated at most once except BAFHror.
 */

#define BAFHInit(h) do {					\
	(h) = 1U;						\
} while (/* CONSTCOND */ 0)

#define BAFHUpdateOctet(h,b) do {				\
	(h) = K32(K32(h) + KBI(b));				\
	(h) = K32((h) + K32((h) << 10));			\
	(h) = K32((h) ^ K32((h) >> 6));				\
} while (/* CONSTCOND */ 0)

#define BAFHror(eax,cl) K32(K32(K32(eax) >> (cl)) | K32(K32(eax) << (32 - (cl))))

#define BAFHFinish__impl(h,v,d)					\
	v = K32(K32(h) >> 7) & 0x01010101U;			\
	v = K32(v + K32(v << 1));				\
	v = K32(v + K32(v << 3));				\
	v = K32(v ^ (K32(K32(h) << 1) & 0xFEFEFEFEU));		\
								\
	v = K32(v ^ BAFHror(v, 8));				\
	v = K32(v ^ (h = BAFHror(h, 8)));			\
	v = K32(v ^ (h = BAFHror(h, 8)));			\
	d = K32(v ^ BAFHror(h, 8));

#define BAFHFinish(h) do {					\
	register k32 BAFHFinish_v;				\
								\
	BAFHFinish__impl((h), BAFHFinish_v, (h))		\
} while (/* CONSTCOND */ 0)

#define BAFHUpdateMem(h,p,z) do {				\
	register const unsigned char *BAFHUpdate_p;		\
	register const unsigned char *BAFHUpdate_d;		\
								\
	BAFHUpdate_p = (const void *)(p);			\
	BAFHUpdate_d = BAFHUpdate_p + (z);			\
	while (BAFHUpdate_p < BAFHUpdate_d)			\
		BAFHUpdateOctet((h), *BAFHUpdate_p++);		\
} while (/* CONSTCOND */ 0)

#define BAFHUpdateStr(h,s) do {					\
	register const unsigned char *BAFHUpdate_s;		\
	register unsigned char BAFHUpdate_c;			\
								\
	BAFHUpdate_s = (const void *)(s);			\
	while ((BAFHUpdate_c = *BAFHUpdate_s++) != 0)		\
		BAFHUpdateOctet((h), BAFHUpdate_c);		\
} while (/* CONSTCOND */ 0)

#endif