1 /**************************************************************************
3 * Java Grande Forum Benchmark Suite - Thread Version 1.0 *
7 * Java Grande Benchmarking Project *
11 * Edinburgh Parallel Computing Centre *
13 * email: epcc-javagrande@epcc.ed.ac.uk *
15 * Original version of this code by *
16 * Gabriel Zachmann (zach@igd.fhg.de) *
18 * This version copyright (c) The University of Edinburgh, 2001. *
19 * All rights reserved. *
21 **************************************************************************/
22 /**************************************************************************
23 * Ported for DSTM Benchmark *
24 **************************************************************************/
30 * This test performs IDEA encryption then decryption. IDEA stands
31 * for International Data Encryption Algorithm. The test is based
32 * on code presented in Applied Cryptography by Bruce Schnier,
33 * which was based on code developed by Xuejia Lai and James L.
46 // Declare class data. Byte buffer plain1 holds the original
47 // data for encryption, crypt1 holds the encrypted data, and
48 // plain2 holds the decrypted data, which should match plain1
53 byte [] plain1; // Buffer for plaintext data.
54 byte [] crypt1; // Buffer for encrypted data.
55 byte [] plain2; // Buffer for decrypted data.
57 short [] userkey; // Key for encryption/decryption.
58 int [] Z; // Encryption subkey (userkey derived).
59 int [] DK; // Decryption subkey (userkey derived).
61 void Do(int nthreads, JGFInstrumentor instr)
64 int mid = (128<<24)|(195<<16)|(175<<8)|73;
69 th = global new IDEARunner [nthreads];
72 // Start the stopwatch.
73 instr.startTimer("Section2:Crypt:Kernel");
76 for(int i=1;i<nthreads;i++) {
78 th[i] = global new IDEARunner(i,plain1,crypt1,Z,nthreads);
85 th[0] = global new IDEARunner(0,plain1,crypt1,Z,nthreads);
91 for(int i=1;i<nthreads;i++) {
99 for(int i=1;i<nthreads;i++) {
101 th[i] = global new IDEARunner(i,crypt1,plain2,DK,nthreads);
108 th[0] = global new IDEARunner(0,crypt1,plain2,DK,nthreads);
114 for(int i=1;i<nthreads;i++) {
122 // Stop the stopwatch.
123 instr.stopTimer("Section2:Crypt:Kernel");
129 //Builds the data used for the test -- each time the test is run.
136 // Create three byte arrays that will be used (and reused) for
137 // encryption/decryption operations.
139 plain1 = new byte [array_rows];
140 crypt1 = new byte [array_rows];
141 plain2 = new byte [array_rows];
144 Random rndnum = new Random(136506717L); // Create random number generator.
147 // Allocate three arrays to hold keys: userkey is the 128-bit key.
148 // Z is the set of 16-bit encryption subkeys derived from userkey,
149 // while DK is the set of 16-bit decryption subkeys also derived
150 // from userkey. NOTE: The 16-bit values are stored here in
151 // 32-bit int arrays so that the values may be used in calculations
152 // as if they are unsigned. Each 64-bit block of plaintext goes
153 // through eight processing rounds involving six of the subkeys
154 // then a final output transform with four of the keys; (8 * 6)
157 userkey = new short [8]; // User key has 8 16-bit shorts.
158 Z = new int [52]; // Encryption subkey (user key derived).
159 DK = new int [52]; // Decryption subkey (user key derived).
161 // Generate user key randomly; eight 16-bit values in an array.
163 for (int i = 0; i < 8; i++)
165 // Again, the random number function returns int. Converting
166 // to a short type preserves the bit pattern in the lower 16
167 // bits of the int and discards the rest.
169 userkey[i] = (short) rndnum.nextInt();
172 // Compute encryption and decryption subkeys.
177 // Fill plain1 with "text."
178 for (int i = 0; i < array_rows; i++)
180 plain1[i] = (byte) i;
182 // Converting to a byte
183 // type preserves the bit pattern in the lower 8 bits of the
184 // int and discards the rest.
191 // Builds the 52 16-bit encryption subkeys Z[] from the user key and
192 //stores in 32-bit int array. The routing corrects an error in the
193 //source code in the Schnier book. Basically, the sense of the 7-
194 //and 9-bit shifts are reversed. It still works reversed, but would
195 //encrypted code would not decrypt with someone else's IDEA code.
198 private void calcEncryptKey()
200 int j; // Utility variable.
202 for (int i = 0; i < 52; i++) // Zero out the 52-int Z array.
205 for (int i = 0; i < 8; i++) // First 8 subkeys are userkey itself.
207 Z[i] = userkey[i] & 0xffff; // Convert "unsigned"
211 // Each set of 8 subkeys thereafter is derived from left rotating
212 // the whole 128-bit key 25 bits to left (once between each set of
213 // eight keys and then before the last four). Instead of actually
214 // rotating the whole key, this routine just grabs the 16 bits
215 // that are 25 bits to the right of the corresponding subkey
216 // eight positions below the current subkey. That 16-bit extent
217 // straddles two array members, so bits are shifted left in one
218 // member and right (with zero fill) in the other. For the last
219 // two subkeys in any group of eight, those 16 bits start to
220 // wrap around to the first two members of the previous eight.
222 for (int i = 8; i < 52; i++)
228 Z[i] = ((Z[i -7]>>>9) | (Z[i-6]<<7)) // Shift and combine.
229 & 0xFFFF; // Just 16 bits.
230 //continue; // Next iteration.
237 if (j == 6) // Wrap to beginning for second chunk.
239 Z[i] = ((Z[i -7]>>>9) | (Z[i-14]<<7))
246 // j == 7 so wrap to beginning for both chunks.
247 Z[i] = ((Z[i -15]>>>9) | (Z[i-14]<<7))
257 //Builds the 52 16-bit encryption subkeys DK[] from the encryption-
258 //subkeys Z[]. DK[] is a 32-bit int array holding 16-bit values as
262 private void calcDecryptKey()
264 int j, k; // Index counters.
265 int t1, t2, t3; // Temps to hold decrypt subkeys.
267 t1 = inv(Z[0]); // Multiplicative inverse (mod x10001).
268 t2 = - Z[1] & 0xffff; // Additive inverse, 2nd encrypt subkey.
269 t3 = - Z[2] & 0xffff; // Additive inverse, 3rd encrypt subkey.
271 DK[51] = inv(Z[3]); // Multiplicative inverse (mod x10001).
276 j = 47; // Indices into temp and encrypt arrays.
278 for (int i = 0; i < 7; i++)
284 t2 = -Z[k++] & 0xffff;
285 t3 = -Z[k++] & 0xffff;
286 DK[j--] = inv(Z[k++]);
296 t2 = -Z[k++] & 0xffff;
297 t3 = -Z[k++] & 0xffff;
298 DK[j--] = inv(Z[k++]);
311 // Performs multiplication, modulo (2**16)+1. This code is structured
312 // on the assumption that untaken branches are cheaper than taken
313 // branches, and that the compiler doesn't schedule branches.
314 // Java: Must work with 32-bit int and one 64-bit long to keep
315 // 16-bit values and their products "unsigned." The routine assumes
316 // that both a and b could fit in 16 bits even though they come in
317 // as 32-bit ints. Lots of "& 0xFFFF" masks here to keep things 16-bit.
318 // Also, because the routine stores mod (2**16)+1 results in a 2**16
319 // space, the result is truncated to zero whenever the result would
320 // zero, be 2**16. And if one of the multiplicands is 0, the result
321 // is not zero, but (2**16) + 1 minus the other multiplicand (sort
322 // of an additive inverse mod 0x10001).
324 // NOTE: The java conversion of this routine works correctly, but
325 // is half the speed of using Java's modulus division function (%)
326 // on the multiplication with a 16-bit masking of the result--running
327 // in the Symantec Caje IDE. So it's not called for now; the test
328 // uses Java % instead.
331 private int mul(int a, int b)
334 long p; // Large enough to catch 16-bit multiply
335 // without hitting sign bit.
341 b = (int) p & 0xFFFF; // Lower 16 bits.
342 a = (int) p >>> 16; // Upper 16 bits.
344 return (b - a + 1) & 0xFFFF;
346 return (b - a) & 0xFFFF;
349 return ((1 - a) & 0xFFFF); // If b = 0, then same as
352 else // If a = 0, then return
353 return((1 - b) & 0xFFFF); // same as 0x10001 - b.
359 // Compute multiplicative inverse of x, modulo (2**16)+1 using
360 // extended Euclid's GCD (greatest common divisor) algorithm.
361 // It is unrolled twice to avoid swapping the meaning of
362 // the registers. And some subtracts are changed to adds.
363 // Java: Though it uses signed 32-bit ints, the interpretation
364 // of the bits within is strictly unsigned 16-bit.
367 private int inv(int x)
372 if (x <= 1) // Assumes positive x.
373 return(x); // 0 and 1 are self-inverse.
375 t1 = 0x10001 / x; // (2**16+1)/x; x is >= 2, so fits 16 bits.
378 return((1 - t1) & 0xFFFF);
385 if (x == 1) return(t0);
391 return((1 - t1) & 0xFFFF);
397 // Nulls arrays and forces garbage collection to free up memory.
400 void freeTestData(int array_rows)
402 for(int i = 0; i<array_rows; i++) {
403 plain1[i] = (byte) 0;
404 crypt1[i] = (byte) 0;
405 plain2[i] = (byte) 0;
408 for(int i = 0; i<8; i++) {
409 userkey[i] = (short) 0;
412 for(int i = 0; i<52; i++) {
417 //System.gc(); // Force garbage collection.
424 class IDEARunner extends Thread {
427 byte text1[],text2[];
430 public IDEARunner(int id, byte [] text1, byte [] text2, int [] key, int nthreads) {
435 this.nthreads = nthreads;
440 // IDEA encryption/decryption algorithm. It processes plaintext in
441 // 64-bit blocks, one at a time, breaking the block into four 16-bit
442 // unsigned subblocks. It goes through eight rounds of processing
443 // using 6 new subkeys each time, plus four for last step. The source
444 // text is in array text1, the destination text goes into array text2
445 // The routine represents 16-bit subblocks and subkeys as type int so
446 // that they can be treated more easily as unsigned. Multiplication
447 // modulo 0x10001 interprets a zero sub-block as 0x10000; it must to
452 int ilow, iupper, slice, tslice, ttslice;
454 tslice = text1.length / 8;
455 ttslice = (tslice + nthreads-1) / nthreads;
459 iupper = (id+1)*slice;
460 if(iupper > text1.length) iupper = text1.length;
462 int i1 = ilow; // Index into first text array.
463 int i2 = ilow; // Index into second text array.
464 int ik; // Index into key array.
465 int x1, x2, x3, x4, t1, t2; // Four "16-bit" blocks, two temps.
466 int r; // Eight rounds of processing.
468 for (int i =ilow ; i <iupper ; i +=8)
471 ik = 0; // Restart key index.
472 r = 8; // Eight rounds of processing.
474 // Load eight plain1 bytes as four 16-bit "unsigned" integers.
475 // Masking with 0xff prevents sign extension with cast to int.
477 x1 = text1[i1++] & 0xff; // Build 16-bit x1 from 2 bytes,
478 x1 |= (text1[i1++] & 0xff) << 8; // assuming low-order byte first.
479 x2 = text1[i1++] & 0xff;
480 x2 |= (text1[i1++] & 0xff) << 8;
481 x3 = text1[i1++] & 0xff;
482 x3 |= (text1[i1++] & 0xff) << 8;
483 x4 = text1[i1++] & 0xff;
484 x4 |= (text1[i1++] & 0xff) << 8;
487 // 1) Multiply (modulo 0x10001), 1st text sub-block
488 // with 1st key sub-block.
490 x1 = (int) ((long) x1 * key[ik++] % 0x10001L & 0xffff);
492 // 2) Add (modulo 0x10000), 2nd text sub-block
493 // with 2nd key sub-block.
495 x2 = x2 + key[ik++] & 0xffff;
497 // 3) Add (modulo 0x10000), 3rd text sub-block
498 // with 3rd key sub-block.
500 x3 = x3 + key[ik++] & 0xffff;
502 // 4) Multiply (modulo 0x10001), 4th text sub-block
503 // with 4th key sub-block.
505 x4 = (int) ((long) x4 * key[ik++] % 0x10001L & 0xffff);
507 // 5) XOR results from steps 1 and 3.
511 // 6) XOR results from steps 2 and 4.
512 // Included in step 8.
514 // 7) Multiply (modulo 0x10001), result of step 5
515 // with 5th key sub-block.
517 t2 = (int) ((long) t2 * key[ik++] % 0x10001L & 0xffff);
519 // 8) Add (modulo 0x10000), results of steps 6 and 7.
521 t1 = t2 + (x2 ^ x4) & 0xffff;
523 // 9) Multiply (modulo 0x10001), result of step 8
524 // with 6th key sub-block.
526 t1 = (int) ((long) t1 * key[ik++] % 0x10001L & 0xffff);
528 // 10) Add (modulo 0x10000), results of steps 7 and 9.
530 t2 = t1 + t2 & 0xffff;
532 // 11) XOR results from steps 1 and 9.
536 // 14) XOR results from steps 4 and 10. (Out of order).
540 // 13) XOR results from steps 2 and 10. (Out of order).
544 // 12) XOR results from steps 3 and 9. (Out of order).
548 x3 = t2; // Results of x2 and x3 now swapped.
550 } while(--r != 0); // Repeats seven more rounds.
552 // Final output transform (4 steps).
554 // 1) Multiply (modulo 0x10001), 1st text-block
555 // with 1st key sub-block.
557 x1 = (int) ((long) x1 * key[ik++] % 0x10001L & 0xffff);
559 // 2) Add (modulo 0x10000), 2nd text sub-block
560 // with 2nd key sub-block. It says x3, but that is to undo swap
561 // of subblocks 2 and 3 in 8th processing round.
563 x3 = x3 + key[ik++] & 0xffff;
565 // 3) Add (modulo 0x10000), 3rd text sub-block
566 // with 3rd key sub-block. It says x2, but that is to undo swap
567 // of subblocks 2 and 3 in 8th processing round.
569 x2 = x2 + key[ik++] & 0xffff;
571 // 4) Multiply (modulo 0x10001), 4th text-block
572 // with 4th key sub-block.
574 x4 = (int) ((long) x4 * key[ik++] % 0x10001L & 0xffff);
576 // Repackage from 16-bit sub-blocks to 8-bit byte array text2.
578 text2[i2++] = (byte) x1;
579 text2[i2++] = (byte) (x1 >>> 8);
580 text2[i2++] = (byte) x3; // x3 and x2 are switched
581 text2[i2++] = (byte) (x3 >>> 8); // only in name.
582 text2[i2++] = (byte) x2;
583 text2[i2++] = (byte) (x2 >>> 8);
584 text2[i2++] = (byte) x4;
585 text2[i2++] = (byte) (x4 >>> 8);