OSDN Git Service

Upgrade to mksh 50.
[android-x86/external-mksh.git] / src / mirhash.h
1 /*-
2  * Copyright © 2011, 2014
3  *      Thorsten Glaser <tg@mirbsd.org>
4  *
5  * Provided that these terms and disclaimer and all copyright notices
6  * are retained or reproduced in an accompanying document, permission
7  * is granted to deal in this work without restriction, including un‐
8  * limited rights to use, publicly perform, distribute, sell, modify,
9  * merge, give away, or sublicence.
10  *
11  * This work is provided “AS IS” and WITHOUT WARRANTY of any kind, to
12  * the utmost extent permitted by applicable law, neither express nor
13  * implied; without malicious intent or gross negligence. In no event
14  * may a licensor, author or contributor be held liable for indirect,
15  * direct, other damage, loss, or other issues arising in any way out
16  * of dealing in the work, even if advised of the possibility of such
17  * damage or existence of a defect, except proven that it results out
18  * of said person’s immediate fault when using the work as intended.
19  *-
20  * This file provides BAFH (Better Avalanche for the Jenkins Hash) as
21  * inline macro bodies that operate on “register uint32_t” variables,
22  * with variants that use their local intermediate registers.
23  *
24  * Usage note for BAFH with entropy distribution: input up to 4 bytes
25  * is best combined into a 32-bit unsigned integer, which is then run
26  * through BAFHFinish_reg for mixing and then used as context instead
27  * of 0. Longer input should be handled the same: take the first four
28  * bytes as IV after mixing then add subsequent bytes the same way.
29  * This needs counting input bytes and is endian-dependent, thus not,
30  * for speed reasons, specified for the regular stable hash, but very
31  * much recommended if the actual output value may differ across runs
32  * (so is using a random value instead of 0 for the IV).
33  */
34
35 #ifndef SYSKERN_MIRHASH_H
36 #define SYSKERN_MIRHASH_H 1
37 #define SYSKERN_MIRHASH_BAFH
38
39 #include <sys/types.h>
40
41 __RCSID("$MirOS: src/bin/mksh/mirhash.h,v 1.2 2014/06/29 11:48:05 tg Exp $");
42
43 /*-
44  * BAFH itself is defined by the following primitives:
45  *
46  * • BAFHInit(ctx) initialises the hash context, which consists of a
47  *   sole 32-bit unsigned integer (ideally in a register), to 0.
48  *   It is possible to use any initial value out of [0; 2³²[ – which
49  *   is, in fact, recommended if using BAFH for entropy distribution
50  *   – but for a regular stable hash, the IV 0 is needed.
51  *
52  * • BAFHUpdateOctet(ctx,val) compresses the unsigned 8-bit quantity
53  *   into the hash context. The algorithm used is Jenkins’ one-at-a-
54  *   time, except that an additional constant 1 is added so that, if
55  *   the context is (still) zero, adding a NUL byte is not ignored.
56  *
57  * • BAFHror(eax,cl) evaluates to the unsigned 32-bit integer “eax”,
58  *   rotated right by “cl” ∈ [0;31]; no casting, be careful!
59  *
60  * • BAFHFinish(ctx) avalanches the context around so every sub-byte
61  *   depends on all input octets; afterwards, the context variable’s
62  *   value is the hash output. BAFH does not use any padding, nor is
63  *   the input length added; this is due to the common use case (for
64  *   quick entropy distribution and use with a hashtable).
65  *   Warning: BAFHFinish uses the MixColumn algorithm of AES – which
66  *   is reversible (to avoid introducing funnels and reducing entro‐
67  *   py), so blinding may need to be employed for some uses, e.g. in
68  *   mksh, after a fork.
69  *
70  * The BAFHUpdateOctet and BAFHFinish are available in two flavours:
71  * suffixed with _reg (assumes the context is in a register) or _mem
72  * (which doesn’t).
73  *
74  * The following high-level macros (with _reg and _mem variants) are
75  * available:
76  *
77  * • BAFHUpdateMem(ctx,buf,len) adds a memory block to a context.
78  * • BAFHUpdateStr(ctx,buf) is equivalent to using len=strlen(buf).
79  * • BAFHHostMem(ctx,buf,len) calculates the hash of the memory buf‐
80  *   fer using the first 4 octets (mixed) for IV, as outlined above;
81  *   the result is endian-dependent; “ctx” assumed to be a register.
82  * • BAFHHostStr(ctx,buf) does the same for C strings.
83  *
84  * All macros may use ctx multiple times in their expansion, but all
85  * other arguments are always evaluated at most once.
86  *
87  * To stay portable, never use the BAFHHost*() macros (these are for
88  * host-local entropy shuffling), and encode numbers using ULEB128.
89  */
90
91 #define BAFHInit(h) do {                                        \
92         (h) = 0;                                                \
93 } while (/* CONSTCOND */ 0)
94
95 #define BAFHUpdateOctet_reg(h,b) do {                           \
96         (h) += (uint8_t)(b);                                    \
97         ++(h);                                                  \
98         (h) += (h) << 10;                                       \
99         (h) ^= (h) >> 6;                                        \
100 } while (/* CONSTCOND */ 0)
101
102 #define BAFHUpdateOctet_mem(m,b) do {                           \
103         register uint32_t BAFH_h = (m);                         \
104                                                                 \
105         BAFHUpdateOctet_reg(BAFH_h, (b));                       \
106         (m) = BAFH_h;                                           \
107 } while (/* CONSTCOND */ 0)
108
109 #define BAFHror(eax,cl) (((eax) >> (cl)) | ((eax) << (32 - (cl))))
110
111 #define BAFHFinish_reg(h) do {                                  \
112         register uint32_t BAFHFinish_v;                         \
113                                                                 \
114         BAFHFinish_v = ((h) >> 7) & 0x01010101U;                \
115         BAFHFinish_v += BAFHFinish_v << 1;                      \
116         BAFHFinish_v += BAFHFinish_v << 3;                      \
117         BAFHFinish_v ^= ((h) << 1) & 0xFEFEFEFEU;               \
118                                                                 \
119         BAFHFinish_v ^= BAFHror(BAFHFinish_v, 8);               \
120         BAFHFinish_v ^= ((h) = BAFHror((h), 8));                \
121         BAFHFinish_v ^= ((h) = BAFHror((h), 8));                \
122         (h) = BAFHror((h), 8) ^ BAFHFinish_v;                   \
123 } while (/* CONSTCOND */ 0)
124
125 #define BAFHFinish_mem(m) do {                                  \
126         register uint32_t BAFHFinish_v, BAFH_h = (m);           \
127                                                                 \
128         BAFHFinish_v = (BAFH_h >> 7) & 0x01010101U;             \
129         BAFHFinish_v += BAFHFinish_v << 1;                      \
130         BAFHFinish_v += BAFHFinish_v << 3;                      \
131         BAFHFinish_v ^= (BAFH_h << 1) & 0xFEFEFEFEU;            \
132                                                                 \
133         BAFHFinish_v ^= BAFHror(BAFHFinish_v, 8);               \
134         BAFHFinish_v ^= (BAFH_h = BAFHror(BAFH_h, 8));          \
135         BAFHFinish_v ^= (BAFH_h = BAFHror(BAFH_h, 8));          \
136         (m) = BAFHror(BAFH_h, 8) ^ BAFHFinish_v;                \
137 } while (/* CONSTCOND */ 0)
138
139 #define BAFHUpdateMem_reg(h,p,z) do {                           \
140         register const uint8_t *BAFHUpdate_p;                   \
141         register size_t BAFHUpdate_z = (z);                     \
142                                                                 \
143         BAFHUpdate_p = (const void *)(p);                       \
144         while (BAFHUpdate_z--)                                  \
145                 BAFHUpdateOctet_reg((h), *BAFHUpdate_p++);      \
146 } while (/* CONSTCOND */ 0)
147
148 /* meh should have named them _r/m but that’s not valid C */
149 #define BAFHUpdateMem_mem(m,p,z) do {                           \
150         register uint32_t BAFH_h = (m);                         \
151                                                                 \
152         BAFHUpdateMem_reg(BAFH_h, (p), (z));                    \
153         (m) = BAFH_h;                                           \
154 } while (/* CONSTCOND */ 0)
155
156 #define BAFHUpdateStr_reg(h,s) do {                             \
157         register const uint8_t *BAFHUpdate_s;                   \
158         register uint8_t BAFHUpdate_c;                          \
159                                                                 \
160         BAFHUpdate_s = (const void *)(s);                       \
161         while ((BAFHUpdate_c = *BAFHUpdate_s++) != 0)           \
162                 BAFHUpdateOctet_reg((h), BAFHUpdate_c);         \
163 } while (/* CONSTCOND */ 0)
164
165 #define BAFHUpdateStr_mem(m,s) do {                             \
166         register uint32_t BAFH_h = (m);                         \
167                                                                 \
168         BAFHUpdateStr_reg(BAFH_h, (s));                         \
169         (m) = BAFH_h;                                           \
170 } while (/* CONSTCOND */ 0)
171
172 #define BAFHHostMem(h,p,z) do {                                 \
173         register const uint8_t *BAFHUpdate_p;                   \
174         register size_t BAFHUpdate_z = (z);                     \
175         size_t BAFHHost_z;                                      \
176         union {                                                 \
177                 uint8_t as_u8[4];                               \
178                 uint32_t as_u32;                                \
179         } BAFHHost_v;                                           \
180                                                                 \
181         BAFHUpdate_p = (const void *)(p);                       \
182         BAFHHost_v.as_u32 = 0;                                  \
183         BAFHHost_z = BAFHUpdate_z < 4 ? BAFHUpdate_z : 4;       \
184         memcpy(BAFHHost_v.as_u8, BAFHUpdate_p, BAFHHost_z);     \
185         BAFHUpdate_p += BAFHHost_z;                             \
186         BAFHUpdate_z -= BAFHHost_z;                             \
187         (h) = BAFHHost_v.as_u32;                                \
188         BAFHFinish_reg(h);                                      \
189         while (BAFHUpdate_z--)                                  \
190                 BAFHUpdateOctet_reg((h), *BAFHUpdate_p++);      \
191         BAFHFinish_reg(h);                                      \
192 } while (/* CONSTCOND */ 0)
193
194 #define BAFHHostStr(h,s) do {                                   \
195         register const uint8_t *BAFHUpdate_s;                   \
196         register uint8_t BAFHUpdate_c;                          \
197         union {                                                 \
198                 uint8_t as_u8[4];                               \
199                 uint32_t as_u32;                                \
200         } BAFHHost_v;                                           \
201                                                                 \
202         BAFHUpdate_s = (const void *)(s);                       \
203         if ((BAFHHost_v.as_u8[0] = *BAFHUpdate_s) != 0)         \
204                 ++BAFHUpdate_s;                                 \
205         if ((BAFHHost_v.as_u8[1] = *BAFHUpdate_s) != 0)         \
206                 ++BAFHUpdate_s;                                 \
207         if ((BAFHHost_v.as_u8[2] = *BAFHUpdate_s) != 0)         \
208                 ++BAFHUpdate_s;                                 \
209         if ((BAFHHost_v.as_u8[3] = *BAFHUpdate_s) != 0)         \
210                 ++BAFHUpdate_s;                                 \
211         (h) = BAFHHost_v.as_u32;                                \
212         BAFHFinish_reg(h);                                      \
213         while ((BAFHUpdate_c = *BAFHUpdate_s++) != 0)           \
214                 BAFHUpdateOctet_reg((h), BAFHUpdate_c);         \
215         BAFHFinish_reg(h);                                      \
216 } while (/* CONSTCOND */ 0)
217
218 #endif