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 **************************************************************************/
23 public class JGFCryptBench {
27 private int datasizes[];
30 byte[] plain1; // Buffer for plaintext data.
32 short[] userkey; // Key for encryption/decryption.
33 int[] Z; // Encryption subkey (userkey derived).
34 int[] DK; // Decryption subkey (userkey derived).
36 public boolean validationTest;
39 // Builds the data used for the test -- each time the test is run.
40 void buildTestData() {
42 // Create three byte arrays that will be used (and reused) for
43 // encryption/decryption operations.
45 plain1 = new byte[array_rows];
47 Random rndnum = new Random(136506717L); // Create random number generator.
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)
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).
63 // Generate user key randomly; eight 16-bit values in an array.
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.
70 userkey[i] = (short) rndnum.nextInt();
73 // Compute encryption and decryption subkeys.
78 // Fill plain1 with "text."
79 for (int i = 0; i < array_rows; i++) {
82 // Converting to a byte
83 // type preserves the bit pattern in the lower 8 bits of the
84 // int and discards the rest.
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.
97 private void calcEncryptKey() {
98 int j; // Utility variable.
100 for (int i = 0; i < 52; i++)
101 // Zero out the 52-int Z array.
104 for (int i = 0; i < 8; i++) // First 8 subkeys are userkey itself.
106 Z[i] = userkey[i] & 0xffff; // Convert "unsigned"
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.
121 for (int i = 8; i < 52; i++) {
125 Z[i] = ((Z[i - 7] >>> 9) | (Z[i - 6] << 7)) // Shift and combine.
126 & 0xFFFF; // Just 16 bits.
127 // continue; // Next iteration.
134 if (j == 6) // Wrap to beginning for second chunk.
136 Z[i] = ((Z[i - 7] >>> 9) | (Z[i - 14] << 7)) & 0xFFFF;
142 // j == 7 so wrap to beginning for both chunks.
143 Z[i] = ((Z[i - 15] >>> 9) | (Z[i - 14] << 7)) & 0xFFFF;
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
157 private void calcDecryptKey() {
158 int j, k; // Index counters.
159 int t1, t2, t3; // Temps to hold decrypt subkeys.
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.
165 DK[51] = inv(Z[3]); // Multiplicative inverse (mod x10001).
170 j = 47; // Indices into temp and encrypt arrays.
172 for (int i = 0; i < 7; i++) {
177 t2 = -Z[k++] & 0xffff;
178 t3 = -Z[k++] & 0xffff;
179 DK[j--] = inv(Z[k++]);
189 t2 = -Z[k++] & 0xffff;
190 t3 = -Z[k++] & 0xffff;
191 DK[j--] = inv(Z[k++]);
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).
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.
220 private int mul(int a, int b) {
222 long p; // Large enough to catch 16-bit multiply
223 // without hitting sign bit.
227 b = (int) p & 0xFFFF; // Lower 16 bits.
228 a = (int) p >>> 16; // Upper 16 bits.
230 return (b - a + 1) & 0xFFFF;
232 return (b - a) & 0xFFFF;
234 return ((1 - a) & 0xFFFF); // If b = 0, then same as
237 // If a = 0, then return
238 return ((1 - b) & 0xFFFF); // same as 0x10001 - b.
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.
252 private int inv(int x) {
256 if (x <= 1) // Assumes positive x.
257 return (x); // 0 and 1 are self-inverse.
259 t1 = 0x10001 / x; // (2**16+1)/x; x is >= 2, so fits 16 bits.
262 return ((1 - t1) & 0xFFFF);
276 return ((1 - t1) & 0xFFFF);
279 public JGFCryptBench() {
280 datasizes = new int[3];
281 datasizes[0] = 3000000;
282 datasizes[1] = 20000000;
283 datasizes[2] = 1000000000;
284 validationTest=false;
287 public void JGFsetsize(int size, int nWorker) {
289 this.nWorker = nWorker;
292 public void JGFinitialise() {
293 array_rows = datasizes[size];
297 public void JGFkernel(){
299 byte [] crypt1 = new byte [array_rows];
300 byte [] plain2 = new byte [array_rows];
302 long startT=System.currentTimeMillis();
306 int slice, tslice, ttslice;
307 tslice = plain1.length / 8;
308 ttslice = (tslice + nWorker-1) / nWorker;
311 for(int i=0;i<nW;i++) {
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);
325 System.arraycopy(runner.text2, 0, crypt1, ilow, runner.local_size);
327 for(int idx=0;idx<runner.local_size;idx++){
328 crypt1[ilow+idx]=runner.text2[idx];
336 for(int i=0;i<nW;i++) {
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);
350 System.arraycopy(runner.text2, 0, plain2, ilow, runner.local_size);
352 for(int idx=0;idx<runner.local_size;idx++){
353 plain2[ilow+idx]=runner.text2[idx];
360 long endT=System.currentTimeMillis();
362 System.out.println(p+"runningtime="+(endT-startT));
366 boolean error = false;
367 for (int i = 0; i < array_rows; i++){
368 error = (plain1 [i] != plain2 [i]);
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]);
377 System.out.println("VALID");
382 public void JGFrun(int size, int nWorker) {
384 JGFsetsize(size, nWorker);
385 long startT=System.currentTimeMillis();
387 long endT=System.currentTimeMillis();
391 System.out.println("init="+(endT-startT));
395 public static void main(String argv[]) {
398 JGFCryptBench cb = new JGFCryptBench();
400 int problem_size = 2;
402 if (argv.length > 0) {
403 problem_size = Integer.parseInt(argv[0]);
406 if (argv.length > 1) {
407 nWorker = Integer.parseInt(argv[1]);
411 cb.validationTest=true;
414 cb.JGFrun(problem_size, nWorker);