chiark / gitweb /
progs/perftest.c: Use from Glibc syscall numbers.
[catacomb] / symm / hash.h
1 /* -*-c-*-
2  *
3  * Generic handling for message digest functions
4  *
5  * (c) 1998 Straylight/Edgeware
6  */
7
8 /*----- Licensing notice --------------------------------------------------*
9  *
10  * This file is part of Catacomb.
11  *
12  * Catacomb is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU Library General Public License as
14  * published by the Free Software Foundation; either version 2 of the
15  * License, or (at your option) any later version.
16  *
17  * Catacomb is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU Library General Public License for more details.
21  *
22  * You should have received a copy of the GNU Library General Public
23  * License along with Catacomb; if not, write to the Free
24  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25  * MA 02111-1307, USA.
26  */
27
28 #ifndef CATACOMB_HASH_H
29 #define CATACOMB_HASH_H
30
31 #ifdef __cplusplus
32   extern "C" {
33 #endif
34
35 /*----- Header files ------------------------------------------------------*/
36
37 #include <string.h>
38
39 #include <mLib/bits.h>
40
41 #ifndef CATACOMB_RSVR_H
42 #  include "rsvr.h"
43 #endif
44
45 /*----- Macros ------------------------------------------------------------*/
46
47 /* --- @HASH_BUFFER@ --- *
48  *
49  * Arguments:   @PRE@, @pre@ = prefixes for hash-specific definitions
50  *              @ictx@ = pointer to context block for the hash
51  *              @ibuf@ = pointer to input data to hash
52  *              @isz@ = size of buffer
53  *
54  * Use:         Handles buffering of input data to a hash function.  The
55  *              hash's compression function is called when the buffer is
56  *              full.  Note that the compression function can be called on
57  *              data which is at odd alignments; it is expected to cope
58  *              gracefully with this (possibly by copying the data into its
59  *              internal buffer before starting).
60  */
61
62 #define HASH_BUFFER(PRE, pre, ictx, ibuf, isz) do {                     \
63   pre##_ctx *_bctx = (ictx);                                            \
64   size_t _bsz = (isz);                                                  \
65   const octet *_bbuf = (octet *)(ibuf), *_p;                            \
66   static const rsvr_policy _pol = { 0, PRE##_BUFSZ, PRE##_BUFSZ };      \
67   uint32 _l, _h;                                                        \
68   rsvr_state _st;                                                       \
69                                                                         \
70   /* --- Add on the size done so far --- *                              \
71    *                                                                    \
72    * Messy, because trapping overflow is difficult when you don't know  \
73    * how many bits you've actually got.                                 \
74    */                                                                   \
75                                                                         \
76   _l = U32(_bsz); _h = ((_bsz & ~(size_t)MASK32) >> 16) >> 16;          \
77   _bctx->nl += _l; if (_bctx->nl < _l || _bctx->nl & ~(uint32)MASK32) _h++; \
78   _bctx->nh += _h;                                                      \
79                                                                         \
80   /* --- Accumulate the input data --- */                               \
81                                                                         \
82   rsvr_setup(&_st, &_pol, _bctx->buf, &_bctx->off, _bbuf, _bsz);        \
83   RSVR_DO(&_st) while ((_p = RSVR_NEXT(&_st, PRE##_BUFSZ)) != 0)        \
84     pre##_compress(_bctx, _p);                                          \
85 } while (0)
86
87 /* --- @HASH_PAD@ --- *
88  *
89  * Arguments:   @PRE@, @pre@ = prefixes for hash-specific definitions
90  *              @ictx@ = pointer to context block for the hash
91  *              @term@ = terminator character to write following the data
92  *              @pad@ = pad character to fill with
93  *              @diff@ = size of space to leave at the end of the last block
94  *
95  * Use:         Does padding for message digest functions.
96  */
97
98 #define HASH_PAD(PRE, pre, ictx, term, pad, diff) do {                  \
99   pre##_ctx *_pctx = (ictx);                                            \
100                                                                         \
101   _pctx->buf[_pctx->off] = term;                                        \
102   _pctx->off++;                                                         \
103   if (_pctx->off > PRE##_BUFSZ - diff) {                                \
104     if (_pctx->off < PRE##_BUFSZ)                                       \
105       memset(_pctx->buf + _pctx->off, pad, PRE##_BUFSZ - _pctx->off);   \
106     pre##_compress(_pctx, _pctx->buf);                                  \
107     memset(_pctx->buf, pad, PRE##_BUFSZ - diff);                        \
108   } else                                                                \
109     memset(_pctx->buf + _pctx->off, pad,                                \
110            PRE##_BUFSZ - _pctx->off - diff);                            \
111 } while (0)
112
113 /* --- @HASH_MD5STRENGTH@ --- *
114  *
115  * Arguments:   @PRE@, @pre@ = prefixes for hash-specific definitions
116  *              @ictx@ = pointer to context block for the hash
117  *
118  * Use:         Does MD5-style MD strengthening.  The data is terminated
119  *              by a single set bit, padded with zero bits, and then a 64-
120  *              bit length is written, little-end first.
121  */
122
123 #define HASH_MD5STRENGTH(PRE, pre, ictx) do {                           \
124   pre##_ctx *_mctx = (ictx);                                            \
125   HASH_PAD(PRE, pre, _mctx, 0x80u, 0, 8);                               \
126   STORE32_L(_mctx->buf + PRE##_BUFSZ - 8, _mctx->nl << 3);              \
127   STORE32_L(_mctx->buf + PRE##_BUFSZ - 4,                               \
128             (_mctx->nl >> 29) | (_mctx->nh << 3));                      \
129   pre##_compress(_mctx, _mctx->buf);                                    \
130 } while (0)
131
132 /* --- @HASH_TEST@ --- *
133  *
134  * Arguments:   @PRE@, @pre@ = prefixes for hash-specfic definitions
135  *
136  * Use:         Standard test rig for hash functions.
137  */
138
139 #ifdef TEST_RIG
140
141 #include <mLib/macros.h>
142 #include <mLib/quis.h>
143 #include <mLib/testrig.h>
144
145 #define HASH_BUFLEN 100000
146
147 #define HASH_VERIFY(PRE, pre) HASH_VERIFYX(PRE, pre, #pre)
148
149 #define HASH_VERIFYX(PRE, pre, name)                                    \
150                                                                         \
151 static int vrf_##pre(dstr *v, const test_type *msgty)                   \
152 {                                                                       \
153   pre##_ctx ctx;                                                        \
154   int ok = 1;                                                           \
155   int i;                                                                \
156   octet *p;                                                             \
157   int szs[] = { 1, 7, 192, -1, 0 }, *ip;                                \
158   size_t sz;                                                            \
159   dstr d;                                                               \
160                                                                         \
161   dstr_create(&d);                                                      \
162   dstr_ensure(&d, PRE##_HASHSZ);                                        \
163   d.len = PRE##_HASHSZ;                                                 \
164                                                                         \
165   for (ip = szs; *ip; ip++) {                                           \
166     i = *ip;                                                            \
167     sz = v[0].len;                                                      \
168     if (i == -1)                                                        \
169       i = sz;                                                           \
170     if (i > sz)                                                         \
171       continue;                                                         \
172     p = (octet *)v[0].buf;                                              \
173     pre##_init(&ctx);                                                   \
174     while (sz) {                                                        \
175       if (i > sz)                                                       \
176         i = sz;                                                         \
177       pre##_hash(&ctx, p, i);                                           \
178       p += i;                                                           \
179       sz -= i;                                                          \
180     }                                                                   \
181     pre##_done(&ctx, d.buf);                                            \
182     if (MEMCMP(d.buf, !=, v[1].buf, PRE##_HASHSZ)) {                    \
183       printf("\nfail:\n\tstep = %i\n\tinput = ", *ip);                  \
184       msgty->dump(&v[0], stdout);                                       \
185       printf("\n\texpected = ");                                        \
186       type_hex.dump(&v[1], stdout);                                     \
187       fputs("\n\tcomputed = ", stdout);                                 \
188       type_hex.dump(&d, stdout);                                        \
189       putchar('\n');                                                    \
190       ok = 0;                                                           \
191     }                                                                   \
192   }                                                                     \
193                                                                         \
194   dstr_destroy(&d);                                                     \
195   return (ok);                                                          \
196 }                                                                       \
197                                                                         \
198 static int vrf_##pre##_hex(dstr *v)                                     \
199   { return vrf_##pre(v, &type_hex); }                                   \
200 static int vrf_##pre##_lit(dstr *v)                                     \
201   { return vrf_##pre(v, &type_string); }                                \
202                                                                         \
203 static int vrf_##pre##_rep(dstr *v)                                     \
204 {                                                                       \
205   pre##_ctx ctx;                                                        \
206   size_t len = v[0].len;                                                \
207   int n = *(int *)v[1].buf;                                             \
208   int nd = 0;                                                           \
209   int nn = len;                                                         \
210   int ok = 1;                                                           \
211   octet *p, *q;                                                         \
212   dstr d = DSTR_INIT;                                                   \
213                                                                         \
214   while (nn < HASH_BUFLEN && (n & 1) == 0) { nd++; nn <<= 1; n >>= 1; } \
215   p = xmalloc(nn);                                                      \
216   memcpy(p, v[0].buf, len);                                             \
217   q = p + len;                                                          \
218   while (nd--) { memcpy(q, p, len); q += len; len <<= 1; }              \
219                                                                         \
220   dstr_ensure(&d, PRE##_HASHSZ);                                        \
221   d.len = PRE##_HASHSZ;                                                 \
222   pre##_init(&ctx);                                                     \
223   while (n--) pre##_hash(&ctx, p, len);                                 \
224   pre##_done(&ctx, d.buf);                                              \
225                                                                         \
226   if (MEMCMP(d.buf, !=, v[2].buf, PRE##_HASHSZ)) {                      \
227     printf("\nfail:\n\tinput = `%s'\n\treps = `%i'\n\texpected = ",     \
228              v[0].buf, *(int *)v[1].buf);                               \
229     type_hex.dump(&v[2], stdout);                                       \
230     fputs("\n\tcomputed = ", stdout);                                   \
231     type_hex.dump(&d, stdout);                                          \
232     putchar('\n');                                                      \
233     ok = 0;                                                             \
234   }                                                                     \
235   xfree(p);                                                             \
236   dstr_destroy(&d);                                                     \
237   return (ok);                                                          \
238 }
239
240 #define HASH_TESTDEFS(PRE, pre) HASH_TESTDEFSX(PRE, pre, #pre)
241
242 #define HASH_TESTDEFSX(PRE, pre, name)                                  \
243   { name, vrf_##pre##_lit, { &type_string, &type_hex, 0 } },            \
244   { name "-hex", vrf_##pre##_hex, { &type_hex, &type_hex, 0 } },        \
245   { name "-rep", vrf_##pre##_rep,                                       \
246     { &type_string, &type_int, &type_hex, 0 } },
247
248 #define HASH_TESTX(PRE, pre, name, fname)                               \
249                                                                         \
250 HASH_VERIFYX(PRE, pre, name)                                            \
251                                                                         \
252 static test_chunk defs[] = {                                            \
253   HASH_TESTDEFSX(PRE, pre, name)                                        \
254   { 0, 0, { 0 } }                                                       \
255 };                                                                      \
256                                                                         \
257 int main(int argc, char *argv[])                                        \
258 {                                                                       \
259   ego(argv[0]);                                                         \
260   test_run(argc, argv, defs, SRCDIR"/t/" fname);                        \
261   return (0);                                                           \
262 }
263
264 #else
265 #  define HASH_TESTX(PRE, pre, name, fname)
266 #endif
267
268 #define HASH_TEST(PRE, pre) HASH_TESTX(PRE, pre, #pre, #pre)
269
270 /*----- That's all, folks -------------------------------------------------*/
271
272 #ifdef __cplusplus
273   }
274 #endif
275
276 #endif