1/********************************************************************\
2 *
3 *      FILE:     hashtest.c
4 *
5 *      CONTENTS: test file for sample C-implementation of
6 *                RIPEMD-160 and RIPEMD128
7 *        * command line arguments:
8 *           filename  -- compute hash code of file read binary
9 *           -sstring  -- print string & hashcode
10 *           -t        -- perform time trial
11 *           -x        -- execute standard test suite, ASCII input
12 *        * for linkage with rmd128.c: define RMDsize as 128
13 *          for linkage with rmd160.c: define RMDsize as 160 (default)
14 *      TARGET:   any computer with an ANSI C compiler
15 *
16 *      AUTHOR:   Antoon Bosselaers, ESAT-COSIC
17 *      DATE:     18 April 1996
18 *      VERSION:  1.1
19 *      HISTORY:  bug in RMDonemillion() corrected
20 *
21 *      Copyright (c) Katholieke Universiteit Leuven
22 *      1996, All Rights Reserved
23 *
24\********************************************************************/
25#ifndef RMDsize
26#define RMDsize 160
27#endif
28
29#include <stdio.h>
30#include <stdlib.h>
31#include <time.h>
32#include <string.h>
33#if RMDsize == 128
34#include "rmd128.h"
35#elif RMDsize == 160
36#include "rmd160.h"
37#endif
38
39#define TEST_BLOCK_SIZE 8000
40#define TEST_BLOCKS 1250
41#define TEST_BYTES ((long)TEST_BLOCK_SIZE * (long)TEST_BLOCKS)
42
43/********************************************************************/
44
45byte *RMD(byte *message)
46/*
47 * returns RMD(message)
48 * message should be a string terminated by '\0'
49 */
50{
51   dword         MDbuf[RMDsize/32];   /* contains (A, B, C, D(, E))   */
52   static byte   hashcode[RMDsize/8]; /* for final hash-value         */
53   dword         X[16];               /* current 16-word chunk        */
54   word          i;                   /* counter                      */
55   dword         length;              /* length in bytes of message   */
56   dword         nbytes;              /* # of bytes not yet processed */
57
58   /* initialize */
59   MDinit(MDbuf);
60   length = (dword)strlen((char *)message);
61
62   /* process message in 16-word chunks */
63   for (nbytes=length; nbytes > 63; nbytes-=64) {
64      for (i=0; i<16; i++) {
65         X[i] = BYTES_TO_DWORD(message);
66         message += 4;
67      }
68      compress(MDbuf, X);
69   }                                    /* length mod 64 bytes left */
70
71   /* finish: */
72   MDfinish(MDbuf, message, length, 0);
73
74   for (i=0; i<RMDsize/8; i+=4) {
75      hashcode[i]   =  MDbuf[i>>2];         /* implicit cast to byte  */
76      hashcode[i+1] = (MDbuf[i>>2] >>  8);  /*  extracts the 8 least  */
77      hashcode[i+2] = (MDbuf[i>>2] >> 16);  /*  significant bits.     */
78      hashcode[i+3] = (MDbuf[i>>2] >> 24);
79   }
80
81   return (byte *)hashcode;
82}
83
84/********************************************************************/
85
86byte *RMDbinary(char *fname)
87/*
88 * returns RMD(message in file fname)
89 * fname is read as binary data.
90 */
91{
92   FILE         *mf;                  /* pointer to file <fname>      */
93   byte          data[1024];          /* contains current mess. block */
94   dword         nbytes;              /* length of this block         */
95   dword         MDbuf[RMDsize/32];   /* contains (A, B, C, D(, E))   */
96   static byte   hashcode[RMDsize/8]; /* for final hash-value         */
97   dword         X[16];               /* current 16-word chunk        */
98   word          i, j;                /* counters                     */
99   dword         length[2];           /* length in bytes of message   */
100   dword         offset;              /* # of unprocessed bytes at    */
101                                      /*          call of MDfinish    */
102
103   /* initialize */
104   if ((mf = fopen(fname, "rb")) == NULL) {
105      fprintf(stderr, "\nRMDbinary: cannot open file \"%s\".\n",
106              fname);
107      exit(1);
108   }
109   MDinit(MDbuf);
110   length[0] = 0;
111   length[1] = 0;
112
113   while ((nbytes = fread(data, 1, 1024, mf)) != 0) {
114      /* process all complete blocks */
115      for (i=0; i<(nbytes>>6); i++) {
116         for (j=0; j<16; j++)
117            X[j] = BYTES_TO_DWORD(data+64*i+4*j);
118         compress(MDbuf, X);
119      }
120      /* update length[] */
121      if (length[0] + nbytes < length[0])
122         length[1]++;                  /* overflow to msb of length */
123      length[0] += nbytes;
124   }
125
126   /* finish: */
127   offset = length[0] & 0x3C0;   /* extract bytes 6 to 10 inclusive */
128   MDfinish(MDbuf, data+offset, length[0], length[1]);
129
130   for (i=0; i<RMDsize/8; i+=4) {
131      hashcode[i]   =  MDbuf[i>>2];
132      hashcode[i+1] = (MDbuf[i>>2] >>  8);
133      hashcode[i+2] = (MDbuf[i>>2] >> 16);
134      hashcode[i+3] = (MDbuf[i>>2] >> 24);
135   }
136
137   fclose(mf);
138
139   return (byte *)hashcode;
140}
141
142/********************************************************************/
143
144void speedtest(void)
145/*
146 * A time trial routine, to measure the speed of ripemd.
147 * Measures processor time required to process TEST_BLOCKS times
148 *  a message of TEST_BLOCK_SIZE characters.
149 */
150{
151   clock_t    t0, t1;
152   byte      *data;
153   byte       hashcode[RMDsize/8];
154   dword      X[16];
155   dword      MDbuf[RMDsize/32];
156   word       i, j, k;
157
158   srand(time(NULL));
159
160   /* allocate and initialize test data */
161   if ((data = (byte*)malloc(TEST_BLOCK_SIZE)) == NULL) {
162      fprintf(stderr, "speedtest: allocation error\n");
163      exit(1);
164   }
165   for (i=0; i<TEST_BLOCK_SIZE; i++)
166      data[i] = (byte)(rand() >> 7);
167
168   /* start timer */
169   printf("RIPEMD time trial. Processing %ld characters...\n",
170          TEST_BYTES);
171   t0 = clock();
172
173   /* process data */
174   MDinit(MDbuf);
175   for (i=0; i<TEST_BLOCKS; i++) {
176      for (j=0; j<TEST_BLOCK_SIZE; j+=64) {
177         for (k=0; k<16; k++)
178            X[k] = BYTES_TO_DWORD(data+j+4*k);
179         compress(MDbuf, X);
180      }
181   }
182   MDfinish(MDbuf, data, TEST_BYTES, 0);
183
184   /* stop timer, get time difference */
185   t1 = clock();
186   printf("\nTest input processed in %g seconds.\n",
187          (double)(t1-t0)/(double)CLOCKS_PER_SEC);
188   printf("Characters processed per second: %g\n",
189          (double)CLOCKS_PER_SEC*TEST_BYTES/((double)t1-t0));
190
191   for (i=0; i<RMDsize/8; i+=4) {
192      hashcode[i]   =  MDbuf[i>>2];
193      hashcode[i+1] = (MDbuf[i>>2] >>  8);
194      hashcode[i+2] = (MDbuf[i>>2] >> 16);
195      hashcode[i+3] = (MDbuf[i>>2] >> 24);
196   }
197   printf("\nhashcode: ");
198   for (i=0; i<RMDsize/8; i++)
199      printf("%02x", hashcode[i]);
200
201   free(data);
202   return;
203}
204
205/********************************************************************/
206
207void RMDonemillion(void)
208/*
209 * returns RMD() of message consisting of 1 million 'a' characters
210 */
211{
212   dword         MDbuf[RMDsize/32];   /* contains (A, B, C, D(, E)) */
213   static byte   hashcode[RMDsize/8]; /* for final hash-value       */
214   dword         X[16];               /* current 16-word chunk      */
215   word          i;                   /* counter                    */
216
217   MDinit(MDbuf);
218   memcpy(X, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 32);
219   memcpy(X+8, X, 32);
220   for (i=15625; i>0; i--)
221      compress(MDbuf, X);
222   MDfinish(MDbuf, NULL, 1000000UL, 0);
223   for (i=0; i<RMDsize/8; i+=4) {
224      hashcode[i]   =  MDbuf[i>>2];
225      hashcode[i+1] = (MDbuf[i>>2] >>  8);
226      hashcode[i+2] = (MDbuf[i>>2] >> 16);
227      hashcode[i+3] = (MDbuf[i>>2] >> 24);
228   }
229   printf("\n* message: 1 million times \"a\"\n  hashcode: ");
230   for (i=0; i<RMDsize/8; i++)
231      printf("%02x", hashcode[i]);
232
233}
234
235/********************************************************************/
236
237void RMDstring(char *message, char *print)
238{
239   int i;
240   byte *hashcode;
241
242   hashcode = RMD((byte *)message);
243   printf("\n* message: %s\n  hashcode: ", print);
244   for (i=0; i<RMDsize/8; i++)
245      printf("%02x", hashcode[i]);
246}
247
248/********************************************************************/
249
250void testsuite (void)
251/*
252 *   standard test suite
253 */
254{
255   printf("\nRIPEMD-%u test suite results (ASCII):\n", RMDsize);
256
257   RMDstring("", "\"\" (empty string)");
258   RMDstring("a", "\"a\"");
259   RMDstring("abc", "\"abc\"");
260   RMDstring("message digest", "\"message digest\"");
261   RMDstring("abcdefghijklmnopqrstuvwxyz", "\"abcdefghijklmnopqrstuvwxyz\"");
262   RMDstring("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
263             "\"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq\"");
264   RMDstring("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
265             "\"A...Za...z0...9\"");
266   RMDstring("1234567890123456789012345678901234567890"
267             "1234567890123456789012345678901234567890",
268             "8 times \"1234567890\"");
269   RMDonemillion();
270
271   return;
272}
273
274/********************************************************************/
275
276main (int argc, char *argv[])
277/*
278 *  main program. calls one or more of the test routines depending
279 *  on command line arguments. see the header of this file.
280 *
281 */
282{
283  int   i, j;
284  byte *hashcode;
285
286   if (argc == 1) {
287      printf("For each command line argument in turn:\n");
288      printf("  filename  -- compute hash code of file binary read\n");
289      printf("  -sstring  -- print string & hashcode\n");
290      printf("  -t        -- perform time trial\n");
291      printf("  -x        -- execute standard test suite, ASCII input\n");
292   }
293   else {
294      for (i = 1; i < argc; i++) {
295         if (argv[i][0] == '-' && argv[i][1] == 's') {
296            printf("\n\nmessage: %s", argv[i]+2);
297            hashcode = RMD((byte *)argv[i] + 2);
298            printf("\nhashcode: ");
299            for (j=0; j<RMDsize/8; j++)
300               printf("%02x", hashcode[j]);
301         }
302         else if (strcmp (argv[i], "-t") == 0)
303            speedtest ();
304         else if (strcmp (argv[i], "-x") == 0)
305            testsuite ();
306         else {
307            hashcode = RMDbinary (argv[i]);
308            printf("\n\nmessagefile (binary): %s", argv[i]);
309            printf("\nhashcode: ");
310            for (j=0; j<RMDsize/8; j++)
311               printf("%02x", hashcode[j]);
312         }
313      }
314   }
315   printf("\n");
316
317   return 0;
318}
319
320/********************** end of file hashtest.c **********************/
321
322