6 long currentTimeMillis() {
8 gettimeofday( t, NULL );
9 double micros = (double)t->tv_usec;
10 double millis = micros / 1000.0;
17 void calcEncryptKey();
18 void calcDecryptKey();
20 int mul( int a, int b );
25 void cipher_idea( char* text1, char* text2, int* key );
32 char* plain1; // Buffer for plaintext data.
34 short* userkey; // Key for encryption/decryption.
35 int* Z; // Encryption subkey (userkey derived).
36 int* DK; // Decryption subkey (userkey derived).
41 void main( int argc, char** argv ) {
46 datasizes = malloc( 4*sizeof(int) );
47 datasizes[0] = 3000000;
48 datasizes[1] = 20000000;
49 datasizes[2] = 50000000;
50 datasizes[3] = 1000000000;
53 problem_size = atoi( argv[1] );
56 startT=currentTimeMillis();
58 array_rows = datasizes[problem_size];
61 endT=currentTimeMillis();
65 printf( "init=%d\n", endT-startT );
70 // Builds the data used for the test -- each time the test is run.
71 void buildTestData() {
75 // Create three byte arrays that will be used (and reused) for
76 // encryption/decryption operations.
78 plain1 = malloc( array_rows*sizeof( char ) );
82 // Allocate three arrays to hold keys: userkey is the 128-bit key.
83 // Z is the set of 16-bit encryption subkeys derived from userkey,
84 // while DK is the set of 16-bit decryption subkeys also derived
85 // from userkey. NOTE: The 16-bit values are stored here in
86 // 32-bit int arrays so that the values may be used in calculations
87 // as if they are unsigned. Each 64-bit block of plaintext goes
88 // through eight processing rounds involving six of the subkeys
89 // then a final output transform with four of the keys; (8 * 6)
92 userkey = malloc( 8*sizeof( short ) ); // User key has 8 16-bit shorts.
93 Z = malloc( 52*sizeof( int ) ); // Encryption subkey (user key derived).
94 DK = malloc( 52*sizeof( int ) ); // Decryption subkey (user key derived).
96 // Generate user key randomly; eight 16-bit values in an array.
98 for( i = 0; i < 8; i++ ) {
99 // Again, the random number function returns int. Converting
100 // to a short type preserves the bit pattern in the lower 16
101 // bits of the int and discards the rest.
103 userkey[i] = (short) rand();
106 // Compute encryption and decryption subkeys.
111 // Fill plain1 with "text."
112 for( i = 0; i < array_rows; i++ ) {
113 plain1[i] = (char) i;
115 // Converting to a byte
116 // type preserves the bit pattern in the lower 8 bits of the
117 // int and discards the rest.
123 void calcEncryptKey() {
124 // Builds the 52 16-bit encryption subkeys Z[] from the user key and
125 // stores in 32-bit int array. The routing corrects an error in the
126 // source code in the Schnier book. Basically, the sense of the 7-
127 // and 9-bit shifts are reversed. It still works reversed, but would
128 // encrypted code would not decrypt with someone else's IDEA code.
131 int j; // Utility variables.
135 for( i = 0; i < 52; i++ ) {
136 // Zero out the 52-int Z array.
140 for( i = 0; i < 8; i++ ) { // First 8 subkeys are userkey itself.
141 Z[i] = userkey[i] & 0xffff; // Convert "unsigned"
145 // Each set of 8 subkeys thereafter is derived from left rotating
146 // the whole 128-bit key 25 bits to left (once between each set of
147 // eight keys and then before the last four). Instead of actually
148 // rotating the whole key, this routine just grabs the 16 bits
149 // that are 25 bits to the right of the corresponding subkey
150 // eight positions below the current subkey. That 16-bit extent
151 // straddles two array members, so bits are shifted left in one
152 // member and right (with zero fill) in the other. For the last
153 // two subkeys in any group of eight, those 16 bits start to
154 // wrap around to the first two members of the previous eight.
156 for( i = 8; i < 52; i++ ) {
160 Z[i] = ((Z[i - 7] >> 9) | (Z[i - 6] << 7)) // Shift and combine.
161 & 0xFFFF; // Just 16 bits.
162 // continue; // Next iteration.
169 if (j == 6) { // Wrap to beginning for second chunk.
170 Z[i] = ((Z[i - 7] >> 9) | (Z[i - 14] << 7)) & 0xFFFF;
176 // j == 7 so wrap to beginning for both chunks.
177 Z[i] = ((Z[i - 15] >> 9) | (Z[i - 14] << 7)) & 0xFFFF;
184 void calcDecryptKey() {
185 // Builds the 52 16-bit encryption subkeys DK[] from the encryption-
186 // subkeys Z[]. DK[] is a 32-bit int array holding 16-bit values as
190 int i, j, k; // Index counters.
191 int t1, t2, t3; // Temps to hold decrypt subkeys.
193 t1 = inv(Z[0]); // Multiplicative inverse (mod x10001).
194 t2 = -Z[1] & 0xffff; // Additive inverse, 2nd encrypt subkey.
195 t3 = -Z[2] & 0xffff; // Additive inverse, 3rd encrypt subkey.
197 DK[51] = inv(Z[3]); // Multiplicative inverse (mod x10001).
202 j = 47; // Indices into temp and encrypt arrays.
204 for( i = 0; i < 7; i++ ) {
209 t2 = -Z[k++] & 0xffff;
210 t3 = -Z[k++] & 0xffff;
211 DK[j--] = inv(Z[k++]);
221 t2 = -Z[k++] & 0xffff;
222 t3 = -Z[k++] & 0xffff;
223 DK[j--] = inv(Z[k++]);
231 int mul( int a, int b ) {
232 // Performs multiplication, modulo (2**16)+1. This code is structured
233 // on the assumption that untaken branches are cheaper than taken
234 // branches, and that the compiler doesn't schedule branches.
235 // Java: Must work with 32-bit int and one 64-bit long to keep
236 // 16-bit values and their products "unsigned." The routine assumes
237 // that both a and b could fit in 16 bits even though they come in
238 // as 32-bit ints. Lots of "& 0xFFFF" masks here to keep things 16-bit.
239 // Also, because the routine stores mod (2**16)+1 results in a 2**16
240 // space, the result is truncated to zero whenever the result would
241 // zero, be 2**16. And if one of the multiplicands is 0, the result
242 // is not zero, but (2**16) + 1 minus the other multiplicand (sort
243 // of an additive inverse mod 0x10001).
245 // NOTE: The java conversion of this routine works correctly, but
246 // is half the speed of using Java's modulus division function (%)
247 // on the multiplication with a 16-bit masking of the result--running
248 // in the Symantec Caje IDE. So it's not called for now; the test
249 // uses Java % instead.
253 long p; // Large enough to catch 16-bit multiply
254 // without hitting sign bit.
258 b = (int) p & 0xFFFF; // Lower 16 bits.
259 a = (int) p >> 16; // Upper 16 bits.
261 return (b - a + 1) & 0xFFFF;
263 return (b - a) & 0xFFFF;
265 return ((1 - a) & 0xFFFF); // If b = 0, then same as
268 // If a = 0, then return
269 return ((1 - b) & 0xFFFF); // same as 0x10001 - b.
276 // Compute multiplicative inverse of x, modulo (2**16)+1 using
277 // extended Euclid's GCD (greatest common divisor) algorithm.
278 // It is unrolled twice to avoid swapping the meaning of
279 // the registers. And some subtracts are changed to adds.
280 // Java: Though it uses signed 32-bit ints, the interpretation
281 // of the bits within is strictly unsigned 16-bit.
287 if (x <= 1) // Assumes positive x.
288 return (x); // 0 and 1 are self-inverse.
290 t1 = 0x10001 / x; // (2**16+1)/x; x is >= 2, so fits 16 bits.
293 return ((1 - t1) & 0xFFFF);
307 return ((1 - t1) & 0xFFFF);
316 char* crypt1 = malloc( array_rows*sizeof( char ) );
317 char* plain2 = malloc( array_rows*sizeof( char ) );
319 cipher_idea(plain1, crypt1, Z); // Encrypt plain1.
320 cipher_idea(crypt1, plain2, DK); // Decrypt.
323 for( i = 0; i < array_rows; i++ ){
324 error = (plain1 [i] != plain2 [i]);
326 printf("Validation failed\n");
327 printf("Original Byte %d = %c\n", i, plain1[i]);
328 printf("Encrypted Byte %d = %c\n", i, crypt1[i]);
329 printf("Decrypted Byte %d = %c\n", i, plain2[i]);
333 printf("Validation Success\n");
339 void cipher_idea( char* text1, char* text2, int* key ) {
340 // IDEA encryption/decryption algorithm. It processes plaintext in
341 // 64-bit blocks, one at a time, breaking the block into four 16-bit
342 // unsigned subblocks. It goes through eight rounds of processing
343 // using 6 new subkeys each time, plus four for last step. The source
344 // text is in array text1, the destination text goes into array text2
345 // The routine represents 16-bit subblocks and subkeys as type int so
346 // that they can be treated more easily as unsigned. Multiplication
347 // modulo 0x10001 interprets a zero sub-block as 0x10000; it must to
351 int i1 = 0; // Index into first text array.
352 int i2 = 0; // Index into second text array.
353 int ik; // Index into key array.
354 int x1, x2, x3, x4, t1, t2; // Four "16-bit" blocks, two temps.
355 int r; // Eight rounds of processing.
357 for( i = 0; i < array_rows; i += 8 )
360 ik = 0; // Restart key index.
361 r = 8; // Eight rounds of processing.
363 // Load eight plain1 bytes as four 16-bit "unsigned" integers.
364 // Masking with 0xff prevents sign extension with cast to int.
366 x1 = text1[i1++] & 0xff; // Build 16-bit x1 from 2 bytes,
367 x1 |= (text1[i1++] & 0xff) << 8; // assuming low-order byte first.
368 x2 = text1[i1++] & 0xff;
369 x2 |= (text1[i1++] & 0xff) << 8;
370 x3 = text1[i1++] & 0xff;
371 x3 |= (text1[i1++] & 0xff) << 8;
372 x4 = text1[i1++] & 0xff;
373 x4 |= (text1[i1++] & 0xff) << 8;
376 // 1) Multiply (modulo 0x10001), 1st text sub-block
377 // with 1st key sub-block.
379 x1 = (int) ((long) x1 * key[ik++] % 0x10001L & 0xffff);
381 // 2) Add (modulo 0x10000), 2nd text sub-block
382 // with 2nd key sub-block.
384 x2 = x2 + key[ik++] & 0xffff;
386 // 3) Add (modulo 0x10000), 3rd text sub-block
387 // with 3rd key sub-block.
389 x3 = x3 + key[ik++] & 0xffff;
391 // 4) Multiply (modulo 0x10001), 4th text sub-block
392 // with 4th key sub-block.
394 x4 = (int) ((long) x4 * key[ik++] % 0x10001L & 0xffff);
396 // 5) XOR results from steps 1 and 3.
400 // 6) XOR results from steps 2 and 4.
401 // Included in step 8.
403 // 7) Multiply (modulo 0x10001), result of step 5
404 // with 5th key sub-block.
406 t2 = (int) ((long) t2 * key[ik++] % 0x10001L & 0xffff);
408 // 8) Add (modulo 0x10000), results of steps 6 and 7.
410 t1 = t2 + (x2 ^ x4) & 0xffff;
412 // 9) Multiply (modulo 0x10001), result of step 8
413 // with 6th key sub-block.
415 t1 = (int) ((long) t1 * key[ik++] % 0x10001L & 0xffff);
417 // 10) Add (modulo 0x10000), results of steps 7 and 9.
419 t2 = t1 + t2 & 0xffff;
421 // 11) XOR results from steps 1 and 9.
425 // 14) XOR results from steps 4 and 10. (Out of order).
429 // 13) XOR results from steps 2 and 10. (Out of order).
433 // 12) XOR results from steps 3 and 9. (Out of order).
437 x3 = t2; // Results of x2 and x3 now swapped.
439 } while(--r != 0); // Repeats seven more rounds.
441 // Final output transform (4 steps).
443 // 1) Multiply (modulo 0x10001), 1st text-block
444 // with 1st key sub-block.
446 x1 = (int) ((long) x1 * key[ik++] % 0x10001L & 0xffff);
448 // 2) Add (modulo 0x10000), 2nd text sub-block
449 // with 2nd key sub-block. It says x3, but that is to undo swap
450 // of subblocks 2 and 3 in 8th processing round.
452 x3 = x3 + key[ik++] & 0xffff;
454 // 3) Add (modulo 0x10000), 3rd text sub-block
455 // with 3rd key sub-block. It says x2, but that is to undo swap
456 // of subblocks 2 and 3 in 8th processing round.
458 x2 = x2 + key[ik++] & 0xffff;
460 // 4) Multiply (modulo 0x10001), 4th text-block
461 // with 4th key sub-block.
463 x4 = (int) ((long) x4 * key[ik++] % 0x10001L & 0xffff);
465 // Repackage from 16-bit sub-blocks to 8-bit byte array text2.
467 text2[i2++] = (char) x1;
468 text2[i2++] = (char) (x1 >> 8);
469 text2[i2++] = (char) x3; // x3 and x2 are switched
470 text2[i2++] = (char) (x3 >> 8); // only in name.
471 text2[i2++] = (char) x2;
472 text2[i2++] = (char) (x2 >> 8);
473 text2[i2++] = (char) x4;
474 text2[i2++] = (char) (x4 >> 8);