chiark / gitweb /
ec-bin (ec_binproj): Make curve setup faster.
[catacomb] / whirlpool.c
1 /* -*-c-*-
2  *
3  * $Id$
4  *
5  * Whirlpool hash function
6  *
7  * (c) 2005 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 /*----- Header files ------------------------------------------------------*/
31
32 #include <mLib/bits.h>
33
34 #include "ghash.h"
35 #include "ghash-def.h"
36 #include "hash.h"
37 #include "whirlpool.h"
38 #include "whirlpool-tab.h"
39
40 #if defined(HAVE_UINT64)
41 #  define USE64
42 #endif
43
44 /*----- Static variables --------------------------------------------------*/
45
46 static const kludge64 C[10] = WHIRLPOOL_C;
47
48 #ifdef USE64
49 static const kludge64 T[8][256] = WHIRLPOOL_T;
50 #else
51 static const uint32 U[4][256] = WHIRLPOOL_U, V[4][256] = WHIRLPOOL_V;
52 #endif
53
54 /*----- Main code ---------------------------------------------------------*/
55
56 #define DUMP(k, v) do {                                                 \
57   int i;                                                                \
58   printf("\n");                                                         \
59   for (i = 0; i < 8; i++)                                               \
60     printf("  %08x %08x  :  %08x %08x\n",                               \
61            HI64(k[i]), LO64(k[i]),                                      \
62            HI64(v[i]), LO64(v[i]));                                     \
63 } while (0)
64
65 #define OFFSET(i, n) (((i) + 16 - (n)) % 8)
66
67 #ifdef USE64
68
69 #define BYTE(x, j)                                                      \
70   U8((j) < 4 ?                                                          \
71     (LO64(x) >> ((j) * 8)) :                                            \
72     (HI64(x) >> ((j) * 8 - 32)))
73
74 #define TT(v, i, j) T[j][BYTE(v[OFFSET(i, j)], j)]
75
76 #define XROW(vv, v, i) do {                                             \
77   XOR64(vv[i], vv[i], TT(v, i, 1));                                     \
78   XOR64(vv[i], vv[i], TT(v, i, 2));                                     \
79   XOR64(vv[i], vv[i], TT(v, i, 3));                                     \
80   XOR64(vv[i], vv[i], TT(v, i, 4));                                     \
81   XOR64(vv[i], vv[i], TT(v, i, 5));                                     \
82   XOR64(vv[i], vv[i], TT(v, i, 6));                                     \
83   XOR64(vv[i], vv[i], TT(v, i, 7));                                     \
84 } while (0)
85
86 #define ROWZ(vv, v, i) do {                                             \
87   vv[i] = TT(v, i, 0);                                                  \
88   XROW(vv, v, i);                                                       \
89 } while (0)
90
91 #define ROWK(vv, v, i, k) do {                                          \
92   vv[i] = k;                                                            \
93   XOR64(vv[i], vv[i], TT(v, i, 0));                                     \
94   XROW(vv, v, i);                                                       \
95 } while (0)
96
97 #else
98
99 #define BYTE(x, j) U8((x) >> (((j) & 3) * 8))
100
101 #define UUL(v, i, j) U[j & 3][BYTE(v[OFFSET(i, j)].lo, j)]
102 #define VVL(v, i, j) V[j & 3][BYTE(v[OFFSET(i, j)].lo, j)]
103 #define UUH(v, i, j) U[j & 3][BYTE(v[OFFSET(i, j)].hi, j)]
104 #define VVH(v, i, j) V[j & 3][BYTE(v[OFFSET(i, j)].hi, j)]
105
106 #define XROW(vv, v, i) do {                                             \
107   vv[i].lo ^= UUL(v, i, 1); vv[i].hi ^= VVL(v, i, 1);                   \
108   vv[i].lo ^= UUL(v, i, 2); vv[i].hi ^= VVL(v, i, 2);                   \
109   vv[i].lo ^= UUL(v, i, 3); vv[i].hi ^= VVL(v, i, 3);                   \
110   vv[i].lo ^= VVH(v, i, 4); vv[i].hi ^= UUH(v, i, 4);                   \
111   vv[i].lo ^= VVH(v, i, 5); vv[i].hi ^= UUH(v, i, 5);                   \
112   vv[i].lo ^= VVH(v, i, 6); vv[i].hi ^= UUH(v, i, 6);                   \
113   vv[i].lo ^= VVH(v, i, 7); vv[i].hi ^= UUH(v, i, 7);                   \
114 } while (0)
115
116 #define ROWZ(vv, v, i) do {                                             \
117   vv[i].lo = UUL(v, i, 0);  vv[i].hi = VVL(v, i, 0);                    \
118   XROW(vv, v, i);                                                       \
119 } while (0)
120
121 #define ROWK(vv, v, i, k) do {                                          \
122   vv[i] = k;                                                            \
123   vv[i].lo ^= UUL(v, i, 0); vv[i].hi ^= VVL(v, i, 0);                   \
124   XROW(vv, v, i);                                                       \
125 } while (0)
126   
127 #endif
128
129 #define RHO(vv, v, kk, k) do {                                          \
130   ROWK(kk, k, 0, *c++);   ROWK(vv, v, 0, kk[0]);                        \
131   ROWZ(kk, k, 1);         ROWK(vv, v, 1, kk[1]);                        \
132   ROWZ(kk, k, 2);         ROWK(vv, v, 2, kk[2]);                        \
133   ROWZ(kk, k, 3);         ROWK(vv, v, 3, kk[3]);                        \
134   ROWZ(kk, k, 4);         ROWK(vv, v, 4, kk[4]);                        \
135   ROWZ(kk, k, 5);         ROWK(vv, v, 5, kk[5]);                        \
136   ROWZ(kk, k, 6);         ROWK(vv, v, 6, kk[6]);                        \
137   ROWZ(kk, k, 7);         ROWK(vv, v, 7, kk[7]);                        \
138 } while (0)
139
140 void whirlpool_compress(whirlpool_ctx *ctx, const void *sbuf)
141 {
142   kludge64 m[8], k[8], kk[8], v[8], vv[8];
143   const kludge64 *c = C;
144   const octet *s = sbuf;
145   int i;
146   
147   for (i = 0; i < 8; i++) {
148     LOAD64_L_(m[i], &s[i * 8]);
149     XOR64(v[i], m[i], ctx->s[i]);
150   }
151
152   RHO(vv, v, kk, ctx->s);
153   RHO(v, vv, k, kk);
154   RHO(vv, v, kk, k);
155   RHO(v, vv, k, kk);
156   RHO(vv, v, kk, k);
157   RHO(v, vv, k, kk);
158   RHO(vv, v, kk, k);
159   RHO(v, vv, k, kk);
160   RHO(vv, v, kk, k);
161   RHO(v, vv, k, kk);
162
163   for (i = 0; i < 8; i++) {
164     XOR64(ctx->s[i], ctx->s[i], m[i]);
165     XOR64(ctx->s[i], ctx->s[i], v[i]);
166   }
167 }
168
169 /* --- @whirlpool_init@, @whirlpool256_init@ --- *
170  *
171  * Arguments:   @whirlpool_ctx *ctx@ = pointer to context block to initialize
172  *
173  * Returns:     ---
174  *
175  * Use:         Initializes a context block ready for hashing.
176  */
177
178 void whirlpool_init(whirlpool_ctx *ctx)
179 {
180   int i;
181
182   for (i = 0; i < 8; i++)
183     SET64(ctx->s[i], 0, 0);
184   ctx->off = 0;
185   ctx->nh = ctx->nl = 0;
186 }
187
188 /* --- @whirlpool_set@, @whirlpool256_set@ --- *
189  *
190  * Arguments:   @whirlpool_ctx *ctx@ = pointer to context block
191  *              @const void *buf@ = pointer to state buffer
192  *              @unsigned long count@ = current count of bytes processed
193  *
194  * Returns:     ---
195  *
196  * Use:         Initializes a context block from a given state.  This is
197  *              useful in cases where the initial hash state is meant to be
198  *              secret, e.g., for NMAC and HMAC support.
199  */
200
201 void whirlpool_set(whirlpool_ctx *ctx, const void *buf, unsigned long count)
202 {
203   const octet *p = buf;
204   int i;
205
206   for (i = 0; i < 8; i++) {
207     LOAD64_L_(ctx->s[i], p);
208     p += 8;
209   }
210   ctx->off = 0;
211   ctx->nl = U32(count);
212   ctx->nh = U32(((count & ~MASK32) >> 16) >> 16);
213 }
214
215 /* --- @whirlpool_hash@, @whirlpool256_hash@ --- *
216  *
217  * Arguments:   @whirlpool_ctx *ctx@ = pointer to context block
218  *              @const void *buf@ = buffer of data to hash
219  *              @size_t sz@ = size of buffer to hash
220  *
221  * Returns:     ---
222  *
223  * Use:         Hashes a buffer of data.  The buffer may be of any size and
224  *              alignment.
225  */
226
227 void whirlpool_hash(whirlpool_ctx *ctx, const void *buf, size_t sz)
228 {
229   HASH_BUFFER(WHIRLPOOL, whirlpool, ctx, buf, sz);
230 }
231
232 /* --- @whirlpool_done@, @whirlpool256_done@ --- *
233  *
234  * Arguments:   @whirlpool_ctx *ctx@ = pointer to context block
235  *              @void *hash@ = pointer to output buffer
236  *
237  * Returns:     ---
238  *
239  * Use:         Returns the hash of the data read so far.
240  */
241
242 static void final(whirlpool_ctx *ctx)
243 {
244   HASH_PAD(WHIRLPOOL, whirlpool, ctx, 0x80, 0, 32);
245   memset(ctx->buf + WHIRLPOOL_BUFSZ - 32, 0, 24);
246   STORE32(ctx->buf + WHIRLPOOL_BUFSZ -  8, (ctx->nl >> 29) | (ctx->nh << 3));
247   STORE32(ctx->buf + WHIRLPOOL_BUFSZ -  4, ctx->nl << 3);
248   whirlpool_compress(ctx, ctx->buf);
249 }
250
251 void whirlpool_done(whirlpool_ctx *ctx, void *hash)
252 {
253   octet *p = hash;
254   int i;
255
256   final(ctx);
257   for (i = 0; i < 8; i++) {
258     STORE64_L_(p, ctx->s[i]);
259     p += 8;
260   }
261 }
262
263 void whirlpool256_done(whirlpool256_ctx *ctx, void *hash)
264 {
265   octet *p = hash;
266   int i;
267
268   final(ctx);
269   for (i = 0; i < 4; i++) {
270     STORE64_L_(p, ctx->s[i]);
271     p += 8;
272   }
273 }
274
275 /* --- @whirlpool_state@, @whirlpool256_state@ --- *
276  *
277  * Arguments:   @whirlpool_ctx *ctx@ = pointer to context
278  *              @void *state@ = pointer to buffer for current state
279  *
280  * Returns:     Number of bytes written to the hash function so far.
281  *
282  * Use:         Returns the current state of the hash function such that
283  *              it can be passed to @whirlpool_set@.
284  */
285
286 unsigned long whirlpool_state(whirlpool_ctx *ctx, void *state)
287 {
288   octet *p = state;
289   int i;
290
291   for (i = 0; i < 8; i++) {
292     STORE64_L_(p, ctx->s[i]);
293     p += 8;
294   }
295   return (ctx->nl | ((ctx->nh << 16) << 16));
296 }
297
298 /* --- Generic interface --- */
299
300 GHASH_DEF(WHIRLPOOL, whirlpool)
301
302 /* --- Test code --- */
303
304 HASH_TEST(WHIRLPOOL, whirlpool)
305
306 /*----- That's all, folks -------------------------------------------------*/