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