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 *
16 * This version copyright (c) The University of Edinburgh, 2001. *
17 * All rights reserved. *
19 **************************************************************************/
20 /**************************************************************************
21 * Ported for DSTM Benchmark *
22 **************************************************************************/
25 public class JGFCryptBench {
28 private int datasizes[];
32 byte [] plain1; // Buffer for plaintext data.
33 byte [] crypt1; // Buffer for encrypted data.
34 byte [] plain2; // Buffer for decrypted data.
36 short [] userkey; // Key for encryption/decryption.
37 int [] Z; // Encryption subkey (userkey derived).
38 int [] DK; // Decryption subkey (userkey derived).
43 //Builds the data used for the test -- each time the test is run.
48 // Create three byte arrays that will be used (and reused) for
49 // encryption/decryption operations.
52 plain1 = new byte [array_rows];
53 crypt1 = new byte [array_rows];
54 plain2 = new byte [array_rows];
57 Random rndnum = new Random(136506717L); // Create random number generator.
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)
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).
74 // Generate user key randomly; eight 16-bit values in an array.
76 for (int i = 0; i < 8; i++)
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.
82 userkey[i] = (short) rndnum.nextInt();
85 // Compute encryption and decryption subkeys.
90 // Fill plain1 with "text."
91 for (int i = 0; i < array_rows; i++)
95 // Converting to a byte
96 // type preserves the bit pattern in the lower 8 bits of the
97 // int and discards the rest.
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.
111 private void calcEncryptKey()
113 int j; // Utility variable.
115 for (int i = 0; i < 52; i++) // Zero out the 52-int Z array.
118 for (int i = 0; i < 8; i++) // First 8 subkeys are userkey itself.
120 Z[i] = userkey[i] & 0xffff; // Convert "unsigned"
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.
135 for (int i = 8; i < 52; i++)
141 Z[i] = ((Z[i -7]>>>9) | (Z[i-6]<<7)) // Shift and combine.
142 & 0xFFFF; // Just 16 bits.
143 //continue; // Next iteration.
150 if (j == 6) // Wrap to beginning for second chunk.
152 Z[i] = ((Z[i -7]>>>9) | (Z[i-14]<<7))
159 // j == 7 so wrap to beginning for both chunks.
160 Z[i] = ((Z[i -15]>>>9) | (Z[i-14]<<7))
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
175 private void calcDecryptKey()
177 int j, k; // Index counters.
178 int t1, t2, t3; // Temps to hold decrypt subkeys.
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.
184 DK[51] = inv(Z[3]); // Multiplicative inverse (mod x10001).
189 j = 47; // Indices into temp and encrypt arrays.
191 for (int i = 0; i < 7; i++)
197 t2 = -Z[k++] & 0xffff;
198 t3 = -Z[k++] & 0xffff;
199 DK[j--] = inv(Z[k++]);
209 t2 = -Z[k++] & 0xffff;
210 t3 = -Z[k++] & 0xffff;
211 DK[j--] = inv(Z[k++]);
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).
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.
241 private int mul(int a, int b)
244 long p; // Large enough to catch 16-bit multiply
245 // without hitting sign bit.
251 b = (int) p & 0xFFFF; // Lower 16 bits.
252 a = (int) p >>> 16; // Upper 16 bits.
254 return (b - a + 1) & 0xFFFF;
256 return (b - a) & 0xFFFF;
259 return ((1 - a) & 0xFFFF); // If b = 0, then same as
262 else // If a = 0, then return
263 return((1 - b) & 0xFFFF); // same as 0x10001 - b.
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.
277 private int inv(int x)
282 if (x <= 1) // Assumes positive x.
283 return(x); // 0 and 1 are self-inverse.
285 t1 = 0x10001 / x; // (2**16+1)/x; x is >= 2, so fits 16 bits.
288 return((1 - t1) & 0xFFFF);
295 if (x == 1) return(t0);
301 return((1 - t1) & 0xFFFF);
307 // Nulls arrays and forces garbage collection to free up memory.
310 void freeTestData(int array_rows)
312 for(int i = 0; i<array_rows; i++) {
313 plain1[i] = (byte) 0;
314 crypt1[i] = (byte) 0;
315 plain2[i] = (byte) 0;
318 for(int i = 0; i<8; i++) {
319 userkey[i] = (short) 0;
322 for(int i = 0; i<52; i++) {
327 //System.gc(); // Force garbage collection.
331 public JGFCryptBench(int nthreads)
333 this.nthreads=nthreads;
334 datasizes = new int[3];
335 datasizes[0] = 3000000;
336 datasizes[1] = 20000000;
337 datasizes[2] = 50000000;
341 public void JGFsetsize(int size){
345 public void JGFinitialise(){
346 array_rows = datasizes[size];
351 public void JGFkernel(){
356 public void JGFvalidate(){
360 for (int i = 0; i < array_rows; i++){
361 error = (plain1 [i] != plain2 [i]);
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]);
373 public void JGFtidyup(){
374 freeTestData(array_rows);
378 public void JGFrun(int size){
379 instr.addTimer("Section2:Crypt:Kernel", "Kbyte",size);
385 instr.addOpsToTimer("Section2:Crypt:Kernel", (2*array_rows)/1000.);
386 instr.printTimer("Section2:Crypt:Kernel");