|
Packit Service |
95ac19 |
/*-
|
|
Packit Service |
95ac19 |
* Copyright © 2011, 2014, 2015
|
|
Packit Service |
95ac19 |
* mirabilos <m@mirbsd.org>
|
|
Packit Service |
95ac19 |
*
|
|
Packit Service |
95ac19 |
* Provided that these terms and disclaimer and all copyright notices
|
|
Packit Service |
95ac19 |
* are retained or reproduced in an accompanying document, permission
|
|
Packit Service |
95ac19 |
* is granted to deal in this work without restriction, including un‐
|
|
Packit Service |
95ac19 |
* limited rights to use, publicly perform, distribute, sell, modify,
|
|
Packit Service |
95ac19 |
* merge, give away, or sublicence.
|
|
Packit Service |
95ac19 |
*
|
|
Packit Service |
95ac19 |
* This work is provided “AS IS” and WITHOUT WARRANTY of any kind, to
|
|
Packit Service |
95ac19 |
* the utmost extent permitted by applicable law, neither express nor
|
|
Packit Service |
95ac19 |
* implied; without malicious intent or gross negligence. In no event
|
|
Packit Service |
95ac19 |
* may a licensor, author or contributor be held liable for indirect,
|
|
Packit Service |
95ac19 |
* direct, other damage, loss, or other issues arising in any way out
|
|
Packit Service |
95ac19 |
* of dealing in the work, even if advised of the possibility of such
|
|
Packit Service |
95ac19 |
* damage or existence of a defect, except proven that it results out
|
|
Packit Service |
95ac19 |
* of said person’s immediate fault when using the work as intended.
|
|
Packit Service |
95ac19 |
*-
|
|
Packit Service |
95ac19 |
* This file provides BAFH (Better Avalanche for the Jenkins Hash) as
|
|
Packit Service |
95ac19 |
* inline macro bodies that operate on “register uint32_t” variables,
|
|
Packit Service |
95ac19 |
* with variants that use their local intermediate registers.
|
|
Packit Service |
95ac19 |
*
|
|
Packit Service |
95ac19 |
* Usage note for BAFH with entropy distribution: input up to 4 bytes
|
|
Packit Service |
95ac19 |
* is best combined into a 32-bit unsigned integer, which is then run
|
|
Packit Service |
95ac19 |
* through BAFHFinish_reg for mixing and then used as context instead
|
|
Packit Service |
95ac19 |
* of 0. Longer input should be handled the same: take the first four
|
|
Packit Service |
95ac19 |
* bytes as IV after mixing then add subsequent bytes the same way.
|
|
Packit Service |
95ac19 |
* This needs counting input bytes and is endian-dependent, thus not,
|
|
Packit Service |
95ac19 |
* for speed reasons, specified for the regular stable hash, but very
|
|
Packit Service |
95ac19 |
* much recommended if the actual output value may differ across runs
|
|
Packit Service |
95ac19 |
* (so is using a random value instead of 0 for the IV).
|
|
Packit Service |
95ac19 |
*-
|
|
Packit Service |
95ac19 |
* Little quote gem:
|
|
Packit Service |
95ac19 |
* We are looking into it. Changing the core
|
|
Packit Service |
95ac19 |
* hash function in PHP isn't a trivial change
|
|
Packit Service |
95ac19 |
* and will take us some time.
|
|
Packit Service |
95ac19 |
* -- Rasmus Lerdorf
|
|
Packit Service |
95ac19 |
*/
|
|
Packit Service |
95ac19 |
|
|
Packit Service |
95ac19 |
#ifndef SYSKERN_MIRHASH_H
|
|
Packit Service |
95ac19 |
#define SYSKERN_MIRHASH_H 1
|
|
Packit Service |
95ac19 |
#define SYSKERN_MIRHASH_BAFH
|
|
Packit Service |
95ac19 |
|
|
Packit Service |
95ac19 |
#include <sys/types.h>
|
|
Packit Service |
95ac19 |
|
|
Packit Service |
95ac19 |
__RCSID("$MirOS: src/bin/mksh/mirhash.h,v 1.6 2015/11/29 17:05:02 tg Exp $");
|
|
Packit Service |
95ac19 |
|
|
Packit Service |
95ac19 |
/*-
|
|
Packit Service |
95ac19 |
* BAFH itself is defined by the following primitives:
|
|
Packit Service |
95ac19 |
*
|
|
Packit Service |
95ac19 |
* • BAFHInit(ctx) initialises the hash context, which consists of a
|
|
Packit Service |
95ac19 |
* sole 32-bit unsigned integer (ideally in a register), to 0.
|
|
Packit Service |
95ac19 |
* It is possible to use any initial value out of [0; 2³²[ – which
|
|
Packit Service |
95ac19 |
* is, in fact, recommended if using BAFH for entropy distribution
|
|
Packit Service |
95ac19 |
* – but for a regular stable hash, the IV 0 is needed.
|
|
Packit Service |
95ac19 |
*
|
|
Packit Service |
95ac19 |
* • BAFHUpdateOctet(ctx,val) compresses the unsigned 8-bit quantity
|
|
Packit Service |
95ac19 |
* into the hash context. The algorithm used is Jenkins’ one-at-a-
|
|
Packit Service |
95ac19 |
* time, except that an additional constant 1 is added so that, if
|
|
Packit Service |
95ac19 |
* the context is (still) zero, adding a NUL byte is not ignored.
|
|
Packit Service |
95ac19 |
*
|
|
Packit Service |
95ac19 |
* • BAFHror(eax,cl) evaluates to the unsigned 32-bit integer “eax”,
|
|
Packit Service |
95ac19 |
* rotated right by “cl” ∈ [0; 31] (no casting, be careful!) where
|
|
Packit Service |
95ac19 |
* “eax” must be uint32_t and “cl” an in-range integer.
|
|
Packit Service |
95ac19 |
*
|
|
Packit Service |
95ac19 |
* • BAFHFinish(ctx) avalanches the context around so every sub-byte
|
|
Packit Service |
95ac19 |
* depends on all input octets; afterwards, the context variable’s
|
|
Packit Service |
95ac19 |
* value is the hash output. BAFH does not use any padding, nor is
|
|
Packit Service |
95ac19 |
* the input length added; this is due to the common use case (for
|
|
Packit Service |
95ac19 |
* quick entropy distribution and use with a hashtable).
|
|
Packit Service |
95ac19 |
* Warning: BAFHFinish uses the MixColumn algorithm of AES – which
|
|
Packit Service |
95ac19 |
* is reversible (to avoid introducing funnels and reducing entro‐
|
|
Packit Service |
95ac19 |
* py), so blinding may need to be employed for some uses, e.g. in
|
|
Packit Service |
95ac19 |
* mksh, after a fork.
|
|
Packit Service |
95ac19 |
*
|
|
Packit Service |
95ac19 |
* The BAFHUpdateOctet and BAFHFinish are available in two flavours:
|
|
Packit Service |
95ac19 |
* suffixed with _reg (assumes the context is in a register) or _mem
|
|
Packit Service |
95ac19 |
* (which doesn’t).
|
|
Packit Service |
95ac19 |
*
|
|
Packit Service |
95ac19 |
* The following high-level macros (with _reg and _mem variants) are
|
|
Packit Service |
95ac19 |
* available:
|
|
Packit Service |
95ac19 |
*
|
|
Packit Service |
95ac19 |
* • BAFHUpdateMem(ctx,buf,len) adds a memory block to a context.
|
|
Packit Service |
95ac19 |
* • BAFHUpdateStr(ctx,buf) is equivalent to using len=strlen(buf).
|
|
Packit Service |
95ac19 |
* • BAFHHostMem(ctx,buf,len) calculates the hash of the memory buf‐
|
|
Packit Service |
95ac19 |
* fer using the first 4 octets (mixed) for IV, as outlined above;
|
|
Packit Service |
95ac19 |
* the result is endian-dependent; “ctx” assumed to be a register.
|
|
Packit Service |
95ac19 |
* • BAFHHostStr(ctx,buf) does the same for C strings.
|
|
Packit Service |
95ac19 |
*
|
|
Packit Service |
95ac19 |
* All macros may use ctx multiple times in their expansion, but all
|
|
Packit Service |
95ac19 |
* other arguments are always evaluated at most once except BAFHror.
|
|
Packit Service |
95ac19 |
*
|
|
Packit Service |
95ac19 |
* To stay portable, never use the BAFHHost*() macros (these are for
|
|
Packit Service |
95ac19 |
* host-local entropy shuffling), and encode numbers using ULEB128.
|
|
Packit Service |
95ac19 |
*/
|
|
Packit Service |
95ac19 |
|
|
Packit Service |
95ac19 |
#define BAFHInit(h) do { \
|
|
Packit Service |
95ac19 |
(h) = 0; \
|
|
Packit Service |
95ac19 |
} while (/* CONSTCOND */ 0)
|
|
Packit Service |
95ac19 |
|
|
Packit Service |
95ac19 |
#define BAFHUpdateOctet_reg(h,b) do { \
|
|
Packit Service |
95ac19 |
(h) += (uint8_t)(b); \
|
|
Packit Service |
95ac19 |
++(h); \
|
|
Packit Service |
95ac19 |
(h) += (h) << 10; \
|
|
Packit Service |
95ac19 |
(h) ^= (h) >> 6; \
|
|
Packit Service |
95ac19 |
} while (/* CONSTCOND */ 0)
|
|
Packit Service |
95ac19 |
|
|
Packit Service |
95ac19 |
#define BAFHUpdateOctet_mem(m,b) do { \
|
|
Packit Service |
95ac19 |
register uint32_t BAFH_h = (m); \
|
|
Packit Service |
95ac19 |
\
|
|
Packit Service |
95ac19 |
BAFHUpdateOctet_reg(BAFH_h, (b)); \
|
|
Packit Service |
95ac19 |
(m) = BAFH_h; \
|
|
Packit Service |
95ac19 |
} while (/* CONSTCOND */ 0)
|
|
Packit Service |
95ac19 |
|
|
Packit Service |
95ac19 |
#define BAFHror(eax,cl) (((eax) >> (cl)) | ((eax) << (32 - (cl))))
|
|
Packit Service |
95ac19 |
|
|
Packit Service |
95ac19 |
#define BAFHFinish_reg(h) do { \
|
|
Packit Service |
95ac19 |
register uint32_t BAFHFinish_v; \
|
|
Packit Service |
95ac19 |
\
|
|
Packit Service |
95ac19 |
BAFHFinish_v = ((h) >> 7) & 0x01010101U; \
|
|
Packit Service |
95ac19 |
BAFHFinish_v += BAFHFinish_v << 1; \
|
|
Packit Service |
95ac19 |
BAFHFinish_v += BAFHFinish_v << 3; \
|
|
Packit Service |
95ac19 |
BAFHFinish_v ^= ((h) << 1) & 0xFEFEFEFEU; \
|
|
Packit Service |
95ac19 |
\
|
|
Packit Service |
95ac19 |
BAFHFinish_v ^= BAFHror(BAFHFinish_v, 8); \
|
|
Packit Service |
95ac19 |
BAFHFinish_v ^= ((h) = BAFHror((h), 8)); \
|
|
Packit Service |
95ac19 |
BAFHFinish_v ^= ((h) = BAFHror((h), 8)); \
|
|
Packit Service |
95ac19 |
(h) = BAFHror((h), 8) ^ BAFHFinish_v; \
|
|
Packit Service |
95ac19 |
} while (/* CONSTCOND */ 0)
|
|
Packit Service |
95ac19 |
|
|
Packit Service |
95ac19 |
#define BAFHFinish_mem(m) do { \
|
|
Packit Service |
95ac19 |
register uint32_t BAFHFinish_v, BAFH_h = (m); \
|
|
Packit Service |
95ac19 |
\
|
|
Packit Service |
95ac19 |
BAFHFinish_v = (BAFH_h >> 7) & 0x01010101U; \
|
|
Packit Service |
95ac19 |
BAFHFinish_v += BAFHFinish_v << 1; \
|
|
Packit Service |
95ac19 |
BAFHFinish_v += BAFHFinish_v << 3; \
|
|
Packit Service |
95ac19 |
BAFHFinish_v ^= (BAFH_h << 1) & 0xFEFEFEFEU; \
|
|
Packit Service |
95ac19 |
\
|
|
Packit Service |
95ac19 |
BAFHFinish_v ^= BAFHror(BAFHFinish_v, 8); \
|
|
Packit Service |
95ac19 |
BAFHFinish_v ^= (BAFH_h = BAFHror(BAFH_h, 8)); \
|
|
Packit Service |
95ac19 |
BAFHFinish_v ^= (BAFH_h = BAFHror(BAFH_h, 8)); \
|
|
Packit Service |
95ac19 |
(m) = BAFHror(BAFH_h, 8) ^ BAFHFinish_v; \
|
|
Packit Service |
95ac19 |
} while (/* CONSTCOND */ 0)
|
|
Packit Service |
95ac19 |
|
|
Packit Service |
95ac19 |
#define BAFHUpdateMem_reg(h,p,z) do { \
|
|
Packit Service |
95ac19 |
register const uint8_t *BAFHUpdate_p; \
|
|
Packit Service |
95ac19 |
register size_t BAFHUpdate_z = (z); \
|
|
Packit Service |
95ac19 |
\
|
|
Packit Service |
95ac19 |
BAFHUpdate_p = (const void *)(p); \
|
|
Packit Service |
95ac19 |
while (BAFHUpdate_z--) \
|
|
Packit Service |
95ac19 |
BAFHUpdateOctet_reg((h), *BAFHUpdate_p++); \
|
|
Packit Service |
95ac19 |
} while (/* CONSTCOND */ 0)
|
|
Packit Service |
95ac19 |
|
|
Packit Service |
95ac19 |
/* meh should have named them _r/m but that’s not valid C */
|
|
Packit Service |
95ac19 |
#define BAFHUpdateMem_mem(m,p,z) do { \
|
|
Packit Service |
95ac19 |
register uint32_t BAFH_h = (m); \
|
|
Packit Service |
95ac19 |
\
|
|
Packit Service |
95ac19 |
BAFHUpdateMem_reg(BAFH_h, (p), (z)); \
|
|
Packit Service |
95ac19 |
(m) = BAFH_h; \
|
|
Packit Service |
95ac19 |
} while (/* CONSTCOND */ 0)
|
|
Packit Service |
95ac19 |
|
|
Packit Service |
95ac19 |
#define BAFHUpdateStr_reg(h,s) do { \
|
|
Packit Service |
95ac19 |
register const uint8_t *BAFHUpdate_s; \
|
|
Packit Service |
95ac19 |
register uint8_t BAFHUpdate_c; \
|
|
Packit Service |
95ac19 |
\
|
|
Packit Service |
95ac19 |
BAFHUpdate_s = (const void *)(s); \
|
|
Packit Service |
95ac19 |
while ((BAFHUpdate_c = *BAFHUpdate_s++) != 0) \
|
|
Packit Service |
95ac19 |
BAFHUpdateOctet_reg((h), BAFHUpdate_c); \
|
|
Packit Service |
95ac19 |
} while (/* CONSTCOND */ 0)
|
|
Packit Service |
95ac19 |
|
|
Packit Service |
95ac19 |
#define BAFHUpdateStr_mem(m,s) do { \
|
|
Packit Service |
95ac19 |
register uint32_t BAFH_h = (m); \
|
|
Packit Service |
95ac19 |
\
|
|
Packit Service |
95ac19 |
BAFHUpdateStr_reg(BAFH_h, (s)); \
|
|
Packit Service |
95ac19 |
(m) = BAFH_h; \
|
|
Packit Service |
95ac19 |
} while (/* CONSTCOND */ 0)
|
|
Packit Service |
95ac19 |
|
|
Packit Service |
95ac19 |
#define BAFHHostMem(h,p,z) do { \
|
|
Packit Service |
95ac19 |
register const uint8_t *BAFHUpdate_p; \
|
|
Packit Service |
95ac19 |
register size_t BAFHUpdate_z = (z); \
|
|
Packit Service |
95ac19 |
size_t BAFHHost_z; \
|
|
Packit Service |
95ac19 |
union { \
|
|
Packit Service |
95ac19 |
uint8_t as_u8[4]; \
|
|
Packit Service |
95ac19 |
uint32_t as_u32; \
|
|
Packit Service |
95ac19 |
} BAFHHost_v; \
|
|
Packit Service |
95ac19 |
\
|
|
Packit Service |
95ac19 |
BAFHUpdate_p = (const void *)(p); \
|
|
Packit Service |
95ac19 |
BAFHHost_v.as_u32 = 0; \
|
|
Packit Service |
95ac19 |
BAFHHost_z = BAFHUpdate_z < 4 ? BAFHUpdate_z : 4; \
|
|
Packit Service |
95ac19 |
memcpy(BAFHHost_v.as_u8, BAFHUpdate_p, BAFHHost_z); \
|
|
Packit Service |
95ac19 |
BAFHUpdate_p += BAFHHost_z; \
|
|
Packit Service |
95ac19 |
BAFHUpdate_z -= BAFHHost_z; \
|
|
Packit Service |
95ac19 |
(h) = BAFHHost_v.as_u32; \
|
|
Packit Service |
95ac19 |
BAFHFinish_reg(h); \
|
|
Packit Service |
95ac19 |
while (BAFHUpdate_z--) \
|
|
Packit Service |
95ac19 |
BAFHUpdateOctet_reg((h), *BAFHUpdate_p++); \
|
|
Packit Service |
95ac19 |
BAFHFinish_reg(h); \
|
|
Packit Service |
95ac19 |
} while (/* CONSTCOND */ 0)
|
|
Packit Service |
95ac19 |
|
|
Packit Service |
95ac19 |
#define BAFHHostStr(h,s) do { \
|
|
Packit Service |
95ac19 |
register const uint8_t *BAFHUpdate_s; \
|
|
Packit Service |
95ac19 |
register uint8_t BAFHUpdate_c; \
|
|
Packit Service |
95ac19 |
union { \
|
|
Packit Service |
95ac19 |
uint8_t as_u8[4]; \
|
|
Packit Service |
95ac19 |
uint32_t as_u32; \
|
|
Packit Service |
95ac19 |
} BAFHHost_v; \
|
|
Packit Service |
95ac19 |
\
|
|
Packit Service |
95ac19 |
BAFHUpdate_s = (const void *)(s); \
|
|
Packit Service |
95ac19 |
BAFHHost_v.as_u32 = 0; \
|
|
Packit Service |
95ac19 |
if ((BAFHHost_v.as_u8[0] = *BAFHUpdate_s) != 0) \
|
|
Packit Service |
95ac19 |
++BAFHUpdate_s; \
|
|
Packit Service |
95ac19 |
if ((BAFHHost_v.as_u8[1] = *BAFHUpdate_s) != 0) \
|
|
Packit Service |
95ac19 |
++BAFHUpdate_s; \
|
|
Packit Service |
95ac19 |
if ((BAFHHost_v.as_u8[2] = *BAFHUpdate_s) != 0) \
|
|
Packit Service |
95ac19 |
++BAFHUpdate_s; \
|
|
Packit Service |
95ac19 |
if ((BAFHHost_v.as_u8[3] = *BAFHUpdate_s) != 0) \
|
|
Packit Service |
95ac19 |
++BAFHUpdate_s; \
|
|
Packit Service |
95ac19 |
(h) = BAFHHost_v.as_u32; \
|
|
Packit Service |
95ac19 |
BAFHFinish_reg(h); \
|
|
Packit Service |
95ac19 |
while ((BAFHUpdate_c = *BAFHUpdate_s++) != 0) \
|
|
Packit Service |
95ac19 |
BAFHUpdateOctet_reg((h), BAFHUpdate_c); \
|
|
Packit Service |
95ac19 |
BAFHFinish_reg(h); \
|
|
Packit Service |
95ac19 |
} while (/* CONSTCOND */ 0)
|
|
Packit Service |
95ac19 |
|
|
Packit Service |
95ac19 |
#endif
|