1. /****************************************************************************
  2. * This program finds near-collisions for the FORK-256 compression function.
  3. * For algorithm description and the whole theory behind it, please see
  4. * IACR e-print archive, report 2006/317, http://eprint.iacr.org/2006/317 .
  5. * (C) Scott Contini, Krystian Matusiewicz, 2006-2007
  6. ****************************************************************************/
  7.  
  8. #include <stdio.h>
  9. #include <math.h>
  10. #include <stdlib.h>
  11. #include <time.h>
  12. #include <string.h>
  13.  
  14. /* define this option to use variant of derive1() with the hash tables,
  15. * otherwise an optimized variant of derive1() without the hash table is used*/
  16. #define USEHASHTABLE
  17.  
  18. typedef unsigned int WRD;
  19.  
  20. WRD delta[16] = {
  21. 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
  22. 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
  23. 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
  24. 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174
  25. };
  26.  
  27. /* n-bit left rotation */
  28. #define ROL(x,n) (((x) << (n)) | ((x) >> (32-(n))))
  29. #define f(x) ( (x) + (ROL((x),7) ^ ROL((x),22)) )
  30. #define g(x) ( (x) ^ (ROL((x),13) + ROL((x),27)) )
  31.  
  32. /*using different size of the hash table affects efficiency of the
  33. program. The bigger the hash table, the better properties of the
  34. table lookup, but on the other hand, accessing memory outside cache
  35. is much slower on Pentium processors.
  36. HASH_SIZE is the number of elements in the hash table (different from
  37. the size in memory!) */
  38. #if 0
  39. const int HASH_SIZE = 8388593;
  40. #else
  41. const int HASH_SIZE = ( 1 << 25 );
  42. #endif
  43.  
  44. /* this variable stores the amount of memory reserved for the hash table*/
  45. int HASH_MEM;
  46.  
  47. /* step transformation */
  48. #define step(A,B,C,D,E,F,G,H,M1,M2,D1,D2) \
  49. temp = (H + ROL(g(E+M2),21)) ^ ROL(f(E+M2+D2),17); \
  50. H = (G + ROL(g(E+M2),9)) ^ ROL(f(E+M2+D2),5); \
  51. G = (F + g(E+M2)) ^ f(E+M2+D2); \
  52. F = E + M2 + D2; \
  53. E = (D + ROL(f(A+M1),17)) ^ ROL(g(A+M1+D1),21); \
  54. D = (C + ROL(f(A+M1),5)) ^ ROL(g(A+M1+D1),9); \
  55. C = (B + f(A+M1)) ^ g(A+M1+D1); \
  56. B = A + M1 + D1; \
  57. A = temp;
  58.  
  59. /* inverse of step transformation (step backwards) */
  60. #define back(A,B,C,D,E,F,G,H,M1,M2,D1,D2) \
  61. temp = A; \
  62. temp2 = B; \
  63. A = B - M1 - D1; \
  64. B = (C ^ g(B)) - f(B-D1); \
  65. C = (D ^ ROL(g(temp2),9)) - ROL(f(temp2-D1),5); \
  66. D = (E ^ ROL(g(temp2),21)) - ROL(f(temp2-D1),17); \
  67. E = F - M2 - D2; \
  68. temp2 = G; \
  69. G = (H ^ ROL(f(F),5)) - ROL(g(F-D2),9); \
  70. H = (temp ^ ROL(f(F),17)) - ROL(g(F-D2),21); \
  71. F = (temp2 ^ f(F)) - g(F-D2); \
  72.  
  73.  
  74. /* 32-bit pseudorandom word, even for RNGs that return only 16 bits */
  75. #define RANDOM_WORD (((WRD) rand() & 0xffff)<<16) | (rand() & 0xffff);
  76.  
  77. /** returns Hamming weight of x*/
  78. int hammingWeight(WRD x) {
  79. x -= (x >> 1) & 0x55555555;
  80. x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
  81. x = (x + (x >> 4)) & 0x0f0f0f0f;
  82. x += x >> 8;
  83. x += x >> 16;
  84. return x & 0x3f;
  85. }/*hammingWeight()*/
  86.  
  87.  
  88. /** This function returns 1 if the additive difference y1-y2
  89. * can be transformed by adding a constant so that it "fits"
  90. * into XOR difference dz ie. when a "microcollision" can happen */
  91. int micro_possible( WRD y1, WRD y2, WRD dz) {
  92. WRD tmp, delta_y;
  93. WRD sum;
  94. /* make y1 > y2 : */
  95. if (y2 > y1) {
  96. tmp = y2; y2 = y1; y1 = tmp;
  97. }
  98. delta_y = y1 - y2;
  99. sum = delta_y;
  100. sum += dz;
  101. if (sum < delta_y) {
  102. /* overflow */
  103. if ((dz>>31)==0)
  104. /* no solution! */
  105. return 0;
  106. }
  107. dz <<= 1;
  108. return ( (dz|sum) == dz );
  109. }/*micro_possible()*/
  110.  
  111.  
  112. /** determine which bits of "u" must have 1's and which must have 0's */
  113. void get_ones_and_zeros(WRD y1, WRD y2, WRD z1, WRD z2, WRD *ones, WRD *zeros){
  114. WRD tmp, delta_y;
  115. WRD sum;
  116. /* make y1 > y2 : */
  117. if (y2 > y1) {
  118. tmp = y2; y2 = y1; y1 = tmp;
  119. tmp = z2; z2 = z1; z1 = tmp;
  120. }
  121. tmp = z1 ^ z2;
  122. delta_y = y1 - y2;
  123. sum = delta_y;
  124. sum += tmp;
  125. tmp <<= 1;
  126. *ones = (tmp&sum) >> 1;
  127. *zeros = ((tmp&sum) ^ tmp) >> 1;
  128. }/*get_ones_and_zeros()*/
  129.  
  130. /** Compression function of FORK-256 that based on the value of
  131. * chaining variables CV and message M updates the state of
  132. * chaining variables CV */
  133. void FORK256_compression_function(WRD CV[8],WRD M[16]) {
  134. WRD A1,B1,C1,D1,E1,F1,G1,H1;
  135. WRD A2,B2,C2,D2,E2,F2,G2,H2;
  136. WRD A3,B3,C3,D3,E3,F3,G3,H3;
  137. WRD A4,B4,C4,D4,E4,F4,G4,H4;
  138. WRD temp;
  139. A1 = A2 = A3 = A4 = CV[0]; B1 = B2 = B3 = B4 = CV[1];
  140. C1 = C2 = C3 = C4 = CV[2]; D1 = D2 = D3 = D4 = CV[3];
  141. E1 = E2 = E3 = E4 = CV[4]; F1 = F2 = F3 = F4 = CV[5];
  142. G1 = G2 = G3 = G4 = CV[6]; H1 = H2 = H3 = H4 = CV[7];
  143. /* BRANCH1(CV,M) */
  144. step(A1,B1,C1,D1,E1,F1,G1,H1,M[0],M[1],delta[0],delta[1]);
  145. step(A1,B1,C1,D1,E1,F1,G1,H1,M[2],M[3],delta[2],delta[3]);
  146. step(A1,B1,C1,D1,E1,F1,G1,H1,M[4],M[5],delta[4],delta[5]);
  147. step(A1,B1,C1,D1,E1,F1,G1,H1,M[6],M[7],delta[6],delta[7]);
  148. step(A1,B1,C1,D1,E1,F1,G1,H1,M[8],M[9],delta[8],delta[9]);
  149. step(A1,B1,C1,D1,E1,F1,G1,H1,M[10],M[11],delta[10],delta[11]);
  150. step(A1,B1,C1,D1,E1,F1,G1,H1,M[12],M[13],delta[12],delta[13]);
  151. step(A1,B1,C1,D1,E1,F1,G1,H1,M[14],M[15],delta[14],delta[15]);
  152. /* BRANCH2(CV,M) */
  153. step(A2,B2,C2,D2,E2,F2,G2,H2,M[14],M[15],delta[15],delta[14]);
  154. step(A2,B2,C2,D2,E2,F2,G2,H2,M[11],M[9],delta[13],delta[12]);
  155. step(A2,B2,C2,D2,E2,F2,G2,H2,M[8],M[10],delta[11],delta[10]);
  156. step(A2,B2,C2,D2,E2,F2,G2,H2,M[3],M[4],delta[9],delta[8]);
  157. step(A2,B2,C2,D2,E2,F2,G2,H2,M[2],M[13],delta[7],delta[6]);
  158. step(A2,B2,C2,D2,E2,F2,G2,H2,M[0],M[5],delta[5],delta[4]);
  159. step(A2,B2,C2,D2,E2,F2,G2,H2,M[6],M[7],delta[3],delta[2]);
  160. step(A2,B2,C2,D2,E2,F2,G2,H2,M[12],M[1],delta[1],delta[0]);
  161. /* BRANCH3(CV,M) */
  162. step(A3,B3,C3,D3,E3,F3,G3,H3,M[7],M[6],delta[1],delta[0]);
  163. step(A3,B3,C3,D3,E3,F3,G3,H3,M[10],M[14],delta[3],delta[2]);
  164. step(A3,B3,C3,D3,E3,F3,G3,H3,M[13],M[2],delta[5],delta[4]);
  165. step(A3,B3,C3,D3,E3,F3,G3,H3,M[9],M[12],delta[7],delta[6]);
  166. step(A3,B3,C3,D3,E3,F3,G3,H3,M[11],M[4],delta[9],delta[8]);
  167. step(A3,B3,C3,D3,E3,F3,G3,H3,M[15],M[8],delta[11],delta[10]);
  168. step(A3,B3,C3,D3,E3,F3,G3,H3,M[5],M[0],delta[13],delta[12]);
  169. step(A3,B3,C3,D3,E3,F3,G3,H3,M[1],M[3],delta[15],delta[14]);
  170. /* BRANCH4(CV,M) */
  171. step(A4,B4,C4,D4,E4,F4,G4,H4,M[5],M[12],delta[14],delta[15]);
  172. step(A4,B4,C4,D4,E4,F4,G4,H4,M[1],M[8],delta[12],delta[13]);
  173. step(A4,B4,C4,D4,E4,F4,G4,H4,M[15],M[0],delta[10],delta[11]);
  174. step(A4,B4,C4,D4,E4,F4,G4,H4,M[13],M[11],delta[8],delta[9]);
  175. step(A4,B4,C4,D4,E4,F4,G4,H4,M[3],M[10],delta[6],delta[7]);
  176. step(A4,B4,C4,D4,E4,F4,G4,H4,M[9],M[2],delta[4],delta[5]);
  177. step(A4,B4,C4,D4,E4,F4,G4,H4,M[7],M[14],delta[2],delta[3]);
  178. step(A4,B4,C4,D4,E4,F4,G4,H4,M[4],M[6],delta[0],delta[1]);
  179. /* output : applying feed-forward */
  180. CV[0] = CV[0] + ((A1 + A2) ^ (A3 + A4));
  181. CV[1] = CV[1] + ((B1 + B2) ^ (B3 + B4));
  182. CV[2] = CV[2] + ((C1 + C2) ^ (C3 + C4));
  183. CV[3] = CV[3] + ((D1 + D2) ^ (D3 + D4));
  184. CV[4] = CV[4] + ((E1 + E2) ^ (E3 + E4));
  185. CV[5] = CV[5] + ((F1 + F2) ^ (F3 + F4));
  186. CV[6] = CV[6] + ((G1 + G2) ^ (G3 + G4));
  187. CV[7] = CV[7] + ((H1 + H2) ^ (H3 + H4));
  188. }/* FORK256_compression_function() */
  189.  
  190.  
  191. #ifdef USEHASHTABLE
  192. /************************ HASH TABLE STUFF ******************************/
  193. /************************ HASH TABLE STUFF ******************************/
  194. /************************ HASH TABLE STUFF ******************************/
  195.  
  196. /**
  197. * Given modular difference diff , determine the set of values for
  198. * strand A in step 7 of branch 1 that can posibly cause a microcollision
  199. * in strand D.
  200. */
  201. void get_allowable_values( WRD diff, WRD allowable[], int * count ) {
  202. WRD x1, y1;
  203. WRD x2, y2;
  204. WRD dz;
  205. FILE * fp;
  206. char fileName[20] = {0};
  207. long fileSize;
  208. /*test if we already have a file with precomputed values
  209. * its name should be allowable-hexdiff.dat
  210. * where hexdiff is 8 hex digits representing the difference diff*/
  211. sprintf(fileName,"allowable-%08x.dat",diff);
  212. fp = fopen(fileName,"r");
  213. if ( fp ) {
  214. /*determine file size*/
  215. printf("Using precomputed file %s. ",fileName);
  216. fseek(fp,0,SEEK_END);
  217. fileSize = ftell(fp);
  218. printf("Size: %ld B (%ld values)\n",fileSize, fileSize/sizeof(WRD));
  219. fseek(fp,0,SEEK_SET);
  220. /*read the data into table */
  221. fread(allowable,fileSize / sizeof(WRD), sizeof(WRD),fp);
  222. fclose(fp);
  223. (*count) = fileSize/sizeof(WRD);
  224. } else {
  225. printf("Precomputing allowable values... Please be patient!\n");
  226. printf("| 0 %% | 50 %% | 100 %%\n");
  227. x1 = 0;
  228. do {
  229. x2 = x1 + diff;
  230. y1 = f(x1);
  231. y2 = f(x2);
  232. dz = g(x1 + delta[12]) ^ g(x2 + delta[12]);
  233.  
  234. if ( micro_possible(ROL(y1,17),ROL(y2,17),ROL(dz,21)) ) {
  235. allowable[*count] = x1;
  236. ++*count;
  237. }
  238. ++x1;
  239. if ( (x1 & 0x3ffffff)==0 ) {
  240. printf("*");
  241. fflush(stdout);
  242. }
  243. } while (x1 != 0);
  244. printf("\nnumber of allowable values is %d\n\n",*count);
  245. fflush(stdout);
  246. /*write precomputed allowable values to the file "allowable-hexdiff.dat"
  247. * where hexdiff is a hexadecimal representation of the difference*/
  248. sprintf(fileName,"allowable-%08x.dat",diff);
  249. fp = fopen(fileName,"w");
  250. fwrite(allowable,(*count),sizeof(WRD),fp);
  251. fclose(fp);
  252. }
  253. }/* get_allowable_values() */
  254.  
  255.  
  256. /** Inserts value H into hash table pointed by hash_table */
  257. void insert_into_hash_table( WRD H, unsigned char hash_table[] ) {
  258. int i;
  259. i = H % HASH_SIZE;
  260. hash_table[i>>3] |= 1 << (i&7);
  261. }/* insert_into_hash_table() */
  262.  
  263.  
  264. /** returns non-zero if the value H is in the hash table hash_table,
  265. * zero if not */
  266. int is_in_hash_table( WRD H, unsigned char hash_table[] ) {
  267. int i = H % HASH_SIZE;
  268. return (hash_table[i>>3] >> (i&7))&1;
  269. } /* is_in_hash_table() */
  270.  
  271.  
  272. /** We want to determine all allowable outputs to the G strand of
  273. * step 5 of branch 1 (note output of G_5 = input to H_6), and store
  274. * these in a hash table.
  275. */
  276. void prepare_hash_table(WRD IV[8], WRD M[16], WRD M12prime, WRD allowable[],
  277. int count, unsigned char hash_table[]) {
  278. WRD A1,B1,C1,D1,E1,F1,G1,H1;
  279. WRD temp, temp2;
  280. WRD A1_1,B1_1,C1_1,D1_1,E1_1,F1_1,G1_1,H1_1;
  281. int i;
  282.  
  283. printf("\nBuilding hash table...");
  284. memset( hash_table, 0, HASH_MEM );
  285.  
  286. A1 = IV[0]; B1 = IV[1]; C1 = IV[2]; D1 = IV[3];
  287. E1 = IV[4]; F1 = IV[5]; G1 = IV[6]; H1 = IV[7];
  288. step(A1,B1,C1,D1,E1,F1,G1,H1,M[0],M[1],delta[0],delta[1]);
  289. step(A1,B1,C1,D1,E1,F1,G1,H1,M[2],M[3],delta[2],delta[3]);
  290. step(A1,B1,C1,D1,E1,F1,G1,H1,M[4],M[5],delta[4],delta[5]);
  291. step(A1,B1,C1,D1,E1,F1,G1,H1,M[6],M[7],delta[6],delta[7]);
  292. step(A1,B1,C1,D1,E1,F1,G1,H1,M[8],M[9],delta[8],delta[9]);
  293. step(A1,B1,C1,D1,E1,F1,G1,H1,M[10],M[11],delta[10],delta[11]);
  294. A1_1 = A1; B1_1 = B1; C1_1 = C1; D1_1 = D1;
  295. E1_1 = E1; F1_1 = F1; G1_1 = G1; H1_1 = H1;
  296. for (i=0; i < count; ++i) {
  297. A1 = allowable[i] - M[12];
  298. B1 = B1_1; C1 = C1_1; D1 = D1_1;
  299. E1 = E1_1; F1 = F1_1; G1 = G1_1; H1 = H1_1;
  300. back(A1,B1,C1,D1,E1,F1,G1,H1,M[10],M[11],delta[10],delta[11]);
  301. insert_into_hash_table( H1, hash_table );
  302. }
  303. printf(" done!\n\n");
  304. fflush(stdout);
  305. }/* prepare_hash_table() */
  306.  
  307.  
  308. void advance_M4( WRD IV[8], WRD M[16], WRD M12prime, WRD allowable[],
  309. int count, unsigned char hash_table[] ) {
  310. ++M[4];
  311. prepare_hash_table( IV, M, M12prime, allowable, count, hash_table );
  312. }/* advance_M4() */
  313.  
  314.  
  315. /** This is a version of derive1 using hash tables. The procedure
  316. * looks for such values of M[4] and M[9] that the difference
  317. * in A6 of branch 1 does not propagate to E7 (single microcollision
  318. * in the third line of the left Q-structure in step 7 of branch 1*/
  319. void derive1hash(WRD CV[8],WRD M[16], WRD M12p, WRD allowable[],
  320. WRD a_count, unsigned char hash_table[] ) {
  321. WRD A,B,C,D,E,F,G,H;
  322. WRD A5,C5,D5,E5,H5;
  323. WRD A6,D6, E7_1=0, E7_2=1;
  324. WRD const1, const2;
  325. WRD temp;
  326. int i;
  327.  
  328. printf("\nsolving for branch 1...\n");
  329.  
  330. do {
  331. A = CV[0]; B = CV[1]; C = CV[2]; D = CV[3];
  332. E = CV[4]; F = CV[5]; G = CV[6]; H = CV[7];
  333. step(A,B,C,D,E,F,G,H,M[0],M[1],delta[0],delta[1]); /* step 1 */
  334. step(A,B,C,D,E,F,G,H,M[2],M[3],delta[2],delta[3]); /* step 2 */
  335. step(A,B,C,D,E,F,G,H,M[4],M[5],delta[4],delta[5]); /* step 3 */
  336. step(A,B,C,D,E,F,G,H,M[6],M[7],delta[6],delta[7]); /* step 4 */
  337. /*precompute necessary registers of step 5 beforehand */
  338. C5 = (B + f(A+M[8])) ^ g(A+M[8]+delta[8]);
  339. D5 = (C + ROL(f(A+M[8]),5)) ^ ROL(g(A+M[8]+delta[8]),9);
  340. E5 = (D + ROL(f(A+M[8]),17)) ^ ROL(g(A+M[8]+delta[8]),21);
  341. const1 = ROL(g(E5+M[11]),21);
  342. const2 = ROL(f(E5+M[11]+delta[11]),17);
  343. do {
  344. H5 = (G + ROL(g(E+M[9]),9)) ^ ROL(f(E+M[9]+delta[9]),5);
  345. /*check hash table */
  346. i = H5 % HASH_SIZE;
  347.  
  348. if ((hash_table[i>>3] >> (i&7))&1) {
  349. /*H_5 is in a hash table: it corresponds to one of the
  350. * allowable values -- so now we need to test it */
  351. A5 = (H + ROL(g(E+M[9]),21)) ^ ROL(f(E+M[9]+delta[9]),17);
  352.  
  353. A6 = (H5 + const1) ^ const2;
  354. D6 = (C5 + ROL(f(A5+M[10]),5)) ^ ROL(g(A5+M[10]+delta[10]),9);
  355.  
  356. E7_1 = (D6 + ROL(f(A6+M[12]),17))^ROL(g(A6+M[12]+delta[12]),21);
  357. E7_2 = (D6 + ROL(f(A6+M12p ),17))^ROL(g(A6+ M12p+delta[12]),21);
  358. if (E7_1 == E7_2) {
  359. printf("M[4] = 0x%.8x; M[9] = 0x%.8x;\n",M[4], M[9]);
  360. break;
  361. /*break out of the inner while loop (modifying M[9])*/
  362. }
  363. }
  364. ++M[9];
  365. } while( M[9] != 0 );
  366. if ( E7_1 != E7_2 ) {
  367. advance_M4( CV, M, M12p, allowable, a_count, hash_table );
  368. }
  369. } while (E7_1 != E7_2);
  370. }/* derive1hash() */
  371.  
  372. /************ END OF HASH TABLE SPECIFIC CODE ****************************/
  373. /************ END OF HASH TABLE SPECIFIC CODE ****************************/
  374. /************ END OF HASH TABLE SPECIFIC CODE ****************************/
  375. #endif /* end of code for variant using hash tables */
  376.  
  377.  
  378. /*** This function advances values of M[4] and M[9] until
  379. * it finds a value that yields zero difference in register
  380. * E after step 7 in branch 1
  381. *
  382. * Optimized version without hash tables */
  383. void derive1opt(WRD CV[8],WRD M[16], WRD M12p) {
  384. WRD A,B,C,D,E,F,G,H;
  385. WRD E7_1, E7_2;
  386. WRD A5, C5, D5, E5, H5;
  387. WRD A6, D6;
  388. WRD const1, const2;
  389. WRD temp;
  390. printf("\nsolving for branch 1...\n");
  391. do {
  392. A = CV[0]; B = CV[1]; C = CV[2]; D = CV[3];
  393. E = CV[4]; F = CV[5]; G = CV[6]; H = CV[7];
  394. step(A,B,C,D,E,F,G,H,M[0],M[1],delta[0],delta[1]); /* step 1*/
  395. step(A,B,C,D,E,F,G,H,M[2],M[3],delta[2],delta[3]); /* step 2*/
  396. step(A,B,C,D,E,F,G,H,M[4],M[5],delta[4],delta[5]); /* step 3*/
  397. step(A,B,C,D,E,F,G,H,M[6],M[7],delta[6],delta[7]); /* step 4*/
  398. C5 = (B + f(A+M[8])) ^ g(A+M[8]+delta[8]);
  399. D5 = (C + ROL(f(A+M[8]),5)) ^ ROL(g(A+M[8]+delta[8]),9);
  400. E5 = (D + ROL(f(A+M[8]),17)) ^ ROL(g(A+M[8]+delta[8]),21);
  401. const1 = ROL(g(E5+M[11]),21);
  402. const2 = ROL(f(E5+M[11]+delta[11]),17);
  403. do {
  404. H5 = (G + ROL(g(E+M[9]), 9)) ^ ROL(f(E+M[9]+delta[9]),5);
  405. A5 = (H + ROL(g(E+M[9]),21)) ^ ROL(f(E+M[9]+delta[9]),17);
  406.  
  407. A6 = (H5 + const1) ^ const2;
  408. D6 = (C5 + ROL(f(A5+M[10]),5)) ^ ROL(g(A5+M[10]+delta[10]),9);
  409.  
  410. E7_1 = (D6 + ROL(f(A6+M[12]),17)) ^ ROL(g(A6+M[12]+delta[12]),21);
  411. E7_2 = (D6 + ROL(f(A6+M12p ),17)) ^ ROL(g(A6+ M12p+delta[12]),21);
  412. if (E7_1 == E7_2) {
  413. printf("M[4] = 0x%.8x; M[9] = 0x%.8x;\n",M[4], M[9]);
  414. break;
  415. }/*if E7_1 == E7_2 */
  416. ++M[9];
  417. } while( M[9] != 0 );
  418. if (E7_1 != E7_2) {
  419. ++M[4];
  420. }
  421. } while (E7_1 != E7_2);
  422.  
  423. }/* derive1opt() */
  424.  
  425.  
  426.  
  427. /*** This function solves for branch 3 */
  428. int derive3(WRD CV[8],WRD M[16], WRD M12p ) {
  429. WRD A3,B3,C3,D3,E3,F3,G3,H3;
  430. WRD A,B,C,D,E,F,G,H;
  431. WRD holdF;
  432. WRD temp, temp2;
  433. WRD origE3;
  434. WRD y1, y2, z1, z2, dz;
  435. WRD ones, zeros;
  436. WRD mem1;
  437.  
  438. printf("\nsolving for branch 3...\n");
  439.  
  440. A3 = CV[0]; B3 = CV[1]; C3 = CV[2]; D3 = CV[3];
  441. E3 = CV[4]; F3 = CV[5]; G3 = CV[6]; H3 = CV[7];
  442. step(A3,B3,C3,D3,E3,F3,G3,H3,M[7],M[6],delta[1],delta[0]);
  443. mem1 = A3 + M[10];
  444. step(A3,B3,C3,D3,E3,F3,G3,H3,M[10],M[14],delta[3],delta[2]);
  445. step(A3,B3,C3,D3,E3,F3,G3,H3,M[13],M[2],delta[5],delta[4]);
  446. origE3 = E3;
  447. do {
  448. y1 = g(E3 + M[12]);
  449. y2 = g(E3 + M12p);
  450. z1 = f(E3 + M[12] + delta[6]);
  451. z2 = f(E3 + M12p + delta[6]);
  452. dz = z1 ^ z2;
  453. if (micro_possible( y1, y2, dz) &&
  454. micro_possible(ROL(y1,9),ROL(y2,9),ROL(dz,5)) &&
  455. micro_possible(ROL(y1,21),ROL(y2,21),ROL(dz,17)) ) {
  456. break;
  457. }
  458. ++E3;
  459. } while (E3 != origE3);
  460.  
  461. if (!( micro_possible( y1, y2, dz) &&
  462. micro_possible(ROL(y1,9),ROL(y2,9),ROL(dz,5)) &&
  463. micro_possible(ROL(y1,21),ROL(y2,21),ROL(dz,17)) )) {
  464. printf("no solution for branch 3!\n");
  465. return 1;
  466. }
  467.  
  468. A = A3; B = B3; C = C3; D = D3; E = E3;
  469. get_ones_and_zeros( y1, y2, z1, z2, &ones, &zeros );
  470. if (y1 > y2)
  471. F = F3 = ones - y1;
  472. else
  473. F = F3 = ones - y2;
  474.  
  475. y1 = ROL(y1,9);
  476. y2 = ROL(y2,9);
  477. z1 = ROL(z1,5);
  478. z2 = ROL(z2,5);
  479. get_ones_and_zeros( y1, y2, z1, z2, &ones, &zeros );
  480. if (y1 > y2)
  481. G = G3 = ones - y1;
  482. else
  483. G = G3 = ones - y2;
  484.  
  485. y1 = ROL(y1,12);
  486. y2 = ROL(y2,12);
  487. z1 = ROL(z1,12);
  488. z2 = ROL(z2,12);
  489. get_ones_and_zeros( y1, y2, z1, z2, &ones, &zeros );
  490. if (y1 > y2)
  491. H = H3 = ones - y1;
  492. else
  493. H = H3 = ones - y2;
  494.  
  495. /* These are the values we want at the beginning of step 3: */
  496. A3 = A; B3 = B; C3 = C; D3 = D; E3 = E; F3 = F; G3 = G; H3 = H;
  497. back(A3,B3,C3,D3,E3,F3,G3,H3,M[13],M[2],delta[5],delta[4]);
  498. back(A3,B3,C3,D3,E3,F3,G3,H3,M[10],M[14],delta[3],delta[2]);
  499. M[6] = F3 - delta[0] - CV[4];
  500. printf("M[6] = 0x%.8x;\n",M[6]);
  501. A3 = CV[0]; B3 = CV[1]; C3 = CV[2]; D3 = CV[3];
  502. E3 = CV[4]; F3 = CV[5]; G3 = CV[6]; H3 = CV[7];
  503. step(A3,B3,C3,D3,E3,F3,G3,H3,M[7],M[6],delta[1],delta[0]);
  504. M[10] = mem1 - A3;
  505. printf("M[10] = 0x%.8x;\n",M[10]);
  506.  
  507. /* These are the values we want at the beginning of step 3: */
  508. A3 = A; B3 = B; C3 = C; D3 = D; E3 = E; F3 = F; G3 = G; H3 = H;
  509. back(A3,B3,C3,D3,E3,F3,G3,H3,M[13],M[2],delta[5],delta[4]);
  510. holdF = F3;
  511. A3 = CV[0]; B3 = CV[1]; C3 = CV[2]; D3 = CV[3];
  512. E3 = CV[4]; F3 = CV[5]; G3 = CV[6]; H3 = CV[7];
  513. step(A3,B3,C3,D3,E3,F3,G3,H3,M[7],M[6],delta[1],delta[0]);
  514. M[14] = holdF - E3 - delta[2];
  515. printf("M[14] = 0x%.8x;\n",M[14]);
  516.  
  517. A3 = CV[0]; B3 = CV[1]; C3 = CV[2]; D3 = CV[3];
  518. E3 = CV[4]; F3 = CV[5]; G3 = CV[6]; H3 = CV[7];
  519. step(A3,B3,C3,D3,E3,F3,G3,H3,M[7],M[6],delta[1],delta[0]);
  520. step(A3,B3,C3,D3,E3,F3,G3,H3,M[10],M[14],delta[3],delta[2]);
  521. M[2] = F - E3 - delta[4];
  522. printf("M[2] = 0x%.8x;\n",M[2]);
  523.  
  524. /* These are the values we want at the beginning of step 3: */
  525. A3 = CV[0]; B3 = CV[1]; C3 = CV[2]; D3 = CV[3];
  526. E3 = CV[4]; F3 = CV[5]; G3 = CV[6]; H3 = CV[7];
  527. step(A3,B3,C3,D3,E3,F3,G3,H3,M[7],M[6],delta[1],delta[0]);
  528. step(A3,B3,C3,D3,E3,F3,G3,H3,M[10],M[14],delta[3],delta[2]);
  529. step(A3,B3,C3,D3,E3,F3,G3,H3,M[13],M[2],delta[5],delta[4]);
  530. E3 = E;
  531. back(A3,B3,C3,D3,E3,F3,G3,H3,M[13],M[2],delta[5],delta[4]);
  532. back(A3,B3,C3,D3,E3,F3,G3,H3,M[10],M[14],delta[3],delta[2]);
  533. back(A3,B3,C3,D3,E3,F3,G3,H3,M[7],M[6],delta[1],delta[0]);
  534. CV[1] = B3;
  535. printf("IV[1] = 0x%.8x;\n",CV[1]);
  536. return 0;
  537. }/* derive3() */
  538.  
  539.  
  540. /*** This function solves for branch4 */
  541. int derive4(WRD CV[8], WRD M[16], WRD M12p, WRD * origE4step3plusM11) {
  542. WRD A4,B4,C4,D4,E4,F4,G4,H4;
  543. WRD A4p,B4p,C4p,D4p,E4p,F4p,G4p,H4p;
  544. WRD temp, temp2;
  545. WRD M3 = 0;
  546. WRD ones, zeros;
  547. WRD B, C, D;
  548. WRD A, E, F, G, H;
  549. WRD z1, z2, dz, y1, y2;
  550. WRD holdB, mem1, mem2;
  551. printf("\nsolving for branch 4...\n");
  552. A4 = A4p = CV[0]; B4 = B4p = CV[1]; C4 = C4p = CV[2]; D4 = D4p = CV[3];
  553. E4 = E4p = CV[4]; F4 = F4p = CV[5]; G4 = G4p = CV[6]; H4 = H4p = CV[7];
  554. step(A4,B4,C4,D4,E4,F4,G4,H4,M[5],M[12],delta[14],delta[15]);
  555. step(A4,B4,C4,D4,E4,F4,G4,H4,M[1],M[8],delta[12],delta[13]);
  556. mem1 = E4 + M[0];
  557. step(A4,B4,C4,D4,E4,F4,G4,H4,M[15],M[0],delta[10],delta[11]);
  558. mem2 = E4 + M[11];
  559. step(A4,B4,C4,D4,E4,F4,G4,H4,M[13],M[11],delta[8],delta[9]);
  560. step(A4p,B4p,C4p,D4p,E4p,F4p,G4p,H4p,M[5],M12p,delta[14],delta[15]);
  561. step(A4p,B4p,C4p,D4p,E4p,F4p,G4p,H4p,M[1],M[8],delta[12],delta[13]);
  562. step(A4p,B4p,C4p,D4p,E4p,F4p,G4p,H4p,M[15],M[0],delta[10],delta[11]);
  563. step(A4p,B4p,C4p,D4p,E4p,F4p,G4p,H4p,M[13],M[11],delta[8],delta[9]);
  564.  
  565. do {
  566. y1 = f( A4 + M3 );
  567. y2 = f( A4p + M3 );
  568. z1 = g( A4 + M3 + delta[6] );
  569. z2 = g( A4p + M3 + delta[6] );
  570. dz = z1 ^ z2;
  571. if (micro_possible( y1, y2, dz) &&
  572. micro_possible(ROL(y1,5),ROL(y2,5),ROL(dz,9)) &&
  573. micro_possible(ROL(y1,17),ROL(y2,17),ROL(dz,21)) )
  574. break;
  575. ++M3;
  576. } while (M3 != 0);
  577.  
  578. if (!(micro_possible( y1, y2, dz) &&
  579. micro_possible(ROL(y1,5),ROL(y2,5),ROL(dz,9)) &&
  580. micro_possible(ROL(y1,17),ROL(y2,17),ROL(dz,21)) )) {
  581. printf("no solution for branch 4!\n");
  582. return 1;
  583. }
  584.  
  585. /* now we want to set up B, C, and D to be what we want by choosing
  586. * the right values for M[8], M[0], and M[11]. */
  587. M[3] = M3;
  588. printf("M[3] = 0x%.8x\n",M[3]);
  589. get_ones_and_zeros( y1, y2, z1, z2, &ones, &zeros );
  590. if (y1 > y2)
  591. B = B4 = B4p = ones - y1;
  592. else
  593. B = B4 = B4p = ones - y2;
  594. y1 = ROL(y1,5);
  595. y2 = ROL(y2,5);
  596. z1 = ROL(z1,9);
  597. z2 = ROL(z2,9);
  598. get_ones_and_zeros( y1, y2, z1, z2, &ones, &zeros );
  599. if (y1 > y2)
  600. C = C4 = C4p = ones - y1;
  601. else
  602. C = C4 = C4p = ones - y2;
  603. y1 = ROL(y1,12);
  604. y2 = ROL(y2,12);
  605. z1 = ROL(z1,12);
  606. z2 = ROL(z2,12);
  607. get_ones_and_zeros( y1, y2, z1, z2, &ones, &zeros );
  608. if (y1 > y2)
  609. D = D4 = D4p = ones - y1;
  610. else
  611. D = D4 = D4p = ones - y2;
  612. A = A4; E = E4; F = F4; G = G4; H = H4;
  613. back(A4,B4,C4,D4,E4,F4,G4,H4,M[13],M[11],delta[8],delta[9]);
  614. back(A4,B4,C4,D4,E4,F4,G4,H4,M[15],M[0],delta[10],delta[11]);
  615. holdB = B4;
  616. A4 = CV[0]; B4 = CV[1]; C4 = CV[2]; D4 = CV[3];
  617. E4 = CV[4]; F4 = CV[5]; G4 = CV[6]; H4 = CV[7];
  618. step(A4,B4,C4,D4,E4,F4,G4,H4,M[5],M[12],delta[14],delta[15]);
  619. /* compute the new M[1]: */
  620. M[1]=holdB-delta[12]-A4;
  621. printf("M[1] = 0x%.8x;\n",M[1]);
  622. /* compute the new M[0]: */
  623. y2 = ROL( f(A4 + M[1]), 17 );
  624. z2 = ROL( g(A4 + M[1] + delta[12]), 21 );
  625. M[0] = mem1 - ((D4 + y2) ^ z2);
  626. printf("M[0] = 0x%.8x;\n",M[0]);
  627.  
  628.  
  629. /* now we go back to the 5th step again and set our variables
  630. * accordingly. then we will step back to determine the new
  631. * m[15], m[11]. */
  632. A4 = A; B4 = B; C4 = C; D4 = D; E4 = E; F4 = F; G4 = G; H4 = H;
  633. back(A4,B4,C4,D4,E4,F4,G4,H4,M[13],M[11],delta[8],delta[9]);
  634. holdB = B4;
  635. A4 = CV[0]; B4 = CV[1]; C4 = CV[2]; D4 = CV[3];
  636. E4 = CV[4]; F4 = CV[5]; G4 = CV[6]; H4 = CV[7];
  637. step(A4,B4,C4,D4,E4,F4,G4,H4,M[5],M[12],delta[14],delta[15]);
  638. step(A4,B4,C4,D4,E4,F4,G4,H4,M[1],M[8],delta[12],delta[13]);
  639. /* compute the new M[15]: */
  640. M[15]=holdB-delta[10]-A4;
  641. printf("M[15] = 0x%.8x;\n",M[15]);
  642. /* compute the new M[11]: */
  643. y2 = ROL( f(A4 + M[15]), 17 );
  644. z2 = ROL( g(A4 + M[15] + delta[10]), 21 );
  645. M[11] = mem2 - ((D4 + y2) ^ z2);
  646. printf("M[11] = 0x%.8x;\n",M[11]);
  647.  
  648. /* Finally we determine new M[13] */
  649. holdB = B;
  650. A4 = CV[0]; B4 = CV[1]; C4 = CV[2]; D4 = CV[3];
  651. E4 = CV[4]; F4 = CV[5]; G4 = CV[6]; H4 = CV[7];
  652. step(A4,B4,C4,D4,E4,F4,G4,H4,M[5],M[12],delta[14],delta[15]);
  653. step(A4,B4,C4,D4,E4,F4,G4,H4,M[1],M[8],delta[12],delta[13]);
  654. step(A4,B4,C4,D4,E4,F4,G4,H4,M[15],M[0],delta[10],delta[11]);
  655. /* compute the new M[13]: */
  656. M[13]=holdB-delta[8]-A4;
  657. printf("M[13] = 0x%.8x;\n",M[13]);
  658.  
  659. A4 = CV[0]; B4 = CV[1]; C4 = CV[2]; D4 = CV[3];
  660. E4 = CV[4]; F4 = CV[5]; G4 = CV[6]; H4 = CV[7];
  661. step(A4,B4,C4,D4,E4,F4,G4,H4,M[5],M[12],delta[14],delta[15]);
  662. step(A4,B4,C4,D4,E4,F4,G4,H4,M[1],M[8],delta[12],delta[13]);
  663. step(A4,B4,C4,D4,E4,F4,G4,H4,M[15],M[0],delta[10],delta[11]);
  664. *origE4step3plusM11 = E4 + M[11];
  665.  
  666. return 0;
  667. }/* derive4() */
  668.  
  669.  
  670. /** Corrects the value of M11 after solving for branch 3 */
  671. void fixM11( WRD CV[8],WRD M[16], WRD origE4step3plusM11 ) {
  672. WRD A4,B4,C4,D4,E4,F4,G4,H4;
  673. WRD temp;
  674. printf("\nfixing M[11]...\n");
  675. A4 = CV[0]; B4 = CV[1]; C4 = CV[2]; D4 = CV[3];
  676. E4 = CV[4]; F4 = CV[5]; G4 = CV[6]; H4 = CV[7];
  677. step(A4,B4,C4,D4,E4,F4,G4,H4,M[5],M[12],delta[14],delta[15]);
  678. step(A4,B4,C4,D4,E4,F4,G4,H4,M[1],M[8],delta[12],delta[13]);
  679. step(A4,B4,C4,D4,E4,F4,G4,H4,M[15],M[0],delta[10],delta[11]);
  680. M[11] = origE4step3plusM11 - E4;
  681. printf("M[11] = 0x%.8x;\n",M[11]);
  682. }/* fixM11() */
  683.  
  684. /** Picks randomly M[12] and necessary constants in IV[5,6,7] */
  685. void choose_M12_and_IV( WRD IV[8], WRD diff, WRD * M12, WRD * M12prime ) {
  686. WRD E;
  687. WRD x1, x2;
  688. WRD y1, y2;
  689. WRD z1, z2, dz;
  690. WRD F, G, H, ones, zeros;
  691. WRD startWith;
  692. printf("\nsolving for IV[5,6,7] and M[12]...\n");
  693. fflush(stdout);
  694. E = IV[4];
  695. /* *M12 = 0x1811f2d9; */
  696. /*choosing a random value from the set of candidates for M12 */
  697. startWith = RANDOM_WORD;
  698. *M12 = startWith;
  699. do {
  700. x1 = E + *M12;
  701. x2 = E + *M12 + diff;
  702. y1 = g(x1);
  703. y2 = g(x2);
  704. z1 = f((x1+delta[15]));
  705. z2 = f((x2+delta[15]));
  706. dz = z1 ^ z2;
  707. if (micro_possible( y1, y2, dz) &&
  708. micro_possible(ROL(y1,9),ROL(y2,9),ROL(dz,5)) &
  709. micro_possible(ROL(y1,21),ROL(y2,21),ROL(dz,17)) ) {
  710. get_ones_and_zeros( y1, y2, z1, z2, &ones, &zeros );
  711. if (y1 > y2)
  712. F = ones - y1;
  713. else
  714. F = ones - y2;
  715. y1 = ROL(y1,9);
  716. y2 = ROL(y2,9);
  717. z1 = ROL(z1,5);
  718. z2 = ROL(z2,5);
  719. get_ones_and_zeros( y1, y2, z1, z2, &ones, &zeros );
  720. if (y1 > y2)
  721. G = ones - y1;
  722. else
  723. G = ones - y2;
  724. y1 = ROL(y1,12);
  725. y2 = ROL(y2,12);
  726. z1 = ROL(z1,12);
  727. z2 = ROL(z2,12);
  728. get_ones_and_zeros( y1, y2, z1, z2, &ones, &zeros );
  729. if (y1 > y2)
  730. H = ones - y1;
  731. else
  732. H = ones - y2;
  733. *M12prime = *M12 + diff;
  734. printf("M[12] = 0x%.8x;\n M12p = 0x%.8x;\n",*M12,*M12prime);
  735. printf("IV[5] = 0x%.8x\n",F);
  736. IV[5] = F;
  737. printf("IV[6] = 0x%.8x\n",G);
  738. IV[6] = G;
  739. printf("IV[7] = 0x%.8x\n",H);
  740. IV[7] = H;
  741. return;
  742. }
  743. (*M12)++;
  744. } while ( (*M12) != startWith );
  745. /* If we are here, no microcollision could be found for this additive
  746. * difference, something is wrong! */
  747. printf("Illegal input difference!\n");
  748. exit(1);
  749. }/* choose_M12_and_IV() */
  750.  
  751.  
  752. int main(int argc, char * argv[]) {
  753. int i,hmwt;
  754. WRD IV[8] = {
  755. 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
  756. 0x510e527f, 0x70852362, 0x923cf4a3, 0x4f4a3124
  757. };
  758. WRD M[16], CV1[8], CV2[8], M12prime, M12;
  759. WRD origE4step3plusM11;
  760. WRD out_diff[8];
  761. int seed = 0;
  762. FILE *fp;
  763. WRD diff = 0x22f80000;
  764. /*WRD diff = 0xdd080000;*/
  765. /*WRD diff = 0x5a100000;*/
  766. int num_sols = 0;
  767. double count = 0.0;
  768. WRD startM4 = 0xfeefffff; /* to store the initial value of M4 we start with */
  769. const int MAXWT = 38; /* maximum weight of output diffs we want to output */
  770. double globalCPUtimederive1 = 0; /*total CPU time spent in derive1() */
  771. clock_t clockStart, clockEnd;
  772. char filename[1024];
  773. #ifdef USEHASHTABLE
  774. WRD * allowable = malloc( (1<<22)*sizeof(WRD) );
  775. int a_count = 0;
  776. unsigned char * hash_table = malloc( (HASH_SIZE + 7)/8 );
  777. HASH_MEM = (HASH_SIZE + 7)/8;
  778. #endif
  779.  
  780. /* pseudorandom numbers are used in
  781. * - choose_M12_and_IV() to pick a random value of M12 from the
  782. * set of potentially producing microcollision
  783. * - before derive1() to initialize some message words */
  784.  
  785. /* if possible, read the seed from first command-line parameter */
  786. if ((argc > 1) && (sscanf(argv[1],"%d",&seed)>0) ) {
  787. printf("Using seed : %d \n",seed);
  788. } else {
  789. /*if not, read the seed from the input*/
  790. printf("\n\n\nEnter seed: ");
  791. fflush(stdout);
  792. scanf("%d",&seed);
  793. }
  794. srand(seed);
  795.  
  796. sprintf(filename,"solutions%d.txt",seed);
  797.  
  798. #ifdef USEHASHTABLE
  799. get_allowable_values( diff, allowable, &a_count );
  800. #endif
  801. choose_M12_and_IV( IV, diff, &M12, &M12prime );
  802. /* set up first message */
  803. for (i=0; i < 16; ++i) {
  804. M[i] = 0;
  805. }
  806. M[12] = M12;
  807. M[4] = startM4; /* start is possible from arbitrary value of M[4] */
  808.  
  809. do {
  810. M[1] = RANDOM_WORD;
  811. M[15] = RANDOM_WORD;
  812. M[13] = RANDOM_WORD;
  813. M[8] = RANDOM_WORD;
  814. M[0] = RANDOM_WORD;
  815. M[11] = RANDOM_WORD;
  816. /* pick random words until it is possible to solve for
  817. * branches 4 and 3 */
  818. } while(derive4(IV, M, M12prime, &origE4step3plusM11 ) ||
  819. derive3(IV, M, M12prime ) );
  820.  
  821. fixM11( IV, M, origE4step3plusM11 );
  822.  
  823. #ifdef USEHASHTABLE
  824. prepare_hash_table( IV, M, M12prime, allowable, a_count, hash_table );
  825. #endif
  826.  
  827. do { /* main loop that goes through M[4] and M[9] and find near-colls */
  828. clockStart = clock();
  829. /* find near-collision */
  830. #ifdef USEHASHTABLE
  831. derive1hash( IV, M, M12prime, allowable, a_count, hash_table );
  832. #else
  833. derive1opt( IV, M, M12prime );
  834. #endif
  835. clockEnd = clock();
  836. globalCPUtimederive1 += ((double) (clockEnd-clockStart))/CLOCKS_PER_SEC;
  837. /* compute the first hash */
  838. for (i=0; i < 8; ++i){
  839. CV1[i] = IV[i];
  840. }
  841. FORK256_compression_function( CV1, M );
  842. /* compute the second hash */
  843. M[12] = M12prime;
  844. for (i=0; i < 8; ++i){
  845. CV2[i] = IV[i];
  846. }
  847. FORK256_compression_function( CV2, M );
  848. /* compute the difference of hashes and its Hamming weight */
  849. hmwt = 0;
  850. for (i=0; i < 8; ++i) {
  851. out_diff[i] = CV1[i] ^ CV2[i];
  852. hmwt += hammingWeight(out_diff[i]);
  853. }
  854. /* print to the solutions file hashes with weight less than MAXWT only */
  855. if ( hmwt < MAXWT ) {
  856. fp = fopen(filename,"a");
  857. /* print IV */
  858. fprintf(fp, " IV: ");
  859. for (i=0; i < 8; ++i) {
  860. fprintf(fp,"%.8x ",IV[i]);
  861. }
  862. fprintf(fp,"\n");
  863. /* print the first message */
  864. fprintf(fp, " M: ");
  865. for (i=0; i < 16; ++i) {
  866. fprintf(fp,"%.8x ",M[i]);
  867. }
  868. fprintf(fp,"\n");
  869. /* print M[12] of the second message */
  870. fprintf(fp, "M12': %.8x\n",M12prime);
  871. /* print the first hash */
  872. fprintf(fp, " H1: ");
  873. for (i=0; i < 8; ++i) {
  874. fprintf(fp,"%.8x ",CV1[i]);
  875. }
  876. fprintf(fp,"\n");
  877. /* print the second hash */
  878. fprintf(fp, " H2: ");
  879. for (i=0; i < 8; ++i) {
  880. fprintf(fp,"%.8x ",CV2[i]);
  881. }
  882. fprintf(fp,"\n");
  883. /* print the difference */
  884. fprintf(fp,"diff: ");
  885. for (i=0; i < 8; ++i) {
  886. fprintf(fp,"%.8x ",out_diff[i]);
  887. }
  888. fprintf(fp,"\n");
  889. fprintf(fp,"\nHamming weight of difference is %d\n\n",hmwt);
  890. fclose(fp);
  891. }/*end of printing to solutions file */
  892. ++num_sols;
  893. count = 4294967296.0 * (M[4]-startM4) + (double) M[9];
  894.  
  895. printf("\nSOLUTION NO %d FOUND!!! time %.2f \n\n",num_sols, ((double) (clockEnd-clockStart))/CLOCKS_PER_SEC);
  896. printf("Hamming weight of difference is %d\n\n",hmwt);
  897. printf("observed probability of passing branch1 is about 2^%.4f\n",
  898. (log(num_sols/count)/log(2)) );
  899. fflush(stdout);
  900. if ((++M[9]) == 0)
  901. ++M[4];
  902. M[12] = M12;
  903.  
  904. } while ( num_sols < 50 ); /* change "while ( num_sols<50 )" to "while ( 1 )" for an infinite loop */
  905. #ifdef USEHASHTABLE
  906. free( allowable );
  907. free( hash_table );
  908. #endif
  909. printf ("\nTotal time spent in derive1() : %.2f s\n",globalCPUtimederive1);
  910. printf ("Average time for a single derive1(): %.3f s\n",globalCPUtimederive1/num_sols);
  911. return 0;
  912. }/*main()*/
  913.  
  914.