start of new file
[IRC.git] / Robust / src / Benchmarks / Prefetch / Crypt / java / JGFCryptBench.java
1 /**************************************************************************
2  *                                                                         *
3  *         Java Grande Forum Benchmark Suite - Thread Version 1.0          *
4  *                                                                         *
5  *                            produced by                                  *
6  *                                                                         *
7  *                  Java Grande Benchmarking Project                       *
8  *                                                                         *
9  *                                at                                       *
10  *                                                                         *
11  *                Edinburgh Parallel Computing Centre                      *
12  *                                                                         * 
13  *                email: epcc-javagrande@epcc.ed.ac.uk                     *
14  *                                                                         *
15  *                                                                         *
16  *      This version copyright (c) The University of Edinburgh, 2001.      *
17  *                         All rights reserved.                            *
18  *                                                                         *
19  **************************************************************************/
20 /**************************************************************************
21  *                       Ported for DSTM Benchmark                         *
22  **************************************************************************/
23 import java.util.*;
24
25 public class JGFCryptBench { 
26
27   private int size; 
28   private int datasizes[];
29   public int nthreads;
30   int array_rows; 
31
32   byte [] plain1;       // Buffer for plaintext data.
33   byte [] crypt1;       // Buffer for encrypted data.
34   byte [] plain2;       // Buffer for decrypted data.
35
36   short [] userkey;     // Key for encryption/decryption.
37   int [] Z;             // Encryption subkey (userkey derived).
38   int [] DK;            // Decryption subkey (userkey derived).
39
40
41   //
42   // buildTestData
43   //Builds the data used for the test -- each time the test is run.
44   void buildTestData()
45   {
46
47
48     // Create three byte arrays that will be used (and reused) for
49     // encryption/decryption operations.
50
51
52     plain1 = new byte [array_rows];
53     crypt1 = new byte [array_rows];
54     plain2 = new byte [array_rows];
55
56
57     Random rndnum = new Random(136506717L);  // Create random number generator.
58
59
60     // Allocate three arrays to hold keys: userkey is the 128-bit key.
61     // Z is the set of 16-bit encryption subkeys derived from userkey,
62     // while DK is the set of 16-bit decryption subkeys also derived
63     // from userkey. NOTE: The 16-bit values are stored here in
64     // 32-bit int arrays so that the values may be used in calculations
65     // as if they are unsigned. Each 64-bit block of plaintext goes
66     // through eight processing rounds involving six of the subkeys
67     // then a final output transform with four of the keys; (8 * 6)
68     // + 4 = 52 subkeys.
69
70     userkey = new short [8];  // User key has 8 16-bit shorts.
71     Z = new int [52];         // Encryption subkey (user key derived).
72     DK = new int [52];        // Decryption subkey (user key derived).
73
74     // Generate user key randomly; eight 16-bit values in an array.
75
76     for (int i = 0; i < 8; i++)
77     {
78       // Again, the random number function returns int. Converting
79       // to a short type preserves the bit pattern in the lower 16
80       // bits of the int and discards the rest.
81
82       userkey[i] = (short) rndnum.nextInt();
83     }
84
85     // Compute encryption and decryption subkeys.
86
87     calcEncryptKey();
88     calcDecryptKey();
89
90     // Fill plain1 with "text."
91     for (int i = 0; i < array_rows; i++)
92     {
93       plain1[i] = (byte) i; 
94
95       // Converting to a byte
96       // type preserves the bit pattern in the lower 8 bits of the
97       // int and discards the rest.
98     }
99   }
100
101
102   // calcEncryptKey
103
104   // Builds the 52 16-bit encryption subkeys Z[] from the user key and
105   //stores in 32-bit int array. The routing corrects an error in the
106   //source code in the Schnier book. Basically, the sense of the 7-
107   //and 9-bit shifts are reversed. It still works reversed, but would
108   //encrypted code would not decrypt with someone else's IDEA code.
109   //
110
111   private void calcEncryptKey()
112   {
113     int j;                       // Utility variable.
114
115     for (int i = 0; i < 52; i++) // Zero out the 52-int Z array.
116       Z[i] = 0;
117
118     for (int i = 0; i < 8; i++)  // First 8 subkeys are userkey itself.
119     {
120       Z[i] = userkey[i] & 0xffff;     // Convert "unsigned"
121       // short to int.
122     }
123
124     // Each set of 8 subkeys thereafter is derived from left rotating
125     // the whole 128-bit key 25 bits to left (once between each set of
126     // eight keys and then before the last four). Instead of actually
127     // rotating the whole key, this routine just grabs the 16 bits
128     // that are 25 bits to the right of the corresponding subkey
129     // eight positions below the current subkey. That 16-bit extent
130     // straddles two array members, so bits are shifted left in one
131     // member and right (with zero fill) in the other. For the last
132     // two subkeys in any group of eight, those 16 bits start to
133     // wrap around to the first two members of the previous eight.
134
135     for (int i = 8; i < 52; i++)
136     {
137       int flag1 = 0;
138       j = i % 8;
139       if (j < 6)
140       {
141         Z[i] = ((Z[i -7]>>>9) | (Z[i-6]<<7)) // Shift and combine.
142           & 0xFFFF;                    // Just 16 bits.
143         //continue;                            // Next iteration.
144         flag1 = 1;
145       }
146
147       if(flag1 == 0) {
148         int flag2 = 0;
149
150         if (j == 6)    // Wrap to beginning for second chunk.
151         {
152           Z[i] = ((Z[i -7]>>>9) | (Z[i-14]<<7))
153             & 0xFFFF;
154           //continue;
155           flag2 = 1;
156         }
157
158         if(flag2 == 0) {
159           // j == 7 so wrap to beginning for both chunks.
160           Z[i] = ((Z[i -15]>>>9) | (Z[i-14]<<7))
161             & 0xFFFF;
162         }
163       }
164     }
165   }
166
167   //
168   //calcDecryptKey
169   //
170   //Builds the 52 16-bit encryption subkeys DK[] from the encryption-
171   //subkeys Z[]. DK[] is a 32-bit int array holding 16-bit values as
172   //unsigned.
173   //
174
175   private void calcDecryptKey()
176   {
177     int j, k;                 // Index counters.
178     int t1, t2, t3;           // Temps to hold decrypt subkeys.
179
180     t1 = inv(Z[0]);           // Multiplicative inverse (mod x10001).
181     t2 = - Z[1] & 0xffff;     // Additive inverse, 2nd encrypt subkey.
182     t3 = - Z[2] & 0xffff;     // Additive inverse, 3rd encrypt subkey.
183
184     DK[51] = inv(Z[3]);       // Multiplicative inverse (mod x10001).
185     DK[50] = t3;
186     DK[49] = t2;
187     DK[48] = t1;
188
189     j = 47;                   // Indices into temp and encrypt arrays.
190     k = 4;
191     for (int i = 0; i < 7; i++)
192     {
193       t1 = Z[k++];
194       DK[j--] = Z[k++];
195       DK[j--] = t1;
196       t1 = inv(Z[k++]);
197       t2 = -Z[k++] & 0xffff;
198       t3 = -Z[k++] & 0xffff;
199       DK[j--] = inv(Z[k++]);
200       DK[j--] = t2;
201       DK[j--] = t3;
202       DK[j--] = t1;
203     }
204
205     t1 = Z[k++];
206     DK[j--] = Z[k++];
207     DK[j--] = t1;
208     t1 = inv(Z[k++]);
209     t2 = -Z[k++] & 0xffff;
210     t3 = -Z[k++] & 0xffff;
211     DK[j--] = inv(Z[k++]);
212     DK[j--] = t3;
213     DK[j--] = t2;
214     DK[j--] = t1;
215   }
216
217
218   //
219   //mul
220   //
221   // Performs multiplication, modulo (2**16)+1. This code is structured
222   // on the assumption that untaken branches are cheaper than taken
223   // branches, and that the compiler doesn't schedule branches.
224   // Java: Must work with 32-bit int and one 64-bit long to keep
225   // 16-bit values and their products "unsigned." The routine assumes
226   // that both a and b could fit in 16 bits even though they come in
227   // as 32-bit ints. Lots of "& 0xFFFF" masks here to keep things 16-bit.
228   // Also, because the routine stores mod (2**16)+1 results in a 2**16
229   // space, the result is truncated to zero whenever the result would
230   // zero, be 2**16. And if one of the multiplicands is 0, the result
231   // is not zero, but (2**16) + 1 minus the other multiplicand (sort
232   // of an additive inverse mod 0x10001).
233
234   // NOTE: The java conversion of this routine works correctly, but
235   // is half the speed of using Java's modulus division function (%)
236   // on the multiplication with a 16-bit masking of the result--running
237   // in the Symantec Caje IDE. So it's not called for now; the test
238   // uses Java % instead.
239   //
240
241   private int mul(int a, int b)
242   {
243     int ret;
244     long p;             // Large enough to catch 16-bit multiply
245     // without hitting sign bit.
246     if (a != 0)
247     {
248       if(b != 0)
249       {
250         p = (long) a * b;
251         b = (int) p & 0xFFFF;       // Lower 16 bits.
252         a = (int) p >>> 16;         // Upper 16 bits.
253         if (b < a)
254           return (b - a + 1) & 0xFFFF;
255         else
256           return (b - a) & 0xFFFF;
257       }
258       else
259         return ((1 - a) & 0xFFFF);  // If b = 0, then same as
260       // 0x10001 - a.
261     }
262     else                                // If a = 0, then return
263       return((1 - b) & 0xFFFF);       // same as 0x10001 - b.
264   }
265
266   //
267   // inv
268   //
269   // Compute multiplicative inverse of x, modulo (2**16)+1 using
270   // extended Euclid's GCD (greatest common divisor) algorithm.
271   // It is unrolled twice to avoid swapping the meaning of
272   // the registers. And some subtracts are changed to adds.
273   // Java: Though it uses signed 32-bit ints, the interpretation
274   // of the bits within is strictly unsigned 16-bit.
275   //
276
277   private int inv(int x)
278   {
279     int t0, t1;
280     int q, y;
281
282     if (x <= 1)             // Assumes positive x.
283       return(x);          // 0 and 1 are self-inverse.
284
285     t1 = 0x10001 / x;       // (2**16+1)/x; x is >= 2, so fits 16 bits.
286     y = 0x10001 % x;
287     if (y == 1)
288       return((1 - t1) & 0xFFFF);
289
290     t0 = 1;
291     do {
292       q = x / y;
293       x = x % y;
294       t0 += q * t1;
295       if (x == 1) return(t0);
296       q = y / x;
297       y = y % x;
298       t1 += q * t0;
299     } while (y != 1);
300
301     return((1 - t1) & 0xFFFF);
302   }
303
304   //
305   // freeTestData
306   //
307   // Nulls arrays and forces garbage collection to free up memory.
308   //
309
310   void freeTestData(int array_rows)
311   {
312     for(int i = 0; i<array_rows; i++) {
313       plain1[i] = (byte) 0;
314       crypt1[i] = (byte) 0;
315       plain2[i] = (byte) 0;
316     }
317
318     for(int i = 0; i<8; i++) {
319       userkey[i] = (short) 0;
320     }
321
322     for(int i = 0; i<52; i++) {
323       Z[i] = 0;
324       DK[i] = 0;
325     }
326
327     //System.gc();                // Force garbage collection.
328   }
329
330
331   public JGFCryptBench(int nthreads)
332   {
333     this.nthreads=nthreads;
334     datasizes = new int[3];
335     datasizes[0] = 3000000;
336     datasizes[1] = 20000000;
337     datasizes[2] = 50000000;
338   }
339
340
341   public void JGFsetsize(int size){
342     this.size = size;
343   }
344
345   public void JGFinitialise(){
346     array_rows = datasizes[size];
347     buildTestData();
348   }
349
350   /*
351   public void JGFkernel(){
352     Do(); 
353   }
354   */
355
356   public void JGFvalidate(){
357     boolean error;
358
359     error = false; 
360     for (int i = 0; i < array_rows; i++){
361       error = (plain1 [i] != plain2 [i]); 
362       if (error){
363         System.out.println("Validation failed");
364         System.out.println("Original Byte " + i + " = " + plain1[i]); 
365         System.out.println("Encrypted Byte " + i + " = " + crypt1[i]); 
366         System.out.println("Decrypted Byte " + i + " = " + plain2[i]); 
367         break;
368       }
369     }
370   }
371
372
373   public void JGFtidyup(){
374     freeTestData(array_rows); 
375   }  
376
377   /*
378   public void JGFrun(int size){
379     instr.addTimer("Section2:Crypt:Kernel", "Kbyte",size);
380     JGFsetsize(size); 
381     JGFinitialise(); 
382     JGFkernel(); 
383     JGFvalidate(); 
384     JGFtidyup(); 
385     instr.addOpsToTimer("Section2:Crypt:Kernel", (2*array_rows)/1000.); 
386     instr.printTimer("Section2:Crypt:Kernel"); 
387   }
388   */
389 }