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